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

📄 sd.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			makecom_g0(pkt, devp, flags, com, (int) blkno, count);		}		pkt->pkt_pmon = un->un_dkn;		if (DEBUGGING) {			sdprintf(devp, "%s blk %d amt 0x%x (%d) resid %d",			    scsi_cmd_decode((u_char) com, sd_cmds), blkno,			    count << SECDIV, count << SECDIV, resid);		}	} else {		caddr_t cdb;		int cdblen;		/*		 * stored in bp->b_forw is a pointer to cdb		 */		cdb = (caddr_t) bp->b_forw;		switch (GETCMD((union scsi_cdb *)cdb)) {		case SCMD_FORMAT:			tval = sd_fmt_time;			break;		}		BP_PKT(bp) = NULL;		switch (GETGROUP((union scsi_cdb *)cdb)) {		case CDB_GROUPID_0:			cdblen = CDB_GROUP0;			break;		case CDB_GROUPID_1:			cdblen = CDB_GROUP1;			break;		case CDB_GROUPID_5:			cdblen = CDB_GROUP5;			break;		default:			sdlog(devp, LOG_ERR, "unknown group for special cmd");			u.u_error = EINVAL;			return;		}		pkt = scsi_resalloc(ROUTE, cdblen, 1,		    (bp->b_bcount > 0)? (opaque_t) bp : (opaque_t) 0, func);		if (pkt == (struct scsi_pkt *) NULL) {			u.u_error = ENOMEM;			return;		}		if (kcopy(cdb, (caddr_t) pkt->pkt_cdbp, (u_int)cdblen) != 0) {			scsi_resfree(pkt);			u.u_error = EFAULT;			return;		}		pkt->pkt_pmon = (char) -1;		pkt->pkt_flags = flags;	}	if ((scsi_options&SCSI_OPTIONS_DR) == 0 ||	    (un->un_dp->options & SD_NODISC) != 0) {		pkt->pkt_flags |= FLAG_NODISCON;	}	pkt->pkt_comp = sdintr;	pkt->pkt_time = tval;	pkt->pkt_private = (opaque_t) bp;	BP_PKT(bp) = pkt;}/* * These two routines provide set and test for the * link bit in disk read or write cdb's */static intsd_testlink(pkt)register struct scsi_pkt *pkt;{	switch (CDB_GROUPID(pkt->pkt_cdbp[0])) {	case CDB_GROUPID_0:		return ((CDBP(pkt)->g0_link == 0) ? 0: 1);	case CDB_GROUPID_1:		return ((CDBP(pkt)->g1_link != 0) ? 0: 1);	default:		return (0);	}}static voidsd_setlink(pkt)register struct scsi_pkt *pkt;{	switch (CDB_GROUPID(pkt->pkt_cdbp[0])) {	case CDB_GROUPID_0:		CDBP(pkt)->g0_link = 1;		break;	case CDB_GROUPID_1:		CDBP(pkt)->g1_link = 1;		break;	default:		break;	}	return;}/* * This routine called to see whether unit is (still) there. Must not * be called when un->un_sbufp is in use, and must not be called with * an unattached disk. Soft state of disk is restored to what it was * upon entry- up to caller to set the correct state. * *  Warning: bzero for non-sun4c's will crash on bootup sdopen. */static intsd_unit_ready(dev)dev_t dev;{	struct scsi_device *devp = sdunits[SDUNIT(dev)];	struct scsi_disk *un = UPTR;	auto struct uscsi_cmd scmd, *com = &scmd;	auto char cmdblk[CDB_GROUP0];	register i;	u_char state = un->un_last_state;	New_state(un, SD_STATE_OPENING);	com->uscsi_bufaddr = 0;	com->uscsi_buflen = 0;	cmdblk[0] = (char) SCMD_TEST_UNIT_READY;	for (i = 1; i < CDB_GROUP0; i++)		cmdblk[i] = 0;	com->uscsi_flags = USCSI_DIAGNOSE|USCSI_SILENT|USCSI_WRITE;	com->uscsi_cdb = cmdblk;	com->uscsi_cdblen = CDB_GROUP0;	/*	 * allow for trying it twice...	 */	if (sdioctl_cmd(dev, (caddr_t)com, SD_USCSI_CDB_KERNEL) &&	    sdioctl_cmd(dev, (caddr_t)com, SD_USCSI_CDB_KERNEL)) {		un->un_state = un->un_last_state;		un->un_last_state = state;		return (0);	}	un->un_state = un->un_last_state;	un->un_last_state = state;	return (1);}/* * Lock or Unlock the door for removable media devices */static voidsd_lock_unlock(dev, flag)dev_t dev;int flag;{	struct scsi_device *devp = sdunits[SDUNIT(dev)];	auto struct uscsi_cmd scmd, *com = &scmd;	auto char cmdblk[CDB_GROUP0];	register i;	com->uscsi_bufaddr = 0;	com->uscsi_buflen = 0;	for (i = 0; i < CDB_GROUP0; i++)		cmdblk[i] = 0;	cmdblk[0] = SCMD_DOORLOCK;	cmdblk[4] = flag;	com->uscsi_flags = USCSI_DIAGNOSE|USCSI_SILENT|USCSI_WRITE;	com->uscsi_cdb = cmdblk;	com->uscsi_cdblen = CDB_GROUP0;	if (sdioctl_cmd(dev, (caddr_t)com, SD_USCSI_CDB_KERNEL)) {		sdlog(devp, LOG_INFO, "%s media removal failed",		    flag ? "prevent" : "allow");	}}/* * Interrupt Service Routines */staticsdrestart(arg)caddr_t arg;{	struct scsi_device *devp = (struct scsi_device *) arg;	register struct buf *bp;	register s = splr(sdpri);	bp = UPTR->un_utab.b_forw;	if (bp) {		register struct scsi_pkt *pkt;		if (UPTR->un_state == SD_STATE_SENSING) {			pkt = UPTR->un_rqs;		} else {			pkt = BP_PKT(bp);		}		bp->b_resid = 0;		if (pkt_transport(pkt) != TRAN_ACCEPT) {			sdlog(devp, LOG_ERR, "sdrestart transport failed");			UPTR->un_state = UPTR->un_last_state;			bp->b_resid = bp->b_bcount;			bp->b_flags |= B_ERROR;			sddone(devp);		}	}	(void) splx(s);}/* * Command completion processing */static voidsdintr(pkt)struct scsi_pkt *pkt;{	register struct scsi_device *devp;	register struct scsi_disk *un;	register struct buf *bp;	register action;	bp = (struct buf *) pkt->pkt_private;	devp = sdunits[SDUNIT(bp->b_dev)];	un = UPTR;	DPRINTF(devp, "sdintr");	if (pkt->pkt_reason != CMD_CMPLT) {		action = sd_handle_incomplete(devp);	} else if (un->un_state == SD_STATE_SENSING) {		/*		 * We were running a REQUEST SENSE. Find out what to do next.		 */		Restore_state(un);		pkt = BP_PKT(bp);		action = sd_handle_sense(devp);	} else {		/*		 * Okay, we weren't running a REQUEST SENSE. Call a routine		 * to see if the status bits we're okay. As a side effect,		 * clear state for this device, set non-error b_resid values,		 * etc. If a request sense is to be run, that will happen by		 * sd_check_error() returning a QUE_SENSE action.		 */		action = sd_check_error(devp);	}	/*	 * If a WRITE command is completing, and we're s'posed to verify	 * that it worked okay, we call make_sd_cmd() again here. make_sd_cmd()	 * will note that we've already gotten resources and that the current	 * command is a WRITE command that needs to be turned into a VERIFY	 * command.	 *	 * If a VERIFY command fails with KEY_MISCOMPARE, sd_handle_sense	 * will convert the VERIFY back to a WRITE (by calling make_sd_cmd()	 * again) and retry the the WRITE (modulo retries being exhausted).	 *	 */	if (action == COMMAND_DONE && bp != un->un_sbufp &&	    (bp->b_flags & B_READ) == 0) {		if (un->un_wchkmap & (1<<SDPART(bp->b_dev))) {			if (pkt->pkt_cdbp[0] == SCMD_WRITE ||			    pkt->pkt_cdbp[0] == SCMD_WRITE_G1) {				action = QUE_COMMAND;				make_sd_cmd(devp, bp, NULL_FUNC);			}		}	}	switch (action) {	case COMMAND_DONE_ERROR:error:		un->un_err_severe = DK_FATAL;		un->un_err_resid = bp->b_resid = bp->b_bcount;		bp->b_flags |= B_ERROR;		/* FALL THRU */	case COMMAND_DONE:		sddone(devp);		break;	case QUE_SENSE:		New_state(un, SD_STATE_SENSING);		un->un_rqs->pkt_private = (opaque_t) bp;		bzero((caddr_t)devp->sd_sense, SENSE_LENGTH);		if (pkt_transport(un->un_rqs) != TRAN_ACCEPT) {			sdlog(devp, LOG_ERR,			    "transport of request sense fails");			Restore_state(un);			goto error;		}		break;	case QUE_COMMAND:		if (pkt_transport(BP_PKT(bp)) != TRAN_ACCEPT) {			sdlog(devp, LOG_ERR, "requeue of command fails");			un->un_err_resid = bp->b_resid = bp->b_bcount;			bp->b_flags |= B_ERROR;			sddone(devp);		}		break;	case JUST_RETURN:		break;	}}static intsd_handle_incomplete(devp)register struct scsi_device *devp;{	static char *fail = "SCSI transport failed: reason '%s': %s";	static char *notresp = "disk not responding to selection";	register rval = COMMAND_DONE_ERROR;	register struct scsi_disk *un = UPTR;	register struct buf *bp = un->un_utab.b_forw;	register struct scsi_pkt *pkt = BP_PKT(bp);	int be_chatty = (bp != un->un_sbufp || !(un->un_soptions & DK_SILENT));	int perr = (pkt->pkt_statistics & STAT_PERR);	if (un->un_state == SD_STATE_SENSING) {		pkt = un->un_rqs;		Restore_state(un);	} else if (un->un_state == SD_STATE_DUMPING) {		return (rval);	}	if (pkt->pkt_reason == CMD_TIMEOUT) {		/*		 * If the command timed out, we must assume that		 * the target may still be running that command,		 * so we should try and reset that target.		 */		if (scsi_reset(ROUTE, RESET_TARGET) == 0) {			(void) scsi_reset(ROUTE, RESET_ALL);		}	} else if (pkt->pkt_reason == CMD_UNX_BUS_FREE) {		/*		 * If we had a parity error that caused the target to		 * drop BSY*, don't be chatty about it.		 */		if (perr && be_chatty)			be_chatty = 0;	}	/*	 * If we were running a request sense, try it again if possible.	 */	if (pkt == un->un_rqs) {		if (un->un_retry_ct++ < sd_retry_count) {			rval = QUE_SENSE;		}	} else if (bp == un->un_sbufp && (un->un_soptions & DK_ISOLATE)) {		rval = COMMAND_DONE_ERROR;	} else if (un->un_retry_ct++ < sd_retry_count) {		rval = QUE_COMMAND;	}	if (pkt->pkt_state == STATE_GOT_BUS && rval == COMMAND_DONE_ERROR) {		/*		 * Looks like someone turned off this shoebox.		 */		sdlog(devp, LOG_ERR, notresp);		New_state(un, SD_STATE_DETACHING);	} else if (be_chatty) {		sdlog(devp, LOG_ERR, fail, scsi_rname(pkt->pkt_reason),		    (rval == COMMAND_DONE_ERROR) ?		    "giving up": "retrying command");	}	return (rval);}static intsd_handle_sense(devp)register struct scsi_device *devp;{	register struct scsi_disk *un = UPTR;	register struct buf *bp = un->un_utab.b_forw;	struct scsi_pkt *pkt = BP_PKT(bp), *rqpkt = un->un_rqs;	register rval = COMMAND_DONE_ERROR;	int severity, amt, i;	char *p;	static char *hex = " 0x%x";	char *rq_err_msg;	if (SCBP(rqpkt)->sts_busy) {		sdlog (devp, LOG_ERR, "Busy Status on REQUEST SENSE");		if (un->un_retry_ct++ < sd_retry_count) {			timeout (sdrestart, (caddr_t)devp, SD_BSY_TIMEOUT);			rval = JUST_RETURN;		}		return (rval);	}	if (SCBP_C(rqpkt)) {		rq_err_msg = "Check Condition on REQUEST SENSE";sense_failed:		/*		 * If the request sense failed, for any of a number		 * of reasons, allow the original command to be		 * retried.  Only log error on our last gasp.		 */		if (un->un_retry_ct++ < sd_retry_count) {			un->un_err_severe = DK_NOERROR;			rval = QUE_COMMAND;		} else {			if (rq_err_msg) {				sdlog (devp, LOG_ERR, rq_err_msg);			}			un->un_err_severe = DK_FATAL;			rval = COMMAND_DONE_ERROR;		}		return (rval);	}	amt = SENSE_LENGTH - rqpkt->pkt_resid;	if ((rqpkt->pkt_state & STATE_XFERRED_DATA) == 0 || amt == 0) {		rq_err_msg = "Request Sense couldn't get sense data";		goto sense_failed;	}	/*	 * Now, check to see whether we got enough sense data to make any	 * sense out if it (heh-heh).	 */	if (amt < SUN_MIN_SENSE_LENGTH) {		rq_err_msg = "Not enough sense information";		goto sense_failed;	}	if (devp->sd_sense->es_class != CLASS_EXTENDED_SENSE) {#ifdef	ADAPTEC		if (un->un_dp->ctype == CTYPE_ACB4000) {			sdintr_adaptec(devp);		} else#endif	/* ADAPTEC */		{			auto char tmp[8];			auto char buf[128];			p = (char *) devp->sd_sense;			(void) strcpy(buf, "undecodable sense information:");			for (i = 0; i < amt; i++) {				(void) sprintf(tmp, hex, *(p++)&0xff);				(void) strcpy(&buf[strlen(buf)], tmp);			}			sdlog(devp, LOG_ERR, buf);			rq_err_msg = NULL;			goto sense_failed;		}	}	un->un_status = devp->sd_sense->es_key;	un->un_err_code = devp->sd_sense->es_code;	if (devp->sd_sense->es_valid) {		un->un_err_blkno =	(devp->sd_sense->es_info_1 << 24) |					(devp->sd_sense->es_info_2 << 16) |					(devp->sd_sense->es_info_3 << 8)  |					(devp->sd_sense->es_info_4);	} else {		/*		 * With the valid bit not being set, we have		 * to figure out by hand as close as possible		 * what the real block number might have been		 */		un->un_err_blkno = bp->b_blkno;		if (un->un_gvalid) {			struct dk_map *lp = &un->un_map[SDPART(bp->b_dev)];			un->un_err_blkno = dkblock(bp) +			    (lp->dkl_cylno * un->un_g.dkg_nhead *			    un->un_g.dkg_nsect);		}	}	if (DEBUGGING_ALL || sd_error_level == SDERR_ALL) {		printf("%s%d: cmd:", DNAME, DUNIT);		p = pkt->pkt_cdbp;		for (i = 0; i < CDB_SIZE; i++)			printf(hex, *(p++)&0xff);		p = (char *) devp->sd_sense;		printf("\nsdata:");		for (i = 0; i < amt; i++) {			printf(hex, *(p++)&0xff);		}		printf("\n");	}	switch (un->un_status) {	case KEY_NOT_READY:		/*		 * If we get a not-ready indication, wait a bit and		 * try it again. Some drives pump this out for about		 * 2-3 seconds after a reset.		 */		if (un->un_retry_ct++ < sd_retry_count) {			un->un_err_severe = DK_NOERROR;			severity = SDERR_RETRYABLE;			timeout(sdrestart, (caddr_t)devp, SD_BSY_TIMEOUT);			rval = JUST_RETURN;		} else {			un->un_err_severe = DK_FATAL;			rval = COMMAND_DONE_ERROR;			severity = SDERR_FATAL;		}		break;	case KEY_NO_SENSE:		if (un->un_retry_ct++ < sd_retry_count) {			un->un_err_severe = DK_NOERROR;			severity = SDERR_RETRYABLE;			rval = QUE_COMMAND;		} else {			un->un_err_severe = DK_FATAL;			rval = COMMAND_DONE_ERROR;			severity = SDERR_FATAL;		}		break;	case KEY_RECOVERABLE_ERROR:		un->un_err_severe = DK_CORRECTED;		severity = SDERR_RECOVERED;		rval = COMMAND_DONE;		break;	case KEY_MEDIUM_ERROR:		/*		 * This really ought to be a fatal error, but we'll retry		 * it upon a read, as some drives seem to report spurious		 * media errors.		 */		if (bp != un->un_sbufp && (bp->b_flags & B_READ) != 0) {			if (un->un_retry_ct++ < sd_retry_count) {				rval = QUE_COMMAND;				severity = SDERR_RETRYABLE;				break;			}		}		/* FALLTHROUGH */	case KEY_HARDWARE_ERROR:	case KEY_VOLUME_OVERFLOW:	case KEY_WRITE_PROTECT:	case KEY_BLANK_CHECK:totally_bad:		un->un_err_severe = DK_FATAL;		severity = SDERR_FATAL;		rval = COMMAND_DONE_ERROR;		break;	case KEY_ILLEGAL_REQUEST:		/*		 * If the command is a VERIFY command that the drive		 * apparently doesn't support, whine to

⌨️ 快捷键说明

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