|
|
1.1 root 1: /*
2: * DSA port driver for uda50
3: *
4: * this just passes packets around;
5: * it makes calls to the routines in ra.c
6: * to get the packets filled in
7: */
8:
9: #include "sys/param.h"
10: #include "sys/buf.h"
11: #include "sys/ubaddr.h"
12: #include "sys/map.h"
13: #include "sys/uba.h"
14: #include "sys/uda.h"
15: #include "sys/mscp.h"
16:
17: /*
18: * ONEPATH tries to use only one data path per controller;
19: * a nice idea, but a disaster on the DW780 --
20: * the UDA50 will cheerfully run transfers in parallel from
21: * two drives on the same data path, which confuses the
22: * DW780 and mixes up the data
23: */
24: /* #define ONEPATH 1 /* don't */
25:
26: #define hiword(x) (((long)(x)>>16)&0177777)
27: #define loword(x) ((long)(x)&0177777)
28:
29: extern struct uba uba[];
30: extern struct ubaddr udaddr[];
31: extern struct ud ud[];
32: extern int udcnt;
33:
34: struct ctab {
35: int (*c_seql)();
36: int (*c_dg)();
37: int c_ctype;
38: } udctab[MSMAXID];
39:
40: struct device {
41: short udip;
42: short udsa;
43: };
44:
45: /*
46: * bits in udsa
47: */
48:
49: #define ERR 0100000
50: #define STEP4 040000
51: #define STEP3 020000
52: #define STEP2 010000
53: #define STEP1 04000
54: #define STEPS (STEP1|STEP2|STEP3|STEP4)
55:
56: #define IE 0200 /* step1 interrupt enable */
57: #define PI 01 /* step2 purge intr enab */
58: #define GO 01 /* step4 ok */
59:
60: /*
61: * uda communication area
62: * ring sizes are chosen so that,
63: * with 4K byte buffers,
64: * one udcomm + CSIZE-sized command packets will
65: * fit in one buffer;
66: * RSIZE-sized response packets
67: * will fit in another
68: *
69: * ring sizes must be powers of 2
70: * (they are passed as such to the port)
71: *
72: * a delicacy:
73: * command packets should not cross 64Kb boundaries.
74: * it is believed that the KDB50 gets it wrong if they do.
75: * hence, make CSIZE+4 evenly divide a page,
76: * and get it aligned sensibly in bdreset
77: */
78:
79: #define NCP2 5
80: #define NRP2 5
81: #define NCMD (1<<NCP2)
82: #define NRSP (1<<NRP2)
83:
84: struct udcomm {
85: short ud__r0; /* reserved (ugh) */
86: char ud__r1;
87: char ud_bdp; /* path to purge */
88: short ud_cmdint; /* flag for command interrupt */
89: short ud_rspint; /* flag for response interrupt */
90: long ud_rsp[NRSP]; /* response pointer ring */
91: long ud_cmd[NCMD]; /* command pointer ring */
92: };
93:
94: /*
95: * bits in ring pointers
96: */
97:
98: #define DPOWN 0x80000000 /* port owns descriptor */
99: #define DIE 0x40000000 /* ring transition intr enab */
100:
101: #define CSIZE 60 /* max size of command packet */
102: #define RSIZE 60 /* max size of response packet */
103: #define HDRSIZE 4 /* size of the header */
104:
105: struct udcmd {
106: short uc_len; /* length of message */
107: char uc_tc; /* type, credits */
108: char uc_cid; /* connection id */
109: char uc_data[CSIZE];
110: };
111:
112: struct udrsp {
113: short ur_len; /* length of message */
114: char ur_tc; /* type, credits */
115: char ur_cid; /* connection id */
116: char ur_data[RSIZE];
117: };
118:
119: /*
120: * message types
121: */
122:
123: #define MTYPE 0xf0 /* where type lives */
124: #define MTSEQL 0x00 /* sequential message */
125: #define MTDG 0x10 /* datagram */
126: #define MTCR 0x20 /* credit notification */
127:
128: #define MTNC 0xf /* credits in tc */
129:
130: /*
131: * etc
132: */
133:
134: #define PRIINI (PZERO-3)
135: #define PRIPKT (PZERO-2)
136: #define PRICRED (PZERO-1)
137:
138: /*
139: * command packet to index
140: */
141: #define udmptoi(up, mp) ((struct udcmd *)((char *)(mp) - HDRSIZE) - (up)->ud_cpkt)
142:
143: #define TIMEOUT 15 /* time between checks */
144:
145: int udinit(), udsend(), udmap(), udunmap();
146: struct mscmd *udgpkt();
147: struct msportsw udport = {
148: udinit, udgpkt, udmap, udsend, udunmap
149: };
150:
151: /*
152: * init the port
153: * returns nonzero if probably ok
154: * allowed to sleep
155: */
156:
157: #define UDCOFF (((sizeof(struct udcomm)/sizeof(struct udcmd))+1)*sizeof(struct udcmd))
158:
159: udinit(dev, type, force, cid, seql, dg)
160: unsigned int dev;
161: unsigned int cid;
162: int force;
163: int (*seql)(), (*dg)();
164: {
165: register struct ud *up;
166: register int ubno;
167: struct buf *geteblk();
168: extern udtimer();
169:
170: if (dev >= udcnt)
171: return (0);
172: if (cid >= MSMAXID)
173: return (0);
174: udctab[cid].c_seql = seql;
175: udctab[cid].c_dg = dg;
176: udctab[cid].c_ctype = type;
177: up = &ud[dev];
178: ubno = udaddr[dev].ubno;
179: if (up->ud_flags & UISTART && force == 0)
180: return (1);
181: if ((up->ud_addr = (struct device *)ubaddr(&udaddr[dev])) == 0)
182: return (0);
183: if (ubbadaddr(ubno, &up->ud_addr->udsa, sizeof(short))) {
184: printf("ud%d not present\n", dev);
185: return (0);
186: }
187: udrundown(dev);
188: if ((up->ud_flags & UINIT) == 0) {
189: up->ud_cbuf = geteblk();
190: clrbuf(up->ud_cbuf);
191: up->ud_rbuf = geteblk();
192: clrbuf(up->ud_rbuf);
193: up->ud_cbm = ubmbuf(ubno, up->ud_cbuf, 0);
194: up->ud_rbm = ubmbuf(ubno, up->ud_cbuf, 0);
195: #if ONEPATH
196: up->ud_bdpno = ubmapath(ubno);
197: #endif
198: up->ud_comm = (struct udcomm *)up->ud_cbuf->b_un.b_addr;
199: up->ud_cpkt = (struct udcmd *)(up->ud_cbuf->b_un.b_addr + UDCOFF);
200: up->ud_rpkt = (struct udrsp *)up->ud_rbuf->b_un.b_addr;
201: up->ud_flags |= UINIT;
202: timeout(udtimer, (caddr_t)dev, TIMEOUT * HZ);
203: }
204: return (udreset(dev));
205: }
206:
207: /*
208: * reset device
209: * initially or after error or power fail
210: * -- empirically, INITSTALL must be 200000 or so
211: * to work with TD Systems SCSI adapter on 8550
212: */
213:
214: #define INITSTALL 200000 /* >>1200us */
215:
216: udreset(dev)
217: int dev;
218: {
219: register struct ud *up;
220: register struct device *rp;
221: register uaddr_t pa;
222: register int i;
223:
224: up = &ud[dev];
225: rp = up->ud_addr;
226: up->ud_flags &=~ UIDONE;
227: up->ud_flags |= UISTART;
228: rp->udip = 0; /* hard reset */
229: pa = ubadbuf(udaddr[dev].ubno, up->ud_cbuf, up->ud_cbm);
230: up->ud_pcomm = pa + (4 * sizeof(short)); /* -> ud_rsp */
231: up->ud_pcpkt = pa + UDCOFF;
232: up->ud_cnext = 0;
233: up->ud_rnext = 0;
234: up->ud_credits = 0;
235: for (i = 0; (rp->udsa & STEP1) == 0 && i < INITSTALL; i++)
236: ;
237: if ((rp->udsa & STEP1) == 0) {
238: up->ud_flags &=~ UISTART;
239: printf("ud%d won't init\n", dev);
240: return (0);
241: }
242: rp->udsa = ERR | IE | (NCP2<<11) | (NRP2<<8) | (udaddr[dev].vec>>2);
243: return (1);
244: }
245:
246: /*
247: * finish up init, step by step
248: * called from interrupt code
249: */
250:
251: udinintr(dev)
252: int dev;
253: {
254: register struct ud *up;
255: register struct device *rp;
256: register int i;
257: register uaddr_t pa;
258:
259: up = &ud[dev];
260: rp = up->ud_addr;
261: if (up->ud_flags & UIDONE) {
262: printf("ud%d: unexpected init: sa %o\n", dev, rp->udsa);
263: return;
264: }
265: switch (rp->udsa & STEPS) {
266: case STEP1:
267: udreset(dev);
268: return;
269:
270: case STEP2:
271: /* need to set PI for 780 type unibus. */
272: rp->udsa = loword(up->ud_pcomm)|((uba[udaddr[dev].ubno].flags&UBQBUS)?0:PI);
273: return;
274:
275: case STEP3:
276: rp->udsa = hiword(up->ud_pcomm);
277: return;
278:
279: case STEP4:
280: rp->udsa = GO;
281: for (i = 0; i < NCMD; i++) {
282: up->ud_comm->ud_cmd[i] = 0; /* unnecessary */
283: up->ud_cpkt[i].uc_len = CSIZE;
284: up->ud_cbusy[i] = FREE;
285: up->ud_back[i] = NOBACK;
286: }
287: pa = ubadbuf(udaddr[dev].ubno, up->ud_rbuf, up->ud_rbm);
288: pa += 2 * sizeof(short);
289: for (i = 0; i < NRSP; i++, pa += sizeof(struct udrsp)) {
290: up->ud_comm->ud_rsp[i] = pa | DIE | DPOWN;
291: up->ud_rpkt[i].ur_len = RSIZE;
292: }
293: up->ud_flags |= UIDONE | UFIRST;
294: wakeup((caddr_t)up);
295: return;
296:
297: default:
298: printf("ud%d init bad: sa %o\n", dev, rp->udsa);
299: return;
300: }
301: }
302:
303: /*
304: * tell the class drivers that the controller was reset
305: * so they can clean up
306: * called after controller is stopped (so it's safe to unmap things)
307: */
308: udrundown(dev)
309: int dev;
310: {
311: static struct msend me;
312: register int i;
313:
314: me.m_sts = STRST; /* magic */
315: for (i = 0; i < MSMAXID; i++)
316: if (udctab[i].c_seql)
317: (*udctab[i].c_seql)(dev, udctab[i].c_ctype, &me);
318: }
319:
320: /*
321: * allocate a packet
322: * and sufficient resources to send it
323: * eg credits
324: * may sleep
325: *
326: * somewhat silly assumption:
327: * class driver will allocate a packet, and send it right away or nearly so
328: */
329:
330: struct mscmd *
331: udgpkt(dev)
332: int dev;
333: {
334: register struct ud *up;
335: register int i;
336: int s;
337:
338: up = &ud[dev];
339: if (up->ud_addr->udsa & STEP1) /* was reset somehow */
340: udreset(dev);
341: s = spl6();
342: while ((up->ud_flags & UIDONE) == 0)
343: sleep((caddr_t)up, PRIINI);
344: while (up->ud_credits < 2 && (up->ud_flags & UFIRST) == 0) {
345: if (udpkscan(dev, 1))
346: continue;
347: up->ud_flags |= UCWAIT;
348: sleep((caddr_t)&up->ud_credits, PRICRED);
349: }
350: if ((up->ud_flags & UFIRST) == 0)
351: up->ud_credits--;
352: for (;;) {
353: for (i = 0; i < NCMD; i++)
354: if (up->ud_cbusy[i] == FREE)
355: break;
356: if (i < NCMD)
357: break;
358: if (udpkscan(dev, 1) == 0 && udcmdscan(dev) == 0) { /* kludge for hung controller */
359: up->ud_flags |= UPWAIT;
360: sleep((caddr_t)up->ud_cbusy, PRIPKT);
361: }
362: }
363: up->ud_cbusy[i] = NABBED;
364: splx(s);
365: return ((struct mscmd *)up->ud_cpkt[i].uc_data);
366: }
367:
368: /*
369: * map a transfer into unibus space
370: * and record in the buffer descriptor of a packet
371: * may sleep
372: */
373:
374: udmap(dev, mp, bp)
375: int dev;
376: struct mscmd *mp;
377: register struct buf *bp;
378: {
379: register struct ud *up;
380: register int i;
381:
382: up = &ud[dev];
383: i = udmptoi(up, mp);
384: #if ONEPATH
385: if (up->ud_cmap[i] == 0)
386: up->ud_cmap[i] = ubmbuf(udaddr[dev].ubno, bp, USLP);
387: up->ud_cmap[i] = ubinspath(up->ud_bdpno, up->ud_cmap[i]);
388: #else
389: if (up->ud_cmap[i] == 0)
390: up->ud_cmap[i] = ubmbuf(udaddr[dev].ubno, bp, UBDP|USLP);
391: #endif
392: up->ud_cbusy[i] |= MAPPED;
393: *(long *)&mp->m_buff = ubadbuf(udaddr[dev].ubno, bp, up->ud_cmap[i]);
394: #if ONEPATH
395: *(long *)&mp->m_buff |= up->ud_bdpno << 24;
396: #else
397: *(long *)&mp->m_buff |= ubmpath(up->ud_cmap[i]) << 24;
398: #endif
399: }
400:
401: /*
402: * free a mapped packet
403: * flush the bdp;
404: * change the path in the map to the DDP before freeing (ugh)
405: * so we won't free our reserved BDP too
406: * it is OK to free an already freed packet, mostly to help reset code
407: */
408:
409: udunmap(dev, mp)
410: int dev;
411: struct mscmd *mp;
412: {
413: register struct ud *up;
414: register int i;
415:
416: up = &ud[dev];
417: i = udmptoi(up, mp);
418: if (up->ud_cmap[i]) {
419: #if ONEPATH
420: ubmflush(udaddr[dev].ubno, ubmpath(up->ud_cmap[i]));
421: ubmfree(udaddr[dev].ubno, ubinspath(0, up->ud_cmap[i]));
422: #else
423: ubmfree(udaddr[dev].ubno, up->ud_cmap[i]);
424: #endif
425: up->ud_cmap[i] = 0;
426: }
427: up->ud_cbusy[i] = FREE;
428: if (up->ud_flags & UPWAIT) {
429: up->ud_flags &=~ UPWAIT;
430: wakeup((caddr_t)up->ud_cbusy);
431: }
432: }
433:
434:
435: /*
436: * send a packet
437: * may not sleep
438: * call at spl5
439: */
440: udsend(dev, cid, mp)
441: int dev;
442: int cid;
443: struct mscmd *mp;
444: {
445: register struct ud *up;
446: register int i;
447: register int j;
448: register struct device *rp;
449:
450: up = &ud[dev];
451: up->ud_flags &=~ UFIRST;
452: i = udmptoi(up, mp);
453: up->ud_cpkt[i].uc_cid = cid;
454: j = up->ud_cnext++;
455: if (up->ud_cnext >= NCMD)
456: up->ud_cnext = 0;
457: if (up->ud_comm->ud_cmd[j] & DPOWN)
458: panic("udsend");
459: if (up->ud_back[j] >= 0) { /* ran for a while with no free */
460: udcmdscan(dev);
461: if (up->ud_back[j] >= 0)
462: panic("udsend");
463: }
464: rp = up->ud_addr;
465: if (rp->udsa & ERR) { /* and now we lose a packet */
466: printf("ud%d: hard error %o\n", dev, rp->udsa & 0177777);
467: udreset(dev);
468: return;
469: }
470: up->ud_back[j] = i;
471: up->ud_comm->ud_cmd[j] = DPOWN | DIE |
472: up->ud_pcpkt + (i * sizeof(struct udcmd)) + (2 * sizeof(short));
473: up->ud_cbusy[i] |= SENT;
474: up->ud_cbusy[i] &=~ NABBED;
475: i = rp->udip; /* initiate polling */
476: }
477:
478: /*
479: * interrupt routine
480: */
481:
482: long ud_spur;
483: long ud_npr;
484: #define INIRETRY 5 /* TQK50 botch -- needs time to settle */
485:
486: ud0int(dev)
487: int dev;
488: {
489: register struct ud *up;
490: register struct device *rp;
491: register int i;
492:
493: up = &ud[dev];
494: if (dev >= udcnt || (up->ud_flags & UINIT) == 0) {
495: printf("ud%d: stray intr\n", dev);
496: return;
497: }
498: rp = up->ud_addr;
499: if ((up->ud_flags & UIDONE) == 0) {
500: for (i = 0; i < INIRETRY; i++)
501: if (rp->udsa & (STEPS|ERR))
502: break;
503: if ((rp->udsa & (STEPS|ERR)) == 0) {
504: printf("ud%d: init lost; sa 0%o\n", dev, rp->udsa);
505: return;
506: }
507: }
508: if (rp->udsa & ERR) {
509: printf("ud%d: hard error %o\n", dev, rp->udsa & 0177777);
510: udreset(dev);
511: return;
512: }
513: if (rp->udsa & STEPS) {
514: udinintr(dev);
515: return;
516: }
517: if (up->ud_comm->ud_bdp == 0
518: && up->ud_comm->ud_cmdint == 0
519: && up->ud_comm->ud_rspint == 0)
520: ud_spur++;
521: if (up->ud_comm->ud_bdp) {
522: ubmflush(udaddr[dev].ubno, up->ud_comm->ud_bdp);
523: up->ud_comm->ud_bdp = 0;
524: rp->udsa = 0; /* ack purge */
525: ud_npr++;
526: }
527: while (up->ud_comm->ud_cmdint) {
528: up->ud_comm->ud_cmdint = 0;
529: udcmdscan(dev);
530: }
531: while (up->ud_comm->ud_rspint) {
532: up->ud_comm->ud_rspint = 0;
533: if (udpkscan(dev, 0))
534: up->ud_flags &=~ UTIMER;
535: }
536: }
537:
538: /*
539: * free packets which are completely sent
540: * (and which don't have associated map)
541: */
542:
543: udcmdscan(dev)
544: int dev;
545: {
546: register struct ud *up;
547: register int i, j;
548: register int freed;
549: register struct udcomm *udc;
550:
551: up = &ud[dev];
552: udc = up->ud_comm;
553: freed = 0;
554: for (j = 0; j < NCMD; j++)
555: if (up->ud_back[j] >= 0
556: && (udc->ud_cmd[j] & DPOWN) == 0) {
557: i = up->ud_back[j];
558: if ((up->ud_cbusy[i] & (SENT|MAPPED)) == SENT) {
559: up->ud_cbusy[i] = FREE;
560: freed++;
561: }
562: up->ud_back[j] = NOBACK;
563: }
564: if (freed && up->ud_flags & UPWAIT)
565: wakeup((caddr_t)up->ud_cbusy);
566: return (freed);
567: }
568:
569: /*
570: * check for responses from the controller
571: * and deal with them
572: * return a count for debugging purposes
573: * called at spl6 (because of udtimer)
574: */
575:
576: int
577: udpkscan(dev, doall)
578: int dev;
579: int doall;
580: {
581: register struct ud *up;
582: register int i;
583: int nf;
584: register struct udrsp *pk;
585: register struct ctab *cp;
586: register struct udcomm *udc; /* speed */
587:
588: up = &ud[dev];
589: udc = up->ud_comm;
590: nf = 0;
591: for (i = up->ud_rnext; ; i < NRSP-1 ? i++ : (i=0)) {
592: if (udc->ud_rsp[i] & DPOWN) {
593: up->ud_rnext = i;
594: /* don't stop if doall? */
595: break;
596: }
597: nf++;
598: pk = &up->ud_rpkt[i];
599: up->ud_credits += pk->ur_tc & MTNC;
600: if (up->ud_flags & UCWAIT) {
601: wakeup((caddr_t)&up->ud_credits);
602: up->ud_flags &=~ UCWAIT;
603: }
604: if (pk->ur_cid > MSMAXID)
605: printf("ud%d msg id %d\n", dev, pk->ur_cid);
606: else {
607: cp = &udctab[pk->ur_cid];
608: switch (pk->ur_tc & MTYPE) {
609: case MTSEQL:
610: if (cp->c_seql)
611: (*cp->c_seql)(dev, cp->c_ctype, (struct msend *)pk->ur_data);
612: break;
613:
614: case MTDG:
615: if (cp->c_dg)
616: (*cp->c_dg)(dev, cp->c_ctype, pk->ur_data);
617: break;
618:
619: /* default: ignore */
620: }
621: }
622: pk->ur_len = RSIZE;
623: udc->ud_rsp[i] |= DPOWN | DIE;
624: }
625: return (nf);
626: }
627:
628: /*
629: * timeout routine
630: * return any waiting packets
631: * -- callout routines don't necessarily run at high priority.
632: * hence the spl6, so udpkscan won't be reentered
633: */
634:
635: int ud_kicked;
636:
637: udtimer(i)
638: int i;
639: {
640: register struct ud *up;
641: register int s;
642:
643: up = &ud[i];
644: if ((up->ud_flags & UINIT) == 0)
645: return;
646: if (up->ud_flags & UIDONE) {
647: if ((up->ud_flags & UTIMER) == 0)
648: up->ud_flags |= UTIMER;
649: else {
650: s = spl6();
651: if (udpkscan(i, 1) && up->ud_flags & UPWAIT) {
652: wakeup((caddr_t)up->ud_cbusy);
653: ud_kicked++;
654: }
655: splx(s);
656: up->ud_flags &=~ UTIMER;
657: }
658: }
659: timeout(udtimer, (caddr_t)i, TIMEOUT * HZ);
660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.