This source file includes following definitions.
- ultrastor_14f_detect
- ultrastor_14f_info
- ultrastor_14f_queuecommand
- ultrastor_14f_command
- ultrastor_14f_abort
- ultrastor_14f_reset
- ultrastor_interrupt_service
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 #include <linux/config.h>
38
39 #ifdef CONFIG_SCSI_ULTRASTOR
40
41 #include <linux/stddef.h>
42 #include <linux/string.h>
43 #include <linux/sched.h>
44 #include <linux/kernel.h>
45
46 #include <asm/io.h>
47 #include <asm/system.h>
48
49 #define ULTRASTOR_PRIVATE
50 #include "ultrastor.h"
51 #include "scsi.h"
52 #include "hosts.h"
53
54 #define VERSION "1.0 beta"
55
56 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
57 #define BIT(n) (1ul << (n))
58 #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
59
60
61
62
63 typedef struct {
64 unsigned char bytes[4];
65 } Longword;
66
67
68
69 struct config_1 {
70 unsigned char bios_segment: 3;
71 unsigned char reserved: 1;
72 unsigned char interrupt: 2;
73 unsigned char dma_channel: 2;
74 };
75 struct config_2 {
76 unsigned char ha_scsi_id: 3;
77 unsigned char mapping_mode: 2;
78 unsigned char bios_drive_number: 1;
79 unsigned char tfr_port: 2;
80 };
81
82
83
84 struct config {
85 unsigned short port_address;
86 const void *bios_segment;
87 unsigned char interrupt: 4;
88 unsigned char dma_channel: 3;
89 unsigned char ha_scsi_id: 3;
90 unsigned char heads: 6;
91 unsigned char sectors: 6;
92 unsigned char bios_drive_number: 1;
93 };
94
95
96
97 struct mscp {
98 unsigned char opcode: 3;
99 unsigned char xdir: 2;
100 unsigned char dcn: 1;
101 unsigned char ca: 1;
102 unsigned char sg: 1;
103 unsigned char target_id: 3;
104 unsigned char ch_no: 2;
105 unsigned char lun: 3;
106 Longword transfer_data;
107 Longword transfer_data_length;
108 Longword command_link;
109 unsigned char scsi_command_link_id;
110 unsigned char number_of_sg_list;
111 unsigned char length_of_sense_byte;
112 unsigned char length_of_scsi_cdbs;
113 unsigned char scsi_cdbs[12];
114 unsigned char adapter_status;
115 unsigned char target_status;
116 Longword sense_data;
117 };
118
119
120 static const void *const bios_segment_table[8] = {
121 NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
122 (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
123 };
124
125
126 static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
127
128
129 static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
130
131
132 static const struct {
133 unsigned char heads;
134 unsigned char sectors;
135 } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
136
137
138 static struct config config;
139
140
141 static int host_number;
142
143
144 #ifdef PORT_OVERRIDE
145 # define PORT_ADDRESS PORT_OVERRIDE
146 #else
147 # define PORT_ADDRESS (config.port_address)
148 #endif
149
150 static volatile int aborted = 0;
151
152 #ifndef PORT_OVERRIDE
153 static const unsigned short ultrastor_ports[] = {
154 0x330, 0x340, 0x310, 0x230, 0x240, 0x210, 0x130, 0x140,
155 };
156 #endif
157
158 void ultrastor_interrupt(void);
159
160 static void (*ultrastor_done)(int, int) = 0;
161
162 static const struct {
163 const char *signature;
164 size_t offset;
165 size_t length;
166 } signatures[] = {
167 { "SBIOS 1.01 COPYRIGHT (C) UltraStor Corporation,1990-1992.", 0x10, 57 },
168 };
169
170 int ultrastor_14f_detect(int hostnum)
171 {
172 size_t i;
173 unsigned char in_byte;
174 struct config_1 config_1;
175 struct config_2 config_2;
176
177 #if (ULTRASTOR_DEBUG & UD_DETECT)
178 printk("US14F: detect: called\n");
179 #endif
180
181 #ifndef PORT_OVERRIDE
182 PORT_ADDRESS = 0;
183 for (i = 0; i < ARRAY_SIZE(ultrastor_ports); i++) {
184 PORT_ADDRESS = ultrastor_ports[i];
185 #endif
186
187 #if (ULTRASTOR_DEBUG & UD_DETECT)
188 printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
189 #endif
190
191 in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
192 if (in_byte != US14F_PRODUCT_ID_0) {
193 #if (ULTRASTOR_DEBUG & UD_DETECT)
194 # ifdef PORT_OVERRIDE
195 printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
196 # else
197 printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
198 # endif
199 #endif
200 #ifdef PORT_OVERRIDE
201 return FALSE;
202 #else
203 continue;
204 #endif
205 }
206 in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
207
208 if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
209 #if (ULTRASTOR_DEBUG & UD_DETECT)
210 # ifdef PORT_OVERRIDE
211 printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
212 # else
213 printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
214 # endif
215 #endif
216 #ifdef PORT_OVERRIDE
217 return FALSE;
218 #else
219 continue;
220 #endif
221 }
222 #ifndef PORT_OVERRIDE
223 break;
224 }
225 if (i == ARRAY_SIZE(ultrastor_ports)) {
226 # if (ULTRASTOR_DEBUG & UD_DETECT)
227 printk("US14F: detect: no port address found!\n");
228 # endif
229 return FALSE;
230 }
231 #endif
232
233 #if (ULTRASTOR_DEBUG & UD_DETECT)
234 printk("US14F: detect: adapter found at port address %03X\n",
235 PORT_ADDRESS);
236 #endif
237
238
239
240 *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
241 *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
242 config.bios_segment = bios_segment_table[config_1.bios_segment];
243 config.interrupt = interrupt_table[config_1.interrupt];
244 config.dma_channel = dma_channel_table[config_1.dma_channel];
245 config.ha_scsi_id = config_2.ha_scsi_id;
246 config.heads = mapping_table[config_2.mapping_mode].heads;
247 config.sectors = mapping_table[config_2.mapping_mode].sectors;
248 config.bios_drive_number = config_2.bios_drive_number;
249
250
251
252 if (config.bios_segment != NULL) {
253 int found = 0;
254
255 for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
256 if (memcmp((char *)config.bios_segment + signatures[i].offset,
257 signatures[i].signature, signatures[i].length))
258 found = 1;
259 if (!found)
260 config.bios_segment = NULL;
261 }
262 if (!config.bios_segment) {
263 #if (ULTRASTOR_DEBUG & UD_DETECT)
264 printk("US14F: detect: not detected.\n");
265 #endif
266 return FALSE;
267 }
268
269
270 if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
271 #if (ULTRASTOR_DEBUG & UD_DETECT)
272 printk("US14F: detect: consistancy check failed\n");
273 #endif
274 return FALSE;
275 }
276
277
278
279
280
281
282 #if (ULTRASTOR_DEBUG & UD_DETECT)
283 printk("US14F: detect: detect succeeded\n"
284 " Port address: %03X\n"
285 " BIOS segment: %05X\n"
286 " Interrupt: %u\n"
287 " DMA channel: %u\n"
288 " H/A SCSI ID: %u\n",
289 PORT_ADDRESS, config.bios_segment, config.interrupt,
290 config.dma_channel, config.ha_scsi_id);
291 #endif
292 host_number = hostnum;
293 scsi_hosts[hostnum].this_id = config.ha_scsi_id;
294 #ifndef NO_QUEUEING
295 set_intr_gate(0x20 + config.interrupt, ultrastor_interrupt);
296
297 outb_p(inb_p(0x21) & ~BIT(2), 0x21);
298
299 outb(inb_p(0xA1) & ~BIT(config.interrupt - 8), 0xA1);
300 #endif
301 return TRUE;
302 }
303
304 const char *ultrastor_14f_info(void)
305 {
306 return "UltraStor 14F SCSI driver version "
307 VERSION
308 " by David B. Gentzel\n";
309 }
310
311 static struct mscp mscp = {
312 OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE
313 };
314
315 int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
316 void *buff, int bufflen, void (*done)(int, int))
317 {
318 unsigned char in_byte;
319
320 #if (ULTRASTOR_DEBUG & UD_COMMAND)
321 printk("US14F: queuecommand: called\n");
322 #endif
323
324
325 memset((char *)&mscp + 1, 0, sizeof (struct mscp) - 1);
326 mscp.target_id = target;
327
328 mscp.transfer_data = *(Longword *)&buff;
329 mscp.transfer_data_length = *(Longword *)&bufflen,
330 mscp.length_of_scsi_cdbs = ((*(unsigned char *)cmnd <= 0x1F) ? 6 : 10);
331 memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
332
333
334 do
335 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
336 while (!aborted && (in_byte & 1));
337 if (aborted) {
338 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
339 printk("US14F: queuecommand: aborted\n");
340 #endif
341
342 return (aborted << 16);
343 }
344
345
346 outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
347 outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
348 outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
349 outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
350
351
352 outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
353
354 ultrastor_done = done;
355
356 #if (ULTRASTOR_DEBUG & UD_COMMAND)
357 printk("US14F: queuecommand: returning\n");
358 #endif
359
360 return 0;
361 }
362
363 #ifdef NO_QUEUEING
364 int ultrastor_14f_command(unsigned char target, const void *cmnd,
365 void *buff, int bufflen)
366 {
367 unsigned char in_byte;
368
369 #if (ULTRASTOR_DEBUG & UD_COMMAND)
370 printk("US14F: command: called\n");
371 #endif
372
373 (void)ultrastor_14f_queuecommand(target, cmnd, buff, bufflen, 0);
374
375
376 do
377 in_byte = inb_p(SYS_DOORBELL_INTR(PORT_ADDRESS));
378 while (!aborted && !(in_byte & 1));
379 if (aborted) {
380 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
381 printk("US14F: command: aborted\n");
382 #endif
383
384 return (aborted << 16);
385 }
386
387
388 outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
389
390 #if (ULTRASTOR_DEBUG & UD_COMMAND)
391 printk("US14F: command: returning %08X\n",
392 (mscp.adapter_status << 16) | mscp.target_status);
393 #endif
394
395
396 return (mscp.adapter_status << 16) | mscp.target_status;
397 }
398 #endif
399
400 int ultrastor_14f_abort(int code)
401 {
402 #if (ULTRASTOR_DEBUG & UD_ABORT)
403 printk("US14F: abort: called\n");
404 #endif
405
406 aborted = (code ? code : DID_ABORT);
407
408 #if (ULTRASTOR_DEBUG & UD_ABORT)
409 printk("US14F: abort: returning\n");
410 #endif
411
412 return 0;
413 }
414
415 int ultrastor_14f_reset(void)
416 {
417 unsigned char in_byte;
418
419 #if (ULTRASTOR_DEBUG & UD_RESET)
420 printk("US14F: reset: called\n");
421 #endif
422
423
424 outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
425
426
427 do
428 in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
429 while (in_byte & 0x20);
430
431 aborted = DID_RESET;
432
433 #if (ULTRASTOR_DEBUG & UD_RESET)
434 printk("US14F: reset: returning\n");
435 #endif
436 return 0;
437 }
438
439 #ifndef NO_QUEUEING
440 void ultrastor_interrupt_service(void)
441 {
442 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
443 printk("US14F: interrupt_service: called: status = %08X\n",
444 (mscp.adapter_status << 16) | mscp.target_status);
445 #endif
446
447 if (ultrastor_done == 0)
448 panic("US14F: interrupt_service: unexpected interrupt!\n");
449 else {
450 void (*done)(int, int);
451
452
453
454
455 done = ultrastor_done;
456 ultrastor_done = 0;
457
458
459 outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
460
461
462
463 done(host_number, (mscp.adapter_status << 16) | mscp.target_status);
464 }
465
466 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
467 printk("US14F: interrupt_service: returning\n");
468 #endif
469 }
470
471 __asm__("
472 _ultrastor_interrupt:
473 cld
474 pushl %eax
475 pushl %ecx
476 pushl %edx
477 push %ds
478 push %es
479 push %fs
480 movl $0x10,%eax
481 mov %ax,%ds
482 mov %ax,%es
483 movl $0x17,%eax
484 mov %ax,%fs
485 movb $0x20,%al
486 outb %al,$0xA0 # EOI to interrupt controller #1
487 outb %al,$0x80 # give port chance to breathe
488 outb %al,$0x80
489 outb %al,$0x80
490 outb %al,$0x80
491 outb %al,$0x20
492 call _ultrastor_interrupt_service
493 pop %fs
494 pop %es
495 pop %ds
496 popl %edx
497 popl %ecx
498 popl %eax
499 iret
500 ");
501 #endif
502
503 #endif