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