scsi_pass.c

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

C
861
字号
/* * Copyright (c) 1997, 1998 Justin T. Gibbs. * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. * 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_pass.c,v 1.5.2.3 1999/05/09 01:27:41 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/dkbad.h>#include <sys/disklabel.h>#include <sys/diskslice.h>#include <sys/malloc.h>#include <sys/fcntl.h>#include <sys/stat.h>#include <sys/conf.h>#include <sys/buf.h>#include <sys/proc.h>#include <sys/errno.h>#include <sys/devicestat.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_da.h>#include <cam/scsi/scsi_pass.h>typedef enum {	PASS_FLAG_OPEN			= 0x01,	PASS_FLAG_LOCKED		= 0x02,	PASS_FLAG_INVALID		= 0x04} pass_flags;typedef enum {	PASS_STATE_NORMAL} pass_state;typedef enum {	PASS_CCB_BUFFER_IO,	PASS_CCB_WAITING} pass_ccb_types;#define ccb_type	ppriv_field0#define ccb_bp		ppriv_ptr1struct pass_softc {	pass_state	state;	pass_flags	flags;	u_int8_t	pd_type;	struct		buf_queue_head buf_queue;	union ccb	saved_ccb;	struct devstat	device_stats;#ifdef DEVFS	void		*pass_devfs_token;	void		*ctl_devfs_token;#endif};#ifndef MIN#define MIN(x,y) ((x<y) ? x : y)#endif#define PASS_CDEV_MAJOR 31static	d_open_t	passopen;static	d_read_t	passread;static	d_write_t	passwrite;static	d_close_t	passclose;static	d_ioctl_t	passioctl;static	d_strategy_t	passstrategy;static	periph_init_t	passinit;static	periph_ctor_t	passregister;static	periph_oninv_t	passoninvalidate;static	periph_dtor_t	passcleanup;static	periph_start_t	passstart;static	void		passasync(void *callback_arg, u_int32_t code,				  struct cam_path *path, void *arg);static	void		passdone(struct cam_periph *periph, 				 union ccb *done_ccb);static	int		passerror(union ccb *ccb, u_int32_t cam_flags, 				  u_int32_t sense_flags);static 	int		passsendccb(struct cam_periph *periph, union ccb *ccb,				    union ccb *inccb);static struct periph_driver passdriver ={	passinit, "pass",	TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0};DATA_SET(periphdriver_set, passdriver);static struct cdevsw pass_cdevsw = {	/*d_open*/	passopen,	/*d_close*/	passclose,	/*d_read*/	passread,	/*d_write*/	passwrite,	/*d_ioctl*/	passioctl,	/*d_stop*/	nostop,	/*d_reset*/	noreset,	/*d_devtotty*/	nodevtotty,	/*d_poll*/	seltrue,	/*d_mmap*/	nommap,	/*d_strategy*/	passstrategy,	/*d_name*/	"pass",	/*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 *passperiphs;static voidpassinit(void){	cam_status status;	struct cam_path *path;	/*	 * Create our extend array for storing the devices we attach to.	 */	passperiphs = cam_extend_new();	if (passperiphs == NULL) {		printf("passm: 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 = passasync;                csa.callback_arg = NULL;                xpt_action((union ccb *)&csa);		status = csa.ccb_h.status;                xpt_free_path(path);        }	if (status != CAM_REQ_CMP) {		printf("pass: Failed to attach master async callback "		       "due to status 0x%x!\n", status);	} else {		dev_t dev;		/* If we were successfull, register our devsw */		dev = makedev(PASS_CDEV_MAJOR, 0);		cdevsw_add(&dev, &pass_cdevsw, NULL);	}	}static voidpassoninvalidate(struct cam_periph *periph){	int s;	struct pass_softc *softc;	struct buf *q_bp;	struct ccb_setasync csa;	softc = (struct pass_softc *)periph->softc;	/*	 * De-register any async callbacks.	 */	xpt_setup_ccb(&csa.ccb_h, periph->path,		      /* priority */ 5);	csa.ccb_h.func_code = XPT_SASYNC_CB;	csa.event_enable = 0;	csa.callback = passasync;	csa.callback_arg = periph;	xpt_action((union ccb *)&csa);	softc->flags |= PASS_FLAG_INVALID;	/*	 * Although the oninvalidate() routines are always called at	 * splsoftcam, we need to be at splbio() here to keep the buffer	 * queue from being modified while we traverse it.	 */	s = splbio();	/*	 * Return all queued I/O with ENXIO.	 * XXX Handle any transactions queued to the card	 *     with XPT_ABORT_CCB.	 */	while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){		bufq_remove(&softc->buf_queue, q_bp);		q_bp->b_resid = q_bp->b_bcount;		q_bp->b_error = ENXIO;		q_bp->b_flags |= B_ERROR;		biodone(q_bp);	}	splx(s);	if (bootverbose) {		xpt_print_path(periph->path);		printf("lost device\n");	}}static voidpasscleanup(struct cam_periph *periph){	struct pass_softc *softc;	softc = (struct pass_softc *)periph->softc;	devstat_remove_entry(&softc->device_stats);	cam_extend_release(passperiphs, periph->unit_number);	if (bootverbose) {		xpt_print_path(periph->path);		printf("removing device entry\n");	}	free(softc, M_DEVBUF);}static voidpassasync(void *callback_arg, u_int32_t code,	  struct cam_path *path, void *arg){	struct cam_periph *periph;	periph = (struct cam_periph *)callback_arg;	switch (code) {	case AC_FOUND_DEVICE:	{		struct ccb_getdev *cgd;		cam_status status; 		cgd = (struct ccb_getdev *)arg;		/*		 * Allocate a peripheral instance for		 * this device and start the probe		 * process.		 */		status = cam_periph_alloc(passregister, passoninvalidate,					  passcleanup, passstart, "pass",					  CAM_PERIPH_BIO, cgd->ccb_h.path,					  passasync, AC_FOUND_DEVICE, cgd);		if (status != CAM_REQ_CMP		 && status != CAM_REQ_INPROG)			printf("passasync: Unable to attach new device "				"due to status 0x%x\n", status);		break;	}	case AC_LOST_DEVICE:		cam_periph_invalidate(periph);		break;	case AC_TRANSFER_NEG:	case AC_SENT_BDR:	case AC_SCSI_AEN:	case AC_UNSOL_RESEL:	case AC_BUS_RESET:	default:		break;	}}static cam_statuspassregister(struct cam_periph *periph, void *arg){	struct pass_softc *softc;	struct ccb_setasync csa;	struct ccb_getdev *cgd;	cgd = (struct ccb_getdev *)arg;	if (periph == NULL) {		printf("passregister: periph was NULL!!\n");		return(CAM_REQ_CMP_ERR);	}	if (cgd == NULL) {		printf("passregister: no getdev CCB, can't register device\n");		return(CAM_REQ_CMP_ERR);	}	softc = (struct pass_softc *)malloc(sizeof(*softc),					    M_DEVBUF, M_NOWAIT);	if (softc == NULL) {		printf("passregister: Unable to probe new device. "		       "Unable to allocate softc\n");						return(CAM_REQ_CMP_ERR);	}	bzero(softc, sizeof(*softc));	softc->state = PASS_STATE_NORMAL;	softc->pd_type = cgd->pd_type;	bufq_init(&softc->buf_queue);	periph->softc = softc;	cam_extend_set(passperiphs, periph->unit_number, periph);	/*	 * We pass in 0 for a blocksize, since we don't 	 * know what the blocksize of this device is, if 	 * it even has a blocksize.	 */	devstat_add_entry(&softc->device_stats, "pass", periph->unit_number,			  0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,			  cgd->pd_type |			  DEVSTAT_TYPE_IF_SCSI |			  DEVSTAT_TYPE_PASS,			  DEVSTAT_PRIORITY_PASS);	/*	 * Add an async callback so that we get	 * notified if this device goes away.	 */	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);	csa.ccb_h.func_code = XPT_SASYNC_CB;	csa.event_enable = AC_LOST_DEVICE;	csa.callback = passasync;	csa.callback_arg = periph;	xpt_action((union ccb *)&csa);	if (bootverbose)		xpt_announce_periph(periph, NULL);	return(CAM_REQ_CMP);}static intpassopen(dev_t dev, int flags, int fmt, struct proc *p){	struct cam_periph *periph;	struct pass_softc *softc;	int unit, error;	int s;	error = 0; /* default to no 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;	s = splsoftcam();	if (softc->flags & PASS_FLAG_INVALID) {		splx(s);		return(ENXIO);	}	/*	 * Don't allow access when we're running at a high securelvel.	 */	if (securelevel > 1) {		splx(s);		return(EPERM);	}	/*	 * Only allow read-write access.	 */	if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {		splx(s);		return(EPERM);	}	/*	 * We don't allow nonblocking access.	 */	if ((flags & O_NONBLOCK) != 0) {		xpt_print_path(periph->path);		printf("can't do nonblocking accesss\n");		splx(s);		return(EINVAL);	}	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {		splx(s);

⌨️ 快捷键说明

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