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