|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)si.c 1.1 86/02/03 Copyr 1985 Sun Micro"; ! 3: #endif ! 4: ! 5: /* ! 6: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 7: */ ! 8: ! 9: #include "si.h" ! 10: ! 11: #if NSI > 0 ! 12: /* ! 13: * Generic scsi routines. ! 14: */ ! 15: ! 16: #include "../h/param.h" ! 17: #include "../h/systm.h" ! 18: #include "../h/dk.h" ! 19: #include "../h/buf.h" ! 20: #include "../h/conf.h" ! 21: #include "../h/dir.h" ! 22: #include "../h/user.h" ! 23: #include "../h/map.h" ! 24: #include "../h/vmmac.h" ! 25: /* ! 26: *#include "../h/ioctl.h" ! 27: *#include "../h/uio.h" ! 28: *#include "../h/kernel.h" ! 29: */ ! 30: #include "../h/dkbad.h" ! 31: ! 32: #include "../machine/pte.h" ! 33: #include "../machine/psl.h" ! 34: #include "../machine/mmu.h" ! 35: #include "../machine/cpu.h" ! 36: #include "../machine/scb.h" ! 37: ! 38: #include "../sun/dklabel.h" ! 39: #include "../sun/dkio.h" ! 40: ! 41: #include "../sundev/mbvar.h" ! 42: #include "../sundev/screg.h" ! 43: #include "../sundev/sireg.h" ! 44: #include "../sundev/scsi.h" ! 45: ! 46: struct scsi_ctlr sictlrs[NSI]; ! 47: #define SINUM(si) (si - sictlrs) ! 48: ! 49: int siprobe(), sislave(), siattach(), sigo(), sidone(), sipoll(); ! 50: int siustart(), sistart(), si_getstatus(); ! 51: int si_off(), si_cmd(), si_cmdwait(), si_reset(), si_dmacnt(); ! 52: ! 53: struct mb_ctlr *siinfo[NSI]; ! 54: extern struct mb_device *sdinfo[]; ! 55: struct mb_driver sidriver = { ! 56: siprobe, sislave, siattach, sigo, sidone, sipoll, ! 57: sizeof (struct scsi_si_reg), "sd", sdinfo, "si", siinfo, MDR_BIODMA, ! 58: }; ! 59: ! 60: /* routines available to devices specific portion of scsi driver */ ! 61: struct scsi_ctlr_subr sisubr = { ! 62: siustart, sistart, sidone, si_cmd, si_getstatus, si_cmdwait, ! 63: si_off, si_reset, si_dmacnt, sigo, ! 64: }; ! 65: ! 66: extern int scsi_debug; /* generic debug information */ ! 67: extern int scsi_ntype; ! 68: extern struct scsi_unit_subr scsi_unit_subr[]; ! 69: ! 70: int scsi_disre_enable = 0; /* enable disconnect/reconnect */ ! 71: int scsi_dis_debug = 0; /* disconnect debug info */ ! 72: int scsi_resel_debug = 0; /* reselection debug info */ ! 73: int scsi_reset_debug = 0; /* scsi bus reset debug information */ ! 74: ! 75: /* ! 76: * Determine existence of SCSI host adapter. ! 77: */ ! 78: siprobe(reg, ctlr) ! 79: register struct scsi_si_reg *reg; ! 80: register int ctlr; ! 81: { ! 82: register struct scsi_ctlr *c; ! 83: ! 84: /* probe for different scsi host adaptor interfaces */ ! 85: c = &sictlrs[ctlr]; ! 86: ! 87: /* ! 88: * Check for sbc - NCR 5380 Scsi Bus Ctlr chip. ! 89: * sbc is common to sun3/50 onboard scsi and vme ! 90: * scsi board. ! 91: */ ! 92: if (peekc(®->sbc_rreg.cbsr) == -1) { ! 93: return (0); ! 94: } ! 95: ! 96: /* ! 97: * Determine whether the host adaptor interface is onboard or vme. ! 98: */ ! 99: if (cpu == CPU_SUN3_50) { ! 100: /* probe for sun3/50 dma interface */ ! 101: if (peek(®->udc_rdata) == -1) ! 102: return (0); ! 103: c->c_flags = SCSI_ONBOARD; ! 104: } else { ! 105: /* ! 106: * Probe for vme scsi card but make sure it is not ! 107: * the SC host adaptor interface. SI vme scsi host ! 108: * adaptor occupies 2K bytes in the vme address space. ! 109: * SC vme scsi host adaptor occupies 4K bytes in the ! 110: * vme address space. So, peek past 2K bytes to ! 111: * determine which host adaptor is there. ! 112: */ ! 113: if (peek(®->dma_addr) == -1) ! 114: return (0); ! 115: if (peek((int)reg+0x800) != -1) ! 116: return (0); ! 117: c->c_flags = 0; ! 118: } ! 119: ! 120: /* allocate memory for sense information */ ! 121: c->c_sense = (struct scsi_sense *) rmalloc(iopbmap, ! 122: (long) sizeof (struct scsi_sense)); ! 123: if (c->c_sense == NULL) { ! 124: printf("siprobe: no iopb memory for sense.\n"); ! 125: return (0); ! 126: } ! 127: ! 128: /* init controller information */ ! 129: c->c_flags |= SCSI_PRESENT; ! 130: if (scsi_disre_enable) ! 131: c->c_flags |= SCSI_EN_DISCON; ! 132: c->c_sir = reg; ! 133: c->c_ss = &sisubr; ! 134: si_reset(c); ! 135: return (sizeof (struct scsi_si_reg)); ! 136: } ! 137: ! 138: ! 139: /* ! 140: * See if a slave exists. ! 141: * Since it may exist but be powered off, we always say yes. ! 142: */ ! 143: /*ARGSUSED*/ ! 144: sislave(md, reg) ! 145: register struct mb_device *md; ! 146: register struct scsi_si_reg *reg; ! 147: { ! 148: register struct scsi_unit *un; ! 149: register int type; ! 150: ! 151: /* ! 152: * This kludge allows autoconfig to print out "sd" for ! 153: * disks and "st" for tapes. The problem is that there ! 154: * is only one md_driver for scsi devices. ! 155: */ ! 156: type = TYPE(md->md_flags); ! 157: if (type >= scsi_ntype) { ! 158: panic("sislave: unknown type in md_flags"); ! 159: } ! 160: ! 161: /* link unit to its controller */ ! 162: un = (struct scsi_unit *)(*scsi_unit_subr[type].ss_unit_ptr)(md); ! 163: if (un == 0) { ! 164: panic("sislave: md_flags scsi type not configured in\n"); ! 165: } ! 166: un->un_c = &sictlrs[md->md_ctlr]; ! 167: md->md_driver->mdr_dname = scsi_unit_subr[type].ss_devname; ! 168: return (1); ! 169: } ! 170: ! 171: /* ! 172: * Attach device (boot time). ! 173: */ ! 174: siattach(md) ! 175: register struct mb_device *md; ! 176: { ! 177: register int type = TYPE(md->md_flags); ! 178: register struct mb_ctlr *mc = md->md_mc; ! 179: register struct scsi_ctlr *c = &sictlrs[md->md_ctlr]; ! 180: ! 181: if (type >= scsi_ntype) { ! 182: panic("siattach: unknown type in md_flags"); ! 183: } ! 184: (*scsi_unit_subr[type].ss_attach)(md); ! 185: ! 186: if (c->c_flags & SCSI_ONBOARD) { ! 187: return; ! 188: } ! 189: ! 190: /* ! 191: * Initialize interrupt vector and address modifier register. ! 192: * Address modifier specifies standard supervisor data access ! 193: * with 24 bit vme addresses. May want to change this in the ! 194: * future to handle 32 bit vme addresses. ! 195: */ ! 196: if (mc->mc_intr) { ! 197: /* setup for vectored interrupts - we will pass ctlr ptr */ ! 198: c->c_sir->iv_am = (mc->mc_intr->v_vec & 0xff) | ! 199: VME_SUPV_DATA_24; ! 200: (*mc->mc_intr->v_vptr) = (int)c; ! 201: } ! 202: } ! 203: ! 204: /* ! 205: * SCSI unit start routine. ! 206: * Called by SCSI device drivers. ! 207: */ ! 208: siustart(un) ! 209: register struct scsi_unit *un; ! 210: { ! 211: register struct buf *dp; ! 212: register struct mb_ctlr *mc; ! 213: register int s; ! 214: ! 215: mc = un->un_mc; ! 216: dp = &un->un_utab; ! 217: /* ! 218: * Caller guarantees: dp->b_actf != NULL && dp->b_active == 0 ! 219: * Note: dp->b_active == 1 on a reconnect. ! 220: */ ! 221: /* ! 222: * Put device on ready queue for bus. ! 223: */ ! 224: if (mc->mc_tab.b_actf == NULL) { ! 225: mc->mc_tab.b_actf = dp; ! 226: } else { ! 227: mc->mc_tab.b_actl->b_forw = dp; ! 228: } ! 229: dp->b_forw = NULL; ! 230: mc->mc_tab.b_actl = dp; ! 231: dp->b_active = 1; ! 232: dp->b_un.b_addr = (caddr_t) un; ! 233: } ! 234: ! 235: /* ! 236: * Set up a scsi operation. ! 237: */ ! 238: sistart(un) ! 239: register struct scsi_unit *un; ! 240: { ! 241: register struct mb_ctlr *mc; ! 242: register struct buf *bp, *dp; ! 243: ! 244: mc = un->un_mc; ! 245: dp = mc->mc_tab.b_actf; /* != NULL guaranteed by caller */ ! 246: un = (struct scsi_unit *) dp->b_un.b_addr; ! 247: bp = dp->b_actf; ! 248: for (;;) { ! 249: if (bp == NULL) { /* no more blocks for this device */ ! 250: un->un_utab.b_active = 0; ! 251: dp = mc->mc_tab.b_actf = dp->b_forw; ! 252: if (dp == NULL) { /* no more devices for this ctlr */ ! 253: si_idle(un->un_c); ! 254: return; ! 255: } ! 256: un = (struct scsi_unit *) dp->b_un.b_addr; ! 257: bp = dp->b_actf; ! 258: } else { ! 259: if ((*un->un_ss->ss_start)(bp, un)) { ! 260: mc->mc_tab.b_active = 1; ! 261: un->un_c->c_un = un; ! 262: if (bp == &un->un_sbuf && ! 263: ((un->un_flags & SC_UNF_DVMA) == 0)) { ! 264: sigo(mc); ! 265: } else { ! 266: (void) mbgo(mc); ! 267: } ! 268: return; ! 269: } ! 270: dp->b_actf = bp = bp->av_forw; ! 271: } ! 272: } ! 273: } ! 274: ! 275: /* ! 276: * Start up a scsi operation. ! 277: * Called via mbgo after buffer is in memory. ! 278: */ ! 279: sigo(mc) ! 280: register struct mb_ctlr *mc; ! 281: { ! 282: register struct scsi_unit *un; ! 283: register struct scsi_ctlr *c; ! 284: register struct buf *bp, *dp; ! 285: register int unit; ! 286: ! 287: c = &sictlrs[mc->mc_ctlr]; ! 288: dp = mc->mc_tab.b_actf; ! 289: if (dp == NULL || dp->b_actf == NULL) { ! 290: panic("sigo queueing error 1"); ! 291: } ! 292: bp = dp->b_actf; ! 293: un = c->c_un; ! 294: if (dp != &un->un_utab) { ! 295: panic("sigo queueing error 2"); ! 296: } ! 297: un->un_baddr = MBI_ADDR(mc->mc_mbinfo); ! 298: if ((unit = un->un_md->md_dk) >= 0) { ! 299: dk_busy |= 1<<unit; ! 300: dk_xfer[unit]++; ! 301: dk_wds[unit] += bp->b_bcount >> 6; ! 302: } ! 303: (*un->un_ss->ss_mkcdb)(c, un); ! 304: if (si_cmd(c, un, 1) == 0) { ! 305: (*un->un_ss->ss_intr)(c, 0, SE_FATAL); ! 306: si_off(un); ! 307: } ! 308: } ! 309: ! 310: /* ! 311: * Handle a polling SCSI bus interrupt. ! 312: */ ! 313: sipoll() ! 314: { ! 315: register struct scsi_ctlr *c; ! 316: register int serviced = 0; ! 317: ! 318: for (c = sictlrs; c < &sictlrs[NSI]; c++) { ! 319: if ((c->c_flags & SCSI_PRESENT) == 0) ! 320: continue; ! 321: if ((c->c_sir->csr & ! 322: (SI_CSR_SBC_IP | SI_CSR_DMA_IP | SI_CSR_DMA_CONFLICT)) ! 323: == 0) { ! 324: continue; ! 325: } ! 326: serviced = 1; ! 327: siintr(c); ! 328: } ! 329: return (serviced); ! 330: } ! 331: ! 332: /* ! 333: * Clean up queues, free resources, and start next I/O ! 334: * all done after I/O finishes ! 335: * Called by mbdone after moving read data from Mainbus ! 336: */ ! 337: sidone(mc) ! 338: register struct mb_ctlr *mc; ! 339: { ! 340: register struct buf *bp, *dp; ! 341: register struct scsi_unit *un; ! 342: register struct scsi_ctlr *c; ! 343: ! 344: bp = mc->mc_tab.b_actf->b_actf; ! 345: c = &sictlrs[mc->mc_ctlr]; ! 346: un = c->c_un; ! 347: ! 348: /* advance controller queue */ ! 349: dp = mc->mc_tab.b_actf; ! 350: mc->mc_tab.b_active = 0; ! 351: mc->mc_tab.b_actf = dp->b_forw; ! 352: ! 353: /* advance unit queue */ ! 354: dp->b_active = 0; ! 355: dp->b_actf = bp->av_forw; ! 356: ! 357: iodone(bp); ! 358: ! 359: /* start next I/O on unit */ ! 360: if (dp->b_actf) ! 361: siustart(un); ! 362: ! 363: /* start next I/O on controller */ ! 364: if (mc->mc_tab.b_actf && mc->mc_tab.b_active == 0) { ! 365: sistart(un); ! 366: } else { ! 367: c->c_un = NULL; ! 368: si_idle(c); ! 369: } ! 370: } ! 371: ! 372: /*ARGSUSED*/ ! 373: si_off(un) ! 374: register struct scsi_unit *un; ! 375: { ! 376: ! 377: #ifdef notdef ! 378: /* if done to root real bad things happen... */ ! 379: un->un_present = 0; ! 380: printf("scsi unit %d/%d offline\n", un->un_target, un->un_lun); ! 381: if (un->un_md->md_dk > 0) { ! 382: dk_mspw[un->un_md->md_dk]=0; ! 383: } ! 384: #endif ! 385: } ! 386: ! 387: /* ! 388: * Pass a command to the SCSI bus. ! 389: */ ! 390: si_cmd(c, un, intr) ! 391: register struct scsi_ctlr *c; ! 392: register struct scsi_unit *un; ! 393: register int intr; ! 394: { ! 395: register u_char *cp; ! 396: register int i; ! 397: register int errct; ! 398: register struct scsi_si_reg *sir = c->c_sir; ! 399: ! 400: errct = 0; ! 401: do { ! 402: /* disallow disconnects if waiting for command completion */ ! 403: if (intr == 0) { ! 404: c->c_flags &= ~SCSI_EN_DISCON; ! 405: } else { ! 406: if (scsi_disre_enable) ! 407: c->c_flags |= SCSI_EN_DISCON; ! 408: else ! 409: c->c_flags &= ~SCSI_EN_DISCON; ! 410: un->un_wantint = 1; ! 411: } ! 412: ! 413: /* ! 414: * For vme host adaptor interface, dma enable bit may ! 415: * be set to allow reconnect interrupts to come in. ! 416: * This must be disabled before arbitration/selection ! 417: * of target is done. Don't worry about re-enabling ! 418: * dma. If arb/sel fails, then si_idle() will re-enable. ! 419: * If arb/sel succeeds then handling of command will ! 420: * re-enable. ! 421: * Also, disallow sbc to accept reconnect attempts. ! 422: * Again, si_idle() will re-enable this if arb/sel fails. ! 423: * If arb/sel succeeds then we do not want to allow ! 424: * reconnects anyway. ! 425: */ ! 426: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 427: sir->csr &= ~SI_CSR_DMA_EN; ! 428: } ! 429: sir->sbc_wreg.ser = 0; ! 430: c->c_flags &= ~SCSI_EN_RECON; ! 431: ! 432: /* performing target selection */ ! 433: if (si_arb_sel(c, un) == 0) { ! 434: goto bad; ! 435: } ! 436: ! 437: /* ! 438: * Must split dma setup into 2 parts due to sun3/50 ! 439: * which requires bcr to be set before target ! 440: * changes phase on scsi bus to data phase. ! 441: * ! 442: * Three fields in the per scsi unit structure ! 443: * hold information pertaining to the current dma ! 444: * operation: un_dma_curdir, un_dma_curaddr, and ! 445: * un_dma_curcnt. These fields are used to track ! 446: * the amount of data dma'd especially when disconnects ! 447: * and reconnects occur. ! 448: * If the current command does not involve dma, ! 449: * these fields are set appropriately. ! 450: */ ! 451: if (un->un_dma_count > 0) { ! 452: if ((c->c_cdb.cmd == SC_READ) || ! 453: (c->c_cdb.cmd == SC_REQUEST_SENSE)) { ! 454: un->un_dma_curdir = SI_RECV_DATA; ! 455: sir->csr &= ~SI_CSR_SEND; ! 456: } else { ! 457: un->un_dma_curdir = SI_SEND_DATA; ! 458: sir->csr |= SI_CSR_SEND; ! 459: } ! 460: /* save current dma info for disconnect */ ! 461: un->un_dma_curaddr = un->un_dma_addr; ! 462: un->un_dma_curcnt = un->un_dma_count; ! 463: ! 464: /* tape has scsi id of 4 */ ! 465: if ((un->un_target == 4) && scsi_dis_debug) { ! 466: printf("si_cmd: cmd= %x, addr= %x, cnt= %x\n", ! 467: c->c_cdb.cmd, un->un_dma_curaddr, ! 468: un->un_dma_curcnt); ! 469: } ! 470: ! 471: /* reset fifo */ ! 472: sir->csr &= ~SI_CSR_FIFO_RES; ! 473: sir->csr |= SI_CSR_FIFO_RES; ! 474: ! 475: /* must init bcr before target goes into data phase */ ! 476: sir->bcr = un->un_dma_curcnt; ! 477: ! 478: /* ! 479: * Currently we don't use all 24 bits of the ! 480: * count register on the vme interface. To do ! 481: * this changes are required other places, e.g. ! 482: * in the scsi_unit structure the fields ! 483: * un_dma_curcnt and un_dma_count would need to ! 484: * be changed. ! 485: */ ! 486: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 487: sir->bcrh = 0; ! 488: } ! 489: } else { ! 490: un->un_dma_curdir = SI_NO_DATA; ! 491: un->un_dma_curaddr = 0; ! 492: un->un_dma_curcnt = 0; ! 493: } ! 494: ! 495: cp = (u_char *) &c->c_cdb; ! 496: if (scsi_debug) { ! 497: printf("si%d: si_cmd: target %d issuing command ", ! 498: SINUM(c), un->un_target); ! 499: for (i = 0; i < sizeof (struct scsi_cdb); i++) { ! 500: printf("%x ", *cp++); ! 501: } ! 502: printf("\n"); ! 503: cp = (u_char *) &c->c_cdb; ! 504: } ! 505: ! 506: /* put scsi command out on scsi bus */ ! 507: if (si_putdata(c, PHASE_COMMAND, cp, sizeof(struct scsi_cdb)) ! 508: == 0) { ! 509: errct++; ! 510: } else { ! 511: /* do final dma setup and start dma operation */ ! 512: if (un->un_dma_count > 0) { ! 513: if (c->c_flags & SCSI_ONBOARD) ! 514: si_ob_dma_setup(c, un); ! 515: else ! 516: si_vme_dma_setup(c, un); ! 517: } else if (un->un_wantint) { ! 518: /* ! 519: * If this command does not involve ! 520: * any dma, we must set things up ! 521: * so we get an interrupt when the ! 522: * target is ready to give us status. ! 523: * The interrupt we get is a phase ! 524: * mismatch, however, to get this ! 525: * interrupt the sbc must be in dma ! 526: * mode. Also, the vme scsi card does ! 527: * not generate any interrupts unless ! 528: * dma is enabled in the csr. ! 529: */ ! 530: sir->sbc_wreg.mr |= SBC_MR_DMA; ! 531: sir->sbc_wreg.tcr = TCR_UNSPECIFIED; ! 532: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 533: sir->csr &= ~SI_CSR_SEND; ! 534: sir->csr |= SI_CSR_DMA_EN; ! 535: } ! 536: } ! 537: return (1); ! 538: } ! 539: } while (errct < SI_NUM_RETRIES); ! 540: ! 541: /* clear fields if we were not able to issue scsi cmd */ ! 542: printf("si_cmd: too many errors\n"); ! 543: if (un->un_dma_count != 0) { ! 544: un->un_dma_curdir = 0; ! 545: un->un_dma_curaddr = 0; ! 546: un->un_dma_curcnt = 0; ! 547: sir->bcr = 0; ! 548: sir->csr &= ~SI_CSR_SEND; ! 549: } ! 550: bad: ! 551: un->un_wantint = 0; ! 552: si_idle(c); ! 553: return (0); ! 554: } ! 555: ! 556: /* ! 557: * Perform the SCSI arbitration and selection phases. ! 558: */ ! 559: si_arb_sel(c, un) ! 560: register struct scsi_ctlr *c; ! 561: register struct scsi_unit *un; ! 562: { ! 563: register struct scsi_si_reg *sir = c->c_sir; ! 564: register u_char *icrp = &sir->sbc_wreg.icr; ! 565: register u_char *mrp = &sir->sbc_wreg.mr; ! 566: register int j; ! 567: register u_char icr; ! 568: u_char id; ! 569: ! 570: /* wait for scsi bus to become free */ ! 571: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_BSY, 0) == 0) { ! 572: printf("si_arb_sel: continuously busy\n"); ! 573: si_reset(c); ! 574: return (0); ! 575: } ! 576: ! 577: /* arbitrate for the scsi bus */ ! 578: sir->sbc_wreg.odr = SI_HOST_ID; ! 579: for (j = 0; j < SI_NUM_RETRIES; j++) { ! 580: *mrp |= SBC_MR_ARB; ! 581: ! 582: /* wait for sbc to begin arbitration */ ! 583: if (si_sbc_wait((caddr_t)icrp, SBC_ICR_AIP, 1) == 0) { ! 584: /* problem with sbc if arb never begins */ ! 585: /* ! 586: * Current bug in Emulex MT02 firmware. ! 587: * It does not go through the reselection timeout ! 588: * procedure documented in the scsi protocol spec. ! 589: */ ! 590: if ((sir->sbc_rreg.cbsr & SBC_CBSR_SEL) && ! 591: (sir->sbc_rreg.cbsr & SBC_CBSR_IO) && ! 592: (sir->sbc_rreg.cdr & SI_HOST_ID)) { ! 593: printf("si_arb_sel: REselect, flgs %x\n", ! 594: c->c_flags); ! 595: if (scsi_resel_debug) halt(""); ! 596: } else { ! 597: printf("si_arb_sel: AIP never set, ??\n"); ! 598: } ! 599: ! 600: *mrp &= ~SBC_MR_ARB; ! 601: return (0); ! 602: /* si_reset(c); */ ! 603: } ! 604: ! 605: /* check to see if we won arbitration */ ! 606: DELAY(SI_ARBITRATION_DELAY); ! 607: if ((*icrp & SBC_ICR_LA) == 0) { ! 608: if ( ((sir->sbc_rreg.cdr & ~SI_HOST_ID) ! 609: < SI_HOST_ID) && ! 610: ((*icrp & SBC_ICR_LA) == 0)) { ! 611: /* won arbitration */ ! 612: icr = *icrp & ~SBC_ICR_AIP; ! 613: *icrp = icr | SBC_ICR_ATN; ! 614: icr = *icrp & ~SBC_ICR_AIP; ! 615: *icrp = icr | SBC_ICR_SEL; ! 616: DELAY(SI_BUS_CLEAR_DELAY + SI_BUS_SETTLE_DELAY); ! 617: break; ! 618: } ! 619: } ! 620: ! 621: /* lost arbitration, clear arbitration mode */ ! 622: *mrp &= ~SBC_MR_ARB; ! 623: } ! 624: ! 625: /* couldn't win arbitration */ ! 626: if (j == SI_NUM_RETRIES) { ! 627: /* should never happen since we have highest pri scsi id */ ! 628: *mrp &= ~SBC_MR_ARB; ! 629: *icrp = 0; ! 630: printf("si_arb_sel: couldn't win arbitration\n"); ! 631: return (0); ! 632: } ! 633: ! 634: /* won arbitration, perform selection */ ! 635: sir->sbc_wreg.odr = (1 << un->un_target) | SI_HOST_ID; ! 636: icr = *icrp & ~SBC_ICR_AIP; ! 637: *icrp = icr | SBC_ICR_DATA | SBC_ICR_BUSY; ! 638: *mrp &= ~SBC_MR_ARB; ! 639: ! 640: /* wait for target to acknowledge selection */ ! 641: *icrp &= ~SBC_ICR_BUSY; ! 642: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_BSY, 1) == 0) { ! 643: if (scsi_debug) ! 644: printf("si_arb_sel: cbsr bsy never set\n"); ! 645: si_reset(c); ! 646: return (0); ! 647: } ! 648: *icrp &= ~(SBC_ICR_SEL | SBC_ICR_DATA); ! 649: ! 650: /* send target identify message */ ! 651: if (c->c_flags & SCSI_EN_DISCON) ! 652: id = SC_DR_IDENTIFY | c->c_cdb.lun; ! 653: else ! 654: id = SC_IDENTIFY | c->c_cdb.lun; ! 655: if (si_putdata(c, PHASE_MSG_OUT, &id, 1) == 0) { ! 656: if (scsi_debug) ! 657: printf("si_arb_sel: put of ID MSG %x failed\n", id); ! 658: } ! 659: *icrp = 0; ! 660: return (1); ! 661: } ! 662: ! 663: /* ! 664: * Set up the SCSI control logic for a dma transfer for vme host adaptor. ! 665: */ ! 666: si_vme_dma_setup(c, un) ! 667: register struct scsi_ctlr *c; ! 668: register struct scsi_unit *un; ! 669: { ! 670: register struct scsi_si_reg *sir = c->c_sir; ! 671: ! 672: /* setup starting dma address and number bytes to dma */ ! 673: sir->dma_addr = un->un_dma_curaddr; ! 674: sir->dma_count = un->un_dma_curcnt; ! 675: ! 676: /* set up byte packing control info */ ! 677: if (sir->dma_addr & 0x2) { ! 678: /* setup word dma transfers across vme bus */ ! 679: sir->csr |= SI_CSR_BPCON; ! 680: } else { ! 681: /* setup longword dma transfers across vme bus */ ! 682: sir->csr &= ~SI_CSR_BPCON; ! 683: } ! 684: ! 685: if (scsi_debug) { ! 686: printf("si_vme_dma_setup: addr %x, cnt %x, csr %x\n", ! 687: sir->dma_addr, sir->dma_count, sir->csr); ! 688: } ! 689: ! 690: /* init sbc for dma transfer */ ! 691: si_sbc_dma_setup(sir, un->un_dma_curdir); ! 692: ! 693: /* enable dma - this must be the last step */ ! 694: sir->csr |= SI_CSR_DMA_EN; ! 695: } ! 696: ! 697: /* ! 698: * Set up the SCSI control logic for a dma transfer for onboard host ! 699: * adaptor. ! 700: */ ! 701: si_ob_dma_setup(c, un) ! 702: register struct scsi_ctlr *c; ! 703: register struct scsi_unit *un; ! 704: { ! 705: register struct scsi_si_reg *sir = c->c_sir; ! 706: register struct udc_table *udct = &c->c_udct; ! 707: register int addr; ! 708: ! 709: /* set up udc dma information */ ! 710: addr = un->un_dma_curaddr; ! 711: if (addr < DVMA_OFFSET) ! 712: addr += DVMA_OFFSET; ! 713: udct->haddr = ((addr & 0xff0000) >> 8) | UDC_ADDR_INFO; ! 714: udct->laddr = addr & 0xffff; ! 715: udct->hcmr = UDC_CMR_HIGH; ! 716: udct->count = un->un_dma_curcnt / 2; /* #bytes -> #words */ ! 717: if (un->un_dma_curdir == SI_RECV_DATA) { ! 718: udct->rsel = UDC_RSEL_RECV; ! 719: udct->lcmr = UDC_CMR_LRECV; ! 720: } else { ! 721: udct->rsel = UDC_RSEL_SEND; ! 722: udct->lcmr = UDC_CMR_LSEND; ! 723: if (un->un_dma_curcnt & 1) { ! 724: udct->count++; ! 725: } ! 726: } ! 727: ! 728: /* initialize udc chain address register */ ! 729: sir->udc_raddr = UDC_ADR_CAR_HIGH; ! 730: DELAY(SI_UDC_WAIT); ! 731: sir->udc_rdata = ((int)udct & 0xff0000) >> 8; ! 732: DELAY(SI_UDC_WAIT); ! 733: sir->udc_raddr = UDC_ADR_CAR_LOW; ! 734: DELAY(SI_UDC_WAIT); ! 735: sir->udc_rdata = (int)udct & 0xffff; ! 736: ! 737: if (scsi_debug) { ! 738: printf("si_ob_dma_setup: udct= %x, %x -> %x\n", udct, ! 739: un->un_dma_curaddr, addr); ! 740: } ! 741: ! 742: /* initialize udc master mode register */ ! 743: DELAY(SI_UDC_WAIT); ! 744: sir->udc_raddr = UDC_ADR_MODE; ! 745: DELAY(SI_UDC_WAIT); ! 746: sir->udc_rdata = UDC_MODE; ! 747: ! 748: /* issue channel interrupt enable command, in case of error, to udc */ ! 749: DELAY(SI_UDC_WAIT); ! 750: sir->udc_raddr = UDC_ADR_COMMAND; ! 751: DELAY(SI_UDC_WAIT); ! 752: sir->udc_rdata = UDC_CMD_CIE; ! 753: ! 754: /* issue start chain command to udc */ ! 755: DELAY(SI_UDC_WAIT); ! 756: sir->udc_rdata = UDC_CMD_STRT_CHN; ! 757: ! 758: /* put sbc in dma mode and start dma transfer */ ! 759: si_sbc_dma_setup(sir, un->un_dma_curdir); ! 760: } ! 761: ! 762: /* ! 763: * Setup and start the sbc for a dma operation. ! 764: */ ! 765: si_sbc_dma_setup(sir, dir) ! 766: register struct scsi_si_reg *sir; ! 767: register int dir; ! 768: { ! 769: sir->sbc_wreg.mr |= SBC_MR_DMA; ! 770: if (dir == SI_RECV_DATA) { ! 771: sir->sbc_wreg.tcr = TCR_DATA_IN; ! 772: sir->sbc_wreg.ircv = 0; ! 773: } else { ! 774: sir->sbc_wreg.tcr = TCR_DATA_OUT; ! 775: sir->sbc_wreg.icr = SBC_ICR_DATA; ! 776: sir->sbc_wreg.send = 0; ! 777: } ! 778: } ! 779: ! 780: /* ! 781: * Cleanup up the SCSI control logic after a dma transfer. ! 782: */ ! 783: si_dma_cleanup(c) ! 784: register struct scsi_ctlr *c; ! 785: { ! 786: register struct scsi_si_reg *sir = c->c_sir; ! 787: ! 788: /* disable dma controller */ ! 789: if (c->c_flags & SCSI_ONBOARD) { ! 790: sir->udc_raddr = UDC_ADR_COMMAND; ! 791: DELAY(SI_UDC_WAIT); ! 792: sir->udc_rdata = UDC_CMD_RESET; ! 793: } else { ! 794: sir->dma_addr = 0; ! 795: sir->dma_count = 0; ! 796: } ! 797: ! 798: /* reset fifo */ ! 799: sir->csr &= ~SI_CSR_FIFO_RES; ! 800: sir->csr |= SI_CSR_FIFO_RES; ! 801: ! 802: /* take sbc out of dma mode and reset bcr */ ! 803: sir->sbc_wreg.icr = 0; ! 804: sir->sbc_wreg.mr &= ~SBC_MR_DMA; ! 805: sir->sbc_wreg.tcr = 0; ! 806: sir->bcr = 0; ! 807: } ! 808: ! 809: /* ! 810: * Handle special dma receive situations, e.g. an odd number of bytes ! 811: * in a dma transfer. ! 812: * The Sun3/50 onboard interface has different situations which ! 813: * must be handled than the vme interface. ! 814: */ ! 815: si_dma_recv(c) ! 816: register struct scsi_ctlr *c; ! 817: { ! 818: register struct scsi_si_reg *sir = c->c_sir; ! 819: register struct scsi_unit *un = c->c_un; ! 820: register int offset; ! 821: ! 822: offset = un->un_dma_curaddr + (un->un_dma_curcnt - sir->bcr); ! 823: ! 824: /* handle the onboard scsi situations */ ! 825: if (c->c_flags & SCSI_ONBOARD) { ! 826: sir->udc_raddr = UDC_ADR_COUNT; ! 827: ! 828: /* wait for the fifo to empty */ ! 829: if (si_wait((u_short *)&sir->csr, SI_CSR_FIFO_EMPTY, 1) == 0) { ! 830: printf("si_dma_recv: fifo never emptied\n"); ! 831: return (0); ! 832: } ! 833: ! 834: /* handle odd byte */ ! 835: if ((un->un_dma_curcnt - sir->bcr) & 1) { ! 836: DVMA[offset - 1] = (sir->fifo_data & 0xff00) >> 8; ! 837: ! 838: /* ! 839: * The udc may not dma the last word from the fifo_data ! 840: * register into memory due to how the hardware turns ! 841: * off the udc at the end of the dma operation. ! 842: */ ! 843: } else if (((sir->udc_rdata*2) - sir->bcr) == 2) { ! 844: DVMA[offset - 2] = (sir->fifo_data & 0xff00) >> 8; ! 845: DVMA[offset - 1] = sir->fifo_data & 0x00ff; ! 846: } ! 847: ! 848: /* handle the vme scsi situations */ ! 849: } else if ((sir->csr & SI_CSR_LOB) != 0) { ! 850: /* ! 851: * Grabs last few bytes which may not have been dma'd. ! 852: * Worst case is when longword dma transfers are being done ! 853: * and there are 3 bytes leftover. ! 854: * If BPCON bit is set then longword dmas were being done, ! 855: * otherwise word dmas were being done. ! 856: */ ! 857: if ((sir->csr & SI_CSR_BPCON) == 0) { ! 858: switch (sir->csr & SI_CSR_LOB) { ! 859: case SI_CSR_LOB_THREE: ! 860: DVMA[offset - 3] = (sir->bpr & 0xff000000) >> 24; ! 861: DVMA[offset - 2] = (sir->bpr & 0x00ff0000) >> 16; ! 862: DVMA[offset - 1] = (sir->bpr & 0x0000ff00) >> 8; ! 863: break; ! 864: ! 865: case SI_CSR_LOB_TWO: ! 866: DVMA[offset - 2] = (sir->bpr & 0xff000000) >> 24; ! 867: DVMA[offset - 1] = (sir->bpr & 0x00ff0000) >> 16; ! 868: break; ! 869: ! 870: case SI_CSR_LOB_ONE: ! 871: DVMA[offset - 1] = (sir->bpr & 0xff000000) >> 24; ! 872: break; ! 873: } ! 874: } else { ! 875: DVMA[offset - 1] = (sir->bpr & 0x0000ff00) >> 8; ! 876: } ! 877: } ! 878: return (1); ! 879: } ! 880: ! 881: ! 882: /* ! 883: * Handle a scsi interrupt. ! 884: */ ! 885: siintr(c) ! 886: register struct scsi_ctlr *c; ! 887: { ! 888: register struct scsi_si_reg *sir = c->c_sir; ! 889: register struct scsi_unit *un = c->c_un; ! 890: register int bsr; ! 891: register int status; ! 892: register int resid; ! 893: register int dma_cleanup; ! 894: register int i; ! 895: int disconnect; ! 896: u_char msg; ! 897: struct buf *dp; ! 898: int reset_occurred; ! 899: ! 900: /* set misc flags */ ! 901: status = SE_NO_ERROR; ! 902: resid = 0; ! 903: dma_cleanup = 0; ! 904: disconnect = 0; ! 905: reset_occurred = 0; ! 906: ! 907: /* ! 908: * For vme host adaptor interface, must disable dma before ! 909: * accessing any registers other than the csr or the ! 910: * SI_CSR_DMA_CONFLICT bit in the csr will be set. ! 911: */ ! 912: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 913: sir->csr &= ~SI_CSR_DMA_EN; ! 914: } ! 915: ! 916: /* check for dma related errors */ ! 917: if (sir->csr & (SI_CSR_DMA_IP | SI_CSR_DMA_CONFLICT)) { ! 918: if (sir->csr & SI_CSR_DMA_BUS_ERR) { ! 919: printf("siintr: bus error during dma\n"); ! 920: } else if (sir->csr & SI_CSR_DMA_CONFLICT) { ! 921: printf("siintr: invalid reg access during dma\n"); ! 922: } else { ! 923: if (c->c_flags & SCSI_ONBOARD) ! 924: printf("siintr: dma ip, unknown reason\n"); ! 925: else ! 926: printf("siintr: dma overrun\n"); ! 927: } ! 928: /* ! 929: * Either we were waiting for an interrupt on a phase change ! 930: * on the scsi bus, an interrupt on a reconnect attempt, ! 931: * or an interrupt upon completion of a real dma operation. ! 932: * Each of these situations must be handled appropriately. ! 933: */ ! 934: if (sir->sbc_rreg.tcr == TCR_UNSPECIFIED) { ! 935: sir->sbc_wreg.mr &= ~SBC_MR_DMA; ! 936: } else if (un == NULL) { ! 937: si_reset(c); ! 938: si_idle(c); ! 939: return; ! 940: } else { ! 941: dma_cleanup = 1; ! 942: } ! 943: status = SE_FATAL; ! 944: ! 945: /* check for interrupt from sbc */ ! 946: } else if (sir->csr & SI_CSR_SBC_IP) { ! 947: ! 948: /* grab the bsr and find out why sbc interrupted */ ! 949: bsr = sir->sbc_rreg.bsr; ! 950: ! 951: /* acknowledge sbc interrupt */ ! 952: msg = sir->sbc_rreg.clr; ! 953: ! 954: /* ! 955: * Check for sbc end of operation interrupt. ! 956: * This is the normal interrupt upon completion ! 957: * of a dma operation. Very soon after this ! 958: * interrupt is generated a phase mismatch ! 959: * should occur on the scsi bus as the target ! 960: * changes from the data in/out phase to the ! 961: * status phase. ! 962: */ ! 963: if (bsr & SBC_BSR_EDMA) { ! 964: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.bsr, ! 965: SBC_BSR_PMTCH, 0) == 0) { ! 966: dma_cleanup = 1; ! 967: status = SE_FATAL; ! 968: printf("si: scsi sbc dma end op\n"); ! 969: goto done; ! 970: } ! 971: goto phmismatch; ! 972: ! 973: /* check for phase mismatch */ ! 974: } else if ((bsr & SBC_BSR_PMTCH) == 0) { ! 975: phmismatch: ! 976: if ((sir->sbc_rreg.mr & SBC_MR_DMA) == 0) { ! 977: if (c->c_flags & SCSI_EN_RECON) ! 978: goto recon; ! 979: else ! 980: goto discon; ! 981: } ! 982: ! 983: /* ! 984: * Handle fake dma mode which is used when we ! 985: * want an interrupt when target changes scsi ! 986: * bus to status phase. ! 987: */ ! 988: sir->sbc_wreg.mr &= ~SBC_MR_DMA; ! 989: if (sir->sbc_rreg.tcr == TCR_UNSPECIFIED) { ! 990: sir->sbc_wreg.tcr = 0; ! 991: } else { ! 992: /* need to reset some registers after a dma */ ! 993: dma_cleanup = 1; ! 994: ! 995: /* handle special dma recv situations */ ! 996: if (un->un_dma_curdir == SI_RECV_DATA) { ! 997: if (si_dma_recv(c) == 0) { ! 998: status = SE_RETRYABLE; ! 999: } ! 1000: } ! 1001: } ! 1002: ! 1003: discon: ! 1004: /* check for disconnect */ ! 1005: if ((sir->sbc_rreg.cbsr & SBC_CBSR_REQ) && ! 1006: ((sir->sbc_rreg.cbsr & CBSR_PHASE_BITS) == ! 1007: PHASE_MSG_IN)) { ! 1008: if (scsi_debug || scsi_dis_debug) ! 1009: printf("siintr: DISconnect\n"); ! 1010: if (si_disconnect(c)) { ! 1011: disconnect = 1; ! 1012: } ! 1013: } ! 1014: goto done; ! 1015: } ! 1016: ! 1017: recon: ! 1018: /* check for reconnect attempt */ ! 1019: if ((sir->sbc_rreg.cbsr & SBC_CBSR_SEL) && ! 1020: (sir->sbc_rreg.cbsr & SBC_CBSR_IO) && ! 1021: (sir->sbc_rreg.cdr & SI_HOST_ID)) { ! 1022: if (scsi_debug || scsi_dis_debug) ! 1023: printf("siintr: REconnect\n"); ! 1024: si_reconnect(c); ! 1025: return; ! 1026: } ! 1027: ! 1028: /* ! 1029: * Scsi bus reset occurred. Put registers in correct ! 1030: * state. Must cleanup disconnected tasks which will ! 1031: * never reconnect due to the scsi bus reset. ! 1032: */ ! 1033: if (scsi_debug) ! 1034: printf("siintr: got scsi bus reset\n"); ! 1035: sir->csr = 0; ! 1036: DELAY(10); ! 1037: sir->csr = SI_CSR_INTR_EN|SI_CSR_SCSI_RES|SI_CSR_FIFO_RES; ! 1038: sir->sbc_wreg.mr = SBC_MR_EEI; ! 1039: c->c_flags &= ~SCSI_EN_RECON; ! 1040: if (c->c_disqh != NULL) { ! 1041: c->c_flags |= SCSI_FLUSH_DISQ; ! 1042: c->c_flush = c->c_disqt; ! 1043: } ! 1044: status = SE_FATAL; ! 1045: reset_occurred = 1; ! 1046: ! 1047: /* flush disconnect tasks now if possible */ ! 1048: if ((un == NULL) && c->c_disqh) { ! 1049: si_idle(c); ! 1050: return; ! 1051: } ! 1052: } ! 1053: ! 1054: done: ! 1055: /* cleanup after a dma operation */ ! 1056: if (dma_cleanup) { ! 1057: resid = sir->bcr; ! 1058: si_dma_cleanup(c); ! 1059: } ! 1060: ! 1061: /* pass interrupt info to unit */ ! 1062: if (un && un->un_wantint && (disconnect == 0)) { ! 1063: un->un_wantint = 0; ! 1064: if (status == SE_NO_ERROR) { ! 1065: if (si_getstatus(un, 0) == 0) { ! 1066: status = SE_RETRYABLE; ! 1067: } ! 1068: } else if (reset_occurred == 0) { ! 1069: si_reset(c); ! 1070: } ! 1071: (*un->un_ss->ss_intr)(c, resid, status); ! 1072: } ! 1073: ! 1074: if (disconnect) { ! 1075: /* start next I/O activity on controller */ ! 1076: if ((un->un_mc->mc_tab.b_actf) && ! 1077: (un->un_mc->mc_tab.b_active == 0)) { ! 1078: sistart(un); ! 1079: } else { ! 1080: /* enable reconnect attempts */ ! 1081: sir->sbc_wreg.ser = SI_HOST_ID; ! 1082: c->c_flags |= SCSI_EN_RECON; ! 1083: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1084: sir->csr &= ~SI_CSR_SEND; ! 1085: sir->csr |= SI_CSR_DMA_EN; ! 1086: } ! 1087: } ! 1088: } ! 1089: } ! 1090: ! 1091: /* ! 1092: * Handle target disconnecting. ! 1093: */ ! 1094: si_disconnect(c) ! 1095: register struct scsi_ctlr *c; ! 1096: { ! 1097: register struct scsi_unit *un = c->c_un; ! 1098: register struct mb_ctlr *mc = un->un_mc; ! 1099: register struct buf *dp; ! 1100: register struct scsi_si_reg *sir = c->c_sir; ! 1101: register u_char msg; ! 1102: ! 1103: /* get disconnect message(s) */ ! 1104: msg = si_getdata(c, PHASE_MSG_IN); ! 1105: if (msg == SC_SAVE_DATA_PTR) { ! 1106: msg = si_getdata(c, PHASE_MSG_IN); ! 1107: } ! 1108: if (msg != SC_DISCONNECT) { ! 1109: return (0); ! 1110: } ! 1111: ! 1112: /* save dma info for reconnect */ ! 1113: if (un->un_dma_curdir != SI_NO_DATA) { ! 1114: ! 1115: /* debug information */ ! 1116: if (c->c_flags & SCSI_ONBOARD) { ! 1117: if (scsi_dis_debug) { ! 1118: sir->udc_raddr = UDC_ADR_COUNT; ! 1119: printf("\tdiscon: udc_cnt %x\n", ! 1120: sir->udc_rdata); ! 1121: } ! 1122: if ((un->un_dma_curaddr & 0xffff) != c->c_udct.laddr) { ! 1123: printf("discon: caddr= %x, udc= %x\n", ! 1124: un->un_dma_curaddr, c->c_udct.laddr); ! 1125: } ! 1126: } ! 1127: if (scsi_dis_debug) { ! 1128: printf("\taddr= %x, cnt= %x, bcr= %x, sr= %x, baddr= %x\n", ! 1129: un->un_dma_curaddr, un->un_dma_curcnt, ! 1130: sir->bcr, sir->csr, un->un_baddr); ! 1131: } ! 1132: ! 1133: /* ! 1134: * Save dma information so dma can be restarted when ! 1135: * a reconnect occurs. ! 1136: */ ! 1137: un->un_dma_curaddr += un->un_dma_curcnt - sir->bcr; ! 1138: un->un_dma_curcnt = sir->bcr; ! 1139: } ! 1140: ! 1141: /* ! 1142: * Remove this disconnected task from the ctlr ready queue and save ! 1143: * on disconnect queue until a reconnect is done. ! 1144: * Advance controller queue. Remove mainbus resource alloc info. ! 1145: */ ! 1146: dp = mc->mc_tab.b_actf; ! 1147: mc->mc_tab.b_active = 0; ! 1148: mc->mc_tab.b_actf = dp->b_forw; ! 1149: mc->mc_mbinfo = 0; ! 1150: if (c->c_disqh == NULL) ! 1151: c->c_disqh = dp; ! 1152: else ! 1153: c->c_disqt->b_forw = dp; ! 1154: dp->b_forw = NULL; ! 1155: c->c_disqt = dp; ! 1156: c->c_un = NULL; ! 1157: return (1); ! 1158: } ! 1159: ! 1160: /* ! 1161: * Complete reselection phase and reconnect to target. ! 1162: * ! 1163: * NOTE: this routine cannot use si_getdata() to get identify msg ! 1164: * from reconnecting target due to sun3/50 scsi interface. The bcr ! 1165: * must be setup before the target changes scsi bus to data phase ! 1166: * if the command being reconnected involves dma (which we do not ! 1167: * know until we get the identify msg). Thus we cannot acknowledge ! 1168: * the identify msg until some setup of the host adaptor registers ! 1169: * is done. ! 1170: */ ! 1171: si_reconnect(c) ! 1172: register struct scsi_ctlr *c; ! 1173: { ! 1174: register struct scsi_si_reg *sir = c->c_sir; ! 1175: register struct buf *dp; ! 1176: register struct buf *pdp; ! 1177: register struct scsi_unit *un; ! 1178: register int i; ! 1179: register u_char msg; ! 1180: register u_char lun; ! 1181: register u_char cdr; ! 1182: ! 1183: /* get reselecting target scsi id */ ! 1184: cdr = sir->sbc_rreg.cdr & ~SI_HOST_ID; ! 1185: ! 1186: /* make sure there are only 2 scsi id's set */ ! 1187: for (i=0; i < 8; i++) { ! 1188: if (cdr & (1<<i)) ! 1189: break; ! 1190: } ! 1191: cdr &= ~(1<<i); ! 1192: if (cdr != 0) { ! 1193: printf("si_recon: > 2 scsi ids\n"); ! 1194: return; ! 1195: } ! 1196: ! 1197: /* acknowledge reselection */ ! 1198: sir->sbc_wreg.icr = SBC_ICR_BUSY; ! 1199: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_SEL, 0) == 0) { ! 1200: printf("si_recon: target never rel SEL\n"); ! 1201: si_reset(c); ! 1202: return; ! 1203: } ! 1204: sir->sbc_wreg.icr = 0; ! 1205: ! 1206: /* setup for getting identify message from reconnecting target */ ! 1207: sir->sbc_wreg.tcr = TCR_MSG_IN; ! 1208: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 1) == 0) { ! 1209: printf("si_recon: REQ not active\n"); ! 1210: si_reset(c); ! 1211: return; ! 1212: } ! 1213: if ((sir->sbc_rreg.bsr & SBC_BSR_PMTCH) == 0) { ! 1214: printf("si_recon: phase mismatch\n"); ! 1215: si_reset(c); ! 1216: return; ! 1217: } ! 1218: ! 1219: /* grab identify message */ ! 1220: msg = sir->sbc_rreg.cdr; ! 1221: sir->sbc_wreg.tcr = 0; ! 1222: if ((msg != SC_IDENTIFY) && (msg != SC_DR_IDENTIFY)) { ! 1223: printf("si: recon, not id msg\n"); ! 1224: si_reset(c); ! 1225: return; ! 1226: } ! 1227: lun = msg & 0x07; ! 1228: ! 1229: /* search disconnect q for reconnecting task */ ! 1230: for (dp = c->c_disqh, pdp = NULL; dp; pdp = dp, dp = dp->b_forw) { ! 1231: un = (struct scsi_unit *)dp->b_un.b_addr; ! 1232: if ((un->un_target == i) && (un->un_lun == lun)) ! 1233: break; ! 1234: } ! 1235: if (dp == NULL) { ! 1236: printf("si: recon, never found dis unit\n"); ! 1237: si_reset(c); ! 1238: return; ! 1239: } ! 1240: ! 1241: /* make sure there is no active I/O */ ! 1242: if (un->un_mc->mc_tab.b_actf != NULL) { ! 1243: printf("si: recon, other I/O active\n"); ! 1244: si_reset(c); ! 1245: return; ! 1246: } ! 1247: ! 1248: /* disable other reconnection attempts */ ! 1249: sir->sbc_wreg.ser = 0; ! 1250: c->c_flags &= ~SCSI_EN_RECON; ! 1251: ! 1252: /* remove entity from disconnect q */ ! 1253: if (dp == c->c_disqh) ! 1254: c->c_disqh = dp->b_forw; ! 1255: else ! 1256: pdp->b_forw = dp->b_forw; ! 1257: if (dp == c->c_disqt) ! 1258: c->c_disqt = pdp; ! 1259: dp->b_forw = NULL; ! 1260: ! 1261: /* requeue on controller queue */ ! 1262: siustart(un); ! 1263: un->un_mc->mc_tab.b_active = 1; ! 1264: c->c_un = un; ! 1265: ! 1266: /* restart disconnect activity */ ! 1267: if (un->un_dma_curdir != SI_NO_DATA) { ! 1268: /* restore mainbus resource allocation info */ ! 1269: un->un_mc->mc_mbinfo = un->un_baddr; ! 1270: ! 1271: /* do initial dma setup */ ! 1272: if (un->un_dma_curdir == SI_RECV_DATA) ! 1273: sir->csr &= ~SI_CSR_SEND; ! 1274: else ! 1275: sir->csr |= SI_CSR_SEND; ! 1276: sir->csr &= ~SI_CSR_FIFO_RES; ! 1277: sir->csr |= SI_CSR_FIFO_RES; ! 1278: sir->bcr = un->un_dma_curcnt; ! 1279: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1280: sir->bcrh = 0; ! 1281: } ! 1282: ! 1283: if (scsi_dis_debug) { ! 1284: printf("\taddr= %x, cnt= %x, bcr= %x, sr= %x, baddr= %x\n", ! 1285: un->un_dma_curaddr, un->un_dma_curcnt, sir->bcr, ! 1286: sir->csr, un->un_baddr); ! 1287: } ! 1288: ! 1289: } ! 1290: ! 1291: /* we can finally acknowledge identify message */ ! 1292: sir->sbc_wreg.icr = SBC_ICR_ACK; ! 1293: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 0) == 0) { ! 1294: printf("si_recon: REQ not INactive\n"); ! 1295: si_reset(c); ! 1296: return; ! 1297: } ! 1298: sir->sbc_wreg.icr = 0; ! 1299: ! 1300: /* may get restore pointers message */ ! 1301: if ((sir->sbc_rreg.cbsr & SBC_CBSR_REQ) && ! 1302: ((sir->sbc_rreg.cbsr & CBSR_PHASE_BITS) == PHASE_MSG_IN)) { ! 1303: msg = si_getdata(c, PHASE_MSG_IN); ! 1304: } ! 1305: ! 1306: /* do final setup for dma operation and start dma */ ! 1307: if (un->un_dma_curdir != SI_NO_DATA) { ! 1308: if (c->c_flags & SCSI_ONBOARD) ! 1309: si_ob_dma_setup(c, un); ! 1310: else ! 1311: si_vme_dma_setup(c, un); ! 1312: } else if (un->un_wantint) { ! 1313: sir->sbc_wreg.mr |= SBC_MR_DMA; ! 1314: sir->sbc_wreg.tcr = TCR_UNSPECIFIED; ! 1315: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1316: sir->csr &= ~SI_CSR_SEND; ! 1317: sir->csr |= SI_CSR_DMA_EN; ! 1318: } ! 1319: } ! 1320: } ! 1321: ! 1322: /* ! 1323: * No current activity for the scsi bus. May need to flush some ! 1324: * disconnected tasks if a scsi bus reset occurred before the ! 1325: * target reconnected, since a scsi bus reset causes targets to ! 1326: * "forget" about any disconnected activity. ! 1327: * Also, enable reconnect attempts. ! 1328: */ ! 1329: si_idle(c) ! 1330: register struct scsi_ctlr *c; ! 1331: { ! 1332: register struct scsi_si_reg *sir = c->c_sir; ! 1333: register struct buf *dp; ! 1334: register struct scsi_unit *un; ! 1335: register int i; ! 1336: register int resid; ! 1337: ! 1338: if (c->c_flags & SCSI_FLUSHING) { ! 1339: if (scsi_reset_debug) ! 1340: printf("si_idle: flushing, flags %x\n", c->c_flags); ! 1341: return; ! 1342: } ! 1343: ! 1344: /* flush disconnect tasks if a reconnect will never occur */ ! 1345: if (c->c_flags & SCSI_FLUSH_DISQ) { ! 1346: if (scsi_reset_debug) { ! 1347: printf("si_idle: flush: flags= %x, disqh= %x, disqt= %x\n", ! 1348: c->c_flags, c->c_disqh, c->c_disqt); ! 1349: } ! 1350: ! 1351: /* now in process of flushing tasks */ ! 1352: c->c_flags &= ~SCSI_FLUSH_DISQ; ! 1353: c->c_flags |= SCSI_FLUSHING; ! 1354: ! 1355: for (dp = c->c_disqh; dp && c->c_flush; dp = c->c_disqh) { ! 1356: /* keep track of last task to flush */ ! 1357: if (c->c_flush == c->c_disqh) ! 1358: c->c_flush = NULL; ! 1359: ! 1360: /* remove tasks from disconnect q */ ! 1361: un = (struct scsi_unit *)dp->b_un.b_addr; ! 1362: c->c_disqh = dp->b_forw; ! 1363: dp->b_forw = NULL; ! 1364: ! 1365: /* requeue on controller q */ ! 1366: siustart(un); ! 1367: un->un_mc->mc_tab.b_active = 1; ! 1368: c->c_un = un; ! 1369: ! 1370: /* inform device routines of error */ ! 1371: if (un->un_dma_curdir != SI_NO_DATA) { ! 1372: un->un_mc->mc_mbinfo = un->un_baddr; ! 1373: resid = un->un_dma_curcnt; ! 1374: } else { ! 1375: resid = 0; ! 1376: } ! 1377: (*un->un_ss->ss_intr)(c, resid, SE_FATAL); ! 1378: } ! 1379: if (c->c_disqh == NULL) { ! 1380: c->c_disqt = NULL; ! 1381: } ! 1382: c->c_flags &= ~SCSI_FLUSHING; ! 1383: } ! 1384: ! 1385: /* enable reconnect attempts */ ! 1386: sir->sbc_wreg.ser = SI_HOST_ID; ! 1387: c->c_flags |= SCSI_EN_RECON; ! 1388: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1389: sir->csr &= ~SI_CSR_SEND; ! 1390: sir->csr |= SI_CSR_DMA_EN; ! 1391: } ! 1392: } ! 1393: ! 1394: /* ! 1395: * Get status bytes from scsi bus. ! 1396: */ ! 1397: si_getstatus(un, recurse) ! 1398: register struct scsi_unit *un; ! 1399: { ! 1400: register struct scsi_ctlr *c = un->un_c; ! 1401: register u_char *cp = (u_char *)&c->c_scb; ! 1402: struct scsi_cdb save_cdb; ! 1403: struct scsi_scb save_scb; ! 1404: register int i; ! 1405: register int b; ! 1406: register int save_dma_addr; ! 1407: register int save_dma_count; ! 1408: register int save_reg_dma_count; ! 1409: int resid; ! 1410: short retval = 1; ! 1411: int s; ! 1412: ! 1413: /* get all the status bytes */ ! 1414: for (i = 0;;) { ! 1415: b = si_getdata(c, PHASE_STATUS); ! 1416: if (b < 0) { ! 1417: break; ! 1418: } ! 1419: if (i < STATUS_LEN) { ! 1420: cp[i++] = b; ! 1421: } ! 1422: } ! 1423: ! 1424: /* get command complete message */ ! 1425: b = si_getdata(c, PHASE_MSG_IN); ! 1426: if (b != SC_COMMAND_COMPLETE) { ! 1427: if (scsi_debug) { ! 1428: printf("Invalid SCSI message: %x\n", b); ! 1429: printf("Status bytes (%d):", i); ! 1430: for (b = 0; b < i; b++) { ! 1431: printf(" %x", cp[b]); ! 1432: } ! 1433: printf("\n"); ! 1434: } ! 1435: return (0); ! 1436: } ! 1437: if (scsi_debug) { ! 1438: printf("si%d: si_getstatus: Got status (%d) ", SINUM(c), i); ! 1439: for (b = 0; b < i; b++) { ! 1440: printf(" %x", cp[b]); ! 1441: } ! 1442: printf("\n"); ! 1443: } ! 1444: if (c->c_scb.busy) { ! 1445: return (0); ! 1446: } ! 1447: ! 1448: /* check for sense data */ ! 1449: if (c->c_scb.chk) { ! 1450: if (recurse) { ! 1451: printf("scsi: chk on sense: invalid\n"); ! 1452: return (0); ! 1453: } ! 1454: ! 1455: /* save information while we get sense */ ! 1456: save_cdb = c->c_cdb; ! 1457: save_scb = c->c_scb; ! 1458: save_dma_addr = un->un_dma_addr; ! 1459: save_dma_count = un->un_dma_count; ! 1460: save_reg_dma_count = c->c_sir->bcr; ! 1461: ! 1462: /* set up for getting sense */ ! 1463: c->c_cdb.cmd = SC_REQUEST_SENSE; ! 1464: c->c_cdb.lun = un->un_lun; ! 1465: cdbaddr(&c->c_cdb, 0); ! 1466: c->c_cdb.count = sizeof(struct scsi_sense); ! 1467: un->un_dma_addr = (int)c->c_sense - (int)DVMA; ! 1468: un->un_dma_count = sizeof(struct scsi_sense); ! 1469: ! 1470: /* get sense */ ! 1471: if ((s=0),si_cmd(c, un, 0) == 0 || ! 1472: (s=1),si_cmdwait(c) == 0 || ! 1473: (s=2),si_getstatus(un, 1) == 0) { ! 1474: printf("scsi: cannot get sense %d\n", s); ! 1475: si_off(un); ! 1476: retval = 0; ! 1477: } ! 1478: ! 1479: /* restore pre sense information */ ! 1480: c->c_cdb = save_cdb; ! 1481: c->c_scb = save_scb; ! 1482: un->un_dma_addr = save_dma_addr; ! 1483: un->un_dma_count = save_dma_count; ! 1484: c->c_sir->bcr = save_reg_dma_count; ! 1485: } ! 1486: return (retval); ! 1487: } ! 1488: ! 1489: /* ! 1490: * Wait for a scsi dma request to complete. ! 1491: * Disconnects were disabled in si_cmd() when polling for command completion. ! 1492: */ ! 1493: si_cmdwait(c) ! 1494: register struct scsi_ctlr *c; ! 1495: { ! 1496: register struct scsi_si_reg *sir = c->c_sir; ! 1497: register struct scsi_unit *un = c->c_un; ! 1498: register u_char junk; ! 1499: ! 1500: /* wait for dma transfer to complete */ ! 1501: if (si_wait((u_short *)&sir->csr, SI_CSR_DMA_ACTIVE, 0) == 0) { ! 1502: printf("si_cmdwait: DMA_ACTIVE still on\n"); ! 1503: si_reset(c); ! 1504: return (0); ! 1505: } ! 1506: ! 1507: /* if command does not involve dma activity, then we are finished */ ! 1508: if (un->un_dma_curdir == SI_NO_DATA) { ! 1509: return (1); ! 1510: } ! 1511: ! 1512: /* wait for indication of dma completion */ ! 1513: if (si_wait((u_short *)&sir->csr, ! 1514: SI_CSR_SBC_IP|SI_CSR_DMA_IP|SI_CSR_DMA_CONFLICT, 1) == 0) { ! 1515: printf("si_cmdwait: dma op never completed\n"); ! 1516: si_reset(c); ! 1517: return (0); ! 1518: } ! 1519: ! 1520: /* ! 1521: * For vme host adaptor interface, must disable dma before ! 1522: * accessing any registers other than the csr or a dma ! 1523: * conflict error will occur. ! 1524: */ ! 1525: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1526: sir->csr &= ~SI_CSR_DMA_EN; ! 1527: } ! 1528: ! 1529: /* make sure dma completely complete */ ! 1530: if ((sir->csr & SI_CSR_SBC_IP) == 0) { ! 1531: if (sir->csr & SI_CSR_DMA_BUS_ERR) { ! 1532: printf("si_cmdwait: bus error during dma\n"); ! 1533: } else if (sir->csr & SI_CSR_DMA_CONFLICT) { ! 1534: printf("si_cmdwait: invalid reg access during dma\n"); ! 1535: } else { ! 1536: if (c->c_flags & SCSI_ONBOARD) ! 1537: printf("si_cmdwait: dma ip, unknown reason\n"); ! 1538: else ! 1539: printf("si_cmdwait: dma overrun\n"); ! 1540: } ! 1541: si_reset(c); ! 1542: return (0); ! 1543: } ! 1544: ! 1545: /* handle special dma recv situations */ ! 1546: if (un->un_dma_curdir == SI_RECV_DATA) { ! 1547: if (si_dma_recv(c) == 0) { ! 1548: si_reset(c); ! 1549: return (0); ! 1550: } ! 1551: } ! 1552: ! 1553: /* ack sbc interrupt and cleanup */ ! 1554: junk = sir->sbc_rreg.clr; ! 1555: si_dma_cleanup(c); ! 1556: return (1); ! 1557: } ! 1558: ! 1559: /* ! 1560: * Wait for a condition to be (de)asserted on the scsi bus. ! 1561: */ ! 1562: si_sbc_wait(reg, cond, set) ! 1563: register caddr_t reg; ! 1564: register u_char cond; ! 1565: register int set; ! 1566: { ! 1567: register int i; ! 1568: register u_char regval; ! 1569: ! 1570: for (i = 0; i < SI_WAIT_COUNT; i++) { ! 1571: regval = *reg; ! 1572: if ((set == 1) && (regval & cond)) { ! 1573: return (1); ! 1574: } ! 1575: if ((set == 0) && !(regval & cond)) { ! 1576: return (1); ! 1577: } ! 1578: DELAY(10); ! 1579: } ! 1580: return (0); ! 1581: } ! 1582: ! 1583: /* ! 1584: * Wait for a condition to be (de)asserted. ! 1585: */ ! 1586: si_wait(reg, cond, set) ! 1587: register u_short *reg; ! 1588: register u_short cond; ! 1589: register int set; ! 1590: { ! 1591: register int i; ! 1592: register u_short regval; ! 1593: ! 1594: for (i = 0; i < SI_WAIT_COUNT; i++) { ! 1595: regval = *reg; ! 1596: if ((set == 1) && (regval & cond)) { ! 1597: return (1); ! 1598: } ! 1599: if ((set == 0) && !(regval & cond)) { ! 1600: return (1); ! 1601: } ! 1602: DELAY(10); ! 1603: } ! 1604: return (0); ! 1605: } ! 1606: ! 1607: /* ! 1608: * Put data onto the scsi bus. ! 1609: */ ! 1610: si_putdata(c, phase, data, num) ! 1611: register struct scsi_ctlr *c; ! 1612: register u_short phase; ! 1613: register u_char *data; ! 1614: register int num; ! 1615: { ! 1616: register struct scsi_si_reg *sir = c->c_sir; ! 1617: register int i; ! 1618: ! 1619: /* set up tcr so a phase match will occur */ ! 1620: if (phase == PHASE_COMMAND) { ! 1621: sir->sbc_wreg.tcr = TCR_COMMAND; ! 1622: } else if (phase == PHASE_MSG_OUT) { ! 1623: sir->sbc_wreg.tcr = TCR_MSG_OUT; ! 1624: } else { ! 1625: if (scsi_debug) ! 1626: printf("si_putdata %d phase not supported\n", phase); ! 1627: return (0); ! 1628: } ! 1629: ! 1630: /* put all desired bytes onto scsi bus */ ! 1631: for (i = 0; i < num; i++ ) { ! 1632: ! 1633: /* wait for target to request a byte */ ! 1634: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 1) ! 1635: == 0) { ! 1636: if (scsi_debug) ! 1637: printf("si: putdata, REQ not active\n"); ! 1638: si_reset(c); ! 1639: return (0); ! 1640: } ! 1641: ! 1642: /* make sure phase match occurred */ ! 1643: if ((sir->sbc_rreg.bsr & SBC_BSR_PMTCH) == 0) { ! 1644: if (phase != PHASE_MSG_OUT) { ! 1645: if (scsi_debug) ! 1646: printf("si: putdata, phase mismatch\n"); ! 1647: si_reset(c); ! 1648: } else { ! 1649: sir->sbc_wreg.tcr = 0; ! 1650: } ! 1651: return (0); ! 1652: } ! 1653: ! 1654: /* load data */ ! 1655: sir->sbc_wreg.odr = *data++; ! 1656: sir->sbc_wreg.icr = SBC_ICR_DATA; ! 1657: ! 1658: /* complete req/ack handshake */ ! 1659: sir->sbc_wreg.icr |= SBC_ICR_ACK; ! 1660: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 0) ! 1661: == 0) { ! 1662: if (scsi_debug) ! 1663: printf("si: putdata, req not INactive\n"); ! 1664: si_reset(c); ! 1665: return (0); ! 1666: } ! 1667: sir->sbc_wreg.icr = 0; ! 1668: } ! 1669: sir->sbc_wreg.tcr = 0; ! 1670: return (1); ! 1671: } ! 1672: ! 1673: /* ! 1674: * Get data from the scsi bus. ! 1675: */ ! 1676: si_getdata(c, phase) ! 1677: register struct scsi_ctlr *c; ! 1678: register u_short phase; ! 1679: { ! 1680: register struct scsi_si_reg *sir = c->c_sir; ! 1681: register u_char data; ! 1682: ! 1683: /* check for valid phase */ ! 1684: if (phase == PHASE_STATUS) { ! 1685: sir->sbc_wreg.tcr = TCR_STATUS; ! 1686: } else if (phase == PHASE_MSG_IN) { ! 1687: sir->sbc_wreg.tcr = TCR_MSG_IN; ! 1688: } else { ! 1689: if (scsi_debug) ! 1690: printf("si: getdata %d phase not supported\n", phase); ! 1691: return (-1); ! 1692: } ! 1693: ! 1694: /* wait for target request */ ! 1695: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 1) == 0) { ! 1696: if (scsi_debug) { ! 1697: printf("si: getdata, REQ not active, cbsr %x\n", ! 1698: sir->sbc_rreg.cbsr); ! 1699: } ! 1700: sir->sbc_wreg.tcr = 0; ! 1701: return (-1); ! 1702: } ! 1703: ! 1704: /* check for correct phase on scsi bus */ ! 1705: if ((sir->sbc_rreg.bsr & SBC_BSR_PMTCH) == 0) { ! 1706: if (phase != PHASE_STATUS) { ! 1707: if (scsi_debug) { ! 1708: printf("si: getdata, bad phase\n"); ! 1709: } ! 1710: si_reset(c); ! 1711: } else { ! 1712: sir->sbc_wreg.tcr = 0; ! 1713: } ! 1714: return (-1); ! 1715: } ! 1716: ! 1717: /* grab data and complete req/ack handshake */ ! 1718: data = sir->sbc_rreg.cdr; ! 1719: sir->sbc_wreg.icr = SBC_ICR_ACK; ! 1720: if (si_sbc_wait((caddr_t)&sir->sbc_rreg.cbsr, SBC_CBSR_REQ, 0) == 0) { ! 1721: if (scsi_debug) ! 1722: printf("si: getdata, REQ not inactive\n"); ! 1723: si_reset(c); ! 1724: return (-1); ! 1725: } ! 1726: sir->sbc_wreg.icr = 0; ! 1727: sir->sbc_wreg.tcr = 0; ! 1728: return (data); ! 1729: } ! 1730: ! 1731: /* ! 1732: * Reset SCSI control logic and bus. ! 1733: */ ! 1734: si_reset(c) ! 1735: register struct scsi_ctlr *c; ! 1736: { ! 1737: register struct scsi_si_reg *sir = c->c_sir; ! 1738: register u_char junk; ! 1739: ! 1740: if (scsi_debug) { ! 1741: printf("scsi reset, sr= %x, bcr= %x\n", sir->csr, sir->bcr); ! 1742: } ! 1743: ! 1744: /* reset scsi control logic */ ! 1745: sir->bcr = 0; ! 1746: sir->csr = 0; ! 1747: DELAY(10); ! 1748: sir->csr = SI_CSR_SCSI_RES|SI_CSR_FIFO_RES; ! 1749: if ((c->c_flags & SCSI_ONBOARD) == 0) { ! 1750: sir->dma_addr = 0; ! 1751: sir->dma_count = 0; ! 1752: } ! 1753: ! 1754: /* issue scsi bus reset (make sure interrupts from sbc are disabled) */ ! 1755: sir->sbc_wreg.icr = SBC_ICR_RST; ! 1756: DELAY(10); ! 1757: sir->sbc_wreg.icr = 0; ! 1758: junk = sir->sbc_rreg.clr; ! 1759: ! 1760: /* enable sbc interrupts */ ! 1761: sir->csr |= SI_CSR_INTR_EN; ! 1762: sir->sbc_wreg.mr = SBC_MR_EEI; ! 1763: ! 1764: /* reconnection attempts are no longer enabled */ ! 1765: c->c_flags &= ~SCSI_EN_RECON; ! 1766: ! 1767: /* disconnect queue needs to be flushed */ ! 1768: if (c->c_disqh != NULL) { ! 1769: c->c_flags |= SCSI_FLUSH_DISQ; ! 1770: c->c_flush = c->c_disqt; ! 1771: } ! 1772: } ! 1773: ! 1774: /* ! 1775: * Return residual count for a dma. ! 1776: */ ! 1777: si_dmacnt(c) ! 1778: register struct scsi_ctlr *c; ! 1779: { ! 1780: if (c->c_flags & SCSI_ONBOARD) { ! 1781: return (c->c_sir->bcr); ! 1782: } else { ! 1783: return ( ((c->c_sir->bcrh) << 16) | (c->c_sir->bcr) ); ! 1784: } ! 1785: } ! 1786: ! 1787: #endif NSI > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.