|
|
1.1 ! root 1: /* ! 2: * Ultrastor [13]4f SCSI Host Adapter. ! 3: * Originally written by Charles Forsyth, [email protected]. ! 4: * Needs work: ! 5: * handle multiple controllers; ! 6: * set options from user-level; ! 7: * split out to handle adaptec too; ! 8: */ ! 9: #include "u.h" ! 10: #include "../port/lib.h" ! 11: #include "mem.h" ! 12: #include "dat.h" ! 13: #include "fns.h" ! 14: #include "io.h" ! 15: #include "../port/error.h" ! 16: ! 17: #include "ureg.h" ! 18: ! 19: typedef struct Ctlr Ctlr; ! 20: typedef struct Mailbox Mailbox; ! 21: typedef struct Scatter Scatter; ! 22: ! 23: enum { ! 24: Nctl = 1, /* only support one */ ! 25: Nmbox = 8, /* number of Mailboxes; up to 16? */ ! 26: Nscatter = 33, /* s/g list limit fixed by Ultrastor controller */ ! 27: ! 28: Port = 0x330, /* factory defaults: I/O port */ ! 29: CtlrID = 7, /* adapter SCSI id */ ! 30: Irq = 14, /* interrupt request level */ ! 31: }; ! 32: ! 33: struct Scatter { ! 34: ulong start; /* physical address; Intel byte order */ ! 35: ulong len; /* length in bytes; Intel byte order */ ! 36: }; ! 37: ! 38: /* ! 39: * Ultrastor mailbox pointers point to one of these structures ! 40: */ ! 41: struct Mailbox { ! 42: uchar op; /* Adapter operation */ ! 43: uchar addr; /* lun, chan, scsi ID */ ! 44: uchar datap[4]; /* transfer data phys. pointer */ ! 45: uchar datalen[4]; /* transfer data length */ ! 46: uchar cmdlink[4]; /* command link phys. pointer */ ! 47: uchar linkid; /* SCSI command link ID */ ! 48: uchar nscatter; /* scatter/gather length (8 bytes per entry) */ ! 49: uchar senselen; /* length of sense data */ ! 50: uchar cmdlen; /* length of CDB */ ! 51: uchar cmd[12]; /* SCSI command */ ! 52: uchar adapterstatus; ! 53: uchar targetstatus; ! 54: uchar sensep[4]; /* sense data phys. pointer */ ! 55: ! 56: /* the remainder is used by software, not the device */ ! 57: uchar sensedata[64]; /* enough for AdapterInquiry data too */ ! 58: Scatter sglist[Nscatter]; ! 59: Rendez iodone; ! 60: int busy; /* interrupt pending */ ! 61: ulong physaddr; /* physical address of this Mailbox */ ! 62: int p9status; /* p9 status value */ ! 63: Mailbox *next; /* next Mailbox in free list */ ! 64: }; ! 65: ! 66: /* pack pointer as Intel order bytes (can simply assign) */ ! 67: #define PL(buf,p) (*(ulong*)(buf)=(ulong)(p)) ! 68: ! 69: enum { ! 70: /* bits in Mailbox.op[0] */ ! 71: /* 3 bit opcode */ ! 72: OpAdapter = 0x01, /* adapter command, not SCSI command */ ! 73: OpTarget = 0x02, /* SCSI command for device */ ! 74: OpReset = 0x04, /* device reset */ ! 75: /* 2 bit transfer direction */ ! 76: CmdDirection = 0<<3, /* transfer direction determined by SCSI command */ ! 77: DataIn = 1<<3, /* SCSI Data In */ ! 78: DataOut = 2<<3, /* SCSI Data Out */ ! 79: NoTransfer = 3<<3, ! 80: Nodiscon= 1<<5, /* disable disconnect */ ! 81: Usecache= 1<<6, /* use adapter cache (if available) */ ! 82: Scattered= 1<<7, /* transfer pointer refers to S/G list */ ! 83: ! 84: /* OpAdapter commands in Mailbox.cmd[0] */ ! 85: AdapterInquiry = 0x01, ! 86: AdapterSelftest = 0x02, ! 87: AdapterRead = 0x03, /* read adapter's buffer */ ! 88: AdapterWrite = 0x04, /* write to adapter's buffer */ ! 89: ! 90: /* IO port offsets and bits */ ! 91: AdapterMask = 0x00, /* local doorbell mask register */ ! 92: OGMIntEnable = 0x01, ! 93: SoftResetEnable = 0x40, ! 94: AdapterReady = 0xe1, /* adapter ready for work when all these set */ ! 95: AdapterIntr = 0x01, /* adapter interrupt/status; set by host, reset by adapter */ ! 96: SignalAdapter = 0x01, /* tell adapter to read OGMpointer */ ! 97: BusReset = 0x20, /* SCSI Bus Reset */ ! 98: SoftReset = 0x40, /* Adapter Soft Reset */ ! 99: HostMask = 0x02, /* host doorbell mask register */ ! 100: ICMIntEnable = 0x01, /* incoming mail enable */ ! 101: SIntEnable = 0x80, /* enable interrupt from HostIntr reg */ ! 102: HostIntr = 0x03, /* host doorbell interrupt/status; set by adapter, reset by host */ ! 103: IntPending = 0x80, /* interrupt pending for host */ ! 104: SignalHost = 0x01, /* Incoming Mail Interrupt */ ! 105: ProductID = 0x04, /* two byte product ID */ ! 106: Config1 = 0x06, ! 107: Config2 = 0x07, ! 108: OGMpointer = 0x08, /* pointer to Outgoing Mail */ ! 109: ICMpointer = 0x0c, /* pointer to Incoming Mail */ ! 110: }; ! 111: ! 112: #define OUT(c,v) outb(ctlr->io+(c), (v)) ! 113: #define IN(c) inb(ctlr->io+(c)) ! 114: ! 115: struct Ctlr { ! 116: Lock; ! 117: QLock; ! 118: int io; /* io port */ ! 119: int irq; /* interrupt vector */ ! 120: int dma; /* DMA channel */ ! 121: int ownid; /* adapter's SCSI ID */ ! 122: Mailbox mbox[Nmbox]; ! 123: Mailbox *free; /* next free Mailbox */ ! 124: Rendez mboxes; /* wait for free mbox */ ! 125: QLock mboxq; /* mutex for mboxes */ ! 126: Rendez ogm; /* wait for free OGM slot with Ctlr qlocked */ ! 127: }; ! 128: ! 129: static Ctlr ultra[Nctl]; ! 130: ! 131: int scsidebugs[8] = {0}; ! 132: int scsiownid = 7; ! 133: ! 134: static void ! 135: prmbox(Mailbox *m) ! 136: { ! 137: int i; ! 138: ! 139: print("scsi %lx: op=%2.2x dir=%x cmd=%d [", m->physaddr, m->op&07, (m->op>>3)&3, m->cmdlen); ! 140: for(i=0; i<m->cmdlen; i++) ! 141: print(" %2.2x", m->cmd[i]); ! 142: print("] id=%d lun=%d chan=%d", m->addr&7, (m->addr>>5)&7, (m->addr>>3)&3); ! 143: print(" dlen=%lx dptr=%lx\n", *(long*)m->datalen, *(long*)m->datap); ! 144: print(" astat=%2.2x dstat=%2.2x sc=%d [", m->adapterstatus, m->targetstatus, m->nscatter); ! 145: for(i=0; i<m->nscatter; i++) ! 146: print(" %lx,%ld", m->sglist[i].start, m->sglist[i].len); ! 147: print("]\n"); ! 148: /*for(i=0; i<10; i++) ! 149: print(" %2.2x", m->sensedata[i]);*/ ! 150: print("\n"); ! 151: } ! 152: ! 153: static void ! 154: resetadapter(int busreset) ! 155: { ! 156: Ctlr *ctlr = &ultra[0]; ! 157: int i; ! 158: ! 159: if(IN(AdapterMask) & SoftResetEnable){ ! 160: OUT(AdapterIntr, SoftReset|busreset); ! 161: for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);) ! 162: if(--i<0) { ! 163: print("Ultrastor reset timed out\n"); ! 164: break; ! 165: } ! 166: } ! 167: } ! 168: ! 169: static void ! 170: freebox(Ctlr *ctlr, Mailbox *m) ! 171: { ! 172: lock(ctlr); ! 173: if((m->next = ctlr->free) == 0) ! 174: wakeup(&ctlr->mboxes); ! 175: ctlr->free = m; ! 176: unlock(ctlr); ! 177: } ! 178: ! 179: static int ! 180: boxavail(void *a) ! 181: { ! 182: return ((Ctlr*)a)->free != 0; ! 183: } ! 184: ! 185: static int ! 186: scatter(Scatter *list, void *va, ulong nb) ! 187: { ! 188: char *p = (char *)va; ! 189: Scatter *sp = list; ! 190: int limit = Nscatter; ! 191: ! 192: for(; nb != 0; sp++){ ! 193: if(--limit < 0) ! 194: panic("Ultrastor I/O too scattered"); ! 195: sp->start = PADDR(p); ! 196: sp->len = BY2PG - (sp->start&(BY2PG-1)); /* the rest of that page */ ! 197: if(sp->len > nb) ! 198: sp->len = nb; ! 199: nb -= sp->len; ! 200: p += sp->len; ! 201: } ! 202: return sp - list; ! 203: } ! 204: ! 205: static int ! 206: isready(void *a) ! 207: { ! 208: Ctlr *ctlr = (Ctlr*)a; ! 209: ! 210: return (IN(AdapterIntr) & SignalAdapter) == 0; ! 211: } ! 212: ! 213: static int ! 214: isdone(void *a) ! 215: { ! 216: return ((Mailbox*)a)->busy == 0; ! 217: } ! 218: ! 219: static int ! 220: ultra14fexec(Scsi *p, int rflag) ! 221: { ! 222: Ctlr *ctlr = &ultra[0]; ! 223: Mailbox *m; ! 224: long n; ! 225: uchar *cp; ! 226: ! 227: if (p == 0 || ctlr->io == 0) ! 228: return 0x0200; /* device not available */ ! 229: ! 230: /* ! 231: * get a free Mailbox and build an Ultrastor command ! 232: */ ! 233: while(lock(ctlr), (m = ctlr->free) == 0){ ! 234: unlock(ctlr); ! 235: qlock(&ctlr->mboxq); ! 236: if(waserror()){ ! 237: qunlock(&ctlr->mboxq); ! 238: nexterror(); ! 239: } ! 240: sleep(&ctlr->mboxes, boxavail, ctlr); ! 241: poperror(); ! 242: qunlock(&ctlr->mboxq); ! 243: } ! 244: ctlr->free = m->next; ! 245: unlock(ctlr); ! 246: p->rflag = rflag; ! 247: m->p9status = 0; ! 248: m->op = OpTarget | CmdDirection | Usecache; /* BUG? is it safe always to Usecache? */ ! 249: m->addr = p->target | (p->lun<<5); ! 250: if(p->cmd.lim - p->cmd.ptr > sizeof(m->cmd)) ! 251: panic("scsiexec"); ! 252: m->cmdlen = p->cmd.lim - p->cmd.ptr; ! 253: for(cp = m->cmd; p->cmd.ptr < p->cmd.lim;) ! 254: *cp++ = *p->cmd.ptr++; ! 255: n = p->data.lim - p->data.ptr; ! 256: if(n){ ! 257: PL(m->datap, PADDR(m->sglist)); ! 258: m->op |= Scattered; ! 259: m->nscatter = scatter(m->sglist, p->data.ptr, n); ! 260: } else { ! 261: m->nscatter = 0; /* controller will not allow s/g when n==0 */ ! 262: PL(m->datap, 0); ! 263: } ! 264: PL(m->datalen, n); ! 265: m->adapterstatus = 0; ! 266: m->targetstatus = 0; ! 267: ! 268: /* ! 269: * send the command to the host adapter ! 270: */ ! 271: while(lock(ctlr), IN(AdapterIntr) & SignalAdapter) { /* adapter busy: infrequent? */ ! 272: static int fred; ! 273: if(fred == 0){ ! 274: print("ultrastor busy\n"); ! 275: fred = 1; ! 276: } ! 277: unlock(ctlr); ! 278: qlock(ctlr); ! 279: if(waserror()) { ! 280: freebox(ctlr, m); ! 281: qunlock(ctlr); ! 282: nexterror(); ! 283: } ! 284: sleep(&ctlr->ogm, isready, ctlr); ! 285: poperror(); ! 286: qunlock(ctlr); ! 287: } ! 288: m->busy = 1; ! 289: outl(ctlr->io+OGMpointer, m->physaddr); ! 290: OUT(AdapterIntr, SignalAdapter); ! 291: unlock(ctlr); ! 292: ! 293: /* ! 294: * wait for reply ! 295: */ ! 296: while(waserror()) ! 297: ; /* could send MSCP abort request to adapter */ ! 298: while(m->busy) ! 299: sleep(&m->iodone, isdone, m); ! 300: poperror(); ! 301: p->status = m->p9status; ! 302: if(scsidebugs[2]) ! 303: prmbox(m); ! 304: if(p->status == 0x6000) ! 305: p->data.ptr = p->data.lim; /* can only assume no residue */ ! 306: freebox(ctlr, m); ! 307: return p->status; ! 308: } ! 309: ! 310: static void ! 311: scsimoan(char *msg, Mailbox *m) ! 312: { ! 313: /*int i;*/ ! 314: ! 315: print("SCSI error: %s:", msg); ! 316: print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", m->addr&7, m->cmd[0], m->targetstatus, m->adapterstatus); ! 317: /*print(" sense:"); ! 318: for(i=0; i<10; i++) ! 319: print(" %2.2x", m->sensedata[i]);*/ ! 320: print("\n"); ! 321: } ! 322: ! 323: static void ! 324: interrupt(Ureg *ur, void *a) ! 325: { ! 326: Ctlr *ctlr = &ultra[0]; ! 327: Mailbox *m; ! 328: ulong pa; ! 329: ! 330: USED(ur, a); ! 331: if(ctlr->ogm.p && (IN(AdapterIntr) & SignalAdapter) == 0) ! 332: wakeup(&ctlr->ogm); ! 333: if((IN(HostIntr) & SignalHost) == 0) ! 334: return; /* no incoming mail */ ! 335: pa = inl(ctlr->io+ICMpointer); ! 336: OUT(HostIntr, SignalHost); /* release ICM slot */ ! 337: for(m = &ctlr->mbox[0]; m->physaddr != pa;) ! 338: if(++m >= &ctlr->mbox[Nmbox]) { ! 339: /* these sometimes happen in response to a scsi bus reset; ignore them */ ! 340: print("ultrastor: invalid ICM pointer #%lux\n", pa); ! 341: return; ! 342: } ! 343: if(scsidebugs[1]) ! 344: prmbox(m); ! 345: ! 346: m->p9status = 0x1000 | m->adapterstatus; ! 347: switch(m->adapterstatus){ ! 348: default: ! 349: scsimoan("adapter", m); ! 350: if(m->adapterstatus >= 0x92) /* ie, scsi command protocol error */ ! 351: resetadapter(BusReset); ! 352: /* might adapter reset be required in other cases? */ ! 353: break; ! 354: ! 355: case 0x91: /* selection timed out */ ! 356: m->p9status = 0x0200; ! 357: if(scsidebugs[0]) ! 358: scsimoan("timeout", m); ! 359: break; ! 360: ! 361: case 0xA3: ! 362: scsimoan("SCSI bus reset error", m); ! 363: break; ! 364: ! 365: case 0x00: ! 366: m->p9status = 0x6000 | m->targetstatus; ! 367: if(m->targetstatus && scsidebugs[0]) ! 368: scsimoan("device", m); ! 369: break; ! 370: } ! 371: m->busy = 0; ! 372: wakeup(&m->iodone); ! 373: } ! 374: ! 375: static ISAConf ultra14f = { ! 376: "ultra14f", ! 377: Port, ! 378: Irq, ! 379: 0, ! 380: 0, ! 381: }; ! 382: ! 383: static int irq[4] = { ! 384: 15, 14, 11, 10, ! 385: }; ! 386: ! 387: int (* ! 388: ultra14freset(void))(Scsi*, int) ! 389: { ! 390: ISAConf *isa = &ultra14f; ! 391: Ctlr *ctlr = &ultra[0]; ! 392: Mailbox *m; ! 393: int i, model; ! 394: ! 395: /* ! 396: * See if we have any configuration info ! 397: * and check it is an Ultrastor [13]4f. ! 398: * Only one controller for now. ! 399: */ ! 400: if(isaconfig("scsi", 0, &ultra14f) == 0) ! 401: return 0; ! 402: memset(ctlr, 0, sizeof(Ctlr)); ! 403: ctlr->io = isa->port; ! 404: ! 405: if(IN(ProductID) != 0x56) ! 406: return 0; ! 407: model = IN(ProductID+1); ! 408: switch(model){ ! 409: ! 410: case 0x40: ! 411: model = 14; ! 412: break; ! 413: ! 414: case 0x41: ! 415: model = 34; ! 416: break; ! 417: ! 418: default: ! 419: return 0; ! 420: } ! 421: ! 422: i = IN(Config1); ! 423: ctlr->irq = irq[((i>>4)&03)]; ! 424: if(model == 14) ! 425: ctlr->dma = 5 + ((i>>6)&03); ! 426: ctlr->ownid = IN(Config2)&07; ! 427: /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n", ! 428: model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/ ! 429: ! 430: /* ! 431: * set the DMA controller to cascade mode for bus master ! 432: */ ! 433: switch(ctlr->dma){ ! 434: case 5: ! 435: outb(0xd6, 0xc1); outb(0xd4, 1); break; ! 436: case 6: ! 437: outb(0xd6, 0xc2); outb(0xd4, 2); break; ! 438: case 7: ! 439: outb(0xd6, 0xc3); outb(0xd4, 3); break; ! 440: } ! 441: ! 442: resetadapter(0); ! 443: ctlr->free = 0; ! 444: for(i=0; i<Nmbox; i++){ ! 445: m = &ctlr->mbox[i]; ! 446: memset(m, 0, sizeof(*m)); ! 447: m->physaddr = PADDR(m); ! 448: PL(m->sensep, 0); /* DON'T collect sense data automatically: messes up scuzz? */ ! 449: m->senselen = 0; ! 450: m->next = ctlr->free; ! 451: ctlr->free = m; ! 452: } ! 453: ! 454: setvec(Int0vec+ctlr->irq, interrupt, 0); ! 455: ! 456: /* ! 457: * issue AdapterInquiry command to check it's alive ! 458: * -- could check enquiry data ! 459: */ ! 460: OUT(HostMask, 0); /* mask interrupts */ ! 461: m = &ctlr->mbox[0]; ! 462: m->op = OpAdapter | CmdDirection; ! 463: m->addr = ctlr->ownid; ! 464: m->cmdlen = 1; ! 465: m->cmd[0] = AdapterInquiry; ! 466: PL(m->datap, PADDR(m->sensedata)); ! 467: PL(m->datalen, 38); ! 468: while(IN(AdapterIntr) & SignalAdapter) ! 469: ; ! 470: outl(ctlr->io+OGMpointer, m->physaddr); ! 471: OUT(AdapterIntr, SignalAdapter); ! 472: for(i=100000; (IN(HostIntr)&SignalHost)==0;) ! 473: if(--i < 0){ ! 474: print("No response to UltraStor Inquiry\n"); ! 475: ctlr->io = 0; ! 476: return 0; ! 477: } ! 478: OUT(HostIntr, SignalHost); ! 479: ! 480: OUT(HostMask, ICMIntEnable|SIntEnable); ! 481: scsiownid = ctlr->ownid; ! 482: ! 483: print("scsi%d: %s: port %lux irq %d, dma = %d\n", ! 484: 0, isa->type, ctlr->io, ctlr->irq, ctlr->dma); ! 485: ! 486: return ultra14fexec; ! 487: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.