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