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

📄 sd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1990, 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * 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, Lawrence Berkeley Laboratory. * * 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. * *	@(#)sd.c	8.1 (Berkeley) 6/10/93 * * from: $Header: sd.c,v 1.27 93/04/29 01:22:19 torek Exp $ *//* * SCSI CCS (Command Command Set) disk driver. * * MACHINE INDEPENDENT (do not put machine dependent goo in here!) * * (from sd.c,v 1.7 90/12/15 14:11:26 van Exp) */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/errno.h>#include <sys/device.h>#include <sys/disklabel.h>#include <sys/dkstat.h>#include <sys/disk.h>#include <sys/ioctl.h>#include <sys/malloc.h>#include <dev/scsi/scsi.h>#include <dev/scsi/disk.h>#include <dev/scsi/scsivar.h>#include <dev/scsi/scsi_ioctl.h>#include <machine/cpu.h>#include <dev/scsi/sdtrace.h>#ifdef sparc					/* XXX */#define SUN_LABEL_HACK				/* XXX */#endif						/* XXX */#ifdef SUN_LABEL_HACK#include <sparc/sunos/sun_disklabel.h>#endif/* * Per-disk variables. * * sd_dk contains all the `disk' specific stuff (label/partitions, * transfer rate, etc).  We need only things that are special to * scsi disks.  Note that our blocks are in terms of DEV_BSIZE blocks. */struct sd_softc {	struct	dkdevice sc_dk;	/* base disk device, must be first */	struct	unit sc_unit;	/* scsi unit */	pid_t	sc_format_pid;	/* process using "format" mode */	u_char	sc_type;	/* drive type */	u_char	sc_bshift;	/* convert device blocks to DEV_BSIZE blks */	short	sc_flags;	/* see below */	u_int	sc_blks;	/* number of blocks on device */	int	sc_blksize;	/* device block size in bytes */	/* should be in dkdevice?? */	struct	buf sc_tab;	/* transfer queue */	/* statistics */	long	sc_resets;	/* number of times reset */	long	sc_transfers;	/* count of total transfers */	long	sc_partials;	/* count of `partial' transfers */	/* for user formatting */	struct	scsi_cdb sc_cmd;	struct	scsi_fmt_sense sc_sense;};#define	SDF_ALIVE	1	/* drive OK for regular kernel use *//* definition of the autoconfig driver */int	sdmatch __P((struct device *, struct cfdata *, void *));void	sdattach __P((struct device *, struct device *, void *));struct cfdriver sdcd =    { NULL, "sd", sdmatch, sdattach, DV_DISK, sizeof(struct sd_softc) };/* definition of the unit driver, for hba */void	sdigo __P((struct device *, struct scsi_cdb *));void	sdgo __P((struct device *, struct scsi_cdb *));void	sdintr __P((struct device *, int, int));void	sdreset __P((struct unit *));static struct unitdriver sdunitdriver = { /*sdgo, sdintr*/ sdreset };/* definition of the disk driver, for kernel */void	sdstrategy __P((struct buf *));static struct dkdriver sddkdriver = { sdstrategy };#ifdef DEBUGint sddebug = 1;#define SDB_ERROR	0x01#define SDB_PARTIAL	0x02#endif#define	sdunit(x)	(minor(x) >> 3)#define sdpart(x)	(minor(x) & 0x7)#define	b_cylin		b_resid#define	SDRETRY		2/* * Table of scsi commands users are allowed to access via `format' * mode.  0 means not legal.  1 means `immediate' (doesn't need dma). * -1 means needs dma and/or wait for intr (i.e., `slow'). */static char legal_cmds[256] = {/*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F *//*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,/*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,/*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,};intsdmatch(parent, cf, aux)	struct device *parent;	register struct cfdata *cf;	void *aux;{	register struct scsi_attach_args *sa = aux;#ifdef DEBUG	char *whynot;#endif	/*	 * unit number must match, or be given as `any'	 */	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != sa->sa_unit)		return (0);	/*	 * drive must be a disk, and of a kind we recognize	 */	if ((sa->sa_inq_status & STS_MASK) != STS_GOOD) {#ifdef DEBUG		whynot = "INQUIRY failed";#endif		goto notdisk;	}	switch (sa->sa_si.si_type & TYPE_TYPE_MASK) {	case TYPE_DAD:		/* disk */	case TYPE_WORM:		/* WORM */	case TYPE_ROM:		/* CD-ROM */	case TYPE_MO:		/* Magneto-optical */	case TYPE_JUKEBOX:	/* medium changer */		break;	default:	notdisk:#ifdef DEBUG		whynot = "not a disk";		printf("[not matching `sd' at unit %d: %s]\n",		    sa->sa_unit, whynot);#endif		return (0);	}	/*	 * It is a disk of some kind; take it.  We will figure out	 * the rest in the attach routine.	 */	return (1);}/* * Attach a disk (called after sdmatch returns true). * Note that this routine is never reentered (so we can use statics). */voidsdattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	register struct sd_softc *sc = (struct sd_softc *)self;	register struct scsi_attach_args *sa = aux;	register int i;	char vendor[10], drive[17], rev[5];	static u_char capbuf[8];	static struct scsi_cdb cap = { CMD_READ_CAPACITY };#ifdef SUN_LABEL_HACK	static struct scsi_cdb rd0 = { CMD_READ10, 0, 0, 0, 0, 0, 0, 0, 1, 0 };	caddr_t sector;#endif	/*	 * Declare our existence.	 */	sc->sc_unit.u_driver = &sdunitdriver;	scsi_establish(&sc->sc_unit, &sc->sc_dk.dk_dev, sa->sa_unit);	/*	 * Figure out what kind of disk this is.	 * We only accepted it if the inquiry succeeded, so	 * we can inspect those fields.	 */	i = (sa->sa_si.si_version >> VER_ANSI_SHIFT) & VER_ANSI_MASK;	if (i == 1 || i == 2) {		scsi_inq_ansi((struct scsi_inq_ansi *)&sa->sa_si,		    vendor, drive, rev);		printf(": %s %s", vendor, drive);		/* XXX should we even ever bother printing this? */		if (rev[0])			printf(" %s", rev);	} else {		/* bleah */		bcopy("<unknown>", vendor, 10);		bcopy("<unknown>", drive, 10);		printf(": type 0x%x, qual 0x%x, ver %d",		    sa->sa_si.si_type, sa->sa_si.si_qual,		    sa->sa_si.si_version);	}	CDB10(&cap)->cdb_lun_rel = sc->sc_unit.u_unit << 5;	i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,	    sc->sc_unit.u_targ, &cap, (char *)capbuf, sizeof capbuf, B_READ);	i &= STS_MASK;	if (i == STS_GOOD) {#define	NUMBER(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])		sc->sc_blks = NUMBER(&capbuf[0]);		sc->sc_blksize = NUMBER(&capbuf[4]);	} else if (i == STS_CHECKCOND &&	    (strcmp(vendor, "HP") == 0 && strcmp(drive, "S6300.650A") == 0)) {		/* XXX unformatted or nonexistent MO medium: fake it */		sc->sc_blks = 318664;		sc->sc_blksize = 1024;	} else {		/* XXX shouldn't bail for removable media */		printf(": unable to determine drive capacity [sts=%x]\n", i);		return;	}	/* return value from read capacity is last valid block, not nblocks */	sc->sc_blks++;	printf(", %u %d byte blocks\n", sc->sc_blks, sc->sc_blksize);	if (sc->sc_blksize != DEV_BSIZE) {		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)			++sc->sc_bshift;		if (i != DEV_BSIZE) {			printf("%s: blksize not multiple of %d: cannot use\n",			    sc->sc_dk.dk_dev.dv_xname, DEV_BSIZE);			return;		}		sc->sc_blks <<= sc->sc_bshift;	}	sc->sc_type = sa->sa_si.si_type;	/* sufficient? */	sc->sc_dk.dk_driver = &sddkdriver;#ifdef notyet	dk_establish(&sc->sc_dk);	/* READ DISK LABEL HERE, UNLESS REMOVABLE MEDIUM... NEEDS THOUGHT */#else	sc->sc_dk.dk_label.d_secsize = 512;	/* XXX */	sc->sc_dk.dk_bps = (3600/60) * 32 * 512;/* XXX */#ifdef SUN_LABEL_HACK	sector = (caddr_t)malloc(sc->sc_blksize, M_DEVBUF, M_NOWAIT);	CDB10(&rd0)->cdb_lun_rel = sc->sc_unit.u_unit << 5;	i = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,	    sc->sc_unit.u_targ, &rd0, sector, sc->sc_blksize, B_READ);	if (i == STS_GOOD) {		printf("%s: <%s>\n", sc->sc_dk.dk_dev.dv_xname,		    ((struct sun_disklabel *)sector)->sl_text);		if (sun_disklabel(sector, &sc->sc_dk.dk_label))			sc->sc_flags |= SDF_ALIVE;		else			printf("%s: sun_disklabel fails\n",			    sc->sc_dk.dk_dev.dv_xname);	} else		printf("%s: could not read sector 0 for disk label\n",		    sc->sc_dk.dk_dev.dv_xname);	free(sector, M_DEVBUF);#endif#endif /* notyet */}/* * Reset a disk, after a SCSI bus reset. * * XXX untested and probably incomplete/incorrect */voidsdreset(u)	register struct unit *u;{	register struct sd_softc *sc = (struct sd_softc *)u->u_dev;	printf(" %s", sc->sc_dk.dk_dev.dv_xname);	sc->sc_resets++;}/* dev_t is short, must use prototype syntax */intsdopen(dev_t dev, int flags, int ifmt, struct proc *p){	register int unit = sdunit(dev);	register struct sd_softc *sc;	if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL)		return (ENXIO);	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))		return (ENXIO);	return (0);}intsdclose(dev_t dev, int flags, int ifmt, struct proc *p){	register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)];	sc->sc_format_pid = 0;	return (0);}/* * This routine is called for partial block transfers and non-aligned * transfers (the latter only being possible on devices with a block size * larger than DEV_BSIZE).  The operation is performed in three steps * using a locally allocated buffer: *	1. transfer any initial partial block *	2. transfer full blocks *	3. transfer any final partial block */static voidsdlblkstrat(bp, bsize)	register struct buf *bp;	register int bsize;{	register int bn, resid, boff, count;	register caddr_t addr, cbuf;	struct buf *tbp;	/* should probably use geteblk() here, but I fear consequences */	cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);	tbp = (struct buf *)malloc(sizeof *tbp, M_DEVBUF, M_WAITOK);	bzero((caddr_t)tbp, sizeof *tbp);	tbp->b_proc = curproc;	tbp->b_dev = bp->b_dev;	bn = bp->b_blkno;	resid = bp->b_bcount;	addr = bp->b_un.b_addr;#ifdef DEBUG	if (sddebug & SDB_PARTIAL)		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",		       bp, bp->b_flags, bn, resid, addr);#endif	while (resid > 0) {		boff = dbtob(bn) & (bsize - 1);		if (boff || resid < bsize) {			struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)];			sc->sc_partials++;			count = min(resid, bsize - boff);			tbp->b_flags = B_BUSY | B_READ;			tbp->b_blkno = bn - btodb(boff);			tbp->b_un.b_addr = cbuf;			tbp->b_bcount = bsize;#ifdef DEBUG			if (sddebug & SDB_PARTIAL)				printf(" readahead: bn %x cnt %x off %x addr %x\n",				       tbp->b_blkno, count, boff, addr);#endif			sdstrategy(tbp);			biowait(tbp);			if (tbp->b_flags & B_ERROR) {				bp->b_flags |= B_ERROR;				bp->b_error = tbp->b_error;				break;			}			if (bp->b_flags & B_READ) {				bcopy(&cbuf[boff], addr, count);				goto done;			}			bcopy(addr, &cbuf[boff], count);#ifdef DEBUG			if (sddebug & SDB_PARTIAL)				printf(" writeback: bn %x cnt %x off %x addr %x\n",				       tbp->b_blkno, count, boff, addr);#endif		} else {			count = resid & ~(bsize - 1);			tbp->b_blkno = bn;			tbp->b_un.b_addr = addr;			tbp->b_bcount = count;#ifdef DEBUG			if (sddebug & SDB_PARTIAL)				printf(" fulltrans: bn %x cnt %x addr %x\n",				       tbp->b_blkno, count, addr);#endif		}		tbp->b_flags = B_BUSY | (bp->b_flags & B_READ);		sdstrategy(tbp);		biowait(tbp);		if (tbp->b_flags & B_ERROR) {			bp->b_flags |= B_ERROR;			bp->b_error = tbp->b_error;

⌨️ 快捷键说明

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