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 Longword address;
127 Longword 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 = 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 = *(Longword *)&(sl[i].address);
352 sglist[i].num_bytes = *(Longword *)&(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 mscp.ca = TRUE;
388 mscp.target_id = SCpnt->target;
389 mscp.ch_no = 0;
390 mscp.lun = SCpnt->lun;
391 if (SCpnt->use_sg) {
392
393 mscp.sg = TRUE;
394 build_sg_list(SCpnt);
395 }
396 else {
397
398 mscp.sg = FALSE;
399 mscp.transfer_data = *(Longword *)&SCpnt->request_buffer;
400 mscp.transfer_data_length = *(Longword *)&SCpnt->request_bufflen;
401 SCpnt->host_scribble = NULL;
402 }
403 memset(&mscp.command_link, 0, sizeof(mscp.command_link));
404 mscp.scsi_command_link_id = 0;
405 mscp.length_of_sense_byte = 0;
406 mscp.length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
407 memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
408 mscp.adapter_status = 0;
409 mscp.target_status = 0;
410 memset(&mscp.sense_data, 0, sizeof(mscp.sense_data));
411
412
413 do
414 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
415 while (!aborted && (in_byte & 1));
416 if (aborted) {
417 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
418 printk("US14F: queuecommand: aborted\n");
419 #endif
420
421 return (aborted << 16);
422 }
423
424
425 outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
426 outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
427 outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
428 outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
429
430
431 outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
432
433 ultrastor_done = done;
434 SCint = SCpnt;
435
436 #if (ULTRASTOR_DEBUG & UD_COMMAND)
437 printk("US14F: queuecommand: returning\n");
438 #endif
439
440 return 0;
441 }
442
443 int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
444 {
445 #if (ULTRASTOR_DEBUG & UD_ABORT)
446 printk("US14F: abort: called\n");
447 #endif
448
449 aborted = (code ? code : DID_ABORT);
450
451
452 if (SCpnt->host_scribble)
453 scsi_free(SCpnt->host_scribble, 512);
454
455
456 mscp_free = TRUE;
457
458 #if (ULTRASTOR_DEBUG & UD_ABORT)
459 printk("US14F: abort: returning\n");
460 #endif
461
462 return 0;
463 }
464
465 int ultrastor_reset(void)
466 {
467 #if 0
468 unsigned char in_byte;
469 #endif
470
471 #if (ULTRASTOR_DEBUG & UD_RESET)
472 printk("US14F: reset: called\n");
473 #endif
474
475
476 #if 0
477
478 outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
479
480
481 do
482 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
483 while (in_byte & 0x20);
484
485 aborted = DID_RESET;
486 #endif
487
488 #if (ULTRASTOR_DEBUG & UD_RESET)
489 printk("US14F: reset: returning\n");
490 #endif
491 return 0;
492 }
493
494 int ultrastor_biosparam(int size, int dev, int *info)
495 {
496 unsigned int s = config.heads * config.sectors;
497
498 info[0] = config.heads;
499 info[1] = config.sectors;
500 info[2] = (size + (s - 1)) / s;
501
502
503 return 0;
504 }
505
506 static void ultrastor_interrupt(int cpl)
507 {
508 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
509 printk("US14F: interrupt: called: status = %08X\n",
510 (mscp.adapter_status << 16) | mscp.target_status);
511 #endif
512
513 if (ultrastor_done == 0)
514 panic("US14F: interrupt: unexpected interrupt");
515 else {
516 void (*done)(Scsi_Cmnd *);
517 Scsi_Cmnd *SCtmp;
518
519
520
521
522 done = ultrastor_done;
523 ultrastor_done = 0;
524 SCtmp = SCint;
525
526
527 outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
528
529
530
531 SCtmp->result = (mscp.adapter_status << 16) | mscp.target_status;
532
533
534 if (SCtmp->host_scribble)
535 scsi_free(SCtmp->host_scribble, 512);
536
537
538 mscp_free = TRUE;
539
540 done(SCtmp);
541 }
542
543 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
544 printk("US14F: interrupt: returning\n");
545 #endif
546 }