📄 uda.c
字号:
sc->sc_micro = i; printf("uda%d: version %d model %d\n", ctlr, i & 0xf, i >> 4); } /* * Present the burst size, then remove it. Why this * should be done this way, I have no idea. * * Note that this assumes udaburst[ctlr] > 0. */ udaddr->udasa = UDA_GO | (udaburst[ctlr] - 1) << 2; udaddr->udasa = UDA_GO; printf("uda%d: DMA burst size set to %d\n", ctlr, udaburst[ctlr]); udainitds(ctlr); /* initialise data structures */ /* * Before we can get a command packet, we need some * credits. Fake some up to keep mscp_getcp() happy, * get a packet, and cancel all credits (the right * number should come back in the response to the * SCC packet). */ sc->sc_mi.mi_credits = MSCP_MINCREDITS + 1; mp = mscp_getcp(&sc->sc_mi, MSCP_DONTWAIT); if (mp == NULL) /* `cannot happen' */ panic("udaintr"); sc->sc_mi.mi_credits = 0; mp->mscp_opcode = M_OP_SETCTLRC; mp->mscp_unit = 0; mp->mscp_sccc.sccc_ctlrflags = M_CF_ATTN | M_CF_MISC | M_CF_THIS; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; i = udaddr->udaip; sc->sc_state = ST_SETCHAR; return; case ST_SETCHAR: case ST_RUN: /* * Handle Set Ctlr Characteristics responses and operational * responses (via mscp_dorsp). */ break; default: printf("uda%d: driver bug, state %d\n", ctlr, sc->sc_state); panic("udastate"); } if (udaddr->udasa & UDA_ERR) { /* ctlr fatal error */ udasaerror(um, 1); return; } ud = &uda[ctlr]; /* * Handle buffer purge requests. */ if (ud->uda_ca.ca_bdp) { UBAPURGE(um->um_hd->uh_uba, ud->uda_ca.ca_bdp); ud->uda_ca.ca_bdp = 0; udaddr->udasa = 0; /* signal purge complete */ } /* * Check for response and command ring transitions. */ if (ud->uda_ca.ca_rspint) { ud->uda_ca.ca_rspint = 0; mscp_dorsp(&sc->sc_mi); } if (ud->uda_ca.ca_cmdint) { ud->uda_ca.ca_cmdint = 0; MSCP_DOCMD(&sc->sc_mi); } udastart(um);}/* * Initialise the various data structures that control the UDA50. */udainitds(ctlr) int ctlr;{ register struct uda *ud = &uda[ctlr]; register struct uda *uud = uda_softc[ctlr].sc_uda; register struct mscp *mp; register int i; for (i = 0, mp = ud->uda_rsp; i < NRSP; i++, mp++) { ud->uda_ca.ca_rspdsc[i] = MSCP_OWN | MSCP_INT | (long)&uud->uda_rsp[i].mscp_cmdref; mp->mscp_addr = &ud->uda_ca.ca_rspdsc[i]; mp->mscp_msglen = MSCP_MSGLEN; } for (i = 0, mp = ud->uda_cmd; i < NCMD; i++, mp++) { ud->uda_ca.ca_cmddsc[i] = MSCP_INT | (long)&uud->uda_cmd[i].mscp_cmdref; mp->mscp_addr = &ud->uda_ca.ca_cmddsc[i]; mp->mscp_msglen = MSCP_MSGLEN; }}/* * Handle an error datagram. */udadgram(mi, mp) struct mscp_info *mi; struct mscp *mp;{ mscp_decodeerror(mi->mi_md->md_mname, mi->mi_ctlr, mp); /* * SDI status information bytes 10 and 11 are the microprocessor * error code and front panel code respectively. These vary per * drive type and are printed purely for field service information. */ if (mp->mscp_format == M_FM_SDI) printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n", mp->mscp_erd.erd_sdistat[10], mp->mscp_erd.erd_sdistat[11]);}/* * The Set Controller Characteristics command finished. * Record the new state of the controller. */udactlrdone(mi, mp) register struct mscp_info *mi; struct mscp *mp;{ register struct uda_softc *sc = &uda_softc[mi->mi_ctlr]; if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) sc->sc_state = ST_RUN; else { printf("uda%d: SETCTLRC failed: ", mi->mi_ctlr, mp->mscp_status); mscp_printevent(mp); sc->sc_state = ST_IDLE; } if (sc->sc_flags & SC_DOWAKE) { sc->sc_flags &= ~SC_DOWAKE; wakeup((caddr_t)sc); }}/* * Received a response from an as-yet unconfigured drive. Configure it * in, if possible. */udaunconf(mi, mp) struct mscp_info *mi; register struct mscp *mp;{ /* * If it is a slave response, copy it to udaslavereply for * udaslave() to look at. */ if (mp->mscp_opcode == (M_OP_GETUNITST | M_OP_END) && (uda_softc[mi->mi_ctlr].sc_flags & SC_INSLAVE) != 0) { udaslavereply = *mp; return (MSCP_DONE); } /* * Otherwise, it had better be an available attention response. */ if (mp->mscp_opcode != M_OP_AVAILATTN) return (MSCP_FAILED); /* do what autoconf does */ return (MSCP_FAILED); /* not yet, arwhite, not yet */}/* * A drive came on line. Check its type and size. Return DONE if * we think the drive is truly on line. In any case, awaken anyone * sleeping on the drive on-line-ness. */udaonline(ui, mp) register struct uba_device *ui; struct mscp *mp;{ register struct ra_info *ra = &ra_info[ui->ui_unit]; wakeup((caddr_t)&ui->ui_flags); if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { if (!cold) printf("uda%d: ra%d", ui->ui_ctlr, ui->ui_unit); printf(": attempt to bring on line failed: "); mscp_printevent(mp); ra->ra_state = CLOSED; return (MSCP_FAILED); } ra->ra_state = OPENRAW; ra->ra_dsize = (daddr_t)mp->mscp_onle.onle_unitsize; if (!cold) printf("ra%d: uda%d, unit %d, size = %d sectors\n", ui->ui_unit, ui->ui_ctlr, mp->mscp_unit, ra->ra_dsize); /* can now compute ncyl */ ra->ra_geom.rg_ncyl = ra->ra_dsize / ra->ra_geom.rg_ntracks / ra->ra_geom.rg_nsectors; return (MSCP_DONE);}/* * We got some (configured) unit's status. Return DONE if it succeeded. */udagotstatus(ui, mp) register struct uba_device *ui; register struct mscp *mp;{ if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("uda%d: attempt to get status for ra%d failed: ", ui->ui_ctlr, ui->ui_unit); mscp_printevent(mp); return (MSCP_FAILED); } /* record for (future) bad block forwarding and whatever else */ uda_rasave(ui->ui_unit, mp, 1); return (MSCP_DONE);}/* * A transfer failed. We get a chance to fix or restart it. * Need to write the bad block forwaring code first.... *//*ARGSUSED*/udaioerror(ui, mp, bp) register struct uba_device *ui; register struct mscp *mp; struct buf *bp;{ if (mp->mscp_flags & M_EF_BBLKR) { /* * A bad block report. Eventually we will * restart this transfer, but for now, just * log it and give up. */ log(LOG_ERR, "ra%d: bad block report: %d%s\n", ui->ui_unit, mp->mscp_seq.seq_lbn, mp->mscp_flags & M_EF_BBLKU ? " + others" : ""); } else { /* * What the heck IS a `serious exception' anyway? * IT SURE WOULD BE NICE IF DEC SOLD DOCUMENTATION * FOR THEIR OWN CONTROLLERS. */ if (mp->mscp_flags & M_EF_SEREX) log(LOG_ERR, "ra%d: serious exception reported\n", ui->ui_unit); } return (MSCP_FAILED);}/* * A replace operation finished. *//*ARGSUSED*/udareplace(ui, mp) struct uba_device *ui; struct mscp *mp;{ panic("udareplace");}/* * A bad block related operation finished. *//*ARGSUSED*/udabb(ui, mp, bp) struct uba_device *ui; struct mscp *mp; struct buf *bp;{ panic("udabb");}/* * I/O controls. */udaioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ register int unit = udaunit(dev); register struct disklabel *lp; register struct ra_info *ra = &ra_info[unit]; int error = 0; lp = &udalabel[unit]; switch (cmd) { case DIOCGDINFO: *(struct disklabel *)data = *lp; break; case DIOCGPART: ((struct partinfo *)data)->disklab = lp; ((struct partinfo *)data)->part = &lp->d_partitions[udapart(dev)]; break; case DIOCSDINFO: if ((flag & FWRITE) == 0) error = EBADF; else error = setdisklabel(lp, (struct disklabel *)data, (ra->ra_state == OPENRAW) ? 0 : ra->ra_openpart); break; case DIOCWLABEL: if ((flag & FWRITE) == 0) error = EBADF; else ra->ra_wlabel = *(int *)data; break; case DIOCWDINFO: if ((flag & FWRITE) == 0) error = EBADF; else if ((error = setdisklabel(lp, (struct disklabel *)data, (ra->ra_state == OPENRAW) ? 0 : ra->ra_openpart)) == 0) { int wlab; ra->ra_state = OPEN; /* simulate opening partition 0 so write succeeds */ ra->ra_openpart |= (1 << 0); /* XXX */ wlab = ra->ra_wlabel; ra->ra_wlabel = 1; error = writedisklabel(dev, udastrategy, lp); ra->ra_openpart = ra->ra_copenpart | ra->ra_bopenpart; ra->ra_wlabel = wlab; } break;#ifdef notyet case UDAIOCREPLACE: /* * Initiate bad block replacement for the given LBN. * (Should we allow modifiers?) */ error = EOPNOTSUPP; break; case UDAIOCGMICRO: /* * Return the microcode revision for the UDA50 running * this drive. */ *(int *)data = uda_softc[uddinfo[unit]->ui_ctlr].sc_micro; break;#endif default: error = ENOTTY; break; } return (error);}/* * A Unibus reset has occurred on UBA uban. Reinitialise the controller(s) * on that Unibus, and requeue outstanding I/O. */udareset(uban) int uban;{ register struct uba_ctlr *um; register struct uda_softc *sc; register int ctlr; for (ctlr = 0, sc = uda_softc; ctlr < NUDA; ctlr++, sc++) { if ((um = udaminfo[ctlr]) == NULL || um->um_ubanum != uban || um->um_alive == 0) continue; printf(" uda%d", ctlr); /* * Our BDP (if any) is gone; our command (if any) is * flushed; the device is no longer mapped; and the * UDA50 is not yet initialised. */ if (um->um_bdp) { printf("<%d>", UBAI_BDP(um->um_bdp)); um->um_bdp = 0; } um->um_ubinfo = 0; um->um_cmd = 0; sc->sc_flags &= ~SC_MAPPED; sc->sc_state = ST_IDLE; /* reset queues and requeue pending transfers */ mscp_requeue(&sc->sc_mi); /* * If it fails to initialise we will notice later and * try again (and again...). Do not call udastart() * here; it will be done after the controller finishes * initialisation. */ if (udainit(ctlr)) printf(" (hung)"); }}/* * Watchdog timer: If the controller is active, and no interrupts * have occurred for 30 seconds, assume it has gone away. */udawatch(){ register int i; register struct uba_ctlr *um; register struct uda_softc *sc; timeout(udawatch, (caddr_t) 0, hz); /* every second */ for (i = 0, sc = uda_softc; i < NUDA; i++, sc++) { if ((um = udaminfo[i]) == 0 || !um->um_alive) continue; if (sc->sc_state == ST_IDLE) continue; if (sc->sc_state == ST_RUN && !um->um_tab.b_active) sc->sc_wticks = 0; else if (++sc->sc_wticks >= 30) { sc->sc_wticks = 0; printf("uda%d: lost interrupt\n", i); ubareset(um->um_ubanum); } }}/* * Do a panic dump. We set up the controller for one command packet * and one response packet, for which we use `struct uda1'. */struct uda1 { struct uda1ca uda1_ca; /* communications area */ struct mscp uda1_rsp; /* response packet */ struct mscp uda1_cmd; /* command packet */} uda1;#define DBSIZE 32 /* dump 16K at a time */udadump(dev) dev_t dev;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -