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

📄 sd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1990, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Van Jacobson of 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.4 (Berkeley) 4/22/94 *//* * SCSI CCS (Command Command Set) disk driver. */#include "sd.h"#if NSD > 0#ifndef lintstatic char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $";#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <sys/stat.h>#include <sys/dkstat.h>#include <sys/disklabel.h>#include <sys/malloc.h>#include <sys/proc.h>#include <sys/ioctl.h>#include <sys/fcntl.h>#include <hp/dev/device.h>#include <hp300/dev/scsireg.h>#include <hp300/dev/sdvar.h>#ifdef USELEDS#include <hp300/hp300/led.h>#endif#include <vm/vm_param.h>#include <vm/lock.h>#include <vm/vm_prot.h>#include <vm/pmap.h>extern int scsi_test_unit_rdy();extern int scsi_request_sense();extern int scsi_inquiry();extern int scsi_read_capacity();extern int scsi_tt_write();extern int scsireq();extern int scsiustart();extern int scsigo();extern void scsifree();extern void scsireset();extern void scsi_delay();extern void disksort();extern void biodone();extern int physio();extern void TBIS();int	sdinit();void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();struct	driver sddriver = {	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,};#ifdef DEBUGint sddebug = 1;#define SDB_ERROR	0x01#define SDB_PARTIAL	0x02#define SDB_CAPACITY	0x04#endifstruct	sd_softc sd_softc[NSD];struct	sdstats sdstats[NSD];struct	buf sdtab[NSD];struct	scsi_fmt_cdb sdcmd[NSD];struct	scsi_fmt_sense sdsense[NSD];static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };/* * 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. */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,};static struct scsi_inquiry inqbuf;static struct scsi_fmt_cdb inq = {	6,	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0};static intsdident(sc, hd)	struct sd_softc *sc;	struct hp_device *hd;{	int unit;	register int ctlr, slave;	register int i;	register int tries = 10;	char idstr[32];	int isrm = 0;	ctlr = hd->hp_ctlr;	slave = hd->hp_slave;	unit = sc->sc_punit;	scsi_delay(-1);	/*	 * See if unit exists and is a disk then read block size & nblocks.	 */	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {		if (i == -1 || --tries < 0) {			if (isrm)				break;			/* doesn't exist or not a CCS device */			goto failed;		}		if (i == STS_CHECKCOND) {			u_char sensebuf[128];			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;			scsi_request_sense(ctlr, slave, unit, sensebuf,					   sizeof(sensebuf));			if (sp->class == 7)				switch (sp->key) {				/*				 * Not ready -- might be removable media				 * device with no media.  Assume as much,				 * if it really isn't, the inquiry commmand				 * below will fail.				 */				case 2:					isrm = 1;					break;				/* drive doing an RTZ -- give it a while */				case 6:					DELAY(1000000);					break;				default:					break;				}		}		DELAY(1000);	}	/*	 * Find out about device	 */	if (scsi_immed_command(ctlr, slave, unit, &inq,			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))		goto failed;	switch (inqbuf.type) {	case 0:		/* disk */	case 4:		/* WORM */	case 5:		/* CD-ROM */	case 7:		/* Magneto-optical */		break;	default:	/* not a disk */		goto failed;	}	/*	 * Get a usable id string	 */	switch (inqbuf.version) {	case 1:	case 2:		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);		for (i = 27; i > 23; --i)			if (idstr[i] != ' ')				break;		idstr[i+1] = 0;		for (i = 23; i > 7; --i)			if (idstr[i] != ' ')				break;		idstr[i+1] = 0;		for (i = 7; i >= 0; --i)			if (idstr[i] != ' ')				break;		idstr[i+1] = 0;		break;	default:		bcopy("UNKNOWN", &idstr[0], 8);		bcopy("DRIVE TYPE", &idstr[8], 11);	}	if (inqbuf.qual & 0x80)		sc->sc_flags |= SDF_RMEDIA;	if (sdgetcapacity(sc, hd, NODEV) < 0)		goto failed;	switch (inqbuf.version) {	case 1:	case 2:		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],			&idstr[24]);		if (inqbuf.version == 2)			printf(" (SCSI-2)");		break;	default:		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,		       inqbuf.type, inqbuf.qual, inqbuf.version);		break;	}	if (sc->sc_blks)		printf(", %d %d byte blocks",		       sc->sc_blks >> sc->sc_bshift, sc->sc_blksize);	printf("\n");	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */	scsi_delay(0);	return(inqbuf.type);failed:	scsi_delay(0);	return(-1);}intsdinit(hd)	register struct hp_device *hd;{	register struct sd_softc *sc = &sd_softc[hd->hp_unit];	sc->sc_hd = hd;	sc->sc_flags = 0;	/*	 * XXX formerly 0 meant unused but now pid 0 can legitimately	 * use this interface (sdgetcapacity).	 */	sc->sc_format_pid = -1;	sc->sc_punit = sdpunit(hd->hp_flags);	sc->sc_type = sdident(sc, hd);	if (sc->sc_type < 0)		return(0);	sc->sc_dq.dq_ctlr = hd->hp_ctlr;	sc->sc_dq.dq_unit = hd->hp_unit;	sc->sc_dq.dq_slave = hd->hp_slave;	sc->sc_dq.dq_driver = &sddriver;	sc->sc_flags |= SDF_ALIVE;	return(1);}voidsdreset(sc, hd)	register struct sd_softc *sc;	register struct hp_device *hd;{	sdstats[hd->hp_unit].sdresets++;}/* * Determine capacity of a drive. * Returns -1 on a failure, 0 on success, 1 on a failure that is probably * due to missing media. */intsdgetcapacity(sc, hd, dev)	struct sd_softc *sc;	struct hp_device *hd;	dev_t dev;{	static struct scsi_fmt_cdb cap = {		10,		CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	u_char *capbuf;	int i, capbufsize;	/*	 * Cannot use stack space for this buffer since stack KVA may not	 * be valid (i.e. in context of this process) when the operation	 * actually starts.	 */	capbufsize = 8;	capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK);	if (dev == NODEV) {		i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit,				       &cap, capbuf, capbufsize, B_READ);	} else {		struct buf *bp;		/*		 * XXX this is horrible		 */		if (sc->sc_format_pid >= 0)			panic("sdgetcapacity");		bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK);		sc->sc_format_pid = curproc->p_pid;		bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap);		bp->b_dev = dev;		bp->b_flags = B_READ | B_BUSY;		bp->b_un.b_addr = (caddr_t)capbuf;		bp->b_bcount = capbufsize;		sdstrategy(bp);		i = biowait(bp) ? sdsense[hd->hp_unit].status : 0;		free(bp, M_DEVBUF);		sc->sc_format_pid = -1;	}	if (i) {		if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) {#ifdef DEBUG			if (sddebug & SDB_CAPACITY)				printf("sd%d: read_capacity returns %d\n",				       hd->hp_unit, i);#endif			free(capbuf, M_DEVBUF);			return (-1);		}		/*		 * XXX assume unformatted or non-existant media		 */		sc->sc_blks = 0;		sc->sc_blksize = DEV_BSIZE;		sc->sc_bshift = 0;#ifdef DEBUG		if (sddebug & SDB_CAPACITY)			printf("sd%d: removable media not present\n",			       hd->hp_unit);#endif		free(capbuf, M_DEVBUF);		return (1);	}	sc->sc_blks = *(u_int *)&capbuf[0];	sc->sc_blksize = *(int *)&capbuf[4];	free(capbuf, M_DEVBUF);	sc->sc_bshift = 0;	/* return value of read capacity is last valid block number */	sc->sc_blks++;	if (sc->sc_blksize != DEV_BSIZE) {		if (sc->sc_blksize < DEV_BSIZE) {			printf("sd%d: need at least %d byte blocks - %s\n",				hd->hp_unit, DEV_BSIZE, "drive ignored");			return (-1);		}		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)			++sc->sc_bshift;		sc->sc_blks <<= sc->sc_bshift;	}#ifdef DEBUG	if (sddebug & SDB_CAPACITY)		printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit,		       sc->sc_blks, sc->sc_blksize, sc->sc_bshift);#endif	return (0);}/* * Read or constuct a disklabel */intsdgetinfo(dev)	dev_t dev;{	int unit = sdunit(dev);	register struct sd_softc *sc = &sd_softc[unit];	register struct disklabel *lp = &sc->sc_info.si_label;	register struct partition *pi;	char *msg, *readdisklabel();#ifdef COMPAT_NOLABEL	int usedefault = 1;	/*	 * For CD-ROM just define a single partition	 */	if (sc->sc_type == 5)		usedefault = 0;#endif	bzero((caddr_t)lp, sizeof *lp);	msg = NULL;	/*	 * If removable media or the size unavailable at boot time	 * (i.e. unformatted hard disk), attempt to set the capacity	 * now.	 */	if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) {		switch (sdgetcapacity(sc, sc->sc_hd, dev)) {		case 0:			break;		case -1:			/*			 * Hard error, just return (open will fail).			 */			return (EIO);		case 1:			/*			 * XXX return 0 so open can continue just in case			 * the media is unformatted and we want to format it.			 * We set the error flag so they cannot do much else.			 */			sc->sc_flags |= SDF_ERROR;			msg = "unformatted/missing media";#ifdef COMPAT_NOLABEL			usedefault = 0;#endif			break;		}	}	/*	 * Set some default values to use while reading the label	 * (or to use if there isn't a label) and try reading it.	 */	if (msg == NULL) {		lp->d_type = DTYPE_SCSI;		lp->d_secsize = DEV_BSIZE;		lp->d_nsectors = 32;		lp->d_ntracks = 20;		lp->d_ncylinders = 1;		lp->d_secpercyl = 32*20;		lp->d_npartitions = 3;		lp->d_partitions[2].p_offset = 0;		/* XXX we can open a device even without SDF_ALIVE */		if (sc->sc_blksize == 0)			sc->sc_blksize = DEV_BSIZE;		/* XXX ensure size is at least one device block */		lp->d_partitions[2].p_size =			roundup(LABELSECTOR+1, btodb(sc->sc_blksize));		msg = readdisklabel(sdlabdev(dev), sdstrategy, lp);		if (msg == NULL)			return (0);	}	pi = lp->d_partitions;	printf("sd%d: WARNING: %s, ", unit, msg);#ifdef COMPAT_NOLABEL	if (usedefault) {		printf("using old default partitioning\n");		sdmakedisklabel(unit, lp);		return(0);	}#endif	printf("defining `c' partition as entire disk\n");	pi[2].p_size = sc->sc_blks;	return(0);}intsdopen(dev, flags, mode, p)	dev_t dev;	int flags, mode;	struct proc *p;{	register int unit = sdunit(dev);	register struct sd_softc *sc = &sd_softc[unit];	int mask, error;	if (unit >= NSD)		return(ENXIO);	/*	 * If a drive's position was fully qualified (i.e. not wildcarded in	 * any way, we allow root to open the device even though it wasn't	 * found at autoconfig time.  This allows initial formatting of disks.	 * However, if any part of the specification was wildcarded, we won't	 * be able to locate the drive so there is nothing we can do.	 */	if ((sc->sc_flags & SDF_ALIVE) == 0 &&	    (suser(p->p_ucred, &p->p_acflag) ||	     sc->sc_hd->hp_ctlr < 0 || sc->sc_hd->hp_slave < 0))		return(ENXIO);	if (sc->sc_flags & SDF_ERROR)		return(EIO);	/*	 * Wait for any pending opens/closes to complete	 */	while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING))		sleep((caddr_t)sc, PRIBIO);	/*	 * On first open, get label and partition info.	 * We may block reading the label, so be careful	 * to stop any other opens.	 */	if (sc->sc_info.si_open == 0) {		sc->sc_flags |= SDF_OPENING;		error = sdgetinfo(dev);		sc->sc_flags &= ~SDF_OPENING;		wakeup((caddr_t)sc);		if (error)			return(error);	}	if (sc->sc_hd->hp_dk >= 0)		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;	mask = 1 << sdpart(dev);	if (mode == S_IFCHR)		sc->sc_info.si_copen |= mask;	else		sc->sc_info.si_bopen |= mask;	sc->sc_info.si_open |= mask;	return(0);}intsdclose(dev, flag, mode, p)	dev_t dev;	int flag, mode;	struct proc *p;{	int unit = sdunit(dev);	register struct sd_softc *sc = &sd_softc[unit];	register struct sdinfo *si = &sc->sc_info;	int mask, s;	mask = 1 << sdpart(dev);	if (mode == S_IFCHR)		si->si_copen &= ~mask;	else		si->si_bopen &= ~mask;	si->si_open = si->si_bopen | si->si_copen;	/*	 * On last close, we wait for all activity to cease since	 * the label/parition info will become invalid.  Since we	 * might sleep, we must block any opens while we are here.	 * Note we don't have to about other closes since we know	 * we are the last one.	 */	if (si->si_open == 0) {		sc->sc_flags |= SDF_CLOSING;		s = splbio();		while (sdtab[unit].b_active) {			sc->sc_flags |= SDF_WANTED;			sleep((caddr_t)&sdtab[unit], PRIBIO);		}		splx(s);		sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR);		wakeup((caddr_t)sc);	}	sc->sc_format_pid = -1;	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 struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),							M_DEVBUF, M_WAITOK);

⌨️ 快捷键说明

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