|
|
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.