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

📄 wd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			    dprintf(DDSK,"--- badblock code -> Old = %d; ",				blknum);#endif			blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors				- (bt_ptr - dkbad[unit].bt_bad) - 1;			cylin = blknum / secpercyl;			head = (blknum % secpercyl) / secpertrk;			sector = blknum % secpertrk;#ifdef	WDDEBUG			    dprintf(DDSK, "new = %d\n", blknum);#endif			break;		}	}	sector += 1;	/* sectors begin with 1, not 0 */	wdtab.b_active = 1;		/* mark controller active */	if(du->dk_skip==0 || wd_sebyse) {	if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;	while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;	/*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/	outb(wdc+wd_precomp, 0xff);	/*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/	/*if (bp->b_flags & B_FORMAT) {		wr(wdc+wd_sector, du->dk_dd.dk_gap3);		wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);	} else {*/	if(wd_sebyse)		outb(wdc+wd_seccnt, 1);	else		outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));	outb(wdc+wd_sector, sector);	outb(wdc+wd_cyl_lo, cylin);	outb(wdc+wd_cyl_hi, cylin >> 8);	/* Set up the SDH register (select drive).     */	outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));	while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;	/*if (bp->b_flags & B_FORMAT)		wr(wdc+wd_command, WDCC_FORMAT);	else*/		outb(wdc+wd_command,			(bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);#ifdef	WDDEBUG	dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",	    sector, cylin, head, addr, inb(wdc+wd_altsts));#endif}			/* If this is a read operation, just go away until it's done.	*/	if (bp->b_flags & B_READ) return;	/* Ready to send data?	*/	while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);	/* ASSUMES CONTIGUOUS MEMORY */	outsw (wdc+wd_data, addr+du->dk_skip*512, 256);	du->dk_bc -= 512;}/* * these are globally defined so they can be found * by the debugger easily in the case of a system crash */daddr_t wd_errsector;daddr_t wd_errbn;unsigned char wd_errstat;/* Interrupt routine for the controller.  Acknowledge the interrupt, check for * errors on the current operation, mark it done if necessary, and start * the next request.  Also check for a partially done transfer, and * continue with the next chunk if so. */wdintr(unit){	register struct	disk *du;	register struct buf *bp, *dp;	int status;	char partch ;	static wd_haderror;	/* Shouldn't need this, but it may be a slow controller.	*/	while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;	if (!wdtab.b_active) {		printf("wd: extra interrupt\n");		return;	}#ifdef	WDDEBUG	dprintf(DDSK,"I ");#endif	dp = wdtab.b_actf;	bp = dp->b_actf;	du = &wddrives[wdunit(bp->b_dev)];	partch = wdpart(bp->b_dev) + 'a';	if (DISKSTATE(du->dk_state) <= RDLABEL) {		if (wdcontrol(bp))			goto done;		return;	}	if (status & (WDCS_ERR | WDCS_ECCCOR)) {		wd_errstat = inb(wdc+wd_error);		/* save error status */#ifdef	WDDEBUG		printf("status %x error %x\n", status, wd_errstat);#endif		if(wd_sebyse == 0) {			wd_haderror = 1;			goto outt;		}		/*if (bp->b_flags & B_FORMAT) {			du->dk_status = status;			du->dk_error = wdp->wd_error;			bp->b_flags |= B_ERROR;			goto done;		}*/				wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +			(((unsigned long) bp->b_blkno * DEV_BSIZE /			    du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +			du->dk_skip;		wd_errbn = bp->b_blkno			+ du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;		if (status & WDCS_ERR) {			if (++wdtab.b_errcnt < RETRIES) {				wdtab.b_active = 0;			} else {				printf("wd%d%c: ", du->dk_unit, partch);				printf(				"hard %s error, sn %d bn %d status %b error %b\n",					(bp->b_flags & B_READ)? "read":"write",					wd_errsector, wd_errbn, status, WDCS_BITS,					wd_errstat, WDERR_BITS);				bp->b_flags |= B_ERROR;	/* flag the error */			}		} else			log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",				du->dk_unit, partch, wd_errsector,				wd_errbn);	}outt:	/*	 * If this was a successful read operation, fetch the data.	 */	if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {		int chk, dummy;		chk = min(256,du->dk_bc/2);		/* Ready to receive data?	*/		while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;/*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/		insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);		du->dk_bc -= 2*chk;		while (chk++ < 256) insw (wdc+wd_data,&dummy,1);	}	wdxfer[du->dk_unit]++;	if (wdtab.b_active) {		if ((bp->b_flags & B_ERROR) == 0) {			du->dk_skip++;		/* Add to successful sectors. */			if (wdtab.b_errcnt) {				log(LOG_WARNING, "wd%d%c: ",						du->dk_unit, partch);				log(LOG_WARNING,			"soft %s error, sn %d bn %d error %b retries %d\n",				    (bp->b_flags & B_READ) ? "read" : "write",				    wd_errsector, wd_errbn, wd_errstat,				    WDERR_BITS, wdtab.b_errcnt);			}			wdtab.b_errcnt = 0;			/* see if more to transfer */			/*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/			if (du->dk_bc > 0 && wd_haderror == 0) {				wdstart();				return;		/* next chunk is started */			} else if (wd_haderror && wd_sebyse == 0) {				du->dk_skip = 0;				wd_haderror = 0;				wd_sebyse = 1;				wdstart();				return;		/* redo xfer sector by sector */			}		}done:		wd_sebyse = 0;		/* done with this transfer, with or without error */		wdtab.b_actf = dp->b_forw;		wdtab.b_errcnt = 0;		du->dk_skip = 0;		dp->b_active = 0;		dp->b_actf = bp->av_forw;		dp->b_errcnt = 0;		bp->b_resid = 0;		biodone(bp);	}	wdtab.b_active = 0;	if (dp->b_actf)		wdustart(du);		/* requeue disk if more io to do */	if (wdtab.b_actf)		wdstart();		/* start IO on next drive */}/* * Initialize a drive. */wdopen(dev, flags, fmt)        dev_t dev;        int flags, fmt;{	register unsigned int unit;	register struct buf *bp;	register struct disk *du;        int part = wdpart(dev), mask = 1 << part;        struct partition *pp;	struct dkbad *db;	int i, error = 0;	unit = wdunit(dev);	if (unit >= NWD) return (ENXIO) ;	du = &wddrives[unit];#ifdef notdef	if (du->dk_open){		du->dk_open++ ;		return(0);	/* already is open, don't mess with it */	}#endif	du->dk_unit = unit;	wdutab[unit].b_actf = NULL;	/*if (flags & O_NDELAY)		du->dk_state = WANTOPENRAW;	else*/		du->dk_state = WANTOPEN;	/*	 * Use the default sizes until we've read the label,	 * or longer if there isn't one there.	 */	du->dk_dd = dflt_sizes;	/*	 * Recal, read of disk label will be done in wdcontrol	 * during first read operation.	 */	bp = geteblk(512);	bp->b_dev = dev & 0xff00;	bp->b_bcount = 0;	bp->b_blkno = LABELSECTOR;	bp->b_flags = B_READ;	wdstrategy(bp);	biowait(bp);	if (bp->b_flags & B_ERROR) {		error = ENXIO;		du->dk_state = CLOSED;		goto done;	}	if (du->dk_state == OPENRAW) {		du->dk_state = OPENRAW;		goto done;	}	/*	 * Read bad sector table into memory.	 */	i = 0;	do {		bp->b_flags = B_BUSY | B_READ;		bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors			+ i;		if (du->dk_dd.d_secsize > DEV_BSIZE)			bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;		else			bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;		bp->b_bcount = du->dk_dd.d_secsize;		bp->b_cylin = du->dk_dd.d_ncylinders - 1;		wdstrategy(bp);		biowait(bp);	} while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&		i < du->dk_dd.d_nsectors);	db = (struct dkbad *)(bp->b_un.b_addr);#define DKBAD_MAGIC 0x4321	if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&	    db->bt_flag == DKBAD_MAGIC) {		dkbad[unit] = *db;		du->dk_state = OPEN;	} else {		printf("wd%d: %s bad-sector file\n", unit,		    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");		error = ENXIO ;		du->dk_state = OPENRAW;	}done:	bp->b_flags = B_INVAL | B_AGE;	brelse(bp);	if (error == 0)		du->dk_open = 1;        /*         * Warn if a partion is opened         * that overlaps another partition which is open         * unless one is the "raw" partition (whole disk).         */#define RAWPART         8               /* 'x' partition */     /* XXX */        if ((du->dk_openpart & mask) == 0 && part != RAWPART) {		int	start, end;                pp = &du->dk_dd.d_partitions[part];                start = pp->p_offset;                end = pp->p_offset + pp->p_size;                for (pp = du->dk_dd.d_partitions;                     pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];			pp++) {                        if (pp->p_offset + pp->p_size <= start ||                            pp->p_offset >= end)                                continue;                        if (pp - du->dk_dd.d_partitions == RAWPART)                                continue;                        if (du->dk_openpart & (1 << (pp -					du->dk_dd.d_partitions)))                                log(LOG_WARNING,                                    "wd%d%c: overlaps open partition (%c)\n",                                    unit, part + 'a',                                    pp - du->dk_dd.d_partitions + 'a');                }        }        if (part >= du->dk_dd.d_npartitions)                return (ENXIO);        du->dk_openpart |= mask;        switch (fmt) {        case S_IFCHR:                du->dk_copenpart |= mask;                break;        case S_IFBLK:                du->dk_bopenpart |= mask;                break;        }	return (error);}/* * Implement operations other than read/write. * Called from wdstart or wdintr during opens and formats. * Uses finite-state-machine to track progress of operation in progress. * Returns 0 if operation still in progress, 1 if completed. */wdcontrol(bp)	register struct buf *bp;{	register struct disk *du;	register unit;	unsigned char  stat;	int s, cnt;	extern int bootdev, cyloffset;	du = &wddrives[wdunit(bp->b_dev)];	unit = du->dk_unit;	switch (DISKSTATE(du->dk_state)) {	tryagainrecal:	case WANTOPEN:			/* set SDH, step rate, do restore */#ifdef	WDDEBUG		dprintf(DDSK,"wd%d: recal ", unit);#endif		s = splbio();		/* not called from intr level ... */		outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));		wdtab.b_active = 1;		outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);		du->dk_state++;		splx(s);		return(0);	case RECAL:		if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {			printf("wd%d: recal", du->dk_unit);			if (unit == 0) {				printf(": status %b error %b\n",					stat, WDCS_BITS,					inb(wdc+wd_error), WDERR_BITS);				if (++wdtab.b_errcnt < RETRIES)					goto tryagainrecal;			}			goto badopen;		}		/* some compaq controllers require this ... */		wdsetctlr(bp->b_dev, du);		wdtab.b_errcnt = 0;		if (ISRAWSTATE(du->dk_state)) {			du->dk_state = OPENRAW;			return(1);		}retry:#ifdef	WDDEBUG		dprintf(DDSK,"rdlabel ");#endifif( cyloffset < 0 || cyloffset > 8192) cyloffset=0;		/*		 * Read in sector LABELSECTOR to get the pack label		 * and geometry.

⌨️ 快捷键说明

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