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

📄 wd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * Copyright (c) 1990, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)wd.c	8.1 (Berkeley) 6/11/93 *//* TODO:peel out buffer at low ipl,   speed improvement, rewrite to clean code from garbage artifacts */#include "wd.h"#if	NWD > 0#include <sys/param.h>#include <sys/dkbad.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/disklabel.h>#include <sys/buf.h>#include <sys/uio.h>#include <sys/syslog.h>#include <i386/isa/isa_device.h>#include <i386/isa/icu.h>#include <i386/isa/wdreg.h>#include <vm/vm.h>#define	RETRIES		5	/* number of retries before giving up */#define	MAXTRANSFER	32	/* max size of transfer in page clusters */#define wdctlr(dev)	((minor(dev) & 0x80) >> 7)#define wdunit(dev)	((minor(dev) & 0x60) >> 5)#define wdpart(dev)	((minor(dev) & 0x1f))#define b_cylin	b_resid		/* cylinder number for doing IO to */				/* shares an entry in the buf struct *//* * Drive states.  Used for open and format operations. * States < OPEN (> 0) are transient, during an open operation. * OPENRAW is used for unlabeled disks, and for floppies, to inhibit * bad-sector forwarding. */#define RAWDISK		8		/* raw disk operation, no translation*/#define ISRAWSTATE(s)	(RAWDISK&(s))	/* are we in a raw state? */#define DISKSTATE(s)	(~RAWDISK&(s))	/* are we in a given state regardless					   of raw or cooked mode? */#define	CLOSED		0		/* disk is closed. */					/* "cooked" disk states */#define	WANTOPEN	1		/* open requested, not started */#define	RECAL		2		/* doing restore */#define	RDLABEL		3		/* reading pack label */#define	RDBADTBL	4		/* reading bad-sector table */#define	OPEN		5		/* done with open */#define	WANTOPENRAW	(WANTOPEN|RAWDISK)	/* raw WANTOPEN */#define	RECALRAW	(RECAL|RAWDISK)	/* raw open, doing restore */#define	OPENRAW		(OPEN|RAWDISK)	/* open, but unlabeled disk or floppy *//* * The structure of a disk drive. */struct	disk {	struct disklabel dk_dd;	/* device configuration data */	long	dk_bc;		/* byte count left */	short	dk_skip;	/* blocks already transferred */	char	dk_unit;	/* physical unit number */	char	dk_state;	/* control state */	u_char	dk_status;	/* copy of status reg. */	u_char	dk_error;	/* copy of error reg. */	short	dk_open;	/* open/closed refcnt */        u_long  dk_copenpart;   /* character units open on this drive */        u_long  dk_bopenpart;   /* block units open on this drive */        u_long  dk_openpart;    /* all units open on this drive */	short	dk_wlabel;	/* label writable? */};/* * This label is used as a default when initializing a new or raw disk. * It really only lets us access the first track until we know more. */struct disklabel dflt_sizes = {	DISKMAGIC, DTYPE_ST506, 0, "default", "",		512,		/* sector size */		17,		/* # of sectors per track */		8,		/* # of tracks per cylinder */		766,		/* # of cylinders per unit */		17*8,		/* # of sectors per cylinder */		766*8*17,	/* # of sectors per unit */		0,		/* # of spare sectors per track */		0,		/* # of spare sectors per cylinder */		0,		/* # of alt. cylinders per unit */		3600,		/* rotational speed */		1,		/* hardware sector interleave */		0,		/* sector 0 skew, per track */		0,		/* sector 0 skew, per cylinder */		0,		/* head switch time, usec */		0,		/* track-to-track seek, usec */		0,		/* generic flags */		0,0,0,0,0,		0,0,0,0,0,		DISKMAGIC,		0,		8,		8192,		8192,		{{21600,	0, 0,0,0,0},	/* A=root filesystem */	{21600,	40, 0,0,0,0},	{660890, 0, 0,0,0,0},	/* C=whole disk */	{216000,	80, 0,0,0,0},	{0,	0, 0,0,0,0},	{0,	0, 0,0,0,0},	{0,	0, 0,0,0,0},	{399600,	480, 0,0,0,0}}};static	struct	dkbad	dkbad[NWD];struct	disk	wddrives[NWD] = {0};	/* table of units */struct	buf	wdtab = {0};struct	buf	wdutab[NWD] = {0};	/* head of queue per drive */struct	buf	rwdbuf[NWD] = {0};	/* buffers for raw IO */long	wdxfer[NWD] = {0};		/* count of transfers */int	writeprotected[NWD] = { 0 };int	wdprobe(), wdattach(), wdintr();struct	isa_driver wddriver = {	wdprobe, wdattach, "wd",};static wdc;/* * Probe routine */wdprobe(dvp)	struct isa_device *dvp;{wdc = dvp->id_iobase;#ifdef lint	wdintr(0);#endif	/* XXX sorry, needs to be better */	outb(wdc+wd_error, 0x5a) ;	/* error register not writable */	outb(wdc+wd_cyl_lo, 0xa5) ;	/* but all of cyllo are implemented */	if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)		return(1) ;	return (0);}/* * attach each drive if possible. */wdattach(dvp)	struct isa_device *dvp;{	int unit = dvp->id_unit;	outb(wdc+wd_ctlr,12);	DELAY(1000);	outb(wdc+wd_ctlr,8);}/* Read/write routine for a buffer.  Finds the proper unit, range checks * arguments, and schedules the transfer.  Does not wait for the transfer * to complete.  Multi-page transfers are supported.  All I/O requests must * be a multiple of a sector in length. */wdstrategy(bp)	register struct buf *bp;	/* IO operation to perform */{	register struct buf *dp;	register struct disk *du;	/* Disk unit to do the IO.	*/	register struct partition *p;	long maxsz, sz;	int	unit = wdunit(bp->b_dev);	int	s;	if ((unit >= NWD) || (bp->b_blkno < 0)) {		printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",			unit, bp->b_blkno, bp->b_bcount);		pg("wd:error in wdstrategy");		bp->b_flags |= B_ERROR;		goto bad;	}	if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {		printf("wd%d: write protected\n", unit);		goto bad;	}	du = &wddrives[unit];	if (DISKSTATE(du->dk_state) != OPEN)		goto q;#ifdef old	/*	 * Convert DEV_BSIZE "blocks" to sectors.	 * Note: doing the conversions this way limits the partition size	 * to about 8 million sectors (1-8 Gb).	 */	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;	if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||	    bp->b_bcount >= MAXTRANSFER * CLBYTES) {		bp->b_flags |= B_ERROR;		goto bad;	}	nblocks = du->dk_dd.d_partitions[part].p_size;	cyloff = du->dk_dd.d_partitions[part].p_offset;	if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {		if (blknum == nblocks)			bp->b_resid = bp->b_bcount;		else			bp->b_flags |= B_ERROR;		goto bad;	}	bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;#else        /*         * Determine the size of the transfer, and make sure it is         * within the boundaries of the partition.         */        p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];        maxsz = p->p_size;        sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;        if (bp->b_blkno + p->p_offset <= LABELSECTOR &&#if LABELSECTOR != 0            bp->b_blkno + p->p_offset + sz > LABELSECTOR &&#endif            (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {                bp->b_error = EROFS;                goto bad;        }        if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {                /* if exactly at end of disk, return an EOF */                if (bp->b_blkno == maxsz) {                        bp->b_resid = bp->b_bcount;                        biodone(bp);                        return;                }                /* or truncate if part of it fits */                sz = maxsz - bp->b_blkno;                if (sz <= 0)                        goto bad;                bp->b_bcount = sz << DEV_BSHIFT;        }        bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;#endifq:	dp = &wdutab[unit];	s = splhigh();	disksort(dp, bp);	if (dp->b_active == 0)		wdustart(du);		/* start drive if idle */	if (wdtab.b_active == 0)		wdstart(s);		/* start IO if controller idle */	splx(s);	return;bad:	bp->b_error = EINVAL;	biodone(bp);}/* Routine to queue a read or write command to the controller.  The request is * linked into the active list for the controller.  If the controller is idle, * the transfer is started. */wdustart(du)	register struct disk *du;{	register struct buf *bp, *dp;	dp = &wdutab[du->dk_unit];	if (dp->b_active)		return;	bp = dp->b_actf;	if (bp == NULL)		return;		dp->b_forw = NULL;	if (wdtab.b_actf  == NULL)		/* link unit into active list */		wdtab.b_actf = dp;	else		wdtab.b_actl->b_forw = dp;	wdtab.b_actl = dp;	dp->b_active = 1;		/* mark the drive as busy */}/* * Controller startup routine.  This does the calculation, and starts * a single-sector read or write operation.  Called to start a transfer, * or from the interrupt routine to continue a multi-sector transfer. * RESTRICTIONS: * 1.	The transfer length must be an exact multiple of the sector size. */static wd_sebyse;wdstart(){	register struct disk *du;	/* disk unit for IO */	register struct buf *bp;	struct buf *dp;	register struct bt_bad *bt_ptr;	long	blknum, pagcnt, cylin, head, sector;	long	secpertrk, secpercyl, addr, i;	int	unit, s;loop:	dp = wdtab.b_actf;	if (dp == NULL)		return;	bp = dp->b_actf;	if (bp == NULL) {		wdtab.b_actf = dp->b_forw;		goto loop;	}	unit = wdunit(bp->b_dev);	du = &wddrives[unit];	if (DISKSTATE(du->dk_state) <= RDLABEL) {		if (wdcontrol(bp)) {			dp->b_actf = bp->av_forw;			goto loop;	/* done */		}		return;	}	secpertrk = du->dk_dd.d_nsectors;	secpercyl = du->dk_dd.d_secpercyl;	/*	 * Convert DEV_BSIZE "blocks" to sectors.	 */	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize		+ du->dk_skip;#ifdef	WDDEBUG	if (du->dk_skip == 0) {		dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,			(bp->b_flags & B_READ) ? "read" : "write",			bp->b_bcount, blknum);	} else {		dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));	}#endif	addr = (int) bp->b_un.b_addr;	if(du->dk_skip==0) du->dk_bc = bp->b_bcount;	cylin = blknum / secpercyl;	head = (blknum % secpercyl) / secpertrk;	sector = blknum % secpertrk;	if (DISKSTATE(du->dk_state) == OPEN)		cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset				/ secpercyl;	/* 	 * See if the current block is in the bad block list.	 * (If we have one, and not formatting.)	 */	if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)	    for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {		if (bt_ptr->bt_cyl > cylin)			/* Sorted list, and we passed our cylinder. quit. */			break;		if (bt_ptr->bt_cyl == cylin &&				bt_ptr->bt_trksec == (head << 8) + sector) {			/*			 * Found bad block.  Calculate new block addr.			 * This starts at the end of the disk (skip the			 * last track which is used for the bad block list),			 * and works backwards to the front of the disk.			 */#ifdef	WDDEBUG

⌨️ 快捷键说明

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