📄 uda.c
字号:
* it is nonexistent, or because it is spun down, or * for some other reason. */ switch (mp->mscp_status & ~M_ST_MASK) { case M_OFFLINE_UNKNOWN: /* * No such drive, and there are none with * higher unit numbers either, if we are * using M_GUM_NEXTUNIT. */ return (0); case M_OFFLINE_UNMOUNTED: /* * The drive is not spun up. Use it anyway. * * N.B.: this seems to be a common occurrance * after a power failure. The first attempt * to bring it on line seems to spin it up * (and thus takes several minutes). Perhaps * we should note here that the on-line may * take longer than usual. */ break; default: /* * In service, or something else equally unusable. */ printf("uda%d: unit %d off line: ", um->um_ctlr, mp->mscp_unit); mscp_printevent(mp); goto try_another; } break; default: printf("uda%d: unable to get unit status: ", um->um_ctlr); mscp_printevent(mp); return (0); } /* * Does this ever happen? What (if anything) does it mean? */ if (mp->mscp_unit < next) { printf("uda%d: unit %d, next %d\n", um->um_ctlr, mp->mscp_unit, next); return (0); } if (mp->mscp_unit >= MAXUNIT) { printf("uda%d: cannot handle unit number %d (max is %d)\n", um->um_ctlr, mp->mscp_unit, MAXUNIT - 1); return (0); } /* * See if we already handle this drive. * (Only likely if ui->ui_slave=='?'.) */ if (udaip[um->um_ctlr][mp->mscp_unit] != NULL) {try_another: if (ui->ui_slave != '?') return (0); next = mp->mscp_unit + 1; goto findunit; } /* * Voila! */ uda_rasave(ui->ui_unit, mp, 0); ui->ui_flags = 0; /* not on line, nor anything else */ ui->ui_slave = mp->mscp_unit; return (1);}/* * Attach a found slave. Make sure the watchdog timer is running. * If this disk is being profiled, fill in the `wpms' value (used by * what?). Set up the inverting pointer, and attempt to bring the * drive on line and read its label. */udaattach(ui) register struct uba_device *ui;{ register int unit = ui->ui_unit; if (udawstart == 0) { timeout(udawatch, (caddr_t) 0, hz); udawstart++; } /* * Floppies cannot be brought on line unless there is * a disk in the drive. Since an ONLINE while cold * takes ten seconds to fail, and (when notyet becomes now) * no sensible person will swap to one, we just * defer the ONLINE until someone tries to use the drive. * * THIS ASSUMES THAT DRIVE TYPES ?X? ARE FLOPPIES */ if (MSCP_MID_ECH(1, ra_info[unit].ra_mediaid) == 'X' - '@') { printf(": floppy"); return; } if (ui->ui_dk >= 0) dk_wpms[ui->ui_dk] = (60 * 31 * 256); /* approx */ udaip[ui->ui_ctlr][ui->ui_slave] = ui; if (uda_rainit(ui, 0)) printf(": offline"); else if (ra_info[unit].ra_state == OPEN) { printf(": %s, size = %d sectors", udalabel[unit].d_typename, ra_info[unit].ra_dsize);#ifdef notyet addswap(makedev(UDADEVNUM, udaminor(unit, 0)), &udalabel[unit]);#endif }}/* * Initialise a UDA50. Return true iff something goes wrong. */udainit(ctlr) int ctlr;{ register struct uda_softc *sc; register struct udadevice *udaddr; struct uba_ctlr *um; int timo, ubinfo; sc = &uda_softc[ctlr]; um = udaminfo[ctlr]; if ((sc->sc_flags & SC_MAPPED) == 0) { /* * Map the communication area and command and * response packets into Unibus space. */ ubinfo = uballoc(um->um_ubanum, (caddr_t) &uda[ctlr], sizeof (struct uda), UBA_CANTWAIT); if (ubinfo == 0) { printf("uda%d: uballoc map failed\n", ctlr); return (-1); } sc->sc_uda = (struct uda *) UBAI_ADDR(ubinfo); sc->sc_flags |= SC_MAPPED; } /* * While we are thinking about it, reset the next command * and response indicies. */ sc->sc_mi.mi_cmd.mri_next = 0; sc->sc_mi.mi_rsp.mri_next = 0; /* * Start up the hardware initialisation sequence. */#define STEP0MASK (UDA_ERR | UDA_STEP4 | UDA_STEP3 | UDA_STEP2 | \ UDA_STEP1 | UDA_NV) sc->sc_state = ST_IDLE; /* in case init fails */ udaddr = (struct udadevice *)um->um_addr; udaddr->udaip = 0; timo = todr() + 1000; while ((udaddr->udasa & STEP0MASK) == 0) { if (todr() > timo) { printf("uda%d: timeout during init\n", ctlr); return (-1); } } if ((udaddr->udasa & STEP0MASK) != UDA_STEP1) { printf("uda%d: init failed, sa=%b\n", ctlr, udaddr->udasa, udasr_bits); udasaerror(um, 0); return (-1); } /* * Success! Record new state, and start step 1 initialisation. * The rest is done in the interrupt handler. */ sc->sc_state = ST_STEP1; udaddr->udasa = UDA_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | UDA_IE | (sc->sc_ivec >> 2); return (0);}/* * Open a drive. *//*ARGSUSED*/udaopen(dev, flag, fmt) dev_t dev; int flag, fmt;{ register int unit; register struct uba_device *ui; register struct uda_softc *sc; register struct disklabel *lp; register struct partition *pp; register struct ra_info *ra; int s, i, part, mask, error = 0; daddr_t start, end; /* * Make sure this is a reasonable open request. */ unit = udaunit(dev); if (unit >= NRA || (ui = udadinfo[unit]) == 0 || ui->ui_alive == 0) return (ENXIO); /* * Make sure the controller is running, by (re)initialising it if * necessary. */ sc = &uda_softc[ui->ui_ctlr]; s = spl5(); if (sc->sc_state != ST_RUN) { if (sc->sc_state == ST_IDLE && udainit(ui->ui_ctlr)) { splx(s); return (EIO); } /* * In case it does not come up, make sure we will be * restarted in 10 seconds. This corresponds to the * 10 second timeouts in udaprobe() and udaslave(). */ sc->sc_flags |= SC_DOWAKE; timeout(wakeup, (caddr_t) sc, 10 * hz); sleep((caddr_t) sc, PRIBIO); if (sc->sc_state != ST_RUN) { splx(s); printf("uda%d: controller hung\n", ui->ui_ctlr); return (EIO); } untimeout(wakeup, (caddr_t) sc); } /* * Wait for the state to settle */ ra = &ra_info[unit]; while (ra->ra_state != OPEN && ra->ra_state != OPENRAW && ra->ra_state != CLOSED) if (error = tsleep((caddr_t)ra, (PZERO + 1) | PCATCH, devopn, 0)) { splx(s); return (error); } /* * If not on line, or we are not sure of the label, reinitialise * the drive. */ if ((ui->ui_flags & UNIT_ONLINE) == 0 || (ra->ra_state != OPEN && ra->ra_state != OPENRAW)) error = uda_rainit(ui, flag); splx(s); if (error) return (error); part = udapart(dev); lp = &udalabel[unit]; if (part >= lp->d_npartitions) return (ENXIO); /* * Warn if a partition is opened that overlaps another * already open, unless either is the `raw' partition * (whole disk). */#define RAWPART 2 /* 'c' partition */ /* XXX */ mask = 1 << part; if ((ra->ra_openpart & mask) == 0 && part != RAWPART) { pp = &lp->d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; for (pp = lp->d_partitions, i = 0; i < lp->d_npartitions; pp++, i++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end || i == RAWPART) continue; if (ra->ra_openpart & (1 << i)) log(LOG_WARNING, "ra%d%c: overlaps open partition (%c)\n", unit, part + 'a', i + 'a'); } } switch (fmt) { case S_IFCHR: ra->ra_copenpart |= mask; break; case S_IFBLK: ra->ra_bopenpart |= mask; break; } ra->ra_openpart |= mask; return (0);}/* ARGSUSED */udaclose(dev, flags, fmt) dev_t dev; int flags, fmt;{ register int unit = udaunit(dev); register struct ra_info *ra = &ra_info[unit]; int s, mask = (1 << udapart(dev)); switch (fmt) { case S_IFCHR: ra->ra_copenpart &= ~mask; break; case S_IFBLK: ra->ra_bopenpart &= ~mask; break; } ra->ra_openpart = ra->ra_copenpart | ra->ra_bopenpart; /* * Should wait for I/O to complete on this partition even if * others are open, but wait for work on blkflush(). */ if (ra->ra_openpart == 0) { s = spl5(); while (udautab[unit].b_actf) sleep((caddr_t)&udautab[unit], PZERO - 1); splx(s); ra->ra_state = CLOSED; ra->ra_wlabel = 0; } return (0);}/* * Initialise a drive. If it is not already, bring it on line, * and set a timeout on it in case it fails to respond. * When on line, read in the pack label. */uda_rainit(ui, flags) register struct uba_device *ui; int flags;{ register struct uda_softc *sc = &uda_softc[ui->ui_ctlr]; register struct disklabel *lp; register struct mscp *mp; register int unit = ui->ui_unit; register struct ra_info *ra; char *msg, *readdisklabel(); int s, i, udastrategy(); extern int cold; ra = &ra_info[unit]; if ((ui->ui_flags & UNIT_ONLINE) == 0) { mp = mscp_getcp(&sc->sc_mi, MSCP_WAIT); mp->mscp_opcode = M_OP_ONLINE; mp->mscp_unit = ui->ui_slave; mp->mscp_cmdref = (long)&ui->ui_flags; *mp->mscp_addr |= MSCP_OWN | MSCP_INT; ra->ra_state = WANTOPEN; if (!cold) s = spl5(); i = ((struct udadevice *)ui->ui_addr)->udaip; if (cold) { i = todr() + 1000; while ((ui->ui_flags & UNIT_ONLINE) == 0) if (todr() > i) break; } else { timeout(wakeup, (caddr_t)&ui->ui_flags, 10 * hz); sleep((caddr_t)&ui->ui_flags, PSWP + 1); splx(s); untimeout(wakeup, (caddr_t)&ui->ui_flags); } if (ra->ra_state != OPENRAW) { ra->ra_state = CLOSED; wakeup((caddr_t)ra); return (EIO); } } lp = &udalabel[unit]; lp->d_secsize = DEV_BSIZE; lp->d_secperunit = ra->ra_dsize; if (flags & O_NDELAY) return (0); ra->ra_state = RDLABEL; /* * Set up default sizes until we have the label, or longer * if there is none. Set secpercyl, as readdisklabel wants * to compute b_cylin (although we do not need it), and set * nsectors in case diskerr is called. */ lp->d_secpercyl = 1; lp->d_npartitions = 1; lp->d_secsize = 512; lp->d_secperunit = ra->ra_dsize; lp->d_nsectors = ra->ra_geom.rg_nsectors; lp->d_partitions[0].p_size = lp->d_secperunit; lp->d_partitions[0].p_offset = 0; /* * Read pack label. */ if ((msg = readdisklabel(udaminor(unit, 0), udastrategy, lp)) != NULL) { if (cold) printf(": %s", msg); else log(LOG_ERR, "ra%d: %s", unit, msg);#ifdef COMPAT_42 if (udamaptype(unit, lp)) ra->ra_state = OPEN; else ra->ra_state = OPENRAW;#else ra->ra_state = OPENRAW; uda_makefakelabel(ra, lp);#endif } else ra->ra_state = OPEN; wakeup((caddr_t)ra); return (0);}/* * Copy the geometry information for the given ra from a * GET UNIT STATUS response. If check, see if it changed. */uda_rasave(unit, mp, check) int unit; register struct mscp *mp; int check;{ register struct ra_info *ra = &ra_info[unit]; if (check && ra->ra_mediaid != mp->mscp_guse.guse_mediaid) { printf("ra%d: changed types! was %d now %d\n", unit, ra->ra_mediaid, mp->mscp_guse.guse_mediaid); ra->ra_state = CLOSED; /* ??? */ } /* ra->ra_type = mp->mscp_guse.guse_drivetype; */ ra->ra_mediaid = mp->mscp_guse.guse_mediaid; ra->ra_geom.rg_nsectors = mp->mscp_guse.guse_nspt; ra->ra_geom.rg_ngroups = mp->mscp_guse.guse_group; ra->ra_geom.rg_ngpc = mp->mscp_guse.guse_ngpc; ra->ra_geom.rg_ntracks = ra->ra_geom.rg_ngroups * ra->ra_geom.rg_ngpc; /* ra_geom.rg_ncyl cannot be computed until we have ra_dsize */#ifdef notyet ra->ra_geom.rg_rctsize = mp->mscp_guse.guse_rctsize; ra->ra_geom.rg_rbns = mp->mscp_guse.guse_nrpt; ra->ra_geom.rg_nrct = mp->mscp_guse.guse_nrct;#endif}/* * Queue a transfer request, and if possible, hand it to the controller. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -