|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "devtab.h"
8: #include "io.h"
9:
10: int scsiintr(void);
11:
12: #define DPRINT if(debug)kprint
13:
14: int scsidebugs[8];
15: int scsiownid = 0x08|7; /* enable advanced features */
16:
17: Scsibuf *
18: scsialloc(ulong n)
19: {
20: Scsibuf *b;
21:
22: b = xalloc(sizeof(Scsibuf));
23: b->virt = b->phys = xalloc(n);
24: return b;
25: }
26:
27: typedef struct Scsictl {
28: uchar asr;
29: uchar data;
30: uchar stat;
31: uchar dma;
32: } Scsictl;
33:
34: #define Scsiaddr 48
35: #define DEV ((Scsictl *)&PORT[Scsiaddr])
36:
37: static long poot;
38: #define WAIT (poot=0, poot==0?0:poot)
39:
40: #define PUT(a,d) (DEV->asr=(a), WAIT, DEV->data=(d))
41: #define GET(a) (DEV->asr=(a), WAIT, DEV->data)
42:
43: enum Int_status {
44: Inten = 0x01, Scsirst = 0x02,
45: INTRQ = 0x01, DMA = 0x02,
46: };
47:
48: enum SBIC_regs {
49: Own_id=0x00, Control=0x01, CDB=0x03, Target_LUN=0x0f,
50: Cmd_phase=0x10, Tc_hi=0x12,
51: Dest_id=0x15, Src_id=0x16, SCSI_Status=0x17,
52: Cmd=0x18, Data=0x19,
53: };
54:
55: enum Commands {
56: Reset = 0x00,
57: Assert_ATN = 0x02,
58: Negate_ACK = 0x03,
59: Select_with_ATN = 0x06,
60: Select_with_ATN_and_Xfr = 0x08,
61: Select_and_Xfr = 0x09,
62: Transfer_Info = 0x20,
63: SBT = 0x80, /* modifier for single-byte transfer */
64: };
65:
66: enum Aux_status {
67: INT=0x80, LCI=0x40, BSY=0x20, CIP=0x10,
68: PE=0x02, DBR=0x01,
69: };
70:
71: static int isscsi;
72: static QLock scsilock;
73: static Rendez scsirendez;
74: static uchar * datap;
75: static uchar * datalim;
76: static long debug, scsirflag, scsibusy, scsiinservice;
77:
78: static void
79: nop(void)
80: {}
81:
82: void
83: resetscsi(void)
84: {
85: static int inited;
86:
87: if(!inited)
88: addportintr(scsiintr);
89: inited = 1;
90: }
91:
92: void
93: initscsi(void)
94: {
95: isscsi = portprobe("scsi", -1, Scsiaddr, -1, 0L);
96: if (isscsi >= 0) {
97: DEV->stat = Scsirst;
98: delay(100);
99: DEV->stat = Inten;
100: while (DEV->stat & (INTRQ|DMA))
101: nop();
102: scsiownid &= 0x0f; /* possibly advanced features */
103: scsiownid |= 0x80; /* 16MHz */
104: PUT(Own_id, scsiownid);
105: PUT(Cmd, Reset);
106: }
107: }
108:
109: static int
110: scsidone(void *arg)
111: {
112: USED(arg);
113: return (scsibusy == 0);
114: }
115:
116: int
117: scsiexec(Scsi *p, int rflag)
118: {
119: long n;
120:
121: debug = scsidebugs[p->target&7];
122: DPRINT("scsi %d.%d %2.2ux ", p->target, p->lun, *(p->cmd.ptr));
123: qlock(&scsilock);
124: scsirflag = rflag;
125: p->rflag = rflag;
126: datap = p->data.base;
127: datalim = p->data.lim;
128: if ((scsiownid & 0x08) && rflag)
129: PUT(Dest_id, 0x40|p->target);
130: else
131: PUT(Dest_id, p->target);
132: PUT(Target_LUN, p->lun);
133: n = p->data.lim - p->data.base;
134: PUT(Tc_hi, n>>16);
135: DEV->data = n>>8;
136: DEV->data = n;
137: if (scsiownid & 0x08) {
138: n = p->cmd.lim - p->cmd.ptr;
139: DPRINT("len=%d ", n);
140: PUT(Own_id, n);
141: }
142: PUT(CDB, *(p->cmd.ptr)++);
143: while (p->cmd.ptr < p->cmd.lim)
144: DEV->data = *(p->cmd.ptr)++;
145: scsibusy = 1;
146: PUT(Cmd, Select_and_Xfr);
147: /*PUT(Cmd, Select_with_ATN_and_Xfr);*/
148: while(waserror())
149: ;
150: DPRINT("S<");
151: sleep(&scsirendez, scsidone, 0);
152: DPRINT(">\n");
153: p->data.ptr = datap;
154: p->status = GET(Target_LUN);
155: p->status |= DEV->data<<8;
156: poperror();
157: qunlock(&scsilock);
158: debug = 0;
159: return p->status;
160: }
161:
162: void
163: scsirun(void)
164: {
165: wakeup(&scsirendez);
166: scsibusy = 0;
167: }
168:
169: void
170: scsireset0(void)
171: {
172: /* PUT(Control, 0x29); /* burst DMA, halt on parity error */
173: PUT(Control, 0x28); /* burst DMA, allow parity errors */
174: PUT(Control+1, 0xff); /* timeout */
175: PUT(Src_id, 0x80); /* enable reselection */
176: scsirun();
177: /*qunlock(&scsilock);*/
178: }
179:
180: int
181: scsiintr(void)
182: {
183: int status, s;
184:
185: if(isscsi < 0 || scsiinservice
186: || !((status = DEV->stat) & (DMA|INTRQ)))
187: return 0;
188: DEV->stat = 0;
189: scsiinservice = 1;
190: s = spl1();
191: DPRINT("i%x ", status);
192: do{
193: if (status & DMA)
194: scsidmaintr();
195: if (status & INTRQ)
196: scsictrlintr();
197: }while ((status = DEV->stat) & (DMA|INTRQ));
198: splx(s);
199: scsiinservice = 0;
200: DEV->stat = Inten;
201: return 1;
202: }
203:
204: void
205: scsidmaintr(void)
206: {
207: uchar *p = 0;
208: /*
209: * if (scsirflag) {
210: * unsigned char *p;
211: * DPRINT("R", p=datap);
212: * do
213: * *datap++ = DEV->dma;
214: * while (DEV->stat & DMA);
215: * DPRINT("%d ", datap-p);
216: * } else {
217: * unsigned char *p;
218: * DPRINT("W", p=datap);
219: * do
220: * DEV->dma = *datap++;
221: * while (DEV->stat & DMA);
222: * DPRINT("%d ", datap-p);
223: * }
224: */
225: if(scsirflag){
226: DPRINT("R", p=datap);
227: datap = scsirecv(datap);
228: DPRINT("%d ", datap-p);
229: }else{
230: DPRINT("X", p=datap);
231: datap = scsixmit(datap);
232: DPRINT("%d ", datap-p);
233: }
234: }
235:
236: void
237: scsictrlintr(void)
238: {
239: int status, phase;
240: long n;
241:
242: status = GET(SCSI_Status);
243: DPRINT("I%2.2x ", status);
244: switch(status){
245: case 0x00: /* reset by command or power-up */
246: case 0x01: /* reset by command or power-up */
247: scsireset0();
248: break;
249: case 0x21: /* Save Data Pointers message received */
250: n = GET(Tc_hi);
251: n = (n<<8)|DEV->data;
252: n = (n<<8)|DEV->data;
253: datap = datalim - n;
254: PUT(Cmd_phase, 0x41);
255: PUT(Cmd, Select_and_Xfr);
256: break;
257: case 0x16: /* select-and-transfer completed */
258: case 0x42: /* timeout during select */
259: scsirun();
260: break;
261: case 0x4b: /* unexpected status phase */
262: DEV->asr = Target_LUN;
263: kprint("lun/status 0x%ux\n", DEV->data);
264: phase = DEV->data;
265: kprint("phase 0x%ux\n", phase);
266: PUT(Tc_hi, 0);
267: DEV->data = 0;
268: DEV->data = 0;
269: switch(phase){
270: case 0x50:
271: case 0x60:
272: break;
273: default:
274: phase = 0x46;
275: break;
276: }
277: PUT(Cmd_phase, phase);
278: PUT(Cmd, Select_and_Xfr);
279: break;
280: default:
281: kprint("scsintr 0x%ux\n", status);
282: DEV->asr = Target_LUN;
283: kprint("lun/status 0x%ux\n", DEV->data);
284: kprint("phase 0x%ux\n", DEV->data);
285: switch (status&0xf0) {
286: case 0x00:
287: case 0x10:
288: case 0x20:
289: case 0x40:
290: case 0x80:
291: if(status & 0x08){
292: kprint("count 0x%ux", GET(Tc_hi));
293: kprint(" 0x%ux", DEV->data);
294: kprint(" 0x%ux\n", DEV->data);
295: }
296: scsirun();
297: break;
298: default:
299: panic("scsi status 0x%2.2ux", status);
300: }
301: kprint("resetting...");
302: PUT(Own_id, scsiownid);
303: PUT(Cmd, Reset);
304: break;
305: }
306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.