|
|
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:
136: if(p->flag&NEXTWR)
137: p->flag &= ~NEXTWR;
138: else {
139: u.u_error = EGREG;
140: return;
141: }
142: if(copyin(u.u_base, &p->tran_id, 4) || copyin(u.u_base+4, &bus_id, 1)
143: || copyin(u.u_base+5, &flag, 1)
144: || copyin(u.u_base+6, &cmd->mscp_scsi, SCSICMD)){
145: u.u_error = EFAULT;
146: return;
147: }
148: if(flag & SCSI_RESET){
149: if(scsiinit(dev) == 0){
150: printf("scsi%d: reset failed\n", minor(dev));
151: p->flag = 0;
152: u.u_error = ENXIO;
153: return;
154: }
155: printf("scsi%d: reset\n", minor(dev));
156: p->flag = USED|OPEN|NEXTWR|DONE;
157: u.u_count = 0;
158: return;
159: }
160: p->timeout = (flag&SCSI_LTMOUT)? SCSILTMT:SCSISTMT;
161: count = u.u_count - (6+SCSICMD);
162: u.u_base += 6+SCSICMD;
163: if((count < 0) || (count > SCSIDATA)){
164: u.u_error = EINVAL;
165: return;
166: }
167: memset(p->data, 0xEE, BUFSIZE);
168: if(flag&SCSI_RD){
169: cmd->m__r1 = 0106;
170: count = scsilen((unsigned char *)&cmd->mscp_scsi);
171: } else if(flag&SCSI_WR){
172: if(copyin(u.u_base, p->data, count)){
173: u.u_error = EFAULT;
174: return;
175: }
176: cmd->m__r1 = 0107;
177: } else {
178: u.u_error = EINVAL;
179: return;
180: }
181: cmd->m_opcd = (flag & SCSI_BRESET)? 0160 : 0130;
182: if(scsi_dbg)
183: printf("c=%d uc=%d, dir=0%o, bus_id=%d, new count=%d timeout=%d\n",
184: count, u.u_count, cmd->m__r1, bus_id, count, p->timeout);
185: cmd->m_unit = bus_id;
186: cmd->m_bcnt = count;
187: cmd->m_fcnt = p->u1;
188: p->flag = (p->flag&~DONE)|PEND;
189: if(flag&SCSI_SENSE)
190: p->flag |= ERRSNSE;
191: p->junk->ca.ca_cmdint = 0;
192: p->junk->ca.ca_rspint = 0;
193: SETDSC(p->junk->ca.ca_cmddsc[0], UDA_OWN);
194: bus_id = p->addr->udaip; /* start controller */
195: u.u_count = 0;
196: }
197:
198: scsiread(dev)
199: dev_t dev;
200: {
201: register struct scsi *p = &scsi[minor(dev)];
202: register count;
203:
204: if(p->flag&NEXTWR){
205: u.u_error = EGREG;
206: return;
207: } else
208: p->flag |= NEXTWR;
209: if((p->flag&DONE) == 0){
210: if(tsleep((caddr_t)p, PZERO+1, p->timeout) != TS_OK){
211: u.u_error = ENXIO;
212: return;
213: }
214: }
215: if(p->sa&0x8000){
216: printf("scsi%d: error sa=#%x\n", minor(dev), p->sa&0xFFFF);
217: u.u_error = EIO;
218: scsiinit(dev);
219: return;
220: }
221: count = u.u_count - SCSIRET;
222: if(count > p->junk->rsp.msg.m_bcnt)
223: count = p->junk->rsp.msg.m_bcnt;
224: if((count < 0) || (count > SCSIDATA)){
225: u.u_error = EINVAL;
226: return;
227: }
228: ((unsigned long *)p->status)[0] = p->tran_id;
229: p->status[4] = p->junk->rsp.msg.m_fbbk;
230: p->status[5] = p->junk->rsp.msg.m_fbbk>>8;
231: p->status[6] = 0; /* flags */
232: p->status[7] = 1; /* viking */
233: ((short *)p->status)[4] = p->sa;
234: ((short *)p->status)[5] = p->junk->rsp.msg.m_sts;
235: if(copyout(p->status, u.u_base, SCSIRET)){
236: u.u_error = EFAULT;
237: return;
238: }
239: if(count)
240: if(copyout(p->data, u.u_base+SCSIRET, count)){
241: u.u_error = EFAULT;
242: return;
243: }
244: if(p->junk->rsp.msg.m_sts){
245: printf("scsi%d: stat=#%x\n", minor(dev), p->junk->rsp.msg.m_sts);
246: u.u_error = (p->junk->rsp.msg.m_sts == 0x80a)? ESRCH : EIO;
247: return;
248: }
249: u.u_count -= SCSIRET+count;
250: SETDSC(p->junk->ca.ca_rspdsc[0], UDA_OWN|UDA_INT);
251: }
252:
253: scsi0int(dev)
254: dev_t dev;
255: {
256: register struct scsi *p = &scsi[minor(dev)];
257: register s;
258:
259: if((p->flag&PEND) == 0){
260: printf("scsi%d: unexpected interrupt\n", minor(dev));
261: return;
262: }
263: if(p->junk->ca.ca_rspint == 0){
264: 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]);
265: return;
266: }
267: p->sa = p->addr->udasa;
268: s = spl6();
269: p->flag = (p->flag&~PEND)|DONE;
270: splx(s);
271: wakeup((caddr_t)p);
272: }
273:
274: /*
275: * hardware initialization handshake
276: * for simplicity, don't bother with init interrupts
277: * returns nonzero if ok
278: */
279:
280: #define UDA_STEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)
281:
282: scsiinit(d)
283: int d;
284: {
285: register struct scsi *p = &scsi[minor(d)];
286: register struct udadevice *udaddr;
287: register int i;
288: time_t out;
289: int s;
290:
291: udaddr = p->addr;
292: out = time + 11;
293: s = spl0();
294: printf("scsi1");
295: udaddr->udaip = 0;
296: while((udaddr->udasa & (UDA_ERR|UDA_STEP1)) == 0 && time <= out)
297: ;
298: if((udaddr->udasa & UDA_STEPS) != UDA_STEP1) {
299: steperr("1", udaddr->udasa, d);
300: splx(s);
301: return (0);
302: }
303: udaddr->udasa = UDA_ERR|(SCSIINTR/4);
304: /* no diagnostic wrap, no interrupts during initialization */
305: printf("2");
306: out = time + 21;
307: while((udaddr->udasa & (UDA_ERR|UDA_STEP2)) == 0 && time <= out)
308: ;
309: if((udaddr->udasa & UDA_STEPS) != UDA_STEP2) {
310: steperr("2", udaddr->udasa, d);
311: splx(s);
312: return (0);
313: }
314: i = p->u2; /* unibus address of bag */
315: i += (long)&p->junk->ca.ca_rspdsc[0] - (long)p->junk;
316: udaddr->udasa = (short)i;
317: out = time + 11;
318: printf("3");
319: while((udaddr->udasa & (UDA_ERR|UDA_STEP3)) == 0 && time <= out)
320: ;
321: if((udaddr->udasa & UDA_STEPS) != UDA_STEP3) {
322: steperr("3", udaddr->udasa, d);
323: splx(s);
324: return (0);
325: }
326: udaddr->udasa = (i >> 16)&0x3F;
327: out = time + 11;
328: printf("4");
329: while((udaddr->udasa & (UDA_ERR|UDA_STEP4)) == 0 && time <= out)
330: ;
331: if((udaddr->udasa & UDA_STEPS) != UDA_STEP4) {
332: steperr("4", udaddr->udasa, d);
333: splx(s);
334: return (0);
335: }
336: i = p->u2 + (long)&p->junk->rsp.msg.m_crf - (long)p->junk;
337: p->junk->ca.ca_rspdsc[0] = UDA_OWN|UDA_INT|i;
338: i = p->u2 + (long)&p->junk->cmd.msg.m_crf - (long)p->junk;
339: p->junk->ca.ca_cmddsc[0] = i;
340: if (udaddr->udasa & UDA_ERR) {
341: steperr("5", udaddr->udasa, d);
342: splx(s);
343: return (0);
344: }
345: udaddr->udasa = UDA_GO; /* finish init */
346: /* finish cmd packet init */
347: p->junk->cmd.msg_len = 44;
348: p->junk->cmd.msg.m_crf = (long)p->junk;
349: p->junk->cmd.msg.m_opcd = 0130;
350: splx(s);
351: printf(" done\n");
352: return (1);
353: }
354:
355: steperr(str, sa, dev)
356: char *str;
357: {
358: printf("scsi%d: step%s error, sa=#%x\n", minor(dev), str, sa&0xFFFF);
359: }
360:
361: /*
362: dreck to figure out how much we should read back
363: */
364:
365: scsilen(cmd)
366: unsigned char *cmd;
367: {
368: switch(cmd[0])
369: {
370: case 0x03: return(cmd[4]);
371: case 0x08: return(cmd[4]*1024);
372: case 0x12: return(cmd[4]);
373: case 0x1A: return(cmd[4]);
374: case 0x1C: return(cmd[3]*256 + cmd[4]);
375: case 0x25: return(8);
376: case 0x28: return(1024*(256*cmd[7] + cmd[8]));
377: case 0x2C: return(6);
378: case 0x2D: return(6);
379: case 0x4D: return(1*(256*cmd[7] + cmd[8]));
380: case 0xC2: return(1024);
381: case 0xC3: return(4096);
382: case 0xD3: return(20);
383: }
384: return(0);
385: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.