|
|
1.1 root 1: /*
2: SCSI Pass-Thru driver for the TD Systems UD? -- Andrew Hume
3: Ninth Edition Unix
4: */
5:
6: #include "sys/param.h"
7: #include "sys/user.h"
8: #include "sys/buf.h"
9: #include "sys/systm.h"
10: #include "sys/pte.h"
11: #include "sys/map.h"
12: #include "sys/ubaddr.h"
13: #include "sys/conf.h"
14:
15: #include "sys/uda.h"
16: #include "sys/mscp.h"
17:
18: #include "sys/scsi.h"
19: #include <scsi.h>
20:
21: #define mscp_scsi m_fmt
22:
23: struct udadevice {
24: short udaip; /* initialization and polling */
25: short udasa; /* status and address */
26: };
27: #define UDA_ERR 0100000 /* error bit */
28: #define UDA_STEP4 0040000 /* step 4 has started */
29: #define UDA_STEP3 0020000 /* step 3 has started */
30: #define UDA_STEP2 0010000 /* step 2 has started */
31: #define UDA_STEP1 0004000 /* step 1 has started */
32: #define UDA_GO 0000001 /* start operation, after init */
33:
34: #define UDA_OWN 0x80000000 /* UDA owns this descriptor */
35: #define UDA_INT 0x40000000 /* allow interrupt on ring transition */
36:
37: #define WAITPRI (PZERO+1)
38: #define SCSILTMT 300 /* long timeout in seconds */
39: #define SCSISTMT 10 /* short timeout in seconds */
40: #define ERROR 0x8000 /* in csr */
41: #define SCSIINTR 0700
42: #define SETDSC(dsc, fl) dsc = (dsc&~(UDA_OWN|UDA_INT))|fl
43:
44: static memset(p, c, n)
45: register char *p, c;
46: register n;
47: {
48: while(n-- > 0)
49: *p++ = c;
50: }
51:
52: int scsiopen(), scsiclose(), scsiread(), scsiwrite();
53:
54: extern struct scsi scsi[];
55: extern struct ubaddr scsiaddr[];
56: extern int scsicnt;
57: struct cdevsw scsicdev =
58: cdinit(scsiopen, scsiclose, scsiread, scsiwrite, nodev);
59: int scsi_dbg = 0;
60:
61: scsiopen(dev)
62: dev_t dev;
63: {
64: register struct scsi *p;
65:
66: if((dev = minor(dev)) >= scsicnt) {
67: u.u_error = ENODEV;
68: return;
69: }
70: if((p = &scsi[dev])->flag&OPEN) {
71: u.u_error = EBUSY;
72: return;
73: }
74: if(((p->addr = (struct udadevice *)ubaddr(&scsiaddr[dev])) == 0)
75: || ubbadaddr(scsiaddr[dev].ubno, (caddr_t)p->addr, sizeof(u_short))) {
76: printf("scsi%d absent\n", dev);
77: u.u_error = ENODEV;
78: return;
79: }
80: if((p->flag&USED) == 0)
81: if(scsistart(dev))
82: return;
83: p->flag = USED|OPEN|NEXTWR|DONE;
84: }
85:
86: scsistart(dev)
87: dev_t dev;
88: {
89: register struct scsi *p = &scsi[minor(dev)];
90:
91: p->flag |= DONE;
92: p->b1 = geteblk();
93: p->b1->b_bcount = BUFSIZE;
94: p->b1->b_flags = B_BUSY;
95: clrbuf(p->b1);
96: p->ub1 = ubmbuf(scsiaddr[minor(dev)].ubno, p->b1, USLP);
97: p->u1 = ubadbuf(scsiaddr[minor(dev)].ubno, p->b1, p->ub1);
98: p->data = (unsigned char *)p->b1->b_un.b_addr;
99: p->b2 = geteblk();
100: p->b2->b_bcount = BUFSIZE;
101: p->b2->b_flags = B_BUSY;
102: clrbuf(p->b2);
103: p->ub2 = ubmbuf(scsiaddr[minor(dev)].ubno, p->b2, USLP);
104: p->u2 = ubadbuf(scsiaddr[minor(dev)].ubno, p->b2, p->ub2);
105: p->junk = (struct bag *)p->b2->b_un.b_addr;
106: p->timeout = SCSISTMT;
107: if(scsiinit(dev) == 0){
108: scsiclose(dev);
109: p->flag = 0;
110: u.u_error = ENXIO;
111: return(1);
112: }
113: printf("scsi%d run\n", minor(dev));
114: return(0);
115: }
116:
117: scsiclose(dev)
118: dev_t dev;
119: {
120: register struct scsi *p = &scsi[minor(dev)];
121:
122: if((p->flag&DONE) == 0){ /* wait for I/O to complete */
123: (void)tsleep((caddr_t)p, PZERO+1, p->timeout);
124: }
125: p->flag = USED;
126: }
127:
128: scsiwrite(dev)
129: dev_t dev;
130: {
131: register count;
132: register struct scsi *p = &scsi[minor(dev)];
133: register struct mscmd *cmd = &p->junk->cmd.msg;
134: unsigned char flag, bus_id;
135: long readback;
136:
137: if(p->flag&NEXTWR)
138: p->flag &= ~NEXTWR;
139: else {
140: u.u_error = EGREG;
141: return;
142: }
143: if(copyin(u.u_base, &p->tran_id, 4) || copyin(u.u_base+4, &bus_id, 1)
144: || copyin(u.u_base+5, &flag, 1)
145: || copyin(u.u_base+6, &readback, 4)
146: || copyin(u.u_base+10, &cmd->mscp_scsi, SCSICMD)){
147: u.u_error = EFAULT;
148: return;
149: }
150: if(flag & SCSI_RESET){
151: if(scsiinit(dev) == 0){
152: printf("scsi%d: reset failed\n", minor(dev));
153: p->flag = 0;
154: u.u_error = ENXIO;
155: return;
156: }
157: printf("scsi%d: reset\n", minor(dev));
158: p->flag = USED|OPEN|NEXTWR|DONE;
159: u.u_count = 0;
160: return;
161: }
162: p->timeout = (flag&SCSI_LTMOUT)? SCSILTMT:SCSISTMT;
163: count = u.u_count - (10+SCSICMD);
164: u.u_base += 10+SCSICMD;
165: if((count < 0) || (count > SCSIDATA)){
166: u.u_error = EINVAL;
167: return;
168: }
169: memset(p->data, 0xEE, BUFSIZE);
170: if(flag&SCSI_RD){
171: cmd->m__r1 = 0106;
172: count = readback;
173: } else if(flag&SCSI_WR){
174: if(copyin(u.u_base, p->data, count)){
175: u.u_error = EFAULT;
176: return;
177: }
178: cmd->m__r1 = 0107;
179: } else {
180: u.u_error = EINVAL;
181: return;
182: }
183: cmd->m_opcd = (flag & SCSI_BRESET)? 0160 : 0130;
184: if(scsi_dbg)
185: printf("c=%d uc=%d, dir=0%o, bus_id=%d, new count=%d timeout=%d\n",
186: count, u.u_count, cmd->m__r1, bus_id, count, p->timeout);
187: cmd->m_unit = bus_id;
188: cmd->m_bcnt = count;
189: cmd->m_fcnt = p->u1;
190: p->flag = (p->flag&~DONE)|PEND;
191: if(flag&SCSI_SENSE)
192: p->flag |= ERRSNSE;
193: p->junk->ca.ca_cmdint = 0;
194: p->junk->ca.ca_rspint = 0;
195: SETDSC(p->junk->ca.ca_cmddsc[0], UDA_OWN);
196: bus_id = p->addr->udaip; /* start controller */
197: u.u_count = 0;
198: }
199:
200: scsiread(dev)
201: dev_t dev;
202: {
203: register struct scsi *p = &scsi[minor(dev)];
204: register count;
205:
206: if(p->flag&NEXTWR){
207: u.u_error = EGREG;
208: return;
209: } else
210: p->flag |= NEXTWR;
211: if((p->flag&DONE) == 0){
212: if(tsleep((caddr_t)p, PZERO+1, p->timeout) != TS_OK){
213: u.u_error = ENXIO;
214: return;
215: }
216: }
217: if(p->sa&0x8000){
218: printf("scsi%d: error sa=#%x\n", minor(dev), p->sa&0xFFFF);
219: u.u_error = EIO;
220: scsiinit(dev);
221: return;
222: }
223: count = u.u_count - SCSIRET;
224: if(count > p->junk->rsp.msg.m_bcnt)
225: count = p->junk->rsp.msg.m_bcnt;
226: if((count < 0) || (count > SCSIDATA)){
227: u.u_error = EINVAL;
228: return;
229: }
230: ((unsigned long *)p->status)[0] = p->tran_id;
231: p->status[4] = p->junk->rsp.msg.m_fbbk;
232: p->status[5] = p->junk->rsp.msg.m_fbbk>>8;
233: p->status[6] = 0; /* flags */
234: p->status[7] = 1; /* viking */
235: ((short *)p->status)[4] = p->sa;
236: ((short *)p->status)[5] = p->junk->rsp.msg.m_sts;
237: if(copyout(p->status, u.u_base, SCSIRET)){
238: u.u_error = EFAULT;
239: return;
240: }
241: if(count)
242: if(copyout(p->data, u.u_base+SCSIRET, count)){
243: u.u_error = EFAULT;
244: return;
245: }
246: if(p->junk->rsp.msg.m_sts){
247: printf("scsi%d: stat=#%x\n", minor(dev), p->junk->rsp.msg.m_sts);
248: u.u_error = (p->junk->rsp.msg.m_sts == 0x80a)? ESRCH : EIO;
249: return;
250: }
251: u.u_count -= SCSIRET+count;
252: SETDSC(p->junk->ca.ca_rspdsc[0], UDA_OWN|UDA_INT);
253: }
254:
255: scsi0int(dev)
256: dev_t dev;
257: {
258: register struct scsi *p = &scsi[minor(dev)];
259: register s;
260:
261: if((p->flag&PEND) == 0){
262: printf("scsi%d: unexpected interrupt\n", minor(dev));
263: return;
264: }
265: if(p->junk->ca.ca_rspint == 0){
266: printf("scsi%d: rspint=0 cmdint=%d rsp=#%x cmd=#%x\n", minor(dev), p->junk->ca.ca_cmdint, p->junk->ca.ca_rspdsc[0], p->junk->ca.ca_cmddsc[0]);
267: return;
268: }
269: p->sa = p->addr->udasa;
270: s = spl6();
271: p->flag = (p->flag&~PEND)|DONE;
272: splx(s);
273: wakeup((caddr_t)p);
274: }
275:
276: /*
277: * hardware initialization handshake
278: * for simplicity, don't bother with init interrupts
279: * returns nonzero if ok
280: */
281:
282: #define UDA_STEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)
283:
284: scsiinit(d)
285: int d;
286: {
287: register struct scsi *p = &scsi[minor(d)];
288: register struct udadevice *udaddr;
289: register int i;
290: time_t out;
291: int s;
292:
293: udaddr = p->addr;
294: out = time + 11;
295: s = spl0();
296: printf("scsi1");
297: udaddr->udaip = 0;
298: while((udaddr->udasa & (UDA_ERR|UDA_STEP1)) == 0 && time <= out)
299: ;
300: if((udaddr->udasa & UDA_STEPS) != UDA_STEP1) {
301: steperr("1", udaddr->udasa, d);
302: splx(s);
303: return (0);
304: }
305: udaddr->udasa = UDA_ERR|(SCSIINTR/4);
306: /* no diagnostic wrap, no interrupts during initialization */
307: printf("2");
308: out = time + 21;
309: while((udaddr->udasa & (UDA_ERR|UDA_STEP2)) == 0 && time <= out)
310: ;
311: if((udaddr->udasa & UDA_STEPS) != UDA_STEP2) {
312: steperr("2", udaddr->udasa, d);
313: splx(s);
314: return (0);
315: }
316: i = p->u2; /* unibus address of bag */
317: i += (long)&p->junk->ca.ca_rspdsc[0] - (long)p->junk;
318: udaddr->udasa = (short)i;
319: out = time + 11;
320: printf("3");
321: while((udaddr->udasa & (UDA_ERR|UDA_STEP3)) == 0 && time <= out)
322: ;
323: if((udaddr->udasa & UDA_STEPS) != UDA_STEP3) {
324: steperr("3", udaddr->udasa, d);
325: splx(s);
326: return (0);
327: }
328: udaddr->udasa = (i >> 16)&0x3F;
329: out = time + 11;
330: printf("4");
331: while((udaddr->udasa & (UDA_ERR|UDA_STEP4)) == 0 && time <= out)
332: ;
333: if((udaddr->udasa & UDA_STEPS) != UDA_STEP4) {
334: steperr("4", udaddr->udasa, d);
335: splx(s);
336: return (0);
337: }
338: i = p->u2 + (long)&p->junk->rsp.msg.m_crf - (long)p->junk;
339: p->junk->ca.ca_rspdsc[0] = UDA_OWN|UDA_INT|i;
340: i = p->u2 + (long)&p->junk->cmd.msg.m_crf - (long)p->junk;
341: p->junk->ca.ca_cmddsc[0] = i;
342: if (udaddr->udasa & UDA_ERR) {
343: steperr("5", udaddr->udasa, d);
344: splx(s);
345: return (0);
346: }
347: udaddr->udasa = UDA_GO; /* finish init */
348: /* finish cmd packet init */
349: p->junk->cmd.msg_len = 44;
350: p->junk->cmd.msg.m_crf = (long)p->junk;
351: p->junk->cmd.msg.m_opcd = 0130;
352: splx(s);
353: printf(" done\n");
354: return (1);
355: }
356:
357: steperr(str, sa, dev)
358: char *str;
359: {
360: printf("scsi%d: step%s error, sa=#%x\n", minor(dev), str, sa&0xFFFF);
361: }
362:
363: /*
364: dreck to figure out how much we should read back
365: */
366:
367: scsilen(cmd)
368: unsigned char *cmd;
369: {
370: switch(cmd[0])
371: {
372: case 0x03: return(cmd[4]);
373: case 0x08: return(cmd[4]*1024);
374: case 0x12: return(cmd[4]);
375: case 0x1A: return(cmd[4]);
376: case 0x1C: return(cmd[3]*256 + cmd[4]);
377: case 0x25: return(8);
378: case 0x28: return(1024*(256*cmd[7] + cmd[8]));
379: case 0x2C: return(6);
380: case 0x2D: return(6);
381: case 0x4D: return(1*(256*cmd[7] + cmd[8]));
382: case 0xC2: return(1024);
383: case 0xC3: return(4096);
384: case 0xD3: return(20);
385: }
386: return(0);
387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.