This source file includes following definitions.
- ultrastor_detect
- ultrastor_info
- build_sg_list
- ultrastor_queuecommand
- ultrastor_abort
- ultrastor_reset
- ultrastor_biosparam
- ultrastor_interrupt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #include <linux/stddef.h>
43 #include <linux/string.h>
44 #include <linux/sched.h>
45 #include <linux/kernel.h>
46
47 #include <asm/io.h>
48 #include <asm/system.h>
49 #include <asm/dma.h>
50
51 #define ULTRASTOR_PRIVATE
52 #include "../blk.h"
53 #include "scsi.h"
54 #include "hosts.h"
55 #include "ultrastor.h"
56
57 #define ULTRASTOR_DEBUG 0
58
59 #define VERSION "1.1 alpha"
60
61 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
62 #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
63
64
65
66
67 typedef struct {
68 unsigned char bytes[4];
69 } Longword;
70
71
72
73 struct config_1 {
74 unsigned char bios_segment: 3;
75 unsigned char removable_disks_as_fixed: 1;
76 unsigned char interrupt: 2;
77 unsigned char dma_channel: 2;
78 };
79 struct config_2 {
80 unsigned char ha_scsi_id: 3;
81 unsigned char mapping_mode: 2;
82 unsigned char bios_drive_number: 1;
83 unsigned char tfr_port: 2;
84 };
85
86
87
88 struct config {
89 const void *bios_segment;
90 unsigned short port_address;
91 unsigned char interrupt: 4;
92 unsigned char dma_channel: 3;
93 unsigned char bios_drive_number: 1;
94 unsigned char heads;
95 unsigned char sectors;
96 unsigned char ha_scsi_id: 3;
97 unsigned char subversion: 4;
98 };
99
100
101
102 struct mscp {
103 unsigned char opcode: 3;
104 unsigned char xdir: 2;
105 unsigned char dcn: 1;
106 unsigned char ca: 1;
107 unsigned char sg: 1;
108 unsigned char target_id: 3;
109 unsigned char ch_no: 2;
110 unsigned char lun: 3;
111 Longword transfer_data;
112 Longword transfer_data_length;
113 Longword command_link;
114 unsigned char scsi_command_link_id;
115 unsigned char number_of_sg_list;
116 unsigned char length_of_sense_byte;
117 unsigned char length_of_scsi_cdbs;
118 unsigned char scsi_cdbs[12];
119 unsigned char adapter_status;
120 unsigned char target_status;
121 Longword sense_data;
122 };
123
124
125 typedef struct {
126 unsigned long address;
127 unsigned long num_bytes;
128 } ultrastor_sg_list;
129
130
131 int mscp_free = TRUE;
132
133
134 static const void *const bios_segment_table_14f[8] = {
135 NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
136 (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
137 };
138
139
140 static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 };
141
142
143 static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
144
145
146 static const struct {
147 unsigned char heads;
148 unsigned char sectors;
149 } mapping_table_14f[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
150
151
152 static const char *const subversion_names[] = { "14F", "34F" };
153
154
155 static struct config config;
156
157
158 static int host_number;
159
160
161 #ifdef PORT_OVERRIDE
162 # define PORT_ADDRESS PORT_OVERRIDE
163 #else
164 # define PORT_ADDRESS (config.port_address)
165 #endif
166
167 static volatile int aborted = 0;
168
169 #ifndef PORT_OVERRIDE
170
171 static const unsigned short ultrastor_ports_14f[] = {
172 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,
173 };
174 #endif
175
176 static void ultrastor_interrupt(int cpl);
177 static inline void build_sg_list(Scsi_Cmnd *SCpnt);
178
179 static void (*ultrastor_done)(Scsi_Cmnd *) = 0;
180 static Scsi_Cmnd *SCint = NULL;
181
182 int ultrastor_detect(int hostnum)
183 {
184 size_t i;
185 unsigned char in_byte, version_byte = 0;
186 struct config_1 config_1;
187 struct config_2 config_2;
188
189 #if (ULTRASTOR_DEBUG & UD_DETECT)
190 printk("US14F: detect: called\n");
191 #endif
192
193 #ifndef PORT_OVERRIDE
194 PORT_ADDRESS = 0;
195 for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
196 PORT_ADDRESS = ultrastor_ports_14f[i];
197 #endif
198
199 #if (ULTRASTOR_DEBUG & UD_DETECT)
200 printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
201 #endif
202
203 in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
204 if (in_byte != US14F_PRODUCT_ID_0) {
205 #if (ULTRASTOR_DEBUG & UD_DETECT)
206 # ifdef PORT_OVERRIDE
207 printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
208 # else
209 printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
210 # endif
211 #endif
212 #ifdef PORT_OVERRIDE
213 return FALSE;
214 #else
215 continue;
216 #endif
217 }
218 in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
219
220 if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
221 #if (ULTRASTOR_DEBUG & UD_DETECT)
222 # ifdef PORT_OVERRIDE
223 printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
224 # else
225 printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
226 # endif
227 #endif
228 #ifdef PORT_OVERRIDE
229 return FALSE;
230 #else
231 continue;
232 #endif
233 }
234 version_byte = in_byte;
235 #ifndef PORT_OVERRIDE
236 break;
237 }
238 if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
239 # if (ULTRASTOR_DEBUG & UD_DETECT)
240 printk("US14F: detect: no port address found!\n");
241 # endif
242 return FALSE;
243 }
244 #endif
245
246 #if (ULTRASTOR_DEBUG & UD_DETECT)
247 printk("US14F: detect: adapter found at port address %03X\n",
248 PORT_ADDRESS);
249 #endif
250
251
252
253 *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
254 *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
255 config.bios_segment = bios_segment_table_14f[config_1.bios_segment];
256 config.interrupt = interrupt_table_14f[config_1.interrupt];
257 config.ha_scsi_id = config_2.ha_scsi_id;
258 config.heads = mapping_table_14f[config_2.mapping_mode].heads;
259 config.sectors = mapping_table_14f[config_2.mapping_mode].sectors;
260 config.bios_drive_number = config_2.bios_drive_number;
261 config.subversion = (version_byte & 0x0F);
262 if (config.subversion == U34F)
263 config.dma_channel = 0;
264 else
265 config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
266
267 if (!config.bios_segment) {
268 #if (ULTRASTOR_DEBUG & UD_DETECT)
269 printk("US14F: detect: not detected.\n");
270 #endif
271 return FALSE;
272 }
273
274
275 if (config.subversion != U34F)
276 if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
277 #if (ULTRASTOR_DEBUG & UD_DETECT)
278 printk("US14F: detect: consistancy check failed\n");
279 #endif
280 return FALSE;
281 }
282
283
284
285
286
287
288 #if (ULTRASTOR_DEBUG & UD_DETECT)
289 printk("US14F: detect: detect succeeded\n"
290 " Port address: %03X\n"
291 " BIOS segment: %05X\n"
292 " Interrupt: %u\n"
293 " DMA channel: %u\n"
294 " H/A SCSI ID: %u\n"
295 " Subversion: %u\n",
296 PORT_ADDRESS, config.bios_segment, config.interrupt,
297 config.dma_channel, config.ha_scsi_id, config.subversion);
298 #endif
299 host_number = hostnum;
300 scsi_hosts[hostnum].this_id = config.ha_scsi_id;
301 scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);
302
303 if (request_irq(config.interrupt, ultrastor_interrupt)) {
304 printk("Unable to allocate IRQ%u for UltraStor controller.\n",
305 config.interrupt);
306 return FALSE;
307 }
308 if (config.dma_channel && request_dma(config.dma_channel)) {
309 printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
310 config.dma_channel);
311 free_irq(config.interrupt);
312 return FALSE;
313 }
314 scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
315 printk("UltraStor: scatter/gather enabled. Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG);
316
317 return TRUE;
318 }
319
320 const char *ultrastor_info(void)
321 {
322 static char buf[64];
323
324 (void)sprintf(buf, "UltraStor %s SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
325 ((config.subversion < ARRAY_SIZE(subversion_names))
326 ? subversion_names[config.subversion] : "14F?"),
327 PORT_ADDRESS, (int)config.bios_segment, config.interrupt,
328 config.dma_channel);
329 return buf;
330 }
331
332 static struct mscp mscp = {
333 OP_SCSI, DTD_SCSI, 0, 1, 0
334 };
335
336 static inline void build_sg_list(Scsi_Cmnd *SCpnt)
337 {
338 ultrastor_sg_list *sglist;
339 struct scatterlist *sl;
340 long transfer_length = 0;
341 int i;
342
343 sl = (struct scatterlist *) SCpnt->request_buffer;
344 SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
345 if (SCpnt->host_scribble == NULL)
346
347 panic("US14F: Can't allocate DMA buffer for scatter-gather list!\n");
348
349 sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
350 for (i = 0; i < SCpnt->use_sg; i++) {
351 sglist[i].address = sl[i].address;
352 sglist[i].num_bytes = sl[i].length;
353 transfer_length += sl[i].length;
354 }
355 mscp.number_of_sg_list = (char) SCpnt->use_sg;
356 mscp.transfer_data = *(Longword *)&sglist;
357
358
359 mscp.transfer_data_length = *(Longword *)&transfer_length;
360 }
361
362 int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
363 {
364 unsigned char in_byte;
365
366 #if (ULTRASTOR_DEBUG & UD_COMMAND)
367 printk("US14F: queuecommand: called\n");
368 #endif
369
370
371
372
373
374
375 while (1) {
376 cli();
377 if (mscp_free) {
378 mscp_free = FALSE;
379 sti();
380 break;
381 }
382 sti();
383 }
384 mscp.opcode = OP_SCSI;
385 mscp.xdir = DTD_SCSI;
386 mscp.dcn = FALSE;
387
388
389
390
391
392
393
394 mscp.ca = scsi_devices[SCpnt->index].type != TYPE_TAPE;
395 mscp.target_id = SCpnt->target;
396 mscp.ch_no = 0;
397 mscp.lun = SCpnt->lun;
398 if (SCpnt->use_sg) {
399
400 mscp.sg = TRUE;
401 build_sg_list(SCpnt);
402 }
403 else {
404
405 mscp.sg = FALSE;
406 mscp.transfer_data = *(Longword *)&SCpnt->request_buffer;
407 mscp.transfer_data_length = *(Longword *)&SCpnt->request_bufflen;
408 SCpnt->host_scribble = NULL;
409 }
410 memset(&mscp.command_link, 0, sizeof(mscp.command_link));
411 mscp.scsi_command_link_id = 0;
412 mscp.length_of_sense_byte = 0;
413 mscp.length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
414 memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
415 mscp.adapter_status = 0;
416 mscp.target_status = 0;
417 memset(&mscp.sense_data, 0, sizeof(mscp.sense_data));
418
419
420 do
421 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
422 while (!aborted && (in_byte & 1));
423 if (aborted) {
424 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
425 printk("US14F: queuecommand: aborted\n");
426 #endif
427
428 return (aborted << 16);
429 }
430
431
432 outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
433 outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
434 outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
435 outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
436
437
438 outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
439
440 ultrastor_done = done;
441 SCint = SCpnt;
442
443 #if (ULTRASTOR_DEBUG & UD_COMMAND)
444 printk("US14F: queuecommand: returning\n");
445 #endif
446
447 return 0;
448 }
449
450 int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
451 {
452 #if (ULTRASTOR_DEBUG & UD_ABORT)
453 printk("US14F: abort: called\n");
454 #endif
455
456 aborted = (code ? code : DID_ABORT);
457
458
459 if (SCpnt->host_scribble)
460 scsi_free(SCpnt->host_scribble, 512);
461
462
463 mscp_free = TRUE;
464
465 #if (ULTRASTOR_DEBUG & UD_ABORT)
466 printk("US14F: abort: returning\n");
467 #endif
468
469 return 0;
470 }
471
472 int ultrastor_reset(void)
473 {
474 #if 0
475 unsigned char in_byte;
476 #endif
477
478 #if (ULTRASTOR_DEBUG & UD_RESET)
479 printk("US14F: reset: called\n");
480 #endif
481
482
483 #if 0
484
485 outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
486
487
488 do
489 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
490 while (in_byte & 0x20);
491
492 aborted = DID_RESET;
493 #endif
494
495 #if (ULTRASTOR_DEBUG & UD_RESET)
496 printk("US14F: reset: returning\n");
497 #endif
498 return 0;
499 }
500
501 int ultrastor_biosparam(int size, int dev, int *ip)
502 {
503 unsigned int s = config.heads * config.sectors;
504
505 ip[0] = config.heads;
506 ip[1] = config.sectors;
507 ip[2] = (size + (s - 1)) / s;
508
509
510 return 0;
511 }
512
513 static void ultrastor_interrupt(int cpl)
514 {
515 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
516 printk("US14F: interrupt: called: status = %08X\n",
517 (mscp.adapter_status << 16) | mscp.target_status);
518 #endif
519
520 if (ultrastor_done == 0)
521 panic("US14F: interrupt: unexpected interrupt");
522 else {
523 void (*done)(Scsi_Cmnd *);
524 Scsi_Cmnd *SCtmp;
525
526
527
528
529 done = ultrastor_done;
530 ultrastor_done = 0;
531 SCtmp = SCint;
532
533
534 outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
535
536
537
538 SCtmp->result = (mscp.adapter_status << 16) | mscp.target_status;
539
540
541 if (SCtmp->host_scribble)
542 scsi_free(SCtmp->host_scribble, 512);
543
544
545 mscp_free = TRUE;
546
547 done(SCtmp);
548 }
549
550 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
551 printk("US14F: interrupt: returning\n");
552 #endif
553 }