|
|
1.1 root 1: /*
2: * UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED! UNFINISHED!
3: *
4: * [email protected] 93/04/02
5: *
6: * I was writing this driver for a wd7000-ASC. Yeah, the "-ASC" not the
7: * "-FASST2". The difference is that the "-ASC" is missing scatter gather
8: * support.
9: *
10: * In any case, the real reason why I never finished it is because the
11: * motherboard I have has broken DMA. This card wants 8MHz 1 wait state
12: * operation, and my board munges about 30% of the words transferred.
13: *
14: * Hopefully someone can finish this for the wd7000-FASST2. It should be
15: * quite easy to do. Look at the Linux wd7000 device driver to see how
16: * scatter gather is done by the board, then look at one of the Adaptec
17: * drivers to finish off the job..
18: */
19: #include "wds.h"
20: #if NWDS > 0
21:
22: #include <sys/types.h>
23: #include <sys/param.h>
24: #include <sys/systm.h>
25: #include <sys/errno.h>
26: #include <sys/ioctl.h>
27: #include <sys/buf.h>
28: #include <sys/proc.h>
29: #include <sys/user.h>
30:
31: #include <i386/isa/isa_device.h>
32: #include <scsi/scsi_all.h>
33: #include <scsi/scsiconf.h>
34:
35: extern int delaycount; /* from clock setup code */
36:
37: #define PHYSTOKV(x) ( (u_long)(x) | 0xFE000000)
38: #define KVTOPHYS(x) vtophys(x)
39: #define PAGESIZ 4096
40: #define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
41:
42:
43: /* WD7000 registers */
44: #define WDS_STAT 0 /* read */
45: #define WDS_IRQSTAT 1 /* read */
46:
47: #define WDS_CMD 0 /* write */
48: #define WDS_IRQACK 1 /* write */
49: #define WDS_HCR 2 /* write */
50:
51: /* WDS_STAT (read) defs */
52: #define WDS_IRQ 0x80
53: #define WDS_RDY 0x40
54: #define WDS_REJ 0x20
55: #define WDS_INIT 0x10
56:
57: /* WDS_IRQSTAT (read) defs */
58: #define WDSI_MASK 0xc0
59: #define WDSI_ERR 0x00
60: #define WDSI_MFREE 0x80
61: #define WDSI_MSVC 0xc0
62:
63: /* WDS_CMD (write) defs */
64: #define WDSC_NOOP 0x00
65: #define WDSC_INIT 0x01
66: #define WDSC_DISUNSOL 0x02
67: #define WDSC_ENAUNSOL 0x03
68: #define WDSC_IRQMFREE 0x04
69: #define WDSC_SCSIRESETSOFT 0x05
70: #define WDSC_SCSIRESETHARD 0x06
71: #define WDSC_MSTART(m) (0x80 + (m))
72: #define WDSC_MMSTART(m) (0xc0 + (m))
73:
74: /* WDS_HCR (write) defs */
75: #define WDSH_IRQEN 0x08
76: #define WDSH_DRQEN 0x04
77: #define WDSH_SCSIRESET 0x02
78: #define WDSH_ASCRESET 0x01
79:
80: struct wds_cmd {
81: u_char cmd;
82: u_char targ;
83: struct scsi_generic scb; /*u_char scb[12];*/
84: u_char stat;
85: u_char venderr;
86: u_char len[3];
87: u_char data[3];
88: u_char next[3];
89: u_char write;
90: u_char xx[6];
91: };
92:
93: struct wds_req {
94: struct wds_cmd cmd;
95: struct wds_cmd sense;
96: struct scsi_xfer *sxp;
97: int busy, polled;
98: int done, ret, ombn;
99: };
100:
101: #define WDSX_SCSICMD 0x00
102: #define WDSX_OPEN_RCVBUF 0x80
103: #define WDSX_RCV_CMD 0x81
104: #define WDSX_RCV_DATA 0x82
105: #define WDSX_RCV_DATASTAT 0x83
106: #define WDSX_SND_DATA 0x84
107: #define WDSX_SND_DATASTAT 0x85
108: #define WDSX_SND_CMDSTAT 0x86
109: #define WDSX_READINIT 0x88
110: #define WDSX_READSCSIID 0x89
111: #define WDSX_SETUNSOLIRQMASK 0x8a
112: #define WDSX_GETUNSOLIRQMASK 0x8b
113: #define WDSX_GETFIRMREV 0x8c
114: #define WDSX_EXECDIAG 0x8d
115: #define WDSX_SETEXECPARM 0x8e
116: #define WDSX_SETEXECPARM 0x8e
117: #define WDSX_GETEXECPARM 0x8f
118:
119: struct wds_mb {
120: u_char stat;
121: u_char addr[3];
122: };
123: /* ICMB status value */
124: #define ICMB_OK 0x01
125: #define ICMB_OKERR 0x02
126: #define ICMB_ETIME 0x04
127: #define ICMB_ERESET 0x05
128: #define ICMB_ETARCMD 0x06
129: #define ICMB_ERESEL 0x80
130: #define ICMB_ESEL 0x81
131: #define ICMB_EABORT 0x82
132: #define ICMB_ESRESET 0x83
133: #define ICMB_EHRESET 0x84
134:
135: struct wds_setup {
136: u_char cmd;
137: u_char scsi_id;
138: u_char buson_t;
139: u_char busoff_t;
140: u_char xx;
141: u_char mbaddr[3];
142: u_char nomb;
143: u_char nimb;
144: };
145:
146: #define WDS_NOMB 16
147: #define WDS_NIMB 8
148: #define MAXSIMUL 8
149: struct wds {
150: u_short addr;
151: struct wds_req wdsr[MAXSIMUL];
152: struct wds_mb ombs[WDS_NOMB], imbs[WDS_NIMB];
153: int devs;
154: } wds[NWDS];
155:
156: static int wdsunit = 0;
157: int wds_debug = 0;
158:
159: int wdsprobe(), wdsattach(), wdsintr();
160:
161: struct isa_driver wdsdriver = {
162: wdsprobe,
163: wdsattach,
164: "wds",
165: };
166:
167: int wds_scsi_cmd();
168: void wds_minphys();
169: long wds_adapter_info();
170:
171: struct scsi_switch wds_switch = {
172: wds_scsi_cmd,
173: wds_minphys,
174: 0, 0,
175: wds_adapter_info,
176: 0, 0, 0,
177: };
178:
179: p2x(p, x)
180: u_char *p;
181: u_long x;
182: {
183: p[0] = (x & 0x00ff0000) >> 16;
184: p[1] = (x & 0x0000ff00) >> 8;
185: p[2] = (x & 0x000000ff);
186: }
187:
188: u_char *
189: x2p(x)
190: u_char *x;
191: {
192: u_long q;
193:
194: q = ((x[0]<<16) & 0x00ff0000) + ((x[1]<<8) & 0x0000ff00) + (x[2] & 0x000000ff);
195: return (u_char *)q;
196: }
197:
198: wdsprobe(dev)
199: struct isa_device *dev;
200: {
201: scsi_debug = PRINTROUTINES | TRACEOPENS | TRACEINTERRUPTS |
202: SHOWREQUESTS | SHOWSCATGATH | SHOWINQUIRY | SHOWCOMMANDS;
203:
204: if(wdsunit > NWDS)
205: return 0;
206:
207: dev->id_unit = wdsunit;
208: wds[wdsunit].addr = dev->id_iobase;
209:
210: if(wds_init(dev) != 0)
211: return 0;
212: wdsunit++;
213: return 1;
214: }
215:
216: void
217: wds_minphys(bp)
218: struct buf *bp;
219: {
220: int base = (int)bp->b_un.b_addr & (PAGESIZ-1);
221:
222: if(base + bp->b_bcount > PAGESIZ)
223: bp->b_bcount = PAGESIZ - base;
224: }
225:
226: struct wds_req *
227: wdsr_alloc(unit)
228: int unit;
229: {
230: struct wds_req *r;
231: int x;
232: int i;
233:
234: r = NULL;
235: x = splbio();
236: for(i=0; i<MAXSIMUL; i++)
237: if(wds[unit].wdsr[i].busy == 0) {
238: r = &wds[unit].wdsr[i];
239: r->busy = 1;
240: break;
241: }
242: if(r == NULL) {
243: splx(x);
244: return NULL;
245: }
246:
247: r->ombn = -1;
248: for(i=0; i<WDS_NOMB; i++)
249: if(wds[unit].ombs[i].stat==0) {
250: wds[unit].ombs[i].stat = 1;
251: r->ombn = i;
252: break;
253: }
254: if(r->ombn == -1 ) {
255: r->busy = 0;
256: splx(x);
257: return NULL;
258: }
259: splx(x);
260: return r;
261: }
262:
263: int
264: wds_scsi_cmd(sxp)
265: struct scsi_xfer *sxp;
266: {
267: struct wds_req *r;
268: int unit = sxp->adapter;
269: u_short base;
270: u_char c, *p;
271: int i;
272:
273: base = wds[unit].addr;
274:
275: /*printf("scsi_cmd\n");*/
276:
277: if( sxp->flags & SCSI_RESET) {
278: printf("reset!\n");
279: return COMPLETE;
280: }
281:
282: /* XXX DEBUG */
283: if( sxp->targ != 1) {
284: printf("ignoring target %d/%d\n", sxp->targ, sxp->lu);
285: sxp->error = XS_TIMEOUT;
286: return HAD_ERROR;
287: }
288:
289: r = wdsr_alloc(unit);
290: if(r==NULL) {
291: printf("no request slot available!\n");
292: sxp->error = XS_DRIVER_STUFFUP;
293: return TRY_AGAIN_LATER;
294: }
295: r->done = 0;
296: r->sxp = sxp;
297:
298: printf("wds%d: target %d/%d req %8x flags %08x len %d: ", unit,
299: sxp->targ, sxp->lu, r, sxp->flags, sxp->cmdlen);
300: for(i=0, p=(u_char *)sxp->cmd; i<sxp->cmdlen; i++)
301: printf("%02x ", p[i]);
302: printf("\n");
303: printf(" data %08x datalen %08x\n", sxp->data, sxp->datalen);
304:
305: if(sxp->flags & SCSI_DATA_UIO) {
306: printf("UIO!\n");
307: sxp->error = XS_DRIVER_STUFFUP;
308: return TRY_AGAIN_LATER;
309: }
310:
311: p2x(&wds[unit].ombs[r->ombn].addr[0], KVTOPHYS(&r->cmd));
312: printf("%08x/%08x mbox@%08x: %02x %02x %02x %02x\n",
313: &r->cmd, KVTOPHYS(&r->cmd), &wds[unit].ombs[0],
314: wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0],
315: wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]);
316:
317: bzero(&r->cmd, sizeof r->cmd);
318: r->cmd.cmd = WDSX_SCSICMD;
319: r->cmd.targ = (sxp->targ << 5) | sxp->lu;
320: bcopy(sxp->cmd, &r->cmd.scb, sxp->cmdlen<12 ? sxp->cmdlen : 12);
321: p2x(&r->cmd.len[0], sxp->datalen);
322: p2x(&r->cmd.data[0], sxp->datalen ? KVTOPHYS(sxp->data) : 0);
323: r->cmd.write = (sxp->flags&SCSI_DATA_IN)? 0x80 : 0x00;
324: p2x(&r->cmd.next[0], KVTOPHYS(&r->sense));
325:
326: bzero(&r->sense, sizeof r->sense);
327: r->sense.cmd = r->cmd.cmd;
328: r->sense.targ = r->cmd.targ;
329: r->sense.scb.opcode = REQUEST_SENSE;
330: p2x(&r->sense.data[0], KVTOPHYS(&sxp->sense));
331: p2x(&r->sense.len[0], sizeof sxp->sense);
332: r->sense.write = 0x80;
333:
334: /*printf("wdscmd: ");
335: for(i=0, p=(u_char *)&r->cmd; i<sizeof r->cmd; i++)
336: printf("%02x ", p[i]);
337: printf("\n");*/
338:
339: if(sxp->flags & SCSI_NOMASK) {
340: outb(base+WDS_HCR, WDSH_DRQEN);
341: r->polled = 1;
342: } else
343: r->polled = 0;
344:
345: c = WDSC_MSTART(r->ombn);
346: if( wds_cmd(base, &c, sizeof c) != 0) {
347: printf("wds%d: unable to start outgoing mbox\n", unit);
348: r->busy = 0;
349: /* XXX need to free mailbox */
350: return TRY_AGAIN_LATER;
351: }
352:
353: DELAY(10000);
354: /*printf("%08x/%08x mbox: %02x %02x %02x %02x\n", &r->cmd, KVTOPHYS(&r->cmd),
355: wds[unit].ombs[r->ombn].stat, wds[unit].ombs[r->ombn].addr[0],
356: wds[unit].ombs[r->ombn].addr[1], wds[unit].ombs[r->ombn].addr[2]);*/
357:
358: if(sxp->flags & SCSI_NOMASK) {
359: repoll: printf("wds%d: polling.", unit);
360: i = 0;
361: while( (inb(base+WDS_STAT) & WDS_IRQ) == 0) {
362: printf(".");
363: DELAY(10000);
364: if(++i == 10) {
365: printf("failed %02x\n", inb(base+WDS_IRQSTAT));
366: /*r->busy = 0;*/
367: sxp->error = XS_TIMEOUT;
368: return HAD_ERROR;
369: }
370: }
371: printf("got one!\n");
372: wdsintr(unit);
373: if(r->done) {
374: r->sxp->flags |= ITSDONE;
375: if(r->sxp->when_done)
376: (*r->sxp->when_done)(r->sxp->done_arg,
377: r->sxp->done_arg2);
378: r->busy = 0;
379: return r->ret;
380: }
381: goto repoll;
382: }
383:
384: outb(base+WDS_HCR, WDSH_IRQEN|WDSH_DRQEN);
385: printf("wds%d: successfully queued\n", unit);
386: return SUCCESSFULLY_QUEUED;
387: }
388:
389: long
390: wds_adapter_info(unit)
391: int unit;
392: {
393: return 1;
394: }
395:
396: int
397: wdsintr(unit)
398: {
399: struct wds_cmd *pc, *vc;
400: struct wds_mb *in;
401: u_char stat;
402: u_char c;
403:
404: /*printf("stat=%02x\n", inb(wds[unit].addr + WDS_STAT));*/
405: DELAY(1000);
406: c = inb(wds[unit].addr + WDS_IRQSTAT);
407: printf("wdsintr: %02x\n", c);
408: if( (c&WDSI_MASK) == WDSI_MSVC) {
409: DELAY(1000);
410: c = c & ~WDSI_MASK;
411: in = &wds[unit].imbs[c];
412:
413: printf("incoming mailbox %02x@%08x: ", c, in);
414: printf("%02x %02x %02x %02x\n",
415: in->stat, in->addr[0], in->addr[1], in->addr[2]);
416: pc = (struct wds_cmd *)x2p(&in->addr[0]);
417: vc = (struct wds_cmd *)PHYSTOKV(pc);
418: stat = in->stat;
419: printf("p=%08x v=%08x stat %02xx\n", pc, vc, stat);
420: wds_done(unit, vc, stat);
421: in->stat = 0;
422:
423: outb(wds[unit].addr + WDS_IRQACK, 0xff);
424: }
425: }
426:
427: wds_done(unit, c, stat)
428: int unit;
429: struct wds_cmd *c;
430: u_char stat;
431: {
432: struct wds_req *r;
433: int i;
434:
435: r = (struct wds_req *)NULL;
436: for(i=0; i<MAXSIMUL; i++)
437: if( c == &wds[unit].wdsr[i].cmd ) {
438: /*printf("found at req slot %d\n", i);*/
439: r = &wds[unit].wdsr[i];
440: break;
441: }
442: if(r == (struct wds_req *)NULL) {
443: printf("failed to find request!\n");
444: return;
445: }
446:
447: printf("wds%d: cmd %8x stat %2x/%2x %2x/%2x\n", unit, c,
448: r->cmd.stat, r->cmd.venderr, r->sense.stat, r->sense.venderr);
449:
450: r->done = 1;
451: /* XXX need to free mailbox */
452: r->ret = HAD_ERROR;
453: switch(r->cmd.stat) {
454: case ICMB_OK:
455: /*XXX r->sxp->sense.valid = 0;
456: r->sxp->error = 0;*/
457: r->ret = COMPLETE;
458: break;
459: case ICMB_OKERR:
460: printf("scsi err %02x\n", c->venderr);
461: /*XXX r->sxp->sense.error_code = c->venderr;
462: r->sxp->sense.valid = 1;*/
463: r->ret = COMPLETE;
464: break;
465: case ICMB_ETIME:
466: r->sxp->error = XS_TIMEOUT;
467: r->ret = HAD_ERROR;
468: break;
469: case ICMB_ERESET:
470: case ICMB_ETARCMD:
471: case ICMB_ERESEL:
472: case ICMB_ESEL:
473: case ICMB_EABORT:
474: case ICMB_ESRESET:
475: case ICMB_EHRESET:
476: r->sxp->error = XS_DRIVER_STUFFUP;
477: r->ret = HAD_ERROR;
478: break;
479: }
480: if(r->polled==0) {
481: r->sxp->flags |= ITSDONE;
482: if(r->sxp->when_done)
483: (*r->sxp->when_done)(r->sxp->done_arg, r->sxp->done_arg2);
484: r->busy = 0;
485: }
486: return;
487: }
488:
489: int
490: wdsattach(dev)
491: struct isa_device *dev;
492: {
493: int unit = dev->id_unit;
494:
495: /*printf("start attach...\n");*/
496: scsi_attachdevs(unit, wds[unit].devs, &wds_switch);
497: /*printf("done attach...\n");*/
498: return;
499: }
500:
501: wds_init(dev)
502: struct isa_device *dev;
503: {
504: struct wds_setup init;
505: u_short base;
506: u_char *p, c;
507: int unit, i;
508:
509: unit = dev->id_unit;
510: base = wds[unit].addr;
511:
512: /*
513: * Sending a command causes the CMDRDY bit to clear.
514: */
515: c = inb(base+WDS_STAT);
516: for(i=0; i<4; i++)
517: if( (inb(base+WDS_STAT) & WDS_RDY) != 0) {
518: goto ready;
519: DELAY(10);
520: }
521: return 1;
522:
523: ready:
524: outb(base+WDS_CMD, WDSC_NOOP);
525: if( inb(base+WDS_STAT) & WDS_RDY)
526: return 1;
527:
528: /*
529: * the controller exists. reset and init.
530: */
531: outb(base+WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET);
532: DELAY(3);
533: outb(base+WDS_HCR, WDSH_DRQEN);
534: DELAY(20000);
535:
536: isa_dmacascade(dev->id_drq);
537:
538: if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
539: printf("wds%d: waiting for controller to become ready", unit);
540: for(i=0; i<6; i++) {
541: if( (inb(base+WDS_STAT) & (WDS_RDY)) == WDS_RDY)
542: break;
543: printf(".");
544: DELAY(10000);
545: }
546: if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
547: printf("failed\n");
548: return 1;
549: }
550: }
551:
552: bzero(&init, sizeof init);
553: init.cmd = WDSC_INIT;
554: init.scsi_id = 0;
555: init.buson_t = 24;
556: init.busoff_t = 48;
557: p2x(&init.mbaddr[0], KVTOPHYS(&wds[unit].ombs[0]));
558: init.xx = 0;
559: init.nomb = WDS_NOMB;
560: init.nimb = WDS_NIMB;
561:
562: /*p = (u_char *)&init;
563: printf("wds%d: %08x %08x init: ", unit,
564: &wds[unit].ombs[0], KVTOPHYS(&wds[unit].ombs[0]));
565: for(i=0; i<sizeof init; i++)
566: printf("%02x ", p[i]);
567: printf("\n");*/
568:
569: wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY);
570: if( wds_cmd(base, &init, sizeof init) != 0) {
571: printf("wds%d: wds_cmd failed\n", unit);
572: return 1;
573: }
574: wds_wait(base+WDS_STAT, WDS_INIT, WDS_INIT);
575:
576: wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY);
577: c = WDSC_DISUNSOL;
578: if( wds_cmd(base, &c, sizeof c) != 0) {
579: printf("wds%d: wds_cmd failed\n", unit);
580: return 1;
581: }
582:
583: return 0;
584: }
585:
586: wds_cmd(base, p, l)
587: u_short base;
588: u_char *p;
589: int l;
590: {
591: int i;
592: u_char c;
593:
594: i = 0;
595: while(i < l) {
596: while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0)
597: ;
598:
599: outb(base+WDS_CMD, *p);
600:
601: while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0)
602: ;
603:
604: if(c & WDS_REJ)
605: return 1;
606: p++;
607: i++;
608: }
609: while( ((c=inb(base+WDS_STAT)) & WDS_RDY) == 0)
610: ;
611: if(c & WDS_REJ)
612: return 1;
613: /*printf("wds_cmd: %02x\n", inb(base+WDS_STAT));*/
614: return 0;
615: }
616:
617: wds_wait(reg, mask, val)
618: {
619: while( (inb(reg) & mask) != val)
620: ;
621: }
622:
623: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.