scsi_pt.c

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

C
748
字号
/* * Implementation of SCSI Processor Target Peripheral driver for CAM. * * Copyright (c) 1998 Justin T. Gibbs. * All rights reserved. * * 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, *    without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * *      $Id: scsi_pt.c,v 1.4.2.2 1999/05/09 01:27:42 ken Exp $ */#include <sys/param.h>#include <sys/queue.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/types.h>#include <sys/buf.h>#include <sys/devicestat.h>#include <sys/malloc.h>#include <sys/conf.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_extend.h>#include <cam/cam_periph.h>#include <cam/cam_xpt_periph.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_pt.h>typedef enum {	PT_STATE_PROBE,	PT_STATE_NORMAL} pt_state;typedef enum {	PT_FLAG_NONE		= 0x00,	PT_FLAG_OPEN		= 0x01,	PT_FLAG_DEVICE_INVALID	= 0x02,	PT_FLAG_RETRY_UA	= 0x04} pt_flags;typedef enum {	PT_CCB_BUFFER_IO	= 0x01,	PT_CCB_WAITING		= 0x02,	PT_CCB_RETRY_UA		= 0x04,	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA} pt_ccb_state;/* Offsets into our private area for storing information */#define ccb_state	ppriv_field0#define ccb_bp		ppriv_ptr1struct pt_softc {	struct	 buf_queue_head buf_queue;	struct	 devstat device_stats;	LIST_HEAD(, ccb_hdr) pending_ccbs;	pt_state state;	pt_flags flags;		union	 ccb saved_ccb;};static	d_open_t	ptopen;static	d_read_t	ptread;static	d_write_t	ptwrite;static	d_close_t	ptclose;static	d_strategy_t	ptstrategy;static	periph_init_t	ptinit;static	void		ptasync(void *callback_arg, u_int32_t code,				struct cam_path *path, void *arg);static	periph_ctor_t	ptctor;static	periph_oninv_t	ptoninvalidate;static	periph_dtor_t	ptdtor;static	periph_start_t	ptstart;static	void		ptdone(struct cam_periph *periph,			       union ccb *done_ccb);static  int		pterror(union ccb *ccb, u_int32_t cam_flags,				u_int32_t sense_flags);void	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,			  void (*cbfcnp)(struct cam_periph *, union ccb *),			  u_int tag_action, int readop, u_int byte2,			  u_int32_t xfer_len, u_int8_t *data_ptr,			  u_int8_t sense_len, u_int32_t timeout);static struct periph_driver ptdriver ={	ptinit, "pt",	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0};DATA_SET(periphdriver_set, ptdriver);#define PT_CDEV_MAJOR 61static struct cdevsw pt_cdevsw = {	/*d_open*/	ptopen,	/*d_close*/	ptclose,	/*d_read*/	ptread,	/*d_write*/	ptwrite,	/*d_ioctl*/	noioctl,	/*d_stop*/	nostop,	/*d_reset*/	noreset,	/*d_devtotty*/	nodevtotty,	/*d_poll*/	seltrue,	/*d_mmap*/	nommap,	/*d_strategy*/	ptstrategy,	/*d_name*/	"pt",	/*d_spare*/	NULL,	/*d_maj*/	-1,	/*d_dump*/	nodump,	/*d_psize*/	nopsize,	/*d_flags*/	0,	/*d_maxio*/	0,	/*b_maj*/	-1};static struct extend_array *ptperiphs;static intptopen(dev_t dev, int flags, int fmt, struct proc *p){	struct cam_periph *periph;	struct pt_softc *softc;	int unit;	int error;	int s;	unit = minor(dev);	periph = cam_extend_get(ptperiphs, unit);	if (periph == NULL)		return (ENXIO);		softc = (struct pt_softc *)periph->softc;	s = splsoftcam();	if (softc->flags & PT_FLAG_DEVICE_INVALID) {		splx(s);		return(ENXIO);	}	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,	    ("ptopen: dev=0x%x (unit %d)\n", dev, unit));	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {		splx(s);		return (error); /* error code from tsleep */	}	splx(s);	if ((softc->flags & PT_FLAG_OPEN) == 0) {		if (cam_periph_acquire(periph) != CAM_REQ_CMP)			error = ENXIO;		else			softc->flags |= PT_FLAG_OPEN;	} else		error = EBUSY;	cam_periph_unlock(periph);	return (error);}static intptclose(dev_t dev, int flag, int fmt, struct proc *p){	struct	cam_periph *periph;	struct	pt_softc *softc;	int	unit;	int	error;	unit = minor(dev);	periph = cam_extend_get(ptperiphs, unit);	if (periph == NULL)		return (ENXIO);		softc = (struct pt_softc *)periph->softc;	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)		return (error); /* error code from tsleep */	softc->flags &= ~PT_FLAG_OPEN;	cam_periph_unlock(periph);	cam_periph_release(periph);	return (0);}static intptread(dev_t dev, struct uio *uio, int ioflag){	return(physio(ptstrategy, NULL, dev, 1, minphys, uio));}static intptwrite(dev_t dev, struct uio *uio, int ioflag){	return(physio(ptstrategy, 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 voidptstrategy(struct buf *bp){	struct cam_periph *periph;	struct pt_softc *softc;	u_int  unit;	int    s;		unit = minor(bp->b_dev);	periph = cam_extend_get(ptperiphs, unit);	if (periph == NULL) {		bp->b_error = ENXIO;		goto bad;			}	softc = (struct pt_softc *)periph->softc;	/*	 * 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();		/*	 * If the device has been made invalid, error out	 */	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {		splx(s);		bp->b_error = ENXIO;		goto bad;	}		/*	 * Place it in the queue of disk activities for this disk	 */	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);}static voidptinit(void){	cam_status status;	struct cam_path *path;	/*	 * Create our extend array for storing the devices we attach to.	 */	ptperiphs = cam_extend_new();	if (ptperiphs == NULL) {		printf("pt: Failed to alloc extend array!\n");		return;	}		/*	 * Install a global async callback.  This callback will	 * receive async callbacks like "new device found".	 */	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);	if (status == CAM_REQ_CMP) {		struct ccb_setasync csa;                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);                csa.ccb_h.func_code = XPT_SASYNC_CB;                csa.event_enable = AC_FOUND_DEVICE;                csa.callback = ptasync;                csa.callback_arg = NULL;                xpt_action((union ccb *)&csa);		status = csa.ccb_h.status;                xpt_free_path(path);        }	if (status != CAM_REQ_CMP) {		printf("pt: Failed to attach master async callback "		       "due to status 0x%x!\n", status);	} else {		/* If we were successfull, register our devsw */		dev_t dev;		dev = makedev(PT_CDEV_MAJOR, 0);		cdevsw_add(&dev,&pt_cdevsw, NULL);	}}static cam_statusptctor(struct cam_periph *periph, void *arg){	struct pt_softc *softc;	struct ccb_setasync csa;	struct ccb_getdev *cgd;	cgd = (struct ccb_getdev *)arg;	if (periph == NULL) {		printf("ptregister: periph was NULL!!\n");		return(CAM_REQ_CMP_ERR);	}	if (cgd == NULL) {		printf("ptregister: no getdev CCB, can't register device\n");		return(CAM_REQ_CMP_ERR);	}	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);	if (softc == NULL) {		printf("daregister: Unable to probe new device. "		       "Unable to allocate softc\n");						return(CAM_REQ_CMP_ERR);	}	bzero(softc, sizeof(*softc));	LIST_INIT(&softc->pending_ccbs);	softc->state = PT_STATE_NORMAL;	bufq_init(&softc->buf_queue);	periph->softc = softc;		cam_extend_set(ptperiphs, periph->unit_number, periph);	/*	 * The DA driver supports a blocksize, but	 * we don't know the blocksize until we do 	 * a read capacity.  So, set a flag to	 * indicate that the blocksize is 	 * unavailable right now.  We'll clear the	 * flag as soon as we've done a read capacity.	 */	devstat_add_entry(&softc->device_stats, "pt",			  periph->unit_number, 0,			  DEVSTAT_NO_BLOCKSIZE,

⌨️ 快捷键说明

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