|
|
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.