This source file includes following definitions.
- aha1542_stat
- aha1542_out
- aha1542_in
- makecode
- aha1542_test_port
- aha1542_info
- aha1542_intr_handle
- aha1542_queuecommand
- internal_done
- aha1542_command
- setup_mailboxes
- call_buh
- aha1542_query
- aha1542_detect
- aha1542_abort
- aha1542_reset
1
2
3
4
5
6
7 #include <linux/config.h>
8 #include <linux/kernel.h>
9 #include <linux/head.h>
10 #include <linux/types.h>
11 #include <linux/string.h>
12
13 #include <asm/system.h>
14 #include <asm/io.h>
15 #include "scsi.h"
16 #include "hosts.h"
17
18 #include "aha1542.h"
19 #ifdef DEBUG
20 #define DEB(x) x
21 #else
22 #define DEB(x)
23 #endif
24
25
26
27
28
29 #define base 0x330
30 #define intr_chan 11
31
32 static struct mailbox mb[2];
33 static struct ccb ccb;
34
35 extern int slow_scsi_io;
36
37 long WAITtimeout, WAITnexttimeout = 3000000;
38
39 void (*do_done)(int, int) = NULL;
40 int aha1542_host = 0;
41 extern void aha1542_interrupt();
42
43 #define aha1542_intr_reset() outb(IRST, CONTROL)
44 #define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
45 #define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
46
47 #define WAIT(port, mask, allof, noneof) \
48 { register WAITbits; \
49 register WAITtimeout = WAITnexttimeout; \
50 while (1) { \
51 WAITbits = inb(port) & (mask); \
52 if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
53 break; \
54 if (--WAITtimeout == 0) goto fail; \
55 } \
56 }
57
58 static void aha1542_stat(void)
59 {
60
61
62 }
63
64 static int aha1542_out(unchar *cmdp, int len)
65 {
66 while (len--)
67 {
68 WAIT(STATUS, CDF, 0, CDF);
69 outb(*cmdp++, DATA);
70 }
71 return 0;
72 fail:
73 printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
74 return 1;
75 }
76
77 static int aha1542_in(unchar *cmdp, int len)
78 {
79 while (len--)
80 {
81 WAIT(STATUS, DF, DF, 0);
82 *cmdp++ = inb(DATA);
83 }
84 return 0;
85 fail:
86 printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
87 return 1;
88 }
89 int makecode(unsigned hosterr, unsigned scsierr)
90 {
91 switch (hosterr) {
92 case 0x0:
93 case 0xa:
94 case 0xb:
95 hosterr = 0;
96 break;
97
98 case 0x11:
99
100 hosterr = DID_TIME_OUT;
101 break;
102
103 case 0x12:
104
105
106
107 case 0x13:
108
109 case 0x15:
110
111
112 case 0x16:
113
114
115 case 0x17:
116
117
118 case 0x18:
119
120
121 case 0x19:
122
123
124
125 case 0x1a:
126
127
128 hosterr = DID_ERROR;
129 break;
130
131 case 0x14:
132
133
134
135 hosterr = DID_RESET;
136 break;
137 default:
138 printk("makecode: unknown hoststatus %x\n", hosterr);
139 break;
140 }
141 return scsierr|(hosterr << 16);
142 }
143
144 int aha1542_test_port(void)
145 {
146 volatile int debug = 0;
147
148
149
150
151
152 outb(SRST|IRST, CONTROL);
153
154 debug = 1;
155
156 WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
157
158 debug = 2;
159
160 if (inb(INTRFLAGS)&INTRMASK) goto fail;
161
162 debug = 3;
163
164 outb(CMD_ECHO, DATA);
165
166 debug = 4;
167
168 WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
169
170 debug = 5;
171
172 outb(42, DATA);
173
174 debug = 6;
175
176 WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
177
178 debug = 7;
179
180 if (inb(DATA) != 42) goto fail;
181
182 debug = 8;
183
184 if (inb(STATUS) & DF) goto fail;
185
186 debug = 9;
187
188 WAIT(INTRFLAGS, HACC, HACC, 0);
189
190
191 debug = 10;
192
193 outb(IRST, CONTROL);
194
195 debug = 11;
196
197 return debug;
198 fail:
199 return 0;
200 }
201
202
203 char *aha1542_info(void)
204 {
205 static char buffer[] = "";
206 return buffer;
207 }
208
209
210 void aha1542_intr_handle(void)
211 {
212 void (*my_done)(int, int) = do_done;
213 int errstatus;
214
215 do_done = NULL;
216 #ifdef DEBUG
217 {
218 int flag = inb(INTRFLAGS);
219 printk("aha1542_intr_handle: ");
220 if (!(flag&ANYINTR)) printk("no interrupt?");
221 if (flag&MBIF) printk("MBIF ");
222 if (flag&MBOA) printk("MBOF ");
223 if (flag&HACC) printk("HACC ");
224 if (flag&SCRD) printk("SCRD ");
225 printk("status %02x\n", inb(STATUS));
226 if (ccb.tarstat|ccb.hastat)
227 printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
228 };
229 #endif
230 aha1542_intr_reset();
231 if (!my_done) {
232 printk("aha1542_intr_handle: Unexpected interrupt\n");
233 return;
234 }
235
236
237
238 if (!mb[1].status) {
239 DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
240 my_done(aha1542_host, DID_TIME_OUT << 16);
241 return;
242 }
243
244
245 if (mb[1].status != 1)
246
247 errstatus = makecode(ccb.hastat, ccb.tarstat);
248 else
249 errstatus = 0;
250
251 mb[1].status = 0;
252
253 if (ccb.tarstat == 2) {
254 #ifdef DEBUG
255 int i;
256 #endif
257 DEB(printk("aha1542_intr_handle: sense:"));
258 #ifdef DEBUG
259 for (i = 0; i < 12; i++)
260 printk("%02x ", ccb.cdb[ccb.cdblen+i]);
261 printk("\n");
262 #endif
263
264
265
266
267
268
269 }
270 DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
271 my_done(aha1542_host, errstatus);
272 return;
273 }
274
275 int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int))
276 {
277 unchar ahacmd = CMD_START_SCSI;
278 unchar direction;
279 unchar *cmd = (unchar *) cmnd;
280 DEB(int i);
281
282 DEB(if (target > 1) {done(aha1542_host, DID_TIME_OUT << 16); return 0;});
283
284 if(*cmd == REQUEST_SENSE){
285 memcpy(buff, &ccb.cdb[ccb.cdblen], bufflen);
286 done(aha1542_host, 0);
287 return 0;
288 };
289
290 #ifdef DEBUG
291 if (*cmd == READ_10 || *cmd == WRITE_10)
292 i = xscsi2int(cmd+2);
293 else if (*cmd == READ_6 || *cmd == WRITE_6)
294 i = scsi2int(cmd+2);
295 else
296 i = -1;
297 if (done)
298 printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
299 else
300 printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
301 aha1542_stat();
302 printk("aha1542_queuecommand: dumping scsi cmd:");
303 for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
304 printk("\n");
305 if (*cmd == WRITE_10 || *cmd == WRITE_6)
306 return 0;
307 #endif
308 memset(&ccb, 0, sizeof ccb);
309
310 ccb.cdblen = (*cmd<=0x1f)?6:10;
311
312 direction = 0;
313 if (*cmd == READ_10 || *cmd == READ_6)
314 direction = 8;
315 else if (*cmd == WRITE_10 || *cmd == WRITE_6)
316 direction = 16;
317
318 memcpy(ccb.cdb, cmd, ccb.cdblen);
319 ccb.op = 0;
320 ccb.idlun = (target&7)<<5 | direction;
321 ccb.rsalen = 12;
322 any2scsi(ccb.datalen, bufflen);
323 any2scsi(ccb.dataptr, buff);
324 ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
325 ccb.commlinkid = 0;
326
327 mb[0].status = 1;
328 mb[1].status = 0;
329
330 #ifdef DEBUGd
331 printk("aha1542_command: sending.. ");
332 for (i = 0; i < sizeof(ccb)-10; i++)
333 printk("%02x ", ((unchar *)&ccb)[i]);
334 #endif
335
336 if (done) {
337 DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
338 if (do_done)
339 printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
340 else
341 do_done = done;
342 aha1542_out(&ahacmd, 1);
343 DEB(aha1542_stat());
344 aha1542_enable_intr();
345 }
346 else
347 printk("aha1542_queuecommand: done can't be NULL\n");
348
349 return 0;
350 }
351
352 volatile static int internal_done_flag = 0;
353 volatile static int internal_done_errcode = 0;
354 static void internal_done(int host, int errcode)
355 {
356 internal_done_errcode = errcode;
357 ++internal_done_flag;
358 }
359
360 int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
361 {
362 DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
363 aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
364
365 while (!internal_done_flag);
366 internal_done_flag = 0;
367 return internal_done_errcode;
368 }
369
370
371 static void setup_mailboxes()
372 {
373 static unchar cmd[5] = {CMD_MBINIT, 1};
374
375 mb[0].status = mb[1].status = 0;
376 aha1542_intr_reset();
377 any2scsi((cmd+2), mb);
378 any2scsi(mb[0].ccbptr, &ccb);
379 aha1542_out(cmd, 5);
380 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
381 while (0) {
382 fail:
383 printk("aha1542_detect: failed setting up mailboxes\n");
384 }
385 aha1542_intr_reset();
386 }
387
388
389
390 void call_buh()
391 {
392 set_intr_gate(0x2b,&aha1542_interrupt);
393 }
394
395
396 static void aha1542_query(int hostnum)
397 {
398 static unchar inquiry_cmd[] = {CMD_INQUIRY };
399 static unchar inquiry_result[4];
400 int i;
401 i = inb(STATUS);
402 if (i & DF) {
403 i = inb(DATA);
404 };
405 aha1542_out(inquiry_cmd, 1);
406 aha1542_in(inquiry_result, 4);
407 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
408 while (0) {
409 fail:
410 printk("aha1542_detect: query card type\n");
411 }
412 aha1542_intr_reset();
413
414
415
416
417
418
419
420 if (inquiry_result[0] == 0x43) {
421 slow_scsi_io = hostnum;
422 printk("aha1542.c: Slow SCSI disk I/O selected for AHA 174N hardware.\n");
423 };
424 }
425
426 int aha1542_detect(int hostnum)
427 {
428 int i;
429
430 DEB(printk("aha1542_detect: \n"));
431
432 if (!(i = aha1542_test_port())) {
433 return 0;
434 }
435
436
437 {
438 static unchar oncmd[] = {CMD_BUSON_TIME, 5};
439 static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
440
441 aha1542_intr_reset();
442 aha1542_out(oncmd, 2);
443 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
444 aha1542_intr_reset();
445 aha1542_out(offcmd, 2);
446 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
447 while (0) {
448 fail:
449 printk("aha1542_detect: setting bus on/off-time failed\n");
450 }
451 aha1542_intr_reset();
452 }
453 aha1542_query(hostnum);
454
455 DEB(aha1542_stat());
456 setup_mailboxes();
457
458 DEB(aha1542_stat());
459
460 DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
461 call_buh();
462
463 if (intr_chan >= 8)
464 outb(inb_p(0x21)&0xfb,0x21);
465
466 DEB(printk("aha1542_detect: enabling interrupts\n"));
467 aha1542_enable_intr();
468
469 #ifdef DEBUG
470 DEB(printk(" *** READ CAPACITY ***\n"));
471
472 {
473 unchar buf[8];
474 static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
475 int i;
476
477 for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
478 for (i = 0; i < 2; ++i)
479 if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
480 printk("aha_detect: LU %d sector_size %d device_size %d\n",
481 i, xscsi2int(buf+4), xscsi2int(buf));
482 }
483 }
484
485 DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
486
487 for (i = 0; i < 4; ++i)
488 {
489 unsigned char cmd[10];
490 static buffer[512];
491
492 cmd[0] = READ_10;
493 cmd[1] = 0;
494 xany2scsi(cmd+2, i);
495 cmd[6] = 0;
496 cmd[7] = 0;
497 cmd[8] = 1;
498 cmd[9] = 0;
499 aha1542_command(0, cmd, buffer, 512);
500 }
501 #endif
502 aha1542_host = hostnum;
503 return 1;
504 }
505
506 int aha1542_abort(int i)
507 {
508 DEB(printk("aha1542_abort\n"));
509 return 0;
510 }
511
512 int aha1542_reset(void)
513 {
514 DEB(printk("aha1542_reset called\n"));
515 return 0;
516 }
517
518 __asm__("
519 _aha1542_interrupt:
520 cld
521 pushl %eax
522 pushl %ecx
523 pushl %edx
524 push %ds
525 push %es
526 push %fs
527 movl $0x10,%eax
528 mov %ax,%ds
529 mov %ax,%es
530 movl $0x17,%eax
531 mov %ax,%fs
532 movb $0x20,%al
533 outb %al,$0xA0 # EOI to interrupt controller #1
534 jmp 1f # give port chance to breathe
535 1: jmp 1f
536 1: outb %al,$0x20
537 # Please, someone, change this to use the timer
538 # andl $0xfffeffff,_timer_active
539 movl $_aha1542_intr_handle,%edx
540 call *%edx # ``interesting'' way of handling intr.
541 pop %fs
542 pop %es
543 pop %ds
544 popl %edx
545 popl %ecx
546 popl %eax
547 iret
548 ");