scsi_pass.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 861 行 · 第 1/2 页

C
861
字号
		return (error);	}	splx(s);	if ((softc->flags & PASS_FLAG_OPEN) == 0) {		if (cam_periph_acquire(periph) != CAM_REQ_CMP)			return(ENXIO);		softc->flags |= PASS_FLAG_OPEN;	}	cam_periph_unlock(periph);	return (error);}static intpassclose(dev_t dev, int flag, int fmt, struct proc *p){	struct 	cam_periph *periph;	struct	pass_softc *softc;	int	unit, error;	/* unit = dkunit(dev); */	/* XXX KDM fix this */	unit = minor(dev) & 0xff;	periph = cam_extend_get(passperiphs, unit);	if (periph == NULL)		return (ENXIO);		softc = (struct pass_softc *)periph->softc;	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)		return (error);	softc->flags &= ~PASS_FLAG_OPEN;	cam_periph_unlock(periph);	cam_periph_release(periph);	return (0);}static intpassread(dev_t dev, struct uio *uio, int ioflag){	return(physio(passstrategy, NULL, dev, 1, minphys, uio));}static intpasswrite(dev_t dev, struct uio *uio, int ioflag){	return(physio(passstrategy, NULL, dev, 0, minphys, uio));}/* * Actually translate the requested transfer into one the physical driver * can understand.  The transfer is described by a buf and will include * only one physical transfer. */static voidpassstrategy(struct buf *bp){	struct cam_periph *periph;	struct pass_softc *softc;	u_int  unit;	int    s;	/*	 * The read/write interface for the passthrough driver doesn't	 * really work right now.  So, we just pass back EINVAL to tell the	 * user to go away.	 */	bp->b_error = EINVAL;	goto bad;	/* unit = dkunit(bp->b_dev); */	/* XXX KDM fix this */	unit = minor(bp->b_dev) & 0xff;	periph = cam_extend_get(passperiphs, unit);	if (periph == NULL) {		bp->b_error = ENXIO;		goto bad;	}	softc = (struct pass_softc *)periph->softc;	/*	 * Odd number of bytes or negative offset	 */	/* valid request?  */	if (bp->b_blkno < 0) {		bp->b_error = EINVAL;		goto bad;        }		/*	 * Mask interrupts so that the pack cannot be invalidated until	 * after we are in the queue.  Otherwise, we might not properly	 * clean up one of the buffers.	 */	s = splbio();		bufq_insert_tail(&softc->buf_queue, bp);	splx(s);		/*	 * Schedule ourselves for performing the work.	 */	xpt_schedule(periph, /* XXX priority */1);	return;bad:	bp->b_flags |= B_ERROR;	/*	 * Correctly set the buf to indicate a completed xfer	 */	bp->b_resid = bp->b_bcount;	biodone(bp);	return;}static voidpassstart(struct cam_periph *periph, union ccb *start_ccb){	struct pass_softc *softc;	int s;	softc = (struct pass_softc *)periph->softc;	switch (softc->state) {	case PASS_STATE_NORMAL:	{		struct buf *bp;		s = splbio();		bp = bufq_first(&softc->buf_queue);		if (periph->immediate_priority <= periph->pinfo.priority) {			start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING;						SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,					  periph_links.sle);			periph->immediate_priority = CAM_PRIORITY_NONE;			splx(s);			wakeup(&periph->ccb_list);		} else if (bp == NULL) {			splx(s);			xpt_release_ccb(start_ccb);		} else {			bufq_remove(&softc->buf_queue, bp);			devstat_start_transaction(&softc->device_stats);			/*			 * XXX JGibbs -			 * Interpret the contents of the bp as a CCB			 * and pass it to a routine shared by our ioctl			 * code and passtart.			 * For now, just biodone it with EIO so we don't			 * hang.			 */			bp->b_error = EIO;			bp->b_flags |= B_ERROR;			bp->b_resid = bp->b_bcount;			biodone(bp);			bp = bufq_first(&softc->buf_queue);			splx(s);  			xpt_action(start_ccb);		}		if (bp != NULL) {			/* Have more work to do, so ensure we stay scheduled */			xpt_schedule(periph, /* XXX priority */1);		}		break;	}	}}static voidpassdone(struct cam_periph *periph, union ccb *done_ccb){ 	struct pass_softc *softc;	struct ccb_scsiio *csio;	softc = (struct pass_softc *)periph->softc;	csio = &done_ccb->csio;	switch (csio->ccb_h.ccb_type) {	case PASS_CCB_BUFFER_IO:	{		struct buf		*bp;		cam_status		status;		u_int8_t		scsi_status;		devstat_trans_flags	ds_flags;		status = done_ccb->ccb_h.status;		scsi_status = done_ccb->csio.scsi_status;		bp = (struct buf *)done_ccb->ccb_h.ccb_bp;		/* XXX handle errors */		if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP)		  && (scsi_status == SCSI_STATUS_OK))) {			int error;						if ((error = passerror(done_ccb, 0, 0)) == ERESTART) {				/*				 * A retry was scheuled, so				 * just return.				 */				return;			}			/*			 * XXX unfreeze the queue after we complete			 * the abort process			 */			bp->b_error = error;			bp->b_flags |= B_ERROR;		}		if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)			ds_flags = DEVSTAT_READ;		else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)			ds_flags = DEVSTAT_WRITE;		else			ds_flags = DEVSTAT_NO_DATA;		devstat_end_transaction(&softc->device_stats, bp->b_bcount, 					done_ccb->csio.tag_action & 0xf, 					ds_flags);		biodone(bp);		break;	}	case PASS_CCB_WAITING:	{		/* Caller will release the CCB */		wakeup(&done_ccb->ccb_h.cbfcnp);		return;	}	}	xpt_release_ccb(done_ccb);}static intpassioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p){	struct 	cam_periph *periph;	struct	pass_softc *softc;	u_int8_t unit;	int      error;	/* unit = dkunit(dev); */	/* XXX KDM fix this */	unit = minor(dev) & 0xff;	periph = cam_extend_get(passperiphs, unit);	if (periph == NULL)		return(ENXIO);	softc = (struct pass_softc *)periph->softc;	error = 0;	switch (cmd) {	case CAMIOCOMMAND:	{		union ccb *inccb;		union ccb *ccb;		int ccb_malloced;		inccb = (union ccb *)addr;		/*		 * Some CCB types, like scan bus and scan lun can only go		 * through the transport layer device.		 */		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {			xpt_print_path(periph->path);			printf("CCB function code %#x is restricted to the "			       "XPT device\n", inccb->ccb_h.func_code);			error = ENODEV;			break;		}		/*		 * Non-immediate CCBs need a CCB from the per-device pool		 * of CCBs, which is scheduled by the transport layer.		 * Immediate CCBs and user-supplied CCBs should just be		 * malloced.		 */		if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)		 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {			ccb = cam_periph_getccb(periph,						inccb->ccb_h.pinfo.priority);			ccb_malloced = 0;		} else {			ccb = xpt_alloc_ccb();			if (ccb != NULL)				xpt_setup_ccb(&ccb->ccb_h, periph->path,					      inccb->ccb_h.pinfo.priority);			ccb_malloced = 1;		}		if (ccb == NULL) {			xpt_print_path(periph->path);			printf("unable to allocate CCB\n");			error = ENOMEM;			break;		}		error = passsendccb(periph, ccb, inccb);		if (ccb_malloced)			xpt_free_ccb(ccb);		else			xpt_release_ccb(ccb);		break;	}	default:		error = cam_periph_ioctl(periph, cmd, addr, passerror);		break;	}	return(error);}/* * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb" * should be the CCB that is copied in from the user. */static intpasssendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb){	struct pass_softc *softc;	struct cam_periph_map_info mapinfo;	int error, need_unmap;	softc = (struct pass_softc *)periph->softc;	need_unmap = 0;	/*	 * There are some fields in the CCB header that need to be	 * preserved, the rest we get from the user.	 */	xpt_merge_ccb(ccb, inccb);	/*	 * There's no way for the user to have a completion	 * function, so we put our own completion function in here.	 */	ccb->ccb_h.cbfcnp = passdone;	/*	 * We only attempt to map the user memory into kernel space	 * if they haven't passed in a physical memory pointer,	 * and if there is actually an I/O operation to perform.	 * Right now cam_periph_mapmem() only supports SCSI and device	 * match CCBs.  For the SCSI CCBs, we only pass the CCB in if	 * there's actually data to map.  cam_periph_mapmem() will do the	 * right thing, even if there isn't data to map, but since CCBs	 * without data are a reasonably common occurance (e.g. test unit	 * ready), it will save a few cycles if we check for it here.	 */	if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)	 && (((ccb->ccb_h.func_code == XPT_SCSI_IO)	    && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))	  || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {		bzero(&mapinfo, sizeof(mapinfo));		error = cam_periph_mapmem(ccb, &mapinfo); 		/*		 * cam_periph_mapmem returned an error, we can't continue.		 * Return the error to the user.		 */		if (error)			return(error);		/*		 * We successfully mapped the memory in, so we need to		 * unmap it when the transaction is done.		 */		need_unmap = 1;	}	/*	 * If the user wants us to perform any error recovery, then honor	 * that request.  Otherwise, it's up to the user to perform any	 * error recovery.	 */	error = cam_periph_runccb(ccb,				  (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?				  passerror : NULL,				  /* cam_flags */ 0,				  /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO,				  &softc->device_stats);	if (need_unmap != 0)		cam_periph_unmapmem(ccb, &mapinfo);	ccb->ccb_h.cbfcnp = NULL;	ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;	bcopy(ccb, inccb, sizeof(union ccb));	return(error);}static intpasserror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags){	struct cam_periph *periph;	struct pass_softc *softc;	periph = xpt_path_periph(ccb->ccb_h.path);	softc = (struct pass_softc *)periph->softc;		return(cam_periph_error(ccb, cam_flags, sense_flags, 				 &softc->saved_ccb));}

⌨️ 快捷键说明

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