⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uda.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * 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 + -