|
|
1.1.1.3 root 1: /* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
1.1 root 2: * linux/kernel/aha1542.c
3: *
1.1.1.3 root 4: * Copyright (C) 1992 Tommy Thorn
1.1 root 5: */
6:
7: #include <linux/config.h>
8: #include <linux/kernel.h>
9: #include <linux/head.h>
1.1.1.3 root 10: #include <linux/types.h>
1.1 root 11: #include <linux/string.h>
1.1.1.3 root 12:
1.1 root 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: /*
1.1.1.3 root 26: static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
1.1 root 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: long WAITtimeout, WAITnexttimeout = 3000000;
36:
1.1.1.3 root 37: void (*do_done)(int, int) = NULL;
38: int aha1542_host = 0;
1.1 root 39: extern void aha1542_interrupt();
40:
41: #define aha1542_intr_reset() outb(IRST, CONTROL)
42: #define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
43: #define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
44:
45: #define WAIT(port, mask, allof, noneof) \
46: { register WAITbits; \
47: register WAITtimeout = WAITnexttimeout; \
48: while (1) { \
49: WAITbits = inb(port) & (mask); \
50: if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
51: break; \
52: if (--WAITtimeout == 0) goto fail; \
53: } \
54: }
55:
56: static void aha1542_stat(void)
57: {
1.1.1.3 root 58: /* int s = inb(STATUS), i = inb(INTRFLAGS);
59: printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
1.1 root 60: }
61:
62: static int aha1542_out(unchar *cmdp, int len)
63: {
64: while (len--)
65: {
66: WAIT(STATUS, CDF, 0, CDF);
67: outb(*cmdp++, DATA);
68: }
69: return 0;
70: fail:
71: printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
72: return 1;
73: }
74:
1.1.1.4 ! root 75: static int aha1542_in(unchar *cmdp, int len)
! 76: {
! 77: while (len--)
! 78: {
! 79: WAIT(STATUS, DF, DF, 0);
! 80: *cmdp++ = inb(DATA);
! 81: }
! 82: return 0;
! 83: fail:
! 84: printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
! 85: return 1;
! 86: }
1.1 root 87: int makecode(unsigned hosterr, unsigned scsierr)
88: {
89: switch (hosterr) {
90: case 0x0:
91: case 0xa: /* Linked command complete without error and linked normally */
92: case 0xb: /* Linked command complete without error, interrupt generated */
93: hosterr = 0;
94: break;
95:
96: case 0x11: /* Selection time out-The initiator selection or target
97: reselection was not complete within the SCSI Time out period */
98: hosterr = DID_TIME_OUT;
99: break;
100:
101: case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
102: thean was allocated by the Data Length field or the sum of the
103: Scatter / Gather Data Length fields. */
104:
105: case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
106:
107: case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
108: invalid. This usually indicates a software failure. */
109:
110: case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
111: This usually indicates a software failure. */
112:
113: case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
114: of linked CCB's does not specify the same logical unit number as
115: the first. */
116: case 0x18: /* Invalid Target Direction received from Host-The direction of a
117: Target Mode CCB was invalid. */
118:
119: case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
120: received to service data transfer between the same target LUN
121: and initiator SCSI ID in the same direction. */
122:
123: case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
124: length segment or invalid segment list boundaries was received.
125: A CCB parameter was invalid. */
126: hosterr = DID_ERROR; /* Couldn't find any better */
127: break;
128:
129: case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
130: phase sequence was requested by the target. The host adapter
131: will generate a SCSI Reset Condition, notifying the host with
132: a SCRD interrupt */
133: hosterr = DID_RESET;
134: break;
135: default:
136: printk("makecode: unknown hoststatus %x\n", hosterr);
137: break;
138: }
139: return scsierr|(hosterr << 16);
140: }
141:
142: int aha1542_test_port(void)
143: {
144: volatile int debug = 0;
145:
146: /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
147:
148: /* DEB(printk("aha1542_test_port called \n")); */
149:
150: outb(SRST|IRST/*|SCRST*/, CONTROL);
151:
152: debug = 1;
153: /* Expect INIT and IDLE, any of the others are bad */
154: WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
155:
156: debug = 2;
157: /* Shouldn't have generated any interrupts during reset */
158: if (inb(INTRFLAGS)&INTRMASK) goto fail;
159:
160: debug = 3;
161: /* Test the basic ECHO command */
162: outb(CMD_ECHO, DATA);
163:
164: debug = 4;
165: /* Wait for CDF=0. If any of the others are set, it's bad */
166: WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
167:
168: debug = 5;
169: /* The meaning of life */
170: outb(42, DATA);
171:
172: debug = 6;
173: /* Expect only DF, that is, data ready */
174: WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
175:
176: debug = 7;
177: /* Is the answer correct? */
178: if (inb(DATA) != 42) goto fail;
179:
180: debug = 8;
181: /* Reading port should reset DF */
182: if (inb(STATUS) & DF) goto fail;
183:
184: debug = 9;
185: /* When HACC, command is completed, and we're though testing */
186: WAIT(INTRFLAGS, HACC, HACC, 0);
187: /* now initialize adapter */
188:
189: debug = 10;
190: /* Clear interrupts */
191: outb(IRST, CONTROL);
192:
193: debug = 11;
194:
195: return debug; /* 1 = ok */
196: fail:
197: return 0; /* 0 = not ok */
198: }
199:
200: /* What's this little function for? */
201: char *aha1542_info(void)
202: {
1.1.1.4 ! root 203: static char buffer[] = ""; /* looks nicer without anything here */
1.1 root 204: return buffer;
205: }
206:
207: /* A "high" level interrupt handler */
208: void aha1542_intr_handle(void)
209: {
1.1.1.3 root 210: void (*my_done)(int, int) = do_done;
1.1 root 211: int errstatus;
212:
213: do_done = NULL;
214: #ifdef DEBUG
1.1.1.4 ! root 215: {
! 216: int flag = inb(INTRFLAGS);
1.1 root 217: printk("aha1542_intr_handle: ");
218: if (!(flag&ANYINTR)) printk("no interrupt?");
219: if (flag&MBIF) printk("MBIF ");
220: if (flag&MBOA) printk("MBOF ");
221: if (flag&HACC) printk("HACC ");
222: if (flag&SCRD) printk("SCRD ");
223: printk("status %02x\n", inb(STATUS));
224: if (ccb.tarstat|ccb.hastat)
225: printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
1.1.1.4 ! root 226: };
1.1 root 227: #endif
228: aha1542_intr_reset();
229: if (!my_done) {
230: printk("aha1542_intr_handle: Unexpected interrupt\n");
231: return;
232: }
233:
234: /* is there mail :-) */
235:
236: if (!mb[1].status) {
237: DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
1.1.1.3 root 238: my_done(aha1542_host, DID_TIME_OUT << 16);
1.1 root 239: return;
240: }
241:
242: /* more error checking left out here */
243: if (mb[1].status != 1)
244: /* This is surely wrong, but I don't know what's right */
245: errstatus = makecode(ccb.hastat, ccb.tarstat);
246: else
247: errstatus = 0;
248:
249: mb[1].status = 0;
250:
251: if (ccb.tarstat == 2) {
252: int i;
253: DEB(printk("aha1542_intr_handle: sense:"));
1.1.1.4 ! root 254: #ifdef DEBUG
1.1 root 255: for (i = 0; i < 12; i++)
256: printk("%02x ", ccb.cdb[ccb.cdblen+i]);
257: printk("\n");
1.1.1.4 ! root 258: #endif
1.1 root 259: /*
260: DEB(printk("aha1542_intr_handle: buf:"));
261: for (i = 0; i < bufflen; i++)
262: printk("%02x ", ((unchar *)buff)[i]);
263: printk("\n");
264: */
265: }
266: DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
1.1.1.3 root 267: my_done(aha1542_host, errstatus);
1.1 root 268: return;
269: }
270:
1.1.1.3 root 271: int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int))
1.1 root 272: {
273: unchar ahacmd = CMD_START_SCSI;
1.1.1.4 ! root 274: unchar direction;
1.1 root 275: unchar *cmd = (unchar *) cmnd;
1.1.1.3 root 276: DEB(int i);
1.1 root 277:
1.1.1.3 root 278: DEB(if (target > 1) {done(aha1542_host, DID_TIME_OUT << 16); return 0;});
1.1 root 279:
1.1.1.4 ! root 280: if(*cmd == REQUEST_SENSE){
! 281: memcpy(buff, &ccb.cdb[ccb.cdblen], bufflen);
! 282: done(aha1542_host, 0);
! 283: return 0;
! 284: };
! 285:
1.1 root 286: #ifdef DEBUG
287: if (*cmd == READ_10 || *cmd == WRITE_10)
288: i = xscsi2int(cmd+2);
289: else if (*cmd == READ_6 || *cmd == WRITE_6)
290: i = scsi2int(cmd+2);
291: else
292: i = -1;
293: if (done)
294: printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
295: else
296: printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
297: aha1542_stat();
298: printk("aha1542_queuecommand: dumping scsi cmd:");
299: for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
300: printk("\n");
301: if (*cmd == WRITE_10 || *cmd == WRITE_6)
302: return 0; /* we are still testing, so *don't* write */
303: #endif
304: memset(&ccb, 0, sizeof ccb);
1.1.1.4 ! root 305:
1.1 root 306: ccb.cdblen = (*cmd<=0x1f)?6:10; /* SCSI Command Descriptor Block Length */
1.1.1.4 ! root 307:
! 308: direction = 0;
! 309: if (*cmd == READ_10 || *cmd == READ_6)
! 310: direction = 8;
! 311: else if (*cmd == WRITE_10 || *cmd == WRITE_6)
! 312: direction = 16;
! 313:
1.1 root 314: memcpy(ccb.cdb, cmd, ccb.cdblen);
315: ccb.op = 0; /* SCSI Initiator Command */
1.1.1.4 ! root 316: ccb.idlun = (target&7)<<5 | direction; /* SCSI Target Id */
1.1 root 317: ccb.rsalen = 12;
318: any2scsi(ccb.datalen, bufflen);
319: any2scsi(ccb.dataptr, buff);
320: ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
321: ccb.commlinkid = 0;
322:
323: mb[0].status = 1;
324: mb[1].status = 0;
325:
326: #ifdef DEBUGd
327: printk("aha1542_command: sending.. ");
328: for (i = 0; i < sizeof(ccb)-10; i++)
329: printk("%02x ", ((unchar *)&ccb)[i]);
330: #endif
331:
332: if (done) {
333: DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
334: if (do_done)
335: printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
336: else
337: do_done = done;
338: aha1542_out(&ahacmd, 1); /* start scsi command */
339: DEB(aha1542_stat());
340: aha1542_enable_intr();
341: }
342: else
343: printk("aha1542_queuecommand: done can't be NULL\n");
344:
345: return 0;
346: }
347:
348: volatile static int internal_done_flag = 0;
349: volatile static int internal_done_errcode = 0;
1.1.1.3 root 350: static void internal_done(int host, int errcode)
1.1 root 351: {
352: internal_done_errcode = errcode;
353: ++internal_done_flag;
354: }
355:
356: int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
357: {
358: DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
359: aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
360:
361: while (!internal_done_flag);
362: internal_done_flag = 0;
363: return internal_done_errcode;
364: }
365:
366: /* Initialize mailboxes */
367: static void setup_mailboxes()
368: {
369: static unchar cmd[5] = {CMD_MBINIT, 1};
370:
371: mb[0].status = mb[1].status = 0;
372: aha1542_intr_reset(); /* reset interrupts, so they don't block */
373: any2scsi((cmd+2), mb);
374: any2scsi(mb[0].ccbptr, &ccb);
375: aha1542_out(cmd, 5);
376: WAIT(INTRFLAGS, INTRMASK, HACC, 0);
377: while (0) {
378: fail:
379: printk("aha1542_detect: failed setting up mailboxes\n");
380: }
381: aha1542_intr_reset();
382: }
383:
384: /* a hack to avoid a strange compilation error */
385:
386: void call_buh()
387: {
388: set_intr_gate(0x2b,&aha1542_interrupt);
389: }
390:
1.1.1.4 ! root 391: /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
! 392: static void aha1542_query()
! 393: {
! 394: static unchar inquiry_cmd[] = {CMD_INQUIRY };
! 395: static unchar inquiry_result[4];
! 396: int i;
! 397: i = inb(STATUS);
! 398: if (i & DF) {
! 399: i = inb(DATA);
! 400: printk("Stale data:%x ");
! 401: };
! 402: aha1542_out(inquiry_cmd, 1);
! 403: aha1542_in(inquiry_result, 4);
! 404: WAIT(INTRFLAGS, INTRMASK, HACC, 0);
! 405: while (0) {
! 406: fail:
! 407: printk("aha1542_detect: query card type\n");
! 408: }
! 409: aha1542_intr_reset();
! 410: printk("Inquiry:");
! 411: for(i=0;i<4;i++) printk("%x ",inquiry_result[i]);
! 412: }
1.1 root 413: /* return non-zero on detection */
1.1.1.3 root 414: int aha1542_detect(int hostnum)
1.1 root 415: {
416: int i;
417:
418: DEB(printk("aha1542_detect: \n"));
419:
420: if (!(i = aha1542_test_port())) {
421: return 0;
422: }
423:
424: /* Set the Bus on/off-times as not to ruin floppy performens */
425: {
426: static unchar oncmd[] = {CMD_BUSON_TIME, 5};
427: static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
428:
429: aha1542_intr_reset();
430: aha1542_out(oncmd, 2);
431: WAIT(INTRFLAGS, INTRMASK, HACC, 0);
432: aha1542_intr_reset();
433: aha1542_out(offcmd, 2);
434: WAIT(INTRFLAGS, INTRMASK, HACC, 0);
435: while (0) {
436: fail:
437: printk("aha1542_detect: setting bus on/off-time failed\n");
438: }
439: aha1542_intr_reset();
440: }
1.1.1.4 ! root 441: aha1542_query();
1.1 root 442:
1.1.1.4 ! root 443: DEB(aha1542_stat());
1.1 root 444: setup_mailboxes();
445:
1.1.1.4 ! root 446: DEB(aha1542_stat());
1.1 root 447:
448: DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
449: call_buh();
450:
451: if (intr_chan >= 8)
452: outb(inb_p(0x21)&0xfb,0x21); /* open for slave ?? */
453:
454: DEB(printk("aha1542_detect: enabling interrupts\n"));
455: aha1542_enable_intr();
456:
457: #ifdef DEBUG
458: DEB(printk(" *** READ CAPACITY ***\n"));
459:
460: {
461: unchar buf[8];
462: static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
463: int i;
464:
465: for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
466: for (i = 0; i < 2; ++i)
467: if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
468: printk("aha_detect: LU %d sector_size %d device_size %d\n",
469: i, xscsi2int(buf+4), xscsi2int(buf));
470: }
471: }
472:
473: DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
474:
475: for (i = 0; i < 4; ++i)
476: {
477: unsigned char cmd[10];
478: static buffer[512];
479:
480: cmd[0] = READ_10;
481: cmd[1] = 0;
482: xany2scsi(cmd+2, i);
483: cmd[6] = 0;
484: cmd[7] = 0;
485: cmd[8] = 1;
486: cmd[9] = 0;
487: aha1542_command(0, cmd, buffer, 512);
488: }
489: #endif
1.1.1.3 root 490: aha1542_host = hostnum;
1.1 root 491: return 1;
492: }
493:
494: int aha1542_abort(int i)
495: {
496: DEB(printk("aha1542_abort\n"));
497: return 0;
498: }
499:
500: int aha1542_reset(void)
501: {
502: DEB(printk("aha1542_reset called\n"));
503: return 0;
504: }
505:
506: __asm__("
507: _aha1542_interrupt:
508: cld
509: pushl %eax
510: pushl %ecx
511: pushl %edx
512: push %ds
513: push %es
514: push %fs
515: movl $0x10,%eax
516: mov %ax,%ds
517: mov %ax,%es
518: movl $0x17,%eax
519: mov %ax,%fs
520: movb $0x20,%al
521: outb %al,$0xA0 # EOI to interrupt controller #1
522: jmp 1f # give port chance to breathe
523: 1: jmp 1f
524: 1: outb %al,$0x20
525: # Please, someone, change this to use the timer
526: # andl $0xfffeffff,_timer_active
527: movl $_aha1542_intr_handle,%edx
528: call *%edx # ``interesting'' way of handling intr.
529: pop %fs
530: pop %es
531: pop %ds
532: popl %edx
533: popl %ecx
534: popl %eax
535: iret
536: ");
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.