|
|
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 "lib.h" ! 11: #include "mem.h" ! 12: #include "dat.h" ! 13: #include "fns.h" ! 14: #include "io.h" ! 15: ! 16: typedef struct Ctlr Ctlr; ! 17: typedef struct Mailbox Mailbox; ! 18: typedef struct Scatter Scatter; ! 19: ! 20: enum { ! 21: Nctl = 1, /* only support one */ ! 22: Nmbox = 8, /* number of Mailboxes; up to 16? */ ! 23: Nscatter = 33, /* s/g list limit fixed by Ultrastor controller */ ! 24: Timeout = 10, /* seconds to wait for things to complete */ ! 25: ! 26: Port = 0x330, /* factory defaults: I/O port */ ! 27: CtlrID = 7, /* adapter SCSI id */ ! 28: Irq = 14, /* interrupt request level */ ! 29: }; ! 30: ! 31: struct Scatter { ! 32: ulong start; /* physical address; Intel byte order */ ! 33: ulong len; /* length in bytes; Intel byte order */ ! 34: }; ! 35: ! 36: /* ! 37: * Ultrastor mailbox pointers point to one of these structures ! 38: */ ! 39: struct Mailbox { ! 40: uchar op; /* Adapter operation */ ! 41: uchar addr; /* lun, chan, scsi ID */ ! 42: uchar datap[4]; /* transfer data phys. pointer */ ! 43: uchar datalen[4]; /* transfer data length */ ! 44: uchar cmdlink[4]; /* command link phys. pointer */ ! 45: uchar linkid; /* SCSI command link ID */ ! 46: uchar nscatter; /* scatter/gather length (8 bytes per entry) */ ! 47: uchar senselen; /* length of sense data */ ! 48: uchar cmdlen; /* length of CDB */ ! 49: uchar cmd[12]; /* SCSI command */ ! 50: uchar adapterstatus; ! 51: uchar targetstatus; ! 52: uchar sensep[4]; /* sense data phys. pointer */ ! 53: ! 54: /* the remainder is used by software, not the device */ ! 55: uchar sensedata[64]; /* enough for AdapterInquiry data too */ ! 56: int busy; /* interrupt pending */ ! 57: ulong physaddr; /* physical address of this Mailbox */ ! 58: int p9status; /* p9 status value */ ! 59: Mailbox *next; /* next Mailbox in free list */ ! 60: }; ! 61: ! 62: /* pack pointer as Intel order bytes (can simply assign) */ ! 63: #define PL(buf,p) (*(ulong*)(buf)=(ulong)(p)) ! 64: ! 65: enum { ! 66: /* bits in Mailbox.op[0] */ ! 67: /* 3 bit opcode */ ! 68: OpAdapter = 0x01, /* adapter command, not SCSI command */ ! 69: OpTarget = 0x02, /* SCSI command for device */ ! 70: OpReset = 0x04, /* device reset */ ! 71: /* 2 bit transfer direction */ ! 72: CmdDirection = 0<<3, /* transfer direction determined by SCSI command */ ! 73: DataIn = 1<<3, /* SCSI Data In */ ! 74: DataOut = 2<<3, /* SCSI Data Out */ ! 75: NoTransfer = 3<<3, ! 76: Nodiscon= 1<<5, /* disable disconnect */ ! 77: Usecache= 1<<6, /* use adapter cache (if available) */ ! 78: Scattered= 1<<7, /* transfer pointer refers to S/G list */ ! 79: ! 80: /* OpAdapter commands in Mailbox.cmd[0] */ ! 81: AdapterInquiry = 0x01, ! 82: AdapterSelftest = 0x02, ! 83: AdapterRead = 0x03, /* read adapter's buffer */ ! 84: AdapterWrite = 0x04, /* write to adapter's buffer */ ! 85: ! 86: /* IO port offsets and bits */ ! 87: AdapterMask = 0x00, /* local doorbell mask register */ ! 88: OGMIntEnable = 0x01, ! 89: SoftResetEnable = 0x40, ! 90: AdapterReady = 0xe1, /* adapter ready for work when all these set */ ! 91: AdapterIntr = 0x01, /* adapter interrupt/status; set by host, reset by adapter */ ! 92: SignalAdapter = 0x01, /* tell adapter to read OGMpointer */ ! 93: BusReset = 0x20, /* SCSI Bus Reset */ ! 94: SoftReset = 0x40, /* Adapter Soft Reset */ ! 95: HostMask = 0x02, /* host doorbell mask register */ ! 96: ICMIntEnable = 0x01, /* incoming mail enable */ ! 97: SIntEnable = 0x80, /* enable interrupt from HostIntr reg */ ! 98: HostIntr = 0x03, /* host doorbell interrupt/status; set by adapter, reset by host */ ! 99: IntPending = 0x80, /* interrupt pending for host */ ! 100: SignalHost = 0x01, /* Incoming Mail Interrupt */ ! 101: ProductID = 0x04, /* two byte product ID */ ! 102: Config1 = 0x06, ! 103: Config2 = 0x07, ! 104: OGMpointer = 0x08, /* pointer to Outgoing Mail */ ! 105: ICMpointer = 0x0c, /* pointer to Incoming Mail */ ! 106: }; ! 107: ! 108: #define OUT(c,v) outb(ctlr->io+(c), (v)) ! 109: #define IN(c) inb(ctlr->io+(c)) ! 110: ! 111: struct Ctlr { ! 112: int io; /* io port */ ! 113: int irq; /* interrupt vector */ ! 114: int dma; /* DMA channel */ ! 115: int ownid; /* adapter's SCSI ID */ ! 116: Mailbox mbox[Nmbox]; ! 117: Mailbox *free; /* next free Mailbox */ ! 118: }; ! 119: ! 120: static Ctlr ultra[Nctl]; ! 121: ! 122: static void ! 123: resetadapter(int busreset) ! 124: { ! 125: Ctlr *ctlr = &ultra[0]; ! 126: int i; ! 127: ! 128: if(IN(AdapterMask) & SoftResetEnable){ ! 129: OUT(AdapterIntr, SoftReset|busreset); ! 130: for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);) ! 131: if(--i<0) { ! 132: print("Ultrastor reset timed out\n"); ! 133: break; ! 134: } ! 135: } ! 136: } ! 137: ! 138: static void ! 139: freebox(Ctlr *ctlr, Mailbox *mbox) ! 140: { ! 141: mbox->next = ctlr->free; ! 142: ctlr->free = mbox; ! 143: } ! 144: ! 145: static void ! 146: ultra14fwait(Ctlr *ctlr, Mailbox *mbox) ! 147: { ! 148: ulong start; ! 149: int x; ! 150: static void interrupt(Ureg*, void*); ! 151: ! 152: x = spllo(); ! 153: start = m->ticks; ! 154: while(TK2SEC(m->ticks - start) < Timeout && mbox->busy) ! 155: ; ! 156: if(TK2SEC(m->ticks - start) >= Timeout){ ! 157: print("ultra14fwait timed out\n"); ! 158: interrupt(0, ctlr); ! 159: } ! 160: splx(x); ! 161: } ! 162: ! 163: static int ! 164: ultra14fexec(Scsi *p, int rflag) ! 165: { ! 166: Ctlr *ctlr = &ultra[0]; ! 167: Mailbox *mbox; ! 168: long n; ! 169: uchar *cp; ! 170: ulong s; ! 171: ! 172: if (p == 0 || ctlr->io == 0) ! 173: return 0x6001; /* device not available */ ! 174: ! 175: /* ! 176: * get a free Mailbox and build an Ultrastor command ! 177: */ ! 178: if((mbox = ctlr->free) == 0) ! 179: return 0x6001; ! 180: ctlr->free = mbox->next; ! 181: p->rflag = rflag; ! 182: mbox->p9status = 0; ! 183: mbox->op = OpTarget | CmdDirection | Usecache; /* BUG? is it safe always to Usecache? */ ! 184: mbox->addr = p->target | (p->lun<<5); ! 185: if(p->cmd.lim - p->cmd.ptr > sizeof(mbox->cmd)) ! 186: panic("ultra14fexec"); ! 187: mbox->cmdlen = p->cmd.lim - p->cmd.ptr; ! 188: for(cp = mbox->cmd; p->cmd.ptr < p->cmd.lim;) ! 189: *cp++ = *p->cmd.ptr++; ! 190: n = p->data.lim - p->data.ptr; ! 191: mbox->nscatter = 0; ! 192: PL(mbox->datap, PADDR(p->data.ptr)); ! 193: PL(mbox->datalen, n); ! 194: mbox->adapterstatus = 0; ! 195: mbox->targetstatus = 0; ! 196: ! 197: /* ! 198: * send the command to the host adapter ! 199: */ ! 200: s = splhi(); ! 201: if(IN(AdapterIntr) & SignalAdapter) ! 202: panic("ultrastor busy"); ! 203: mbox->busy = 1; ! 204: outl(ctlr->io+OGMpointer, mbox->physaddr); ! 205: OUT(AdapterIntr, SignalAdapter); ! 206: ! 207: /* ! 208: * wait for reply ! 209: */ ! 210: splx(s); ! 211: ultra14fwait(ctlr, mbox); ! 212: ! 213: p->status = mbox->p9status; ! 214: if(p->status == 0x6000) ! 215: p->data.ptr = p->data.lim; /* can only assume no residue */ ! 216: freebox(ctlr, mbox); ! 217: return p->status; ! 218: } ! 219: ! 220: static void ! 221: scsimoan(char *msg, Mailbox *mbox) ! 222: { ! 223: /*int i;*/ ! 224: ! 225: print("SCSI error: %s:", msg); ! 226: print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", ! 227: mbox->addr&7, mbox->cmd[0], mbox->targetstatus, mbox->adapterstatus); ! 228: /*print(" sense:"); ! 229: for(i=0; i<10; i++) ! 230: print(" %2.2x", mbox->sensedata[i]);*/ ! 231: print("\n"); ! 232: } ! 233: ! 234: static void ! 235: interrupt(Ureg*, void *arg) ! 236: { ! 237: Ctlr *ctlr; ! 238: Mailbox *mbox; ! 239: ulong pa; ! 240: ! 241: ctlr = arg; ! 242: ! 243: if((IN(HostIntr) & SignalHost) == 0) ! 244: return; /* no incoming mail */ ! 245: pa = inl(ctlr->io+ICMpointer); ! 246: OUT(HostIntr, SignalHost); /* release ICM slot */ ! 247: for(mbox = &ctlr->mbox[0]; mbox->physaddr != pa;) ! 248: if(++mbox >= &ctlr->mbox[Nmbox]) { ! 249: /* these sometimes happen in response to a scsi bus reset; ignore them */ ! 250: print("ultrastor: invalid ICM pointer #%lux\n", pa); ! 251: return; ! 252: } ! 253: ! 254: mbox->p9status = 0x1000 | mbox->adapterstatus; ! 255: switch(mbox->adapterstatus){ ! 256: default: ! 257: scsimoan("adapter", mbox); ! 258: if(mbox->adapterstatus >= 0x92) /* ie, scsi command protocol error */ ! 259: resetadapter(BusReset); ! 260: /* might adapter reset be required in other cases? */ ! 261: break; ! 262: ! 263: case 0x91: /* selection timed out */ ! 264: mbox->p9status = 0x20; ! 265: break; ! 266: ! 267: case 0xA3: ! 268: scsimoan("SCSI bus reset error", mbox); ! 269: break; ! 270: ! 271: case 0x00: ! 272: mbox->p9status = 0x6000 | mbox->targetstatus; ! 273: break; ! 274: } ! 275: mbox->busy = 0; ! 276: } ! 277: ! 278: static int irq[4] = { ! 279: 15, 14, 11, 10, ! 280: }; ! 281: ! 282: int (* ! 283: ultra14freset(void))(Scsi*, int) ! 284: { ! 285: Ctlr *ctlr = &ultra[0]; ! 286: Mailbox *mbox; ! 287: int i, model; ! 288: ! 289: /* ! 290: * Check it is an Ultrastor [13]4f. ! 291: * Only one controller for now. ! 292: * For the moment assume the factory default settings. ! 293: */ ! 294: memset(ctlr, 0, sizeof(Ctlr)); ! 295: ctlr->io = Port; ! 296: ! 297: if(IN(ProductID) != 0x56) ! 298: return 0; ! 299: model = IN(ProductID+1); ! 300: switch(model){ ! 301: ! 302: case 0x40: ! 303: model = 14; ! 304: break; ! 305: ! 306: case 0x41: ! 307: model = 34; ! 308: break; ! 309: ! 310: default: ! 311: return 0; ! 312: } ! 313: ! 314: i = IN(Config1); ! 315: ctlr->irq = irq[((i>>4)&03)]; ! 316: if(model == 14) ! 317: ctlr->dma = 5 + ((i>>6)&03); ! 318: ctlr->ownid = IN(Config2)&07; ! 319: /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n", ! 320: model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/ ! 321: ! 322: /* ! 323: * set the DMA controller to cascade mode for bus master ! 324: */ ! 325: switch(ctlr->dma){ ! 326: case 5: ! 327: outb(0xd6, 0xc1); outb(0xd4, 1); break; ! 328: case 6: ! 329: outb(0xd6, 0xc2); outb(0xd4, 2); break; ! 330: case 7: ! 331: outb(0xd6, 0xc3); outb(0xd4, 3); break; ! 332: } ! 333: ! 334: resetadapter(0); ! 335: ctlr->free = 0; ! 336: for(i=0; i<Nmbox; i++){ ! 337: mbox = &ctlr->mbox[i]; ! 338: memset(mbox, 0, sizeof(*mbox)); ! 339: mbox->physaddr = PADDR(mbox); ! 340: PL(mbox->sensep, 0); /* DON'T collect sense data automatically: messes up scuzz? */ ! 341: mbox->senselen = 0; ! 342: mbox->next = ctlr->free; ! 343: ctlr->free = mbox; ! 344: } ! 345: ! 346: setvec(Int0vec+ctlr->irq, interrupt, ctlr); ! 347: ! 348: /* ! 349: * issue AdapterInquiry command to check it's alive ! 350: * -- could check enquiry data ! 351: */ ! 352: OUT(HostMask, 0); /* mask interrupts */ ! 353: mbox = &ctlr->mbox[0]; ! 354: mbox->op = OpAdapter | CmdDirection; ! 355: mbox->addr = ctlr->ownid; ! 356: mbox->cmdlen = 1; ! 357: mbox->cmd[0] = AdapterInquiry; ! 358: PL(mbox->datap, PADDR(mbox->sensedata)); ! 359: PL(mbox->datalen, 38); ! 360: while(IN(AdapterIntr) & SignalAdapter) ! 361: ; ! 362: outl(ctlr->io+OGMpointer, mbox->physaddr); ! 363: OUT(AdapterIntr, SignalAdapter); ! 364: for(i=100000; (IN(HostIntr)&SignalHost)==0;) ! 365: if(--i < 0){ ! 366: print("No response to UltraStor Inquiry\n"); ! 367: ctlr->io = 0; ! 368: return 0; ! 369: } ! 370: OUT(HostIntr, SignalHost); ! 371: ! 372: OUT(HostMask, ICMIntEnable|SIntEnable); ! 373: ! 374: return ultra14fexec; ! 375: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.