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

📄 sd.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#ident  "@(#)sd.c 1.1 92/07/30 SMI"/* * Copyright (c) 1988, 1989, 1990 by Sun Microsystems, Inc. */#include "sd.h"#if	NSD > 0/* *	SCSI fixed disk driver * *//* * * Includes, Declarations and Local Data * */#include <scsi/scsi.h>#include <scsi/targets/sddef.h>#include <scsi/impl/uscsi.h>#include <vm/hat.h>#include <vm/seg.h>#include <vm/as.h>/* * * Global Data Definitions and references * */extern int sd_error_level, sd_io_time, sd_fmt_time;extern int sd_retry_count, sdnspecial;extern struct sd_drivetype sdspecial[];extern int maxphys, dkn;static int sdmaxphys;#ifdef	B_KLUSTERextern int klustsort(), klustdone();extern void klustbust();#endif	/* B_KLUSTER *//* * * Local Static Data * */static struct scsi_device *sdunits[SD_MAXUNIT];static struct scsi_address *sdsvdaddr[SD_MAXUNIT];static int sddebug = 0;static int sdpri = 0;static char *diskokay = "disk okay";/* * Forward reference definitions */extern char *sd_cmds[];/* * Configuration Data */#ifdef	OPENPROMS/* * Device driver ops vector */int sdslave(), sdattach(), sdopen(), sdclose(), sdread(), sdwrite();int sdstrategy(), sddump(), sdioctl(), sdsize();struct dev_ops sd_ops = {	1,	sdslave,	sdattach,	sdopen,	sdclose,	sdread,	sdwrite,	sdstrategy,	sddump,	sdsize,	sdioctl};#else	OPENPROMS/* * sddriver is only used to attach */int sdslave(), sdattach(), sdopen(), sdclose(), sdread(), sdwrite();int sdstrategy(), sddump(), sdioctl(), sdsize();extern int nulldev(), nodev();struct mb_driver sddriver = {	nulldev, sdslave, sdattach, nodev, nodev, nulldev, 0, "sd", 0, 0, 0, 0};#endif/* * * Local Function Declarations * */static void inq_fill(), sdintr(), sd_doattach();static void sderrmsg(), sddone(), sd_offline(), sd_lock_unlock();static void make_sd_cmd(), sdstart(), sddone();static int sdrunout(), sd_findslave(), sd_winchester_exists();static int sd_unit_ready();static void sdprintf(), sdlog();static void sd_setlink();static int sd_testlink(), sd_maptouscsi();#ifdef	ADAPTECstatic void sdintr_adaptec();#endif	/* ADAPTEC *//* * * Autoconfiguration Routines * */intsdslave(devp)struct scsi_device *devp;{	int r, unit;#ifdef	sun4m	sdmaxphys = 0x3f000;#else	sdmaxphys = maxphys;#endif	/* sun4m */	unit = DUNIT;	/*	 * fill in our local array	 */	if (unit >= SD_MAXUNIT || sdunits[unit])		return (0);	sdunits[unit] = devp;#ifdef	OPENPROMS	sdpri = MAX(sdpri, ipltospl(devp->sd_dev->devi_intr->int_pri));#else	sdpri = MAX(sdpri, pritospl(devp->sd_dev->md_intpri));#endif	/*	 * Turn around and call real slave routine. If it returns -1,	 * then try and save the address structure for a possible later open.	 */	r = sd_findslave(devp, 0);	if (r < 0) {		sdsvdaddr[unit] = (struct scsi_address *)		    kmem_zalloc(sizeof (struct scsi_address));		if (sdsvdaddr[unit]) {			sdunits[unit] = 0;			*sdsvdaddr[unit] = devp->sd_address;		} else {			r = 0;		}	}	return (r);}static intsd_findslave(devp, canwait)register struct scsi_device *devp;int canwait;{	static char *nonccs =		"non-CCS device found at target %d lun %d on %s%d";	auto struct scsi_capacity cbuf;	register struct scsi_pkt *rqpkt = (struct scsi_pkt *) 0;	register struct scsi_disk *un = (struct scsi_disk *) 0;	register struct sd_drivetype *dp;	register int made_dp;	/*	 * Call the routine scsi_slave to do some of the dirty work.	 * All scsi_slave does is do a TEST UNIT READY (and possibly	 * a non-extended REQUEST SENSE or two), and an INQUIRY command.	 * If the INQUIRY command succeeds, the field sd_inq in the	 * device structure will be filled in. The sd_sense structure	 * will also be allocated.	 *	 */	switch (scsi_slave(devp, canwait)) {	default:	case SCSIPROBE_NOMEM:	case SCSIPROBE_FAILURE:	case SCSIPROBE_NORESP:		if (devp->sd_inq) {			IOPBFREE (devp->sd_inq, SUN_INQSIZE);			devp->sd_inq = (struct scsi_inquiry *) 0;		}		return (-1);	case SCSIPROBE_NONCCS:#ifdef	ADAPTEC		/*		 * Okay, the INQUIRY command failed.		 * How hard do we want to work at seeing		 * if this is the right device, and how		 * much can we assume about this target?		 */		bzero((caddr_t) devp->sd_inq, SUN_INQSIZE);		devp->sd_inq->inq_dtype = DTYPE_DIRECT;		devp->sd_inq->inq_rdf = RDF_LEVEL0;		bcopy("ADAPTEC", devp->sd_inq->inq_vid, 7);		bcopy("ACB4000", devp->sd_inq->inq_pid, 7);		sdlog(devp, LOG_WARNING, nonccs,		    Tgt(devp), Lun(devp), CNAME, CUNIT);		break;#else	/* ADAPTEC */		sdlog(devp, LOG_ERR, nonccs,		    Tgt(devp), Lun(devp), CNAME, CUNIT);		devp->sd_inq->inq_dtype = DTYPE_NOTPRESENT;		/* FALLTHROUGH */#endif	/* ADAPTEC */	case SCSIPROBE_EXISTS:		switch (devp->sd_inq->inq_dtype) {		case DTYPE_DIRECT:			break;		case DTYPE_NOTPRESENT:		default:			IOPBFREE (devp->sd_inq, SUN_INQSIZE);			devp->sd_inq = (struct scsi_inquiry *) 0;			return (-1);		}	}	/*	 * Allocate a request sense packet.	 */	rqpkt = get_pktiopb(ROUTE, (caddr_t *) &devp->sd_sense, CDB_GROUP0, 1,		SENSE_LENGTH, B_READ, (canwait)? SLEEP_FUNC: NULL_FUNC);	if (!rqpkt) {		return (0);	}	rqpkt->pkt_pmon = -1;	makecom_g0(rqpkt, devp, FLAG_NOPARITY,	    SCMD_REQUEST_SENSE, 0, SENSE_LENGTH);	/*	 * If the device is not a removable media device, make sure that	 * it can be started (if possible) with the START command, and	 * attempt to read it's capacity too (if possible).	 */	cbuf.capacity = -1;	cbuf.lbasize = 0;	if (devp->sd_inq->inq_rmb == 0) {		if (sd_winchester_exists(devp, rqpkt, &cbuf, canwait)) {			goto error;		}	}	/*	 * The actual unit is present.	 * The attach routine will check validity of label	 * (and print out whether it is there).	 * Now is the time to fill in the rest of our info..	 */	un = (struct scsi_disk *) kmem_zalloc(sizeof (struct scsi_disk));	if (!(UPTR = un)) {		goto error;	}	un->un_sbufp = (struct buf *) kmem_zalloc(sizeof (struct buf));	if (un->un_sbufp == (struct buf *) NULL) {		goto error;	}	/*	 * Look through our list of special drives to see whether	 * this drive is known to have special problems.	 */	made_dp = 0;	for (dp = sdspecial; dp < &sdspecial[sdnspecial]; dp++) {		/*		 * It turns out that order is important for strcmp()!		 */		if (bcmp(devp->sd_inq->inq_vid, dp->id, strlen(dp->id)) == 0) {			un->un_dp = dp;			break;		}	}	if (un->un_dp == 0) {		/*		 * Assume CCS drive, assume parity		 */		made_dp = 1;		un->un_dp = (struct sd_drivetype *)			kmem_zalloc(sizeof (struct sd_drivetype));		if (!un->un_dp) {			goto error;		}		un->un_dp->id = kmem_alloc((u_int)12);		if (!un->un_dp->id)			goto error;		bcopy(devp->sd_inq->inq_vid, un->un_dp->id, 12);		un->un_dp->ctype = CTYPE_CCS;	}	if ((un->un_dp->options & SD_NOPARITY) == 0)		rqpkt->pkt_flags &= ~FLAG_NOPARITY;	devp->sd_present = 1;	if (cbuf.capacity != (u_long) -1) {		/*		 * The returned capacity is the LBA of the last		 * addressable logical block, so the real capacity		 * is one greater		 */		un->un_capacity = cbuf.capacity+1;		un->un_lbasize = cbuf.lbasize;	} else {		un->un_capacity = 0;		un->un_lbasize = SECSIZE;	}	rqpkt->pkt_comp = sdintr;	rqpkt->pkt_time = sd_io_time;	if (un->un_dp->options & SD_NODISC)		rqpkt->pkt_flags |= FLAG_NODISCON;	un->un_rqs = rqpkt;	un->un_sd = devp;	un->un_dkn = (char) -1;#ifdef	OPENPROMS	devp->sd_dev->devi_driver = &sd_ops;#endif	OPENPROMS	return (1);error:	if (un) {		if (un->un_sbufp) {			(void) kmem_free((caddr_t)un->un_sbufp,				sizeof (struct buf));		}		if (made_dp) {			if (un->un_dp->id) {				(void) kmem_free(un->un_dp->id, (u_int) 12);			}			if (un->un_dp) {				(void) kmem_free((caddr_t) un->un_dp,					(u_int) sizeof (struct sd_drivetype));			}		}		(void) kmem_free((caddr_t) un, sizeof (struct scsi_disk));		UPTR = (struct scsi_disk *) 0;	}	if (rqpkt) {		free_pktiopb(rqpkt, (caddr_t) devp->sd_sense, SENSE_LENGTH);		devp->sd_sense = (struct scsi_extended_sense *) 0;	}	return (0);}static intsd_winchester_exists(devp, rqpkt, cptr, canwait)struct scsi_device *devp;struct scsi_pkt *rqpkt;struct scsi_capacity *cptr;int canwait;{	static char *emustring = "EMULEX  MD21/S2";	register struct scsi_pkt *pkt;	auto caddr_t wrkbuf;	register rval = -1;	/*	 * Get a work packet to play with. Get one with a buffer big	 * enough for another INQUIRY command, and get one with	 * a cdb big enough for the READ CAPACITY command.	 */	pkt = get_pktiopb(ROUTE, &wrkbuf, CDB_GROUP1, 1, SUN_INQSIZE, B_READ,	    (canwait)? SLEEP_FUNC: NULL_FUNC);	if (pkt == NULL) {		return (rval);	}	/*	 * Send a throwaway START UNIT command.	 *	 * If we fail on this, we don't care present what	 * precisely is wrong. Fire off a throwaway REQUEST	 * SENSE command if the failure is a CHECK_CONDITION.	 *	 */	makecom_g0(pkt, devp, FLAG_NOPARITY, SCMD_START_STOP, 0, 1);	(void) scsi_poll(pkt);	if (SCBP(pkt)->sts_chk) {		(void) scsi_poll (rqpkt);	}	/*	 * Send another Inquiry command to the target. This is necessary	 * for non-removable media direct access devices because their	 * Inquiry data may not be fully qualified until they are spun up	 * (perhaps via the START command above)	 */	bzero(wrkbuf, SUN_INQSIZE);	makecom_g0(pkt, devp, FLAG_NOPARITY, SCMD_INQUIRY, 0, SUN_INQSIZE);	if (scsi_poll(pkt) < 0)  {		goto out;	} else if (SCBP(pkt)->sts_chk) {		(void) scsi_poll (rqpkt);	} else {		if ((pkt->pkt_state & STATE_XFERRED_DATA) &&		    (SUN_INQSIZE - pkt->pkt_resid) >= SUN_MIN_INQLEN) {			bcopy(wrkbuf, (caddr_t) devp->sd_inq, SUN_INQSIZE);		}	}	/*	 * It would be nice to attempt to make sure that there is a disk there,	 * but that turns out to be very hard- We used to use the REZERO	 * command to verify that a disk was attached, but some SCSI disks	 * can't handle a REZERO command. We can't use a READ command	 * because the disk may not be formatted yet. Therefore, we just	 * have to believe a disk is there until proven otherwise, *except*	 * (hack hack hack) for the MD21.	 */	if (bcmp(devp->sd_inq->inq_vid, emustring, strlen(emustring)) == 0) {		makecom_g0(pkt, devp, FLAG_NOPARITY, SCMD_REZERO_UNIT, 0, 0);		if (scsi_poll(pkt) || SCBP_C(pkt) != STATUS_GOOD) {			if (SCBP(pkt)->sts_chk) {				(void) scsi_poll (rqpkt);			}			goto out;		}	}	/*	 * At this point, we've 'succeeded' with this winchester	 */	rval = 0;	/*	 * Attempt to read the drive's capacity.	 * It's okay to fail with this.	 */	makecom_g1(pkt, devp, FLAG_NOPARITY, SCMD_READ_CAPACITY, 0, 0);	if (scsi_poll(pkt) >= 0 && SCBP_C(pkt) == STATUS_GOOD &&	    (pkt->pkt_state & STATE_XFERRED_DATA) &&	    (pkt->pkt_resid == SUN_INQSIZE-(sizeof (struct scsi_capacity)))) {		cptr->capacity = ((struct scsi_capacity *)wrkbuf)->capacity;		cptr->lbasize = ((struct scsi_capacity *)wrkbuf)->lbasize;	} else if (SCBP(pkt)->sts_chk) {		(void) scsi_poll (rqpkt);	}out:	free_pktiopb(pkt, wrkbuf, SUN_INQSIZE);	return (rval);}/* * Attach disk. The controller is there. Is the label valid? * This is a wrapper for sd_doattach. */intsdattach(devp)struct scsi_device *devp;{	sd_doattach(devp, NULL_FUNC);	/*	 * If this is a removable media device,	 * invalidate the geometry in order to	 * force the geometry to be re-examined	 * at open time.	 */	if (devp->sd_inq->inq_rmb && UPTR)		UPTR->un_gvalid = 0;}static voidsd_doattach(devp, f)register struct scsi_device *devp;int (*f)();{	void sd_uselabel();	auto struct dk_label *dkl;	register struct scsi_pkt *pkt;	register struct scsi_disk *un;	int unit, fnoparity;	auto char *label = 0, labelstring[128];	if (!(un = UPTR))		return;	/*	 * FIX ME:	 */	if (un->un_capacity > 0 && un->un_lbasize != SECSIZE) {		sdlog(devp, LOG_ERR,		    "logical block size %d not supported", un->un_lbasize);		return;	}	unit = DUNIT;	if (un->un_dp->options & SD_NOPARITY)		fnoparity = FLAG_NOPARITY;	else		fnoparity = 0;	/*	 * Only DIRECT ACCESS devices will have Sun labels	 */	if (devp->sd_inq->inq_dtype == DTYPE_DIRECT) {		int i;		pkt = get_pktiopb(ROUTE, (caddr_t *) &dkl, CDB_GROUP0,			1, SECSIZE, B_READ, f);		if (pkt == NULL) {			sdlog(devp, LOG_CRIT, "no memory for disk label");			return;		}		bzero ((caddr_t) dkl,  SECSIZE);		makecom_g0(pkt, devp, fnoparity, SCMD_READ, 0, 1);		/*		 * Ok, it's ready - try to read and use the label.		 */		un->un_gvalid = 0;		for (i = 0; i < 3; i++) {			if (scsi_poll(pkt) || SCBP_C(pkt) != STATUS_GOOD ||			    (pkt->pkt_state & STATE_XFERRED_DATA) == 0 ||			    (pkt->pkt_resid != 0)) {				if (i > 2 && un->un_state == SD_STATE_NIL)					sdlog(devp, LOG_ERR,					    "unable to read label");				if (SCBP(pkt)->sts_chk) {					(void) scsi_poll (un->un_rqs);				}			} else {				/*				 * sd_uselabel will establish				 * that the geometry is valid				 */				sd_uselabel(devp, dkl);				break;			}		}		/*		 * XXX: Use Mode Sense to determine things like		 * XXX; rpm, geometry, from SCSI-2 compliant		 * XXX: peripherals		 */		if (un->un_g.dkg_rpm == 0)			un->un_g.dkg_rpm = 3600;		bcopy (dkl->dkl_asciilabel, labelstring, 128);		label = labelstring;		free_pktiopb(pkt, (caddr_t) dkl, SECSIZE);	} else if (un->un_capacity < 0) {		return;	} else  {		/*

⌨️ 快捷键说明

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