|
|
1.1 ! root 1: /* $Id: aha1740.c,v 1.2 1997/03/24 21:51:17 thomas Exp $ ! 2: * 1993/03/31 ! 3: * linux/kernel/aha1740.c ! 4: * ! 5: * Based loosely on aha1542.c which is ! 6: * Copyright (C) 1992 Tommy Thorn and ! 7: * Modified by Eric Youngdale ! 8: * ! 9: * This file is aha1740.c, written and ! 10: * Copyright (C) 1992,1993 Brad McLean ! 11: * ! 12: * Modifications to makecode and queuecommand ! 13: * for proper handling of multiple devices courteously ! 14: * provided by Michael Weller, March, 1993 ! 15: * ! 16: * aha1740_makecode may still need even more work ! 17: * if it doesn't work for your devices, take a look. ! 18: */ ! 19: ! 20: #ifdef MODULE ! 21: #include <linux/module.h> ! 22: #endif ! 23: ! 24: #include <linux/kernel.h> ! 25: #include <linux/head.h> ! 26: #include <linux/types.h> ! 27: #include <linux/string.h> ! 28: #include <linux/ioport.h> ! 29: #include <linux/proc_fs.h> ! 30: #include <linux/sched.h> ! 31: #include <asm/dma.h> ! 32: ! 33: #include <asm/system.h> ! 34: #include <asm/io.h> ! 35: #include <linux/blk.h> ! 36: #include "scsi.h" ! 37: #include "hosts.h" ! 38: #include "sd.h" ! 39: ! 40: #include "aha1740.h" ! 41: #include<linux/stat.h> ! 42: ! 43: struct proc_dir_entry proc_scsi_aha1740 = { ! 44: PROC_SCSI_AHA1740, 7, "aha1740", ! 45: S_IFDIR | S_IRUGO | S_IXUGO, 2 ! 46: }; ! 47: ! 48: /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH ! 49: IT WORK, THEN: ! 50: #define DEBUG ! 51: */ ! 52: #ifdef DEBUG ! 53: #define DEB(x) x ! 54: #else ! 55: #define DEB(x) ! 56: #endif ! 57: ! 58: /* ! 59: static const char RCSid[] = "$Header: /gd4/gnu/cvsroot/gnumach/i386/i386at/gpl/linux/scsi/aha1740.c,v 1.2 1997/03/24 21:51:17 thomas Exp $"; ! 60: */ ! 61: ! 62: static unsigned int slot, base; ! 63: static unsigned char irq_level; ! 64: ! 65: static struct ecb ecb[AHA1740_ECBS]; /* One for each queued operation */ ! 66: ! 67: static int aha1740_last_ecb_used = 0; /* optimization */ ! 68: ! 69: int aha1740_makecode(unchar *sense, unchar *status) ! 70: { ! 71: struct statusword ! 72: { ! 73: ushort don:1, /* Command Done - No Error */ ! 74: du:1, /* Data underrun */ ! 75: :1, qf:1, /* Queue full */ ! 76: sc:1, /* Specification Check */ ! 77: dor:1, /* Data overrun */ ! 78: ch:1, /* Chaining Halted */ ! 79: intr:1, /* Interrupt issued */ ! 80: asa:1, /* Additional Status Available */ ! 81: sns:1, /* Sense information Stored */ ! 82: :1, ini:1, /* Initialization Required */ ! 83: me:1, /* Major error or exception */ ! 84: :1, eca:1, /* Extended Contingent alliance */ ! 85: :1; ! 86: } status_word; ! 87: int retval = DID_OK; ! 88: ! 89: status_word = * (struct statusword *) status; ! 90: #ifdef DEBUG ! 91: printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3], ! 92: sense[0],sense[1],sense[2],sense[3]); ! 93: #endif ! 94: if (!status_word.don) /* Anything abnormal was detected */ ! 95: { ! 96: if ( (status[1]&0x18) || status_word.sc ) /*Additional info available*/ ! 97: { ! 98: /* Use the supplied info for further diagnostics */ ! 99: switch ( status[2] ) ! 100: { ! 101: case 0x12: ! 102: if ( status_word.dor ) ! 103: retval=DID_ERROR; /* It's an Overrun */ ! 104: /* If not overrun, assume underrun and ignore it! */ ! 105: case 0x00: /* No info, assume no error, should not occur */ ! 106: break; ! 107: case 0x11: ! 108: case 0x21: ! 109: retval=DID_TIME_OUT; ! 110: break; ! 111: case 0x0a: ! 112: retval=DID_BAD_TARGET; ! 113: break; ! 114: case 0x04: ! 115: case 0x05: ! 116: retval=DID_ABORT; /* Either by this driver or the AHA1740 ! 117: itself */ ! 118: break; ! 119: default: ! 120: retval=DID_ERROR; /* No further diagnostics possible */ ! 121: } ! 122: } ! 123: else ! 124: { /* Michael suggests, and Brad concurs: */ ! 125: if ( status_word.qf ) ! 126: { ! 127: retval = DID_TIME_OUT; /* forces a redo */ ! 128: /* I think this specific one should not happen -Brad */ ! 129: printk("aha1740.c: WARNING: AHA1740 queue overflow!\n"); ! 130: } ! 131: else if ( status[0]&0x60 ) ! 132: { ! 133: retval = DID_ERROR; /* Didn't find a better error */ ! 134: } ! 135: /* In any other case return DID_OK so for example ! 136: CONDITION_CHECKS make it through to the appropriate ! 137: device driver */ ! 138: } ! 139: } ! 140: /* Under all circumstances supply the target status -Michael */ ! 141: return status[3] | retval << 16; ! 142: } ! 143: ! 144: int aha1740_test_port(void) ! 145: { ! 146: char name[4],tmp; ! 147: ! 148: /* Okay, look for the EISA ID's */ ! 149: name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */ ! 150: name[1]= 'A' -1 + ((tmp & 3) << 3); ! 151: name[1]+= ((tmp = inb(HID1)) >> 5)&0x7; /* Second Character */ ! 152: name[2]= 'A' -1 + (tmp & 0x1f); /* Third Character */ ! 153: name[3]=0; ! 154: tmp = inb(HID2); ! 155: if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD ) ! 156: return 0; /* Not an Adaptec 174x */ ! 157: ! 158: /* if ( inb(HID3) != HID_REV ) ! 159: printk("aha1740: Warning; board revision of %d; expected %d\n", ! 160: inb(HID3),HID_REV); */ ! 161: ! 162: if ( inb(EBCNTRL) != EBCNTRL_VALUE ) ! 163: { ! 164: printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n", ! 165: inb(EBCNTRL)); ! 166: return 0; ! 167: } ! 168: ! 169: /* Try and turn on enhanced mode */ ! 170: tmp = inb (PORTADR); ! 171: outb (PORTADR, tmp | PORTADDR_ENH); ! 172: if ( inb(PORTADR) & PORTADDR_ENH ) ! 173: return 1; /* Okay, we're all set */ ! 174: ! 175: printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n"); ! 176: return 0; ! 177: } ! 178: ! 179: /* A "high" level interrupt handler */ ! 180: void aha1740_intr_handle(int irq, struct pt_regs * regs) ! 181: { ! 182: void (*my_done)(Scsi_Cmnd *); ! 183: int errstatus, adapstat; ! 184: int number_serviced; ! 185: struct ecb *ecbptr; ! 186: Scsi_Cmnd *SCtmp; ! 187: ! 188: number_serviced = 0; ! 189: ! 190: while(inb(G2STAT) & G2STAT_INTPEND) ! 191: { ! 192: DEB(printk("aha1740_intr top of loop.\n")); ! 193: adapstat = inb(G2INTST); ! 194: ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0)); ! 195: outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */ ! 196: ! 197: switch ( adapstat & G2INTST_MASK ) ! 198: { ! 199: case G2INTST_CCBRETRY: ! 200: case G2INTST_CCBERROR: ! 201: case G2INTST_CCBGOOD: ! 202: outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */ ! 203: if (!ecbptr) ! 204: { ! 205: printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n", ! 206: inb(G2STAT),adapstat,inb(G2INTST),number_serviced++); ! 207: continue; ! 208: } ! 209: SCtmp = ecbptr->SCpnt; ! 210: if (!SCtmp) ! 211: { ! 212: printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n", ! 213: inb(G2STAT),adapstat,inb(G2INTST),number_serviced++); ! 214: continue; ! 215: } ! 216: if (SCtmp->host_scribble) ! 217: scsi_free(SCtmp->host_scribble, 512); ! 218: /* Fetch the sense data, and tuck it away, in the required slot. The ! 219: Adaptec automatically fetches it, and there is no guarantee that ! 220: we will still have it in the cdb when we come back */ ! 221: if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) ! 222: { ! 223: memcpy(SCtmp->sense_buffer, ecbptr->sense, ! 224: sizeof(SCtmp->sense_buffer)); ! 225: errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); ! 226: } ! 227: else ! 228: errstatus = 0; ! 229: DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus)); ! 230: SCtmp->result = errstatus; ! 231: my_done = ecbptr->done; ! 232: memset(ecbptr,0,sizeof(struct ecb)); ! 233: if ( my_done ) ! 234: my_done(SCtmp); ! 235: break; ! 236: case G2INTST_HARDFAIL: ! 237: printk("aha1740 hardware failure!\n"); ! 238: panic("aha1740.c"); /* Goodbye */ ! 239: case G2INTST_ASNEVENT: ! 240: printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat, ! 241: inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */ ! 242: outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */ ! 243: break; ! 244: case G2INTST_CMDGOOD: ! 245: /* set immediate command success flag here: */ ! 246: break; ! 247: case G2INTST_CMDERROR: ! 248: /* Set immediate command failure flag here: */ ! 249: break; ! 250: } ! 251: number_serviced++; ! 252: } ! 253: } ! 254: ! 255: int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) ! 256: { ! 257: unchar direction; ! 258: unchar *cmd = (unchar *) SCpnt->cmnd; ! 259: unchar target = SCpnt->target; ! 260: unsigned long flags; ! 261: void *buff = SCpnt->request_buffer; ! 262: int bufflen = SCpnt->request_bufflen; ! 263: int ecbno; ! 264: DEB(int i); ! 265: ! 266: ! 267: if(*cmd == REQUEST_SENSE) ! 268: { ! 269: if (bufflen != sizeof(SCpnt->sense_buffer)) ! 270: { ! 271: printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); ! 272: } ! 273: SCpnt->result = 0; ! 274: done(SCpnt); ! 275: return 0; ! 276: } ! 277: ! 278: #ifdef DEBUG ! 279: if (*cmd == READ_10 || *cmd == WRITE_10) ! 280: i = xscsi2int(cmd+2); ! 281: else if (*cmd == READ_6 || *cmd == WRITE_6) ! 282: i = scsi2int(cmd+2); ! 283: else ! 284: i = -1; ! 285: printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); ! 286: printk("scsi cmd:"); ! 287: for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); ! 288: printk("\n"); ! 289: #endif ! 290: ! 291: /* locate an available ecb */ ! 292: ! 293: save_flags(flags); ! 294: cli(); ! 295: ecbno = aha1740_last_ecb_used + 1; /* An optimization */ ! 296: if (ecbno >= AHA1740_ECBS) ecbno = 0; ! 297: ! 298: do{ ! 299: if( ! ecb[ecbno].cmdw ) ! 300: break; ! 301: ecbno++; ! 302: if (ecbno >= AHA1740_ECBS ) ecbno = 0; ! 303: } while (ecbno != aha1740_last_ecb_used); ! 304: ! 305: if( ecb[ecbno].cmdw ) ! 306: panic("Unable to find empty ecb for aha1740.\n"); ! 307: ! 308: ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command doubles as reserved flag */ ! 309: ! 310: aha1740_last_ecb_used = ecbno; ! 311: restore_flags(flags); ! 312: ! 313: #ifdef DEBUG ! 314: printk("Sending command (%d %x)...",ecbno, done); ! 315: #endif ! 316: ! 317: ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command Descriptor Block Length */ ! 318: ! 319: direction = 0; ! 320: if (*cmd == READ_10 || *cmd == READ_6) ! 321: direction = 1; ! 322: else if (*cmd == WRITE_10 || *cmd == WRITE_6) ! 323: direction = 0; ! 324: ! 325: memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen); ! 326: ! 327: if (SCpnt->use_sg) ! 328: { ! 329: struct scatterlist * sgpnt; ! 330: struct aha1740_chain * cptr; ! 331: int i; ! 332: #ifdef DEBUG ! 333: unsigned char * ptr; ! 334: #endif ! 335: ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/ ! 336: SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); ! 337: sgpnt = (struct scatterlist *) SCpnt->request_buffer; ! 338: cptr = (struct aha1740_chain *) SCpnt->host_scribble; ! 339: if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n"); ! 340: for(i=0; i<SCpnt->use_sg; i++) ! 341: { ! 342: cptr[i].dataptr = (long) sgpnt[i].address; ! 343: cptr[i].datalen = sgpnt[i].length; ! 344: } ! 345: ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain); ! 346: ecb[ecbno].dataptr = (long) cptr; ! 347: #ifdef DEBUG ! 348: printk("cptr %x: ",cptr); ! 349: ptr = (unsigned char *) cptr; ! 350: for(i=0;i<24;i++) printk("%02x ", ptr[i]); ! 351: #endif ! 352: } ! 353: else ! 354: { ! 355: SCpnt->host_scribble = NULL; ! 356: ecb[ecbno].datalen = bufflen; ! 357: ecb[ecbno].dataptr = (long) buff; ! 358: } ! 359: ecb[ecbno].lun = SCpnt->lun; ! 360: ecb[ecbno].ses = 1; /* Suppress underrun errors */ ! 361: ecb[ecbno].dir= direction; ! 362: ecb[ecbno].ars=1; /* Yes, get the sense on an error */ ! 363: ecb[ecbno].senselen = 12; ! 364: ecb[ecbno].senseptr = (long) ecb[ecbno].sense; ! 365: ecb[ecbno].statusptr = (long) ecb[ecbno].status; ! 366: ecb[ecbno].done = done; ! 367: ecb[ecbno].SCpnt = SCpnt; ! 368: #ifdef DEBUG ! 369: { ! 370: int i; ! 371: printk("aha1740_command: sending.. "); ! 372: for (i = 0; i < sizeof(ecb[ecbno])-10; i++) ! 373: printk("%02x ", ((unchar *)&ecb[ecbno])[i]); ! 374: } ! 375: printk("\n"); ! 376: #endif ! 377: if (done) ! 378: { /* You may question the code below, which contains potentially ! 379: non-terminating while loops with interrupts disabled. So did ! 380: I when I wrote it, but the Adaptec Spec says the card is so fast, ! 381: that this problem virtually never occurs so I've kept it. We ! 382: do printk a warning first, so that you'll know if it happens. ! 383: In practice the only time we've seen this message is when some- ! 384: thing else is in the driver was broken, like _makecode(), or ! 385: when a scsi device hung the scsi bus. Even under these conditions, ! 386: The loop actually only cycled < 3 times (we instrumented it). */ ! 387: ! 388: DEB(printk("aha1740[%d] critical section\n",ecbno)); ! 389: save_flags(flags); ! 390: cli(); ! 391: if ( ! (inb(G2STAT) & G2STAT_MBXOUT) ) ! 392: { ! 393: printk("aha1740[%d]_mbxout wait!\n",ecbno); ! 394: cli(); /* printk may have done a sti()! */ ! 395: } ! 396: mb(); ! 397: while ( ! (inb(G2STAT) & G2STAT_MBXOUT) ); /* Oh Well. */ ! 398: outl(virt_to_bus(ecb+ecbno), MBOXOUT0); ! 399: if ( inb(G2STAT) & G2STAT_BUSY ) ! 400: { ! 401: printk("aha1740[%d]_attn wait!\n",ecbno); ! 402: cli(); ! 403: } ! 404: while ( inb(G2STAT) & G2STAT_BUSY ); /* And Again! */ ! 405: outb(ATTN_START | (target & 7), ATTN); /* Start it up */ ! 406: restore_flags(flags); ! 407: DEB(printk("aha1740[%d] request queued.\n",ecbno)); ! 408: } ! 409: else ! 410: printk("aha1740_queuecommand: done can't be NULL\n"); ! 411: ! 412: return 0; ! 413: } ! 414: ! 415: static volatile int internal_done_flag = 0; ! 416: static volatile int internal_done_errcode = 0; ! 417: ! 418: static void internal_done(Scsi_Cmnd * SCpnt) ! 419: { ! 420: internal_done_errcode = SCpnt->result; ! 421: ++internal_done_flag; ! 422: } ! 423: ! 424: int aha1740_command(Scsi_Cmnd * SCpnt) ! 425: { ! 426: aha1740_queuecommand(SCpnt, internal_done); ! 427: ! 428: while (!internal_done_flag); ! 429: internal_done_flag = 0; ! 430: return internal_done_errcode; ! 431: } ! 432: ! 433: /* Query the board for its irq_level. Nothing else matters ! 434: in enhanced mode on an EISA bus. */ ! 435: ! 436: void aha1740_getconfig(void) ! 437: { ! 438: static int intab[] = { 9,10,11,12,0,14,15,0 }; ! 439: ! 440: irq_level = intab [ inb(INTDEF)&0x7 ]; ! 441: outb(inb(INTDEF) | 0x10, INTDEF); ! 442: } ! 443: ! 444: int aha1740_detect(Scsi_Host_Template * tpnt) ! 445: { ! 446: tpnt->proc_dir = &proc_scsi_aha1740; ! 447: ! 448: memset(&ecb, 0, sizeof(struct ecb)); ! 449: DEB(printk("aha1740_detect: \n")); ! 450: ! 451: for ( slot=MINEISA; slot <= MAXEISA; slot++ ) ! 452: { ! 453: base = SLOTBASE(slot); ! 454: /* ! 455: * The ioports for eisa boards are generally beyond that used in the ! 456: * check/allocate region code, but this may change at some point, ! 457: * so we go through the motions. ! 458: */ ! 459: if(check_region(base, 0x5c)) continue; /* See if in use */ ! 460: if ( aha1740_test_port()) break; ! 461: } ! 462: if ( slot > MAXEISA ) ! 463: return 0; ! 464: ! 465: aha1740_getconfig(); ! 466: ! 467: if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT ) ! 468: { /* If the card isn't ready, hard reset it */ ! 469: outb(G2CNTRL_HRST,G2CNTRL); ! 470: outb(0,G2CNTRL); ! 471: } ! 472: ! 473: printk("Configuring Adaptec at IO:%x, IRQ %d\n",base, ! 474: irq_level); ! 475: ! 476: DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level)); ! 477: ! 478: if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740")) ! 479: { ! 480: printk("Unable to allocate IRQ for adaptec controller.\n"); ! 481: return 0; ! 482: } ! 483: request_region(base, 0x5c,"aha1740"); /* Reserve the space that we need to use */ ! 484: return 1; ! 485: } ! 486: ! 487: /* Note: They following two functions do not apply very well to the Adaptec, ! 488: which basically manages its own affairs quite well without our interference, ! 489: so I haven't put anything into them. I can faintly imagine someone with a ! 490: *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(), ! 491: but it hasn't happened yet, and doing aborts brings the Adaptec to its ! 492: knees. I cannot (at this moment in time) think of any reason to reset the ! 493: card once it's running. So there. */ ! 494: ! 495: int aha1740_abort(Scsi_Cmnd * SCpnt) ! 496: { ! 497: DEB(printk("aha1740_abort called\n")); ! 498: return SCSI_ABORT_SNOOZE; ! 499: } ! 500: ! 501: /* We do not implement a reset function here, but the upper level code assumes ! 502: that it will get some kind of response for the command in SCpnt. We must ! 503: oblige, or the command will hang the scsi system */ ! 504: ! 505: int aha1740_reset(Scsi_Cmnd * SCpnt) ! 506: { ! 507: DEB(printk("aha1740_reset called\n")); ! 508: return SCSI_RESET_PUNT; ! 509: } ! 510: ! 511: int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip) ! 512: { ! 513: int size = disk->capacity; ! 514: DEB(printk("aha1740_biosparam\n")); ! 515: ip[0] = 64; ! 516: ip[1] = 32; ! 517: ip[2] = size >> 11; ! 518: /* if (ip[2] >= 1024) ip[2] = 1024; */ ! 519: return 0; ! 520: } ! 521: ! 522: #ifdef MODULE ! 523: /* Eventually this will go into an include file, but this will be later */ ! 524: Scsi_Host_Template driver_template = AHA1740; ! 525: ! 526: #include "scsi_module.c" ! 527: #endif ! 528: ! 529: /* Okay, you made it all the way through. As of this writing, 3/31/93, I'm ! 530: [email protected] or [email protected]. I'll try to help as time ! 531: permits if you have any trouble with this driver. Happy Linuxing! */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.