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