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

📄 sd.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		FORMG1COUNT((union scsi_cdb *)cmdblk, count);		ucom->uscsi_cdblen = CDB_GROUP1;	} else {		FORMG0ADDR((union scsi_cdb *)cmdblk, blkno);		FORMG0COUNT((union scsi_cdb *)cmdblk, count);		ucom->uscsi_cdblen = CDB_GROUP0;	}	ucom->uscsi_bufaddr = dcom->dkc_bufaddr;	ucom->uscsi_buflen = dcom->dkc_buflen;	if (dcom->dkc_flags & DK_SILENT) {		ucom->uscsi_flags |= USCSI_SILENT;	} else if (dcom->dkc_flags & DK_DIAGNOSE) {		ucom->uscsi_flags |= USCSI_DIAGNOSE;	} else if (dcom->dkc_flags & DK_ISOLATE) {		ucom->uscsi_flags |= USCSI_ISOLATE;	}	return (sdioctl_cmd(dev, (caddr_t) ucom, SD_USCSI_CDB_KERNEL));}/* * Run a command for sdioctl. */static intsdioctl_cmd(dev, data, addr_flag)dev_t dev;caddr_t data;int addr_flag;{	register struct scsi_device *devp;	register struct buf *bp;	register struct scsi_disk *un;	int err = 0, flag, s;	struct uscsi_cmd *scmd;	char cmdblk[CDB_SIZE], *cdb = cmdblk;	faultcode_t fault_err = -1;	int blkno = 0;	register caddr_t rb = 0;	u_char cmd;	devp = sdunits[SDUNIT(dev)];	un = UPTR;	scmd = (struct uscsi_cmd *)data;	if (addr_flag & SD_USCSI_CDB_KERNEL) {		cdb = scmd->uscsi_cdb;	} else {		if (copyin((caddr_t) scmd->uscsi_cdb, (caddr_t)cdb,			(u_int) scmd->uscsi_cdblen)) {			return (EFAULT);		}	}	cmd = GETCMD((union scsi_cdb *)cdb);	if (DEBUGGING) {		int i;		printf("%s%d: cdb:", DNAME, DUNIT);		for (i = 0; i != scmd->uscsi_cdblen; i++) {			printf(" 0x%x", (u_char)cdb[i]);		}		printf("\n");	}	if (scmd->uscsi_cdblen == CDB_GROUP0) {		blkno = GETG0ADDR((union scsi_cdb *)cdb);	} else if (scmd->uscsi_cdblen == CDB_GROUP1) {		blkno = GETG1ADDR((union scsi_cdb *)cdb);	} else if (scmd->uscsi_cdblen == CDB_GROUP5) {		blkno = GETG5ADDR((union scsi_cdb *)cdb);	} else {		return (EINVAL);	}	flag = (scmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE;	if (DEBUGGING_ALL) {		printf("sdioctl_cmd:  cmd= %x  blk= %x buflen= 0x%x\n",		    cmd, blkno, scmd->uscsi_buflen);		if (flag == B_WRITE && scmd->uscsi_buflen) {			auto u_int i, amt = min(64, (u_int)scmd->uscsi_buflen);			char bufarray[64], *buf = bufarray;			if (addr_flag & SD_USCSI_BUF_KERNEL) {				buf = scmd->uscsi_bufaddr;			} else {				if (copyin(scmd->uscsi_bufaddr,				    (caddr_t) buf, amt)) {					return (EFAULT);				}			}			printf("user's buf:");			for (i = 0; i < amt; i++) {				printf(" 0x%x", buf[i] & 0xff);			}			printf("\n");		}	}	/*	 * Get buffer resources...	 */	bp = un->un_sbufp;	s = splr(sdpri);	while (bp->b_flags & B_BUSY) {		bp->b_flags |= B_WANTED;		(void) sleep((caddr_t) bp, PRIBIO);	}	bzero((caddr_t) bp, sizeof (struct buf));	bp->b_flags = B_BUSY | flag;	(void) splx(s);	/*	 * Set options.	 */	un->un_soptions = 0;	if ((scmd->uscsi_flags & USCSI_SILENT) && !(DEBUGGING_ALL)) {		un->un_soptions |= USCSI_SILENT;	}	if (scmd->uscsi_flags & USCSI_ISOLATE)		un->un_soptions |= USCSI_ISOLATE;	if (scmd->uscsi_flags & USCSI_DIAGNOSE)		un->un_soptions |= USCSI_DIAGNOSE;	/*	 * NB:	 * I don't know why, but changing the order of some of these things	 * below causes panics in kmem_free later on when ioctl(sys_generic.c)	 * attempt to kmem_free something it shouldn't.	 */	/*	 * Fill in the buffer with information we need	 *	 */	bp->b_forw = (struct buf *) cdb;	bp->b_dev = dev;	if ((bp->b_bcount = scmd->uscsi_buflen) > 0)		bp->b_un.b_addr = scmd->uscsi_bufaddr;	bp->b_blkno = blkno;	/*	 * XXX: I'm not sure but that if the buffer address is in kernel	 * XXX: space, we might want to as_fault it in anyway (using	 * XXX: kas instead of u.u_procp->p_as)	 */	if ((scmd->uscsi_buflen) && !(addr_flag & SD_USCSI_BUF_KERNEL)) {		bp->b_flags |= B_PHYS;		bp->b_proc = u.u_procp;		u.u_procp->p_flag |= SPHYSIO;		/*		 * Fault lock the address range of the buffer.		 */		fault_err = as_fault(u.u_procp->p_as, bp->b_un.b_addr,				(u_int)bp->b_bcount, F_SOFTLOCK,				(bp->b_flags & B_READ) ? S_WRITE : S_READ);		if (fault_err != 0) {			if (FC_CODE(fault_err) == FC_OBJERR)				err = FC_ERRNO(fault_err);			else				err = EFAULT;		} else if (buscheck(bp) < 0) {			err = EFAULT;		}	} else if ((cmd == SCMD_REASSIGN_BLOCK) &&	    (addr_flag & SD_USCSI_CDB_KERNEL)) {#define	SRBAMT	sizeof (struct scsi_reassign_blk)		rb = IOPBALLOC(SRBAMT);		if (rb == (caddr_t) 0) {			err = ENOMEM;		} else {			struct scsi_reassign_blk *srb;			bzero(rb, SRBAMT);			srb = (struct scsi_reassign_blk *) rb;			srb->reserved = 0;			srb->length = 4;			srb->defect = bp->b_blkno;			/*			 * The command is formatted as a Group 1			 * command, although no such command exists.			 * Transform it back into a Group 0 command.			 */			FORMG1ADDR((union scsi_cdb *)cdb, 0);			((union scsi_cdb *)cdb)->scc_cmd &= ~SCMD_GROUP1;			scmd->uscsi_cdblen = CDB_GROUP0;			bp->b_un.b_addr = rb;			bp->b_bcount = SRBAMT;		}	}	/*	 * If no errors, make and run the command.	 */	if (err == 0) {		make_sd_cmd(devp, bp, SLEEP_FUNC);		if (BP_PKT(bp) && u.u_error == 0) {			sdstrategy(bp);			s = splr(sdpri);			while ((bp->b_flags & B_DONE) == 0) {				(void) sleep((caddr_t) bp, PRIBIO);			}			(void) splx(s);			err = geterror(bp);		} else if (u.u_error == 0) {			err = EFAULT;		}		/*		 * get the status block		 */		scmd->uscsi_status = (int)SCBP_C(BP_PKT(bp));		DPRINTF_IOCTL (devp, "sdioctl_cmd status is %0x%x",		    scmd->uscsi_status);		/*		 * Release the resources.		 */		if (fault_err == 0) {			(void) as_fault(u.u_procp->p_as, bp->b_un.b_addr,			    (u_int)bp->b_bcount, F_SOFTUNLOCK,			    (bp->b_flags&B_READ)? S_WRITE: S_READ);			u.u_procp->p_flag &= ~SPHYSIO;			bp->b_flags &= ~B_PHYS;		}		scsi_resfree(BP_PKT(bp));		BP_PKT(bp) = NULL;	}	s = splr(sdpri);	if (cmd == SCMD_REASSIGN_BLOCK && rb != (caddr_t) 0) {		IOPBFREE (rb, SRBAMT);	}	if (bp->b_flags & B_WANTED)		wakeup((caddr_t)bp);	bp->b_flags &= ~(B_BUSY|B_WANTED);	un->un_soptions = 0;	(void) splx(s);	DPRINTF_IOCTL(devp, "returning %d from ioctl", err);	return (err);}/* * Unit start and Completion */static voidsdstart(devp)register struct scsi_device *devp;{	register struct buf *bp;	register struct scsi_disk *un = UPTR;	register struct diskhd *dp = &un->un_utab;	register struct scsi_pkt *pkt;	if (dp->b_forw || (bp = dp->b_actf) == NULL) {		return;	}	if (!(pkt = BP_PKT(bp))) {		make_sd_cmd(devp, bp, sdrunout);		if (!(pkt = BP_PKT(bp))) {			/*			 * XXX: actually, we should see whether or not			 * XXX:	we could fire up a SCMD_SEEK operation			 * XXX:	here. We may not have been able to go			 * XXX:	because DVMA had run out, not because			 * XXX:	we were out of command packets.			 */			New_state(un, SD_STATE_RWAIT);			return;		} else {			New_state(un, SD_STATE_OPEN);		}	}	dp->b_forw = bp;	dp->b_actf = bp->b_actf;	bp->b_actf = 0;	/*	 * Try and link this command with the one that	 * is next, if it makes sense to do so (very rarely).	 */	if ((scsi_options & SCSI_OPTIONS_LINK) &&	    (un->un_dp->options & SD_USELINKS) && dp->b_actf != NULL &&	    bp != un->un_sbufp && un->un_wchkmap == 0 &&	    sd_testlink(BP_PKT(bp)) == 0) {		if (BP_PKT(dp->b_actf)) {			sd_setlink(BP_PKT(bp));		} else {			make_sd_cmd(devp, dp->b_actf, NULL_FUNC);			if (BP_PKT(dp->b_actf)) {				sd_setlink(BP_PKT(bp));			}		}	}	/*	 * b_resid now changes from disksort key to residue storage	 */	bp->b_resid = pkt->pkt_resid;	pkt->pkt_resid = 0;	if (pkt_transport(BP_PKT(bp)) != TRAN_ACCEPT) {		sdlog(devp, LOG_ERR, "transport rejected");		bp->b_flags |= B_ERROR;		sddone(devp);	} else if (dp->b_actf && !BP_PKT(dp->b_actf)) {		make_sd_cmd(devp, dp->b_actf, NULL_FUNC);	}}static intsdrunout(){	register i, s = splr(sdpri);	register struct scsi_device *devp;	register struct scsi_disk *un;	for (i = 0; i < SD_MAXUNIT; i++) {		devp = sdunits[i];		if (devp && devp->sd_present && (un = UPTR)) {			if (un->un_state == SD_STATE_RWAIT) {				sdstart(devp);				if (un->un_state == SD_STATE_RWAIT) {					(void) splx(s);					return (0);				}			}		}	}	(void) splx(s);	return (1);}static voidsddone(devp)register struct scsi_device *devp;{	register struct buf *bp;	register struct scsi_disk *un = UPTR;	register struct diskhd *dp = &un->un_utab;	bp = dp->b_forw;	dp->b_forw = NULL;	/*	 * Start the next one before releasing resources on this one	 */	if (dp->b_actf) {		sdstart(devp);	}	if (bp != un->un_sbufp) {		int flags = bp->b_flags;		scsi_resfree(BP_PKT(bp));		if ((DEBUGGING_ALL && bp->b_resid) || DEBUGGING) {			sdprintf(devp, "regular done: resid %d", bp->b_resid);		}		/*		 * Keep some statistics about the kinds of		 * transfers going to/from this device.		 */		if ((flags & B_ERROR) == 0) {			flags = bp->b_bcount - bp->b_resid;			if (flags > 0 && flags < 2<<10)				flags = SDS_512_2K;			else if (flags < 4<<10)				flags = SDS_2K_4K;			else if (flags < 8<<10)				flags = SDS_4K_8K;			else if (flags < 16<<10)				flags = SDS_8K_16K;			else if (flags < 32<<10)				flags = SDS_16K_32K;			else if (flags < 64<<10)				flags = SDS_32K_64K;			else if (flags < 128<<10)				flags = SDS_64K_128K;			else				flags = SDS_128K_PLUS;			if (bp->b_flags & B_READ)				un->un_sds.sds_rbins[flags]++;			else				un->un_sds.sds_wbins[flags]++;			if (bp->b_flags & B_PAGEIO)				un->un_sds.sds_npgio++;			else if ((bp->b_flags & B_PHYS) == 0)				un->un_sds.sds_nsysv++;			flags = bp->b_flags;		}#ifdef	B_KLUSTER		if (flags & B_KLUSTER) {			if (flags & B_ERROR) {				register struct buf *xbp;				sdlog(devp, LOG_ERR,				    "kluster error- retryings ops singly");				/*				 * Flip off the error bit				 */				bp->b_flags ^= B_ERROR;				/*				 * Bust apart the chain				 */				klustbust(bp);				/*				 * We could restore sort key for first request				 * (other buffer's sort keys are still valid				 * from first time through sdstrategy()), but				 * that is an overoptimization...				 */				bp->b_resid = 0;				/*				 * re-sort each request back into the				 * queue in order to retry them singly.				 */				xbp = bp;				while (xbp) {					bp = xbp->av_forw;					xbp->av_forw = xbp->av_back = NULL;					(void) klustsort(dp, xbp, 0);					xbp = bp;				}				/*				 * re-adjust max queue length by the decrement				 * at the start of the routine above.				 */				sdstart(devp);			} else {				un->un_sds.sds_kluster++;				dp->b_bcount -= klustdone(bp);			}		} else {			dp->b_bcount--;			iodone(bp);		}#else	/* B_KLUSTER */		dp->b_bcount--;		iodone(bp);#endif	/* B_KLUSTER */	} else {		dp->b_bcount--;		DPRINTF(devp, "special done resid %d", bp->b_resid);		bp->b_flags |= B_DONE;		wakeup((caddr_t) bp);	}}static voidmake_sd_cmd(devp, bp, func)register struct scsi_device *devp;register struct buf *bp;int (*func)();{	auto int count, com;	register struct scsi_pkt *pkt;	register struct scsi_disk *un = UPTR;	int tval = sd_io_time;	int flags = (un->un_dp->options & SD_NOPARITY)? FLAG_NOPARITY : 0;	if (bp != un->un_sbufp) {		struct dk_map *lp = &un->un_map[SDPART(bp->b_dev)];		long secnt;		long resid;		daddr_t blkno;		/*		 * Make sure we don't run off the end of a partition.		 *		 * Put this test here so that we can adjust b_count		 * to accurately reflect the actual amount we are		 * goint to transfer.		 *		 */		secnt = (bp->b_bcount + (SECSIZE - 1)) >> SECDIV;		count = MIN(secnt, lp->dkl_nblk - dkblock(bp));		if (count != secnt) {			/*			 * We have an overrun			 */			resid = (secnt - count) << SECDIV;			DPRINTF_ALL(devp, "overrun by %d sectors\n",			    secnt - count);			bp->b_bcount -= resid;		} else {			resid = 0;		}		if ((pkt = BP_PKT(bp)) == (struct scsi_pkt *) 0) {			pkt = scsi_resalloc(ROUTE, CDB_GROUP1, 1,			    (opaque_t)bp, func);			if ((BP_PKT(bp) = pkt) == (struct scsi_pkt *) 0) {				if (resid) {					bp->b_bcount += resid;				}				return;			}			/*			 * We can't store the resid in b_resid because			 * disksort uses it for the sort key.  Thus we			 * use pkt_resid temporarily.			 */			pkt->pkt_resid = resid;			if (bp->b_flags & B_READ) {				com = SCMD_READ;			} else {				com = SCMD_WRITE;			}		} else {			if (bp->b_flags & B_READ) {				com = SCMD_READ;			} else if (pkt->pkt_cdbp[0] == SCMD_WRITE) {				com = SCMD_VERIFY;			} else {				com = SCMD_WRITE;			}			bzero ((caddr_t) pkt->pkt_cdbp, (u_int) CDB_GROUP1);		}		/*		 * restore b_count field if it had been changed.		 */		if (resid) {			bp->b_bcount += resid;		}		blkno = dkblock(bp) +		    (lp->dkl_cylno * un->un_g.dkg_nhead * un->un_g.dkg_nsect);		/*		 * XXX: This needs to be reworked based upon lbasize		 */		if (com == SCMD_VERIFY || blkno >= (2<<20) || count > 0xff) {			com |= SCMD_GROUP1;			makecom_g1(pkt, devp, flags, com, (int) blkno, count);		} else {

⌨️ 快捷键说明

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