📄 uda.c
字号:
* This routine is broken into two so that the internal version * udastrat1() can be called by the (nonexistent, as yet) bad block * revectoring routine. */udastrategy(bp) register struct buf *bp;{ register int unit; register struct uba_device *ui; register struct ra_info *ra; struct partition *pp; int p; daddr_t sz, maxsz; /* * Make sure this is a reasonable drive to use. */ if ((unit = udaunit(bp->b_dev)) >= NRA || (ui = udadinfo[unit]) == NULL || ui->ui_alive == 0 || (ra = &ra_info[unit])->ra_state == CLOSED) { bp->b_error = ENXIO; goto bad; } /* * If drive is open `raw' or reading label, let it at it. */ if (ra->ra_state < OPEN) { udastrat1(bp); return; } p = udapart(bp->b_dev); if ((ra->ra_openpart & (1 << p)) == 0) { bp->b_error = ENODEV; goto bad; } /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. */ pp = &udalabel[unit].d_partitions[p]; maxsz = pp->p_size; if (pp->p_offset + pp->p_size > ra->ra_dsize) maxsz = ra->ra_dsize - pp->p_offset; sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; if (bp->b_blkno + pp->p_offset <= LABELSECTOR &&#if LABELSECTOR != 0 bp->b_blkno + pp->p_offset + sz > LABELSECTOR &&#endif (bp->b_flags & B_READ) == 0 && ra->ra_wlabel == 0) { bp->b_error = EROFS; goto bad; } if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->b_blkno == maxsz) { bp->b_resid = bp->b_bcount; biodone(bp); return; } /* or truncate if part of it fits */ sz = maxsz - bp->b_blkno; if (sz <= 0) { bp->b_error = EINVAL; /* or hang it up */ goto bad; } bp->b_bcount = sz << DEV_BSHIFT; } udastrat1(bp); return;bad: bp->b_flags |= B_ERROR; biodone(bp);}/* * Work routine for udastrategy. */udastrat1(bp) register struct buf *bp;{ register int unit = udaunit(bp->b_dev); register struct uba_ctlr *um; register struct buf *dp; struct uba_device *ui; int s = spl5(); /* * Append the buffer to the drive queue, and if it is not * already there, the drive to the controller queue. (However, * if the drive queue is marked to be requeued, we must be * awaiting an on line or get unit status command; in this * case, leave it off the controller queue.) */ um = (ui = udadinfo[unit])->ui_mi; dp = &udautab[unit]; APPEND(bp, dp, av_forw); if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) { APPEND(dp, &um->um_tab, b_forw); dp->b_active++; } /* * Start activity on the controller. Note that unlike other * Unibus drivers, we must always do this, not just when the * controller is not active. */ udastart(um); splx(s);}/* * Start up whatever transfers we can find. * Note that udastart() must be called at spl5(). */udastart(um) register struct uba_ctlr *um;{ register struct uda_softc *sc = &uda_softc[um->um_ctlr]; register struct buf *bp, *dp; register struct mscp *mp; struct uba_device *ui; struct udadevice *udaddr; struct partition *pp; int i, sz;#ifdef lint i = 0; i = i;#endif /* * If it is not running, try (again and again...) to initialise * it. If it is currently initialising just ignore it for now. */ if (sc->sc_state != ST_RUN) { if (sc->sc_state == ST_IDLE && udainit(um->um_ctlr)) printf("uda%d: still hung\n", um->um_ctlr); return; } /* * If um_cmd is nonzero, this controller is on the Unibus * resource wait queue. It will not help to try more requests; * instead, when the Unibus unblocks and calls udadgo(), we * will call udastart() again. */ if (um->um_cmd) return; sc->sc_flags |= SC_INSTART; udaddr = (struct udadevice *) um->um_addr;loop: /* * Service the drive at the head of the queue. It may not * need anything, in which case it might be shutting down * in udaclose(). */ if ((dp = um->um_tab.b_actf) == NULL) goto out; if ((bp = dp->b_actf) == NULL) { dp->b_active = 0; um->um_tab.b_actf = dp->b_forw; if (ra_info[dp - udautab].ra_openpart == 0) wakeup((caddr_t)dp); /* finish close protocol */ goto loop; } if (udaddr->udasa & UDA_ERR) { /* ctlr fatal error */ udasaerror(um, 1); goto out; } /* * Get an MSCP packet, then figure out what to do. If * we cannot get a command packet, the command ring may * be too small: We should have at least as many command * packets as credits, for best performance. */ if ((mp = mscp_getcp(&sc->sc_mi, MSCP_DONTWAIT)) == NULL) { if (sc->sc_mi.mi_credits > MSCP_MINCREDITS && (sc->sc_flags & SC_GRIPED) == 0) { log(LOG_NOTICE, "uda%d: command ring too small\n", um->um_ctlr); sc->sc_flags |= SC_GRIPED;/* complain only once */ } goto out; } /* * Bring the drive on line if it is not already. Get its status * if we do not already have it. Otherwise just start the transfer. */ ui = udadinfo[udaunit(bp->b_dev)]; if ((ui->ui_flags & UNIT_ONLINE) == 0) { mp->mscp_opcode = M_OP_ONLINE; goto common; } if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) { mp->mscp_opcode = M_OP_GETUNITST;common:if (ui->ui_flags & UNIT_REQUEUE) panic("udastart"); /* * Take the drive off the controller queue. When the * command finishes, make sure the drive is requeued. */ um->um_tab.b_actf = dp->b_forw; dp->b_active = 0; ui->ui_flags |= UNIT_REQUEUE; mp->mscp_unit = ui->ui_slave; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; sc->sc_flags |= SC_STARTPOLL;#ifdef POLLSTATS sc->sc_ncmd++;#endif goto loop; } pp = &udalabel[ui->ui_unit].d_partitions[udapart(bp->b_dev)]; mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE; mp->mscp_unit = ui->ui_slave; mp->mscp_seq.seq_lbn = bp->b_blkno + pp->p_offset; sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; mp->mscp_seq.seq_bytecount = bp->b_blkno + sz > pp->p_size ? (pp->p_size - bp->b_blkno) >> DEV_BSHIFT : bp->b_bcount; /* mscp_cmdref is filled in by mscp_go() */ /* * Drop the packet pointer into the `command' field so udadgo() * can tell what to start. If ubago returns 1, we can do another * transfer. If not, um_cmd will still point at mp, so we will * know that we are waiting for resources. */ um->um_cmd = (int)mp; if (ubago(ui)) goto loop; /* * All done, or blocked in ubago(). If we managed to * issue some commands, start up the beast. */out: if (sc->sc_flags & SC_STARTPOLL) {#ifdef POLLSTATS udastats.cmd[sc->sc_ncmd]++; sc->sc_ncmd = 0;#endif i = ((struct udadevice *)um->um_addr)->udaip; } sc->sc_flags &= ~(SC_INSTART | SC_STARTPOLL);}/* * Start a transfer. * * If we are not called from within udastart(), we must have been * blocked, so call udastart to do more requests (if any). If * this calls us again immediately we will not recurse, because * that time we will be in udastart(). Clever.... */udadgo(um) register struct uba_ctlr *um;{ struct uda_softc *sc = &uda_softc[um->um_ctlr]; struct mscp *mp = (struct mscp *)um->um_cmd; um->um_tab.b_active++; /* another transfer going */ /* * Fill in the MSCP packet and move the buffer to the * I/O wait queue. Mark the controller as no longer on * the resource queue, and remember to initiate polling. */ mp->mscp_seq.seq_buffer = UBAI_ADDR(um->um_ubinfo) | (UBAI_BDP(um->um_ubinfo) << 24); mscp_go(&sc->sc_mi, mp, um->um_ubinfo); um->um_cmd = 0; um->um_ubinfo = 0; /* tyke it awye */ sc->sc_flags |= SC_STARTPOLL;#ifdef POLLSTATS sc->sc_ncmd++;#endif if ((sc->sc_flags & SC_INSTART) == 0) udastart(um);}udaiodone(mi, bp, info) register struct mscp_info *mi; struct buf *bp; int info;{ register struct uba_ctlr *um = udaminfo[mi->mi_ctlr]; um->um_ubinfo = info; ubadone(um); biodone(bp); if (um->um_bdp && mi->mi_wtab.av_forw == &mi->mi_wtab) ubarelse(um->um_ubanum, &um->um_bdp); um->um_tab.b_active--; /* another transfer done */}static struct saerr { int code; /* error code (including UDA_ERR) */ char *desc; /* what it means: Efoo => foo error */} saerr[] = { { 0100001, "Eunibus packet read" }, { 0100002, "Eunibus packet write" }, { 0100003, "EUDA ROM and RAM parity" }, { 0100004, "EUDA RAM parity" }, { 0100005, "EUDA ROM parity" }, { 0100006, "Eunibus ring read" }, { 0100007, "Eunibus ring write" }, { 0100010, " unibus interrupt master failure" }, { 0100011, "Ehost access timeout" }, { 0100012, " host exceeded command limit" }, { 0100013, " unibus bus master failure" }, { 0100014, " DM XFC fatal error" }, { 0100015, " hardware timeout of instruction loop" }, { 0100016, " invalid virtual circuit id" }, { 0100017, "Eunibus interrupt write" }, { 0104000, "Efatal sequence" }, { 0104040, " D proc ALU" }, { 0104041, "ED proc control ROM parity" }, { 0105102, "ED proc w/no BD#2 or RAM parity" }, { 0105105, "ED proc RAM buffer" }, { 0105152, "ED proc SDI" }, { 0105153, "ED proc write mode wrap serdes" }, { 0105154, "ED proc read mode serdes, RSGEN & ECC" }, { 0106040, "EU proc ALU" }, { 0106041, "EU proc control reg" }, { 0106042, " U proc DFAIL/cntl ROM parity/BD #1 test CNT" }, { 0106047, " U proc const PROM err w/D proc running SDI test" }, { 0106055, " unexpected trap" }, { 0106071, "EU proc const PROM" }, { 0106072, "EU proc control ROM parity" }, { 0106200, "Estep 1 data" }, { 0107103, "EU proc RAM parity" }, { 0107107, "EU proc RAM buffer" }, { 0107115, " test count wrong (BD 12)" }, { 0112300, "Estep 2" }, { 0122240, "ENPR" }, { 0122300, "Estep 3" }, { 0142300, "Estep 4" }, { 0, " unknown error code" }};/* * If the error bit was set in the controller status register, gripe, * then (optionally) reset the controller and requeue pending transfers. */udasaerror(um, doreset) register struct uba_ctlr *um; int doreset;{ register int code = ((struct udadevice *)um->um_addr)->udasa; register struct saerr *e; if ((code & UDA_ERR) == 0) return; for (e = saerr; e->code; e++) if (e->code == code) break; printf("uda%d: controller error, sa=0%o (%s%s)\n", um->um_ctlr, code, e->desc + 1, *e->desc == 'E' ? " error" : ""); if (doreset) { mscp_requeue(&uda_softc[um->um_ctlr].sc_mi); (void) udainit(um->um_ctlr); }}/* * Interrupt routine. Depending on the state of the controller, * continue initialisation, or acknowledge command and response * interrupts, and process responses. */udaintr(ctlr) int ctlr;{ register struct uba_ctlr *um = udaminfo[ctlr]; register struct uda_softc *sc = &uda_softc[ctlr]; register struct udadevice *udaddr = (struct udadevice *)um->um_addr; register struct uda *ud; register struct mscp *mp; register int i;#ifdef QBA splx(sc->sc_ipl); /* Qbus interrupt protocol is odd */#endif sc->sc_wticks = 0; /* reset interrupt watchdog */ /* * Combinations during steps 1, 2, and 3: STEPnMASK * corresponds to which bits should be tested; * STEPnGOOD corresponds to the pattern that should * appear after the interrupt from STEPn initialisation. * All steps test the bits in ALLSTEPS. */#define ALLSTEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)#define STEP1MASK (ALLSTEPS | UDA_IE | UDA_NCNRMASK)#define STEP1GOOD (UDA_STEP2 | UDA_IE | (NCMDL2 << 3) | NRSPL2)#define STEP2MASK (ALLSTEPS | UDA_IE | UDA_IVECMASK)#define STEP2GOOD (UDA_STEP3 | UDA_IE | (sc->sc_ivec >> 2))#define STEP3MASK ALLSTEPS#define STEP3GOOD UDA_STEP4 switch (sc->sc_state) { case ST_IDLE: /* * Ignore unsolicited interrupts. */ log(LOG_WARNING, "uda%d: stray intr\n", ctlr); return; case ST_STEP1: /* * Begin step two initialisation. */ if ((udaddr->udasa & STEP1MASK) != STEP1GOOD) { i = 1;initfailed: printf("uda%d: init step %d failed, sa=%b\n", ctlr, i, udaddr->udasa, udasr_bits); udasaerror(um, 0); sc->sc_state = ST_IDLE; if (sc->sc_flags & SC_DOWAKE) { sc->sc_flags &= ~SC_DOWAKE; wakeup((caddr_t)sc); } return; } udaddr->udasa = (int)&sc->sc_uda->uda_ca.ca_rspdsc[0] | (cpu == VAX_780 || cpu == VAX_8600 ? UDA_PI : 0); sc->sc_state = ST_STEP2; return; case ST_STEP2: /* * Begin step 3 initialisation. */ if ((udaddr->udasa & STEP2MASK) != STEP2GOOD) { i = 2; goto initfailed; } udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_rspdsc[0]) >> 16; sc->sc_state = ST_STEP3; return; case ST_STEP3: /* * Set controller characteristics (finish initialisation). */ if ((udaddr->udasa & STEP3MASK) != STEP3GOOD) { i = 3; goto initfailed; } i = udaddr->udasa & 0xff; if (i != sc->sc_micro) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -