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