scsi_ch.c

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

C
1,716
字号
/* * Copyright (c) 1997 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_ch.c,v 1.9.2.2 1999/05/09 01:27:36 ken Exp $ *//* * Derived from the NetBSD SCSI changer driver. * *	$NetBSD: ch.c,v 1.32 1998/01/12 09:49:12 thorpej Exp $ * *//* * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com> * All rights reserved. * * Partially based on an autochanger driver written by Stefan Grefen * and on an autochanger driver written by the Systems Programming Group * at the University of Utah Computer Science Department. * * 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. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgements: *	This product includes software developed by Jason R. Thorpe *	for And Communications, http://www.and.com/ * 4. 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 ``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 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. */#include <sys/param.h>#include <sys/queue.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/types.h>#include <sys/dkbad.h>#include <sys/malloc.h>#include <sys/fcntl.h>#include <sys/stat.h>#include <sys/conf.h>#include <sys/buf.h>#include <sys/chio.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_queue.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_ch.h>/* * Timeout definitions for various changer related commands.  They may * be too short for some devices (especially the timeout for INITIALIZE * ELEMENT STATUS). */static const u_int32_t	CH_TIMEOUT_MODE_SENSE                = 6000;static const u_int32_t	CH_TIMEOUT_MOVE_MEDIUM               = 100000;static const u_int32_t	CH_TIMEOUT_EXCHANGE_MEDIUM           = 100000;static const u_int32_t	CH_TIMEOUT_POSITION_TO_ELEMENT       = 100000;static const u_int32_t	CH_TIMEOUT_READ_ELEMENT_STATUS       = 10000;static const u_int32_t	CH_TIMEOUT_SEND_VOLTAG		     = 10000;static const u_int32_t	CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;typedef enum {	CH_FLAG_INVALID		= 0x001,	CH_FLAG_OPEN		= 0x002} ch_flags;typedef enum {	CH_STATE_PROBE,	CH_STATE_NORMAL} ch_state;typedef enum {	CH_CCB_PROBE,	CH_CCB_WAITING} ch_ccb_types;typedef enum {	CH_Q_NONE	= 0x00,	CH_Q_NO_DBD	= 0x01} ch_quirks;#define ccb_state	ppriv_field0#define ccb_bp		ppriv_ptr1struct scsi_mode_sense_data {	struct scsi_mode_header_6 header;	struct scsi_mode_blk_desc blk_desc;	union {		struct page_element_address_assignment ea;		struct page_transport_geometry_parameters tg;		struct page_device_capabilities cap;	} pages;};struct ch_softc {	ch_flags	flags;	ch_state	state;	ch_quirks	quirks;	union ccb	saved_ccb;	struct devstat	device_stats;	int		sc_picker;	/* current picker */	/*	 * The following information is obtained from the	 * element address assignment page.	 */	int		sc_firsts[4];	/* firsts, indexed by CHET_* */	int		sc_counts[4];	/* counts, indexed by CHET_* */	/*	 * The following mask defines the legal combinations	 * of elements for the MOVE MEDIUM command.	 */	u_int8_t	sc_movemask[4];	/*	 * As above, but for EXCHANGE MEDIUM.	 */	u_int8_t	sc_exchangemask[4];	/*	 * Quirks; see below.  XXX KDM not implemented yet	 */	int		sc_settledelay;	/* delay for settle */};#define CHUNIT(x)       (minor((x)))#define CH_CDEV_MAJOR	17static	d_open_t	chopen;static	d_close_t	chclose;static	d_ioctl_t	chioctl;static	periph_init_t	chinit;static  periph_ctor_t	chregister;static	periph_oninv_t	choninvalidate;static  periph_dtor_t   chcleanup;static  periph_start_t  chstart;static	void		chasync(void *callback_arg, u_int32_t code,				struct cam_path *path, void *arg);static	void		chdone(struct cam_periph *periph,			       union ccb *done_ccb);static	int		cherror(union ccb *ccb, u_int32_t cam_flags,				u_int32_t sense_flags);static	int		chmove(struct cam_periph *periph,			       struct changer_move *cm);static	int		chexchange(struct cam_periph *periph,				   struct changer_exchange *ce);static	int		chposition(struct cam_periph *periph,				   struct changer_position *cp);static	int		chgetelemstatus(struct cam_periph *periph,				struct changer_element_status_request *csr);static	int		chsetvoltag(struct cam_periph *periph,				    struct changer_set_voltag_request *csvr);static	int		chielem(struct cam_periph *periph, 				unsigned int timeout);static	int		chgetparams(struct cam_periph *periph);static struct periph_driver chdriver ={	chinit, "ch",	TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0};DATA_SET(periphdriver_set, chdriver);static struct cdevsw ch_cdevsw = {	/*d_open*/	chopen,	/*d_close*/	chclose,	/*d_read*/	noread,	/*d_write*/	nowrite,	/*d_ioctl*/	chioctl,	/*d_stop*/	nostop,	/*d_reset*/	noreset,	/*d_devtotty*/	nodevtotty,	/*d_poll*/	seltrue,	/*d_mmap*/	nommap,	/*d_strategy*/	nostrategy,	/*d_name*/	"ch",	/*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 *chperiphs;voidchinit(void){	cam_status status;	struct cam_path *path;	/*	 * Create our extend array for storing the devices we attach to.	 */	chperiphs = cam_extend_new();	if (chperiphs == NULL) {		printf("ch: 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 = chasync;                csa.callback_arg = NULL;                xpt_action((union ccb *)&csa);		status = csa.ccb_h.status;                xpt_free_path(path);        }	if (status != CAM_REQ_CMP) {		printf("ch: 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(CH_CDEV_MAJOR, 0);		cdevsw_add(&dev, &ch_cdevsw, NULL);	}}static voidchoninvalidate(struct cam_periph *periph){	struct ch_softc *softc;	struct ccb_setasync csa;	softc = (struct ch_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 = chasync;	csa.callback_arg = periph;	xpt_action((union ccb *)&csa);	softc->flags |= CH_FLAG_INVALID;	xpt_print_path(periph->path);	printf("lost device\n");}static voidchcleanup(struct cam_periph *periph){	struct ch_softc *softc;	softc = (struct ch_softc *)periph->softc;	devstat_remove_entry(&softc->device_stats);	cam_extend_release(chperiphs, periph->unit_number);	xpt_print_path(periph->path);	printf("removing device entry\n");	free(softc, M_DEVBUF);}static voidchasync(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;		if (cgd->pd_type != T_CHANGER)			break;		/*		 * Allocate a peripheral instance for		 * this device and start the probe		 * process.		 */		status = cam_periph_alloc(chregister, choninvalidate,					  chcleanup, chstart, "ch",					  CAM_PERIPH_BIO, cgd->ccb_h.path,					  chasync, AC_FOUND_DEVICE, cgd);		if (status != CAM_REQ_CMP		 && status != CAM_REQ_INPROG)			printf("chasync: Unable to probe 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_statuschregister(struct cam_periph *periph, void *arg){	struct ch_softc *softc;	struct ccb_setasync csa;	struct ccb_getdev *cgd;	cgd = (struct ccb_getdev *)arg;	if (periph == NULL) {		printf("chregister: periph was NULL!!\n");		return(CAM_REQ_CMP_ERR);	}	if (cgd == NULL) {		printf("chregister: no getdev CCB, can't register device\n");		return(CAM_REQ_CMP_ERR);	}	softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);	if (softc == NULL) {		printf("chregister: Unable to probe new device. "		       "Unable to allocate softc\n");						return(CAM_REQ_CMP_ERR);	}	bzero(softc, sizeof(*softc));	softc->state = CH_STATE_PROBE;	periph->softc = softc;	cam_extend_set(chperiphs, periph->unit_number, periph);	softc->quirks = CH_Q_NONE;	/*	 * Changers don't have a blocksize, and obviously don't support	 * tagged queueing.	 */	devstat_add_entry(&softc->device_stats, "ch",			  periph->unit_number, 0,			  DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,			  cgd->pd_type | DEVSTAT_TYPE_IF_SCSI,			  DEVSTAT_PRIORITY_OTHER);	/*	 * 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 = chasync;	csa.callback_arg = periph;	xpt_action((union ccb *)&csa);	/*	 * Lock this peripheral until we are setup.	 * This first call can't block	 */	(void)cam_periph_lock(periph, PRIBIO);	xpt_schedule(periph, /*priority*/5);	return(CAM_REQ_CMP);}static intchopen(dev_t dev, int flags, int fmt, struct proc *p){	struct cam_periph *periph;	struct ch_softc *softc;	int unit, error;	int s;	unit = CHUNIT(dev);	periph = cam_extend_get(chperiphs, unit);	if (periph == NULL)		return(ENXIO);	softc = (struct ch_softc *)periph->softc;	s = splsoftcam();	if (softc->flags & CH_FLAG_INVALID) {		splx(s);		return(ENXIO);	}	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {		splx(s);		return (error);	}		splx(s);	if ((softc->flags & CH_FLAG_OPEN) == 0) {		if (cam_periph_acquire(periph) != CAM_REQ_CMP)			return(ENXIO);		softc->flags |= CH_FLAG_OPEN;	}	/*	 * Load information about this changer device into the softc.	 */	if ((error = chgetparams(periph)) != 0) {		softc->flags &= ~CH_FLAG_OPEN;		cam_periph_unlock(periph);		cam_periph_release(periph);		return(error);	}	cam_periph_unlock(periph);	return(error);}static intchclose(dev_t dev, int flag, int fmt, struct proc *p){	struct	cam_periph *periph;	struct	ch_softc *softc;	int	unit, error;	error = 0;	unit = CHUNIT(dev);	periph = cam_extend_get(chperiphs, unit);	if (periph == NULL)		return(ENXIO);	softc = (struct ch_softc *)periph->softc;	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)		return(error);	softc->flags &= ~CH_FLAG_OPEN;	cam_periph_unlock(periph);	cam_periph_release(periph);	return(0);}static voidchstart(struct cam_periph *periph, union ccb *start_ccb){	struct ch_softc *softc;	int s;	softc = (struct ch_softc *)periph->softc;	switch (softc->state) {	case CH_STATE_NORMAL:	{		s = splbio();		if (periph->immediate_priority <= periph->pinfo.priority){			start_ccb->ccb_h.ccb_state = CH_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			splx(s);		break;	}	case CH_STATE_PROBE:	{		int mode_buffer_len;		void *mode_buffer;		/*		 * Include the block descriptor when calculating the mode		 * buffer length,		 */		mode_buffer_len = sizeof(struct scsi_mode_header_6) +				  sizeof(struct scsi_mode_blk_desc) +				 sizeof(struct page_element_address_assignment);		mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT);		if (mode_buffer == NULL) {			printf("chstart: couldn't malloc mode sense data\n");			break;		}		bzero(mode_buffer, mode_buffer_len);		/*		 * Get the element address assignment page.		 */		scsi_mode_sense(&start_ccb->csio,				/* retries */ 1,				/* cbfcnp */ chdone,				/* tag_action */ MSG_SIMPLE_Q_TAG,				/* dbd */ (softc->quirks & CH_Q_NO_DBD) ?					FALSE : TRUE,				/* page_code */ SMS_PAGE_CTRL_CURRENT,

⌨️ 快捷键说明

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