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

📄 idc.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * If on cylinder, no need to seek.	 */	if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar)		goto done;	/*	 * RB80 can change heads (tracks) just by loading	 * the disk address register, perform optimization	 * here instead of doing a full seek.	 */	if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) {		idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8);		idcaddr->idcdar = cyltrk.dar_dar;		idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;		goto done;	}	/*	 * Need to do a full seek.  Select the unit, clear	 * its attention bit, set the command, load the	 * disk address register, and then go.	 */	idcaddr->idccsr =	    IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));	idcaddr->idcdar = cyltrk.dar_dar;	idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;#ifdef IDCDEBUG	printd("  seek");#endif IDCDEBUG	idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8);	if (ui->ui_dk >= 0) {		dk_busy |= 1<<ui->ui_dk;		dk_seek[ui->ui_dk]++;	}	/*	 * RB80's initiate seeks very quickly.	Wait for it	 * to come ready rather than taking the interrupt.	 */	if (ui->ui_type) {		if (idcwait(idcaddr, 10) == 0)			return (1);		idcaddr->idccsr &= ~IDC_ATTN;		/* has the seek completed? */		if (idcaddr->idccsr & IDC_DRDY) {#ifdef IDCDEBUG			printd(", drdy");#endif IDCDEBUG			idcaddr->idccsr =			    IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));			goto done;		}	}#ifdef IDCDEBUG	printd(", idccsr = 0x%x\n", idcaddr->idccsr);#endif IDCDEBUG	return (1);done:	if (dp->b_active != 2) {#ifdef IDCDEBUG		trace("!=2",dp->b_active);#endif IDCDEBUG		dp->b_forw = NULL;		if (um->um_tab.b_actf == NULL)			um->um_tab.b_actf = dp;		else {#ifdef IDCDEBUG			trace("!NUL",um->um_tab.b_actl);#endif IDCDEBUG			um->um_tab.b_actl->b_forw = dp;		}		um->um_tab.b_actl = dp;		dp->b_active = 2;	}	sc->sc_flags[ui->ui_unit] |= DEV_DONE;	return (0);}idcstart(um)	register struct uba_ctlr *um;{	register struct buf *bp, *dp;	register struct uba_device *ui;	register struct idcdevice *idcaddr;	register struct idc_softc *sc;	struct idcst *st;	daddr_t bn;	int sn, tn, cmd;loop:	if ((dp = um->um_tab.b_actf) == NULL) {#ifdef IDCDEBUG		trace("nodp",um);#endif IDCDEBUG		return (0);	}	if ((bp = dp->b_actf) == NULL) {#ifdef IDCDEBUG		trace("nobp", dp);#endif IDCDEBUG		um->um_tab.b_actf = dp->b_forw;		goto loop;	}	um->um_tab.b_active = 1;	ui = idcdinfo[dkunit(bp)];	bn = dkblock(bp);#ifdef IDCDEBUG	trace("star",bp);#endif IDCDEBUG	if (ui->ui_type == 0)		bn *= 2;	sc = &idc_softc;	st = &idcst[ui->ui_type];	sn = bn%st->nspc;	tn = sn/st->nsect;	sn %= st->nsect;	sc->sc_sect = sn;	sc->sc_trk = tn;	sc->sc_cyl = bp->b_cylin;	idcaddr = (struct idcdevice *)ui->ui_addr;#ifdef IDCDEBUG	printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar);#endif IDCDEBUG	if (bp->b_flags & B_READ)		cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8);	else		cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8);	idcaddr->idccsr = IDC_CRDY|cmd;	if ((idcaddr->idccsr&IDC_DRDY) == 0) {		mprintf("rb%d: not ready\n", dkunit(bp));		um->um_tab.b_active = 0;		um->um_tab.b_errcnt = 0;		dp->b_actf = bp->av_forw;		dp->b_active = 0;		bp->b_flags |= B_ERROR;		iodone(bp);		goto loop;	}	idccyl[ui->ui_unit].dar_dar = sc->sc_dar;	idccyl[ui->ui_unit].dar_sect = 0;	sn = (st->nsect - sn) * st->nbps;	if (sn > bp->b_bcount)		sn = bp->b_bcount;	sc->sc_bcnt = sn;	sc->sc_resid = bp->b_bcount;	sc->sc_unit = ui->ui_slave;#ifdef IDCDEBUG	printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd);#endif IDCDEBUG	um->um_cmd = cmd;	(void) ubago(ui);	return (1);}idcdgo(um)	register struct uba_ctlr *um;{	register struct buf *bp;	register struct uba_device *ui = idcdinfo[dkunit(bp)];	register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;	register struct idc_softc *sc = &idc_softc;	/*	 * VERY IMPORTANT: must load registers in this order.	 */	idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff;	idcaddr->idcbcr = -sc->sc_bcnt;	idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG	printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd);#endif IDCDEBUG	idcaddr->idccsr = um->um_cmd;#ifdef IDCDEBUG	trace("go", um);#endif IDCDEBUG	um->um_tab.b_active = 2;	/*** CLEAR SPURIOUS ATTN ON R80? ***/}idcintr(idc)	int idc;{	register struct uba_ctlr *um = idcminfo[idc];	register struct uba_device *ui;	register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;	register struct idc_softc *sc = &idc_softc;	register struct buf *bp, *dp;	struct idcst *st;	int unit, as, er, cmd, savcsr, ds = 0;	savcsr = idcaddr->idccsr;#ifdef IDCDEBUG	printd("idcintr, idccsr 0x%x", idcaddr->idccsr);#endif IDCDEBUGtop:	idcwticks = 0;#ifdef IDCDEBUG	trace("intr", um->um_tab.b_active);#endif IDCDEBUG	if (um->um_tab.b_active == 2) {		/*		 * Process a data transfer complete interrupt.		 */		um->um_tab.b_active = 1;		dp = um->um_tab.b_actf;		bp = dp->b_actf;		ui = idcdinfo[dkunit(bp)];		unit = ui->ui_slave;		st = &idcst[ui->ui_type];		idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);		if ((er = idcaddr->idccsr) & IDC_ERR) {			if (er & IDC_DE) {				idcaddr->idcmpr = IDCGS_GETSTAT;				idcaddr->idccsr = IDC_GETSTAT|(unit<<8);				(void) idcwait(idcaddr, 0);				ds = idcaddr->idcmpr;				idcaddr->idccsr =				    IDC_IE|IDC_CRDY|(1<<(unit+16));			}#ifdef IDCDEBUG			printd(", er 0x%x, ds 0x%x", er, ds);#endif IDCDEBUG			if (ds & IDCDS_WL) {				sc->sc_flags[unit] |= DEV_WRTLCK;				bp->b_flags |= B_ERROR;			} else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) {hard:				harderr(bp, "rb");				sc->sc_hardcnt[unit]++;				sc->sc_flags[unit] |= DEV_HARDERR;		mprintf("%s: unit# %d: hard error block# %d\n csr=%b ds=%b\n",		    sc->sc_device[unit], ui->ui_unit, bp->b_blkno, er,		    IDCCSR_BITS, ds, ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS);				bp->b_flags |= B_ERROR;			} else if (er & IDC_DCK) {				switch (er & IDC_ECS) {				case IDC_ECS_NONE:					break;				case IDC_ECS_SOFT:					idcecc(ui);					sc->sc_softcnt[unit]++;					sc->sc_flags[unit] |= DEV_SOFTERR;					break;				case IDC_ECS_HARD:				default:					goto hard;				}			} else				/* recoverable error, set up for retry */				goto seek;		}		if ((sc->sc_resid -= sc->sc_bcnt) != 0) {			sc->sc_ubaddr += sc->sc_bcnt;			/*			 * Current transfer is complete, have			 * we overflowed to the next track?			 */			if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) {				sc->sc_sect = 0;				if (++sc->sc_trk == st->ntrak) {					sc->sc_trk = 0;					sc->sc_cyl++;				} else if (ui->ui_type) {					/*					 * RB80 can change heads just by					 * loading the disk address register.					 */					idcaddr->idccsr = IDC_SEEK|IDC_CRDY|					    IDC_IE|(unit<<8);#ifdef IDCDEBUG					printd(", change to track 0x%x", sc->sc_dar);#endif IDCDEBUG					idcaddr->idcdar = sc->sc_dar;					idccyl[ui->ui_unit].dar_dar = sc->sc_dar;					idccyl[ui->ui_unit].dar_sect = 0;					goto cont;				}				/*				 * Changing tracks on RB02 or cylinders				 * on RB80, start a seek.				 */seek:				cmd = IDC_IE|IDC_SEEK|(unit<<8);				idcaddr->idccsr = cmd|IDC_CRDY;				idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG				printd(", seek to 0x%x\n", sc->sc_dar);#endif IDCDEBUG				idccyl[ui->ui_unit].dar_dar = sc->sc_dar;				idccyl[ui->ui_unit].dar_sect = 0;				sc->sc_bcnt = 0;				idcaddr->idccsr = cmd;				if (ui->ui_type) {					if (idcwait(idcaddr, 10) == 0)						return;					idcaddr->idccsr &= ~IDC_ATTN;					if (idcaddr->idccsr & IDC_DRDY)						goto top;				}			} else {				/*				 * Continue transfer on current track.				 */cont:				sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps;				if (sc->sc_bcnt > sc->sc_resid)					sc->sc_bcnt = sc->sc_resid;				if (bp->b_flags & B_READ)					cmd = IDC_IE|IDC_READ|(unit<<8);				else					cmd = IDC_IE|IDC_WRITE|(unit<<8);				idcaddr->idccsr = cmd|IDC_CRDY;				idcaddr->idcbar = sc->sc_ubaddr;				idcaddr->idcbcr = -sc->sc_bcnt;				idcaddr->idcdar = sc->sc_dar;#ifdef IDCDEBUG				printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt);#endif IDCDEBUG				idcaddr->idccsr = cmd;				um->um_tab.b_active = 2;			}			return;		}		/*		 * Entire transfer is done, clean up.		 */		ubadone(um);		dk_busy &= ~(1 << ui->ui_dk);		um->um_tab.b_active = 0;		um->um_tab.b_errcnt = 0;		um->um_tab.b_actf = dp->b_forw;		dp->b_active = 0;		dp->b_errcnt = 0;		dp->b_actf = bp->av_forw;#ifdef IDCDEBUG		trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf);#endif IDCDEBUG		bp->b_resid = sc->sc_resid;#ifdef IDCDEBUG		printd(", iodone, resid 0x%x\n", bp->b_resid);#endif IDCDEBUG		iodone(bp);		if (dp->b_actf)			if (idcustart(ui))				return;	} else if (um->um_tab.b_active == 1) {		/*		 * Got an interrupt while setting up for a command		 * or doing a mid-transfer seek.  Save any attentions		 * for later and process a mid-transfer seek complete.		 */		as = idcaddr->idccsr;		idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);		as = (as >> 16) & 0xf;		dp = um->um_tab.b_actf;		bp = dp->b_actf;		ui = idcdinfo[dkunit(bp)];		unit = sc->sc_unit;		sc->sc_softas |= as & ~(1<<unit);		if (as & (1<<unit)) {#ifdef IDCDEBUG			printd(", seek1 complete");#endif IDCDEBUG			um->um_tab.b_active = 2;			goto top;		}#ifdef IDCDEBUG		printd(", as1 %o\n", as);#endif IDCDEBUG		return;	}	/*	 * Process any seek initiated or complete interrupts.	 */	if ((savcsr & IDC_OPI) && !(savcsr & IDC_DRDY)) {	    unit = ((savcsr & IDC_DS) >> 8);	    ui = idcdinfo[unit];	    if (sc->sc_offline[ui->ui_unit]) {		mprintf("%s: unit# %d: offline\n",sc->sc_device[unit], unit);	    }	    else {		mprintf("%s: unit# %d: drive error: csr=%b\n",		    sc->sc_device[unit], unit, savcsr, IDCCSR_BITS);	    }	    dp = &idcutab[ui->ui_unit];	    bp = dp->b_actf;	    dp->b_actf = bp->av_forw;	    dp->b_active = 0;	    bp->b_flags |= B_ERROR;	    iodone(bp);	    if (idcustart(ui)) {	        return;	    }	}	as = idcaddr->idccsr;	idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);	as = ((as >> 16) & 0xf) | sc->sc_softas;	sc->sc_softas = 0;#ifdef IDCDEBUG	trace("as", as);	printd(", as %o", as);#endif IDCDEBUG	for (unit = 0; unit < nNRB; unit++)		if (as & (1<<unit)) {			as &= ~(1<<unit);			idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);			ui = idcdinfo[unit];			if (ui) {#ifdef IDCDEBUG				printd(", attn unit %d", unit);#endif IDCDEBUG				if (idcaddr->idccsr & IDC_DRDY) {					if (sc->sc_offline[ui->ui_unit]) {						/*						 * read header to synch ucode						 * drive has be spun up						 */						idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR;						(void) idcwait(idcaddr, 0);						/* read the MPR twice */						if (idcaddr->idcmpr == idcaddr->idcmpr);						/* reset the drive */						idcaddr->idcmpr = IDCGS_GETSTAT;						idcaddr->idccsr = IDC_GETSTAT|(unit<<8);						(void) idcwait(idcaddr, 0);#ifdef IDCDEBUG						printd(", drive ready");#endif IDCDEBUG						sc->sc_offline[ui->ui_unit] = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -