File:  [DragonFly] / src / sys / bus / cam / scsi / scsi_ch.c
Revision 1.8: download - view: text, annotated - select for diffs
Mon Mar 15 02:27:56 2004 UTC (10 years, 9 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Do some M_WAITOK<->M_INTWAIT cleanups.  Code entered from userland, such as
device open and device ioctl, generally use M_WAITOK, while low level
structures such as the capacity structure are allocated using M_INTWAIT.

    1: /*
    2:  * Copyright (c) 1997 Justin T. Gibbs.
    3:  * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
    4:  * All rights reserved.
    5:  *
    6:  * Redistribution and use in source and binary forms, with or without
    7:  * modification, are permitted provided that the following conditions
    8:  * are met:
    9:  * 1. Redistributions of source code must retain the above copyright
   10:  *    notice, this list of conditions, and the following disclaimer,
   11:  *    without modification, immediately at the beginning of the file.
   12:  * 2. The name of the author may not be used to endorse or promote products
   13:  *    derived from this software without specific prior written permission.
   14:  *
   15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25:  * SUCH DAMAGE.
   26:  *
   27:  * $FreeBSD: src/sys/cam/scsi/scsi_ch.c,v 1.20.2.2 2000/10/31 08:09:49 dwmalone Exp $
   28:  * $DragonFly: src/sys/bus/cam/scsi/scsi_ch.c,v 1.8 2004/03/15 02:27:56 dillon Exp $
   29:  */
   30: /*
   31:  * Derived from the NetBSD SCSI changer driver.
   32:  *
   33:  *	$NetBSD: ch.c,v 1.32 1998/01/12 09:49:12 thorpej Exp $
   34:  *
   35:  */
   36: /*
   37:  * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
   38:  * All rights reserved.
   39:  *
   40:  * Partially based on an autochanger driver written by Stefan Grefen
   41:  * and on an autochanger driver written by the Systems Programming Group
   42:  * at the University of Utah Computer Science Department.
   43:  *
   44:  * Redistribution and use in source and binary forms, with or without
   45:  * modification, are permitted provided that the following conditions
   46:  * are met:
   47:  * 1. Redistributions of source code must retain the above copyright
   48:  *    notice, this list of conditions and the following disclaimer.
   49:  * 2. Redistributions in binary form must reproduce the above copyright
   50:  *    notice, this list of conditions and the following disclaimer in the
   51:  *    documentation and/or other materials provided with the distribution.
   52:  * 3. All advertising materials mentioning features or use of this software
   53:  *    must display the following acknowledgements:
   54:  *	This product includes software developed by Jason R. Thorpe
   55:  *	for And Communications, http://www.and.com/
   56:  * 4. The name of the author may not be used to endorse or promote products
   57:  *    derived from this software without specific prior written permission.
   58:  *
   59:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   60:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   61:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   62:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   63:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   64:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   65:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   66:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   67:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   69:  * SUCH DAMAGE.
   70:  */
   71: 
   72: #include <sys/param.h>
   73: #include <sys/queue.h>
   74: #include <sys/systm.h>
   75: #include <sys/kernel.h>
   76: #include <sys/types.h>
   77: #include <sys/malloc.h>
   78: #include <sys/fcntl.h>
   79: #include <sys/stat.h>
   80: #include <sys/conf.h>
   81: #include <sys/buf.h>
   82: #include <sys/chio.h>
   83: #include <sys/errno.h>
   84: #include <sys/devicestat.h>
   85: 
   86: #include "../cam.h"
   87: #include "../cam_ccb.h"
   88: #include "../cam_extend.h"
   89: #include "../cam_periph.h"
   90: #include "../cam_xpt_periph.h"
   91: #include "../cam_queue.h"
   92: #include "../cam_debug.h"
   93: 
   94: #include "scsi_all.h"
   95: #include "scsi_message.h"
   96: #include "scsi_ch.h"
   97: 
   98: /*
   99:  * Timeout definitions for various changer related commands.  They may
  100:  * be too short for some devices (especially the timeout for INITIALIZE
  101:  * ELEMENT STATUS).
  102:  */
  103: 
  104: static const u_int32_t	CH_TIMEOUT_MODE_SENSE                = 6000;
  105: static const u_int32_t	CH_TIMEOUT_MOVE_MEDIUM               = 100000;
  106: static const u_int32_t	CH_TIMEOUT_EXCHANGE_MEDIUM           = 100000;
  107: static const u_int32_t	CH_TIMEOUT_POSITION_TO_ELEMENT       = 100000;
  108: static const u_int32_t	CH_TIMEOUT_READ_ELEMENT_STATUS       = 10000;
  109: static const u_int32_t	CH_TIMEOUT_SEND_VOLTAG		     = 10000;
  110: static const u_int32_t	CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;
  111: 
  112: typedef enum {
  113: 	CH_FLAG_INVALID		= 0x001,
  114: 	CH_FLAG_OPEN		= 0x002
  115: } ch_flags;
  116: 
  117: typedef enum {
  118: 	CH_STATE_PROBE,
  119: 	CH_STATE_NORMAL
  120: } ch_state;
  121: 
  122: typedef enum {
  123: 	CH_CCB_PROBE,
  124: 	CH_CCB_WAITING
  125: } ch_ccb_types;
  126: 
  127: typedef enum {
  128: 	CH_Q_NONE	= 0x00,
  129: 	CH_Q_NO_DBD	= 0x01
  130: } ch_quirks;
  131: 
  132: #define ccb_state	ppriv_field0
  133: #define ccb_bp		ppriv_ptr1
  134: 
  135: struct scsi_mode_sense_data {
  136: 	struct scsi_mode_header_6 header;
  137: 	struct scsi_mode_blk_desc blk_desc;
  138: 	union {
  139: 		struct page_element_address_assignment ea;
  140: 		struct page_transport_geometry_parameters tg;
  141: 		struct page_device_capabilities cap;
  142: 	} pages;
  143: };
  144: 
  145: struct ch_softc {
  146: 	ch_flags	flags;
  147: 	ch_state	state;
  148: 	ch_quirks	quirks;
  149: 	union ccb	saved_ccb;
  150: 	struct devstat	device_stats;
  151: 	dev_t		dev;
  152: 
  153: 	int		sc_picker;	/* current picker */
  154: 
  155: 	/*
  156: 	 * The following information is obtained from the
  157: 	 * element address assignment page.
  158: 	 */
  159: 	int		sc_firsts[4];	/* firsts, indexed by CHET_* */
  160: 	int		sc_counts[4];	/* counts, indexed by CHET_* */
  161: 
  162: 	/*
  163: 	 * The following mask defines the legal combinations
  164: 	 * of elements for the MOVE MEDIUM command.
  165: 	 */
  166: 	u_int8_t	sc_movemask[4];
  167: 
  168: 	/*
  169: 	 * As above, but for EXCHANGE MEDIUM.
  170: 	 */
  171: 	u_int8_t	sc_exchangemask[4];
  172: 
  173: 	/*
  174: 	 * Quirks; see below.  XXX KDM not implemented yet
  175: 	 */
  176: 	int		sc_settledelay;	/* delay for settle */
  177: };
  178: 
  179: #define CHUNIT(x)       (minor((x)))
  180: #define CH_CDEV_MAJOR	17
  181: 
  182: static	d_open_t	chopen;
  183: static	d_close_t	chclose;
  184: static	d_ioctl_t	chioctl;
  185: static	periph_init_t	chinit;
  186: static  periph_ctor_t	chregister;
  187: static	periph_oninv_t	choninvalidate;
  188: static  periph_dtor_t   chcleanup;
  189: static  periph_start_t  chstart;
  190: static	void		chasync(void *callback_arg, u_int32_t code,
  191: 				struct cam_path *path, void *arg);
  192: static	void		chdone(struct cam_periph *periph,
  193: 			       union ccb *done_ccb);
  194: static	int		cherror(union ccb *ccb, u_int32_t cam_flags,
  195: 				u_int32_t sense_flags);
  196: static	int		chmove(struct cam_periph *periph,
  197: 			       struct changer_move *cm);
  198: static	int		chexchange(struct cam_periph *periph,
  199: 				   struct changer_exchange *ce);
  200: static	int		chposition(struct cam_periph *periph,
  201: 				   struct changer_position *cp);
  202: static	int		chgetelemstatus(struct cam_periph *periph,
  203: 				struct changer_element_status_request *csr);
  204: static	int		chsetvoltag(struct cam_periph *periph,
  205: 				    struct changer_set_voltag_request *csvr);
  206: static	int		chielem(struct cam_periph *periph, 
  207: 				unsigned int timeout);
  208: static	int		chgetparams(struct cam_periph *periph);
  209: 
  210: static struct periph_driver chdriver =
  211: {
  212: 	chinit, "ch",
  213: 	TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0
  214: };
  215: 
  216: DATA_SET(periphdriver_set, chdriver);
  217: 
  218: static struct cdevsw ch_cdevsw = {
  219: 	/* name */	"ch",
  220: 	/* maj */	CH_CDEV_MAJOR,
  221: 	/* flags */	0,
  222: 	/* port */	NULL,
  223: 	/* autoq */	0,
  224: 
  225: 	/* open */	chopen,
  226: 	/* close */	chclose,
  227: 	/* read */	noread,
  228: 	/* write */	nowrite,
  229: 	/* ioctl */	chioctl,
  230: 	/* poll */	nopoll,
  231: 	/* mmap */	nommap,
  232: 	/* strategy */	nostrategy,
  233: 	/* dump */	nodump,
  234: 	/* psize */	nopsize
  235: };
  236: 
  237: static struct extend_array *chperiphs;
  238: 
  239: void
  240: chinit(void)
  241: {
  242: 	cam_status status;
  243: 	struct cam_path *path;
  244: 
  245: 	/*
  246: 	 * Create our extend array for storing the devices we attach to.
  247: 	 */
  248: 	chperiphs = cam_extend_new();
  249: 	if (chperiphs == NULL) {
  250: 		printf("ch: Failed to alloc extend array!\n");
  251: 		return;
  252: 	}
  253: 
  254: 	/*
  255: 	 * Install a global async callback.  This callback will
  256: 	 * receive async callbacks like "new device found".
  257: 	 */
  258: 	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
  259: 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  260: 
  261: 	if (status == CAM_REQ_CMP) {
  262: 		struct ccb_setasync csa;
  263: 
  264:                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
  265:                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  266:                 csa.event_enable = AC_FOUND_DEVICE;
  267:                 csa.callback = chasync;
  268:                 csa.callback_arg = NULL;
  269:                 xpt_action((union ccb *)&csa);
  270: 		status = csa.ccb_h.status;
  271:                 xpt_free_path(path);
  272:         }
  273: 
  274: 	if (status != CAM_REQ_CMP) {
  275: 		printf("ch: Failed to attach master async callback "
  276: 		       "due to status 0x%x!\n", status);
  277: 	}
  278: }
  279: 
  280: static void
  281: choninvalidate(struct cam_periph *periph)
  282: {
  283: 	struct ch_softc *softc;
  284: 	struct ccb_setasync csa;
  285: 
  286: 	softc = (struct ch_softc *)periph->softc;
  287: 
  288: 	/*
  289: 	 * De-register any async callbacks.
  290: 	 */
  291: 	xpt_setup_ccb(&csa.ccb_h, periph->path,
  292: 		      /* priority */ 5);
  293: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  294: 	csa.event_enable = 0;
  295: 	csa.callback = chasync;
  296: 	csa.callback_arg = periph;
  297: 	xpt_action((union ccb *)&csa);
  298: 
  299: 	softc->flags |= CH_FLAG_INVALID;
  300: 
  301: 	xpt_print_path(periph->path);
  302: 	printf("lost device\n");
  303: 
  304: }
  305: 
  306: static void
  307: chcleanup(struct cam_periph *periph)
  308: {
  309: 	struct ch_softc *softc;
  310: 
  311: 	softc = (struct ch_softc *)periph->softc;
  312: 
  313: 	devstat_remove_entry(&softc->device_stats);
  314: 	destroy_dev(softc->dev);
  315: 	cam_extend_release(chperiphs, periph->unit_number);
  316: 	xpt_print_path(periph->path);
  317: 	printf("removing device entry\n");
  318: 	free(softc, M_DEVBUF);
  319: }
  320: 
  321: static void
  322: chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  323: {
  324: 	struct cam_periph *periph;
  325: 
  326: 	periph = (struct cam_periph *)callback_arg;
  327: 
  328: 	switch(code) {
  329: 	case AC_FOUND_DEVICE:
  330: 	{
  331: 		struct ccb_getdev *cgd;
  332: 		cam_status status;
  333: 
  334: 		cgd = (struct ccb_getdev *)arg;
  335: 
  336: 		if (SID_TYPE(&cgd->inq_data)!= T_CHANGER)
  337: 			break;
  338: 
  339: 		/*
  340: 		 * Allocate a peripheral instance for
  341: 		 * this device and start the probe
  342: 		 * process.
  343: 		 */
  344: 		status = cam_periph_alloc(chregister, choninvalidate,
  345: 					  chcleanup, chstart, "ch",
  346: 					  CAM_PERIPH_BIO, cgd->ccb_h.path,
  347: 					  chasync, AC_FOUND_DEVICE, cgd);
  348: 
  349: 		if (status != CAM_REQ_CMP
  350: 		 && status != CAM_REQ_INPROG)
  351: 			printf("chasync: Unable to probe new device "
  352: 			       "due to status 0x%x\n", status);
  353: 
  354: 		break;
  355: 
  356: 	}
  357: 	default:
  358: 		cam_periph_async(periph, code, path, arg);
  359: 		break;
  360: 	}
  361: }
  362: 
  363: static cam_status
  364: chregister(struct cam_periph *periph, void *arg)
  365: {
  366: 	struct ch_softc *softc;
  367: 	struct ccb_setasync csa;
  368: 	struct ccb_getdev *cgd;
  369: 
  370: 	cgd = (struct ccb_getdev *)arg;
  371: 	if (periph == NULL) {
  372: 		printf("chregister: periph was NULL!!\n");
  373: 		return(CAM_REQ_CMP_ERR);
  374: 	}
  375: 
  376: 	if (cgd == NULL) {
  377: 		printf("chregister: no getdev CCB, can't register device\n");
  378: 		return(CAM_REQ_CMP_ERR);
  379: 	}
  380: 
  381: 	softc = malloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
  382: 	softc->state = CH_STATE_PROBE;
  383: 	periph->softc = softc;
  384: 	cam_extend_set(chperiphs, periph->unit_number, periph);
  385: 	softc->quirks = CH_Q_NONE;
  386: 
  387: 	/*
  388: 	 * Changers don't have a blocksize, and obviously don't support
  389: 	 * tagged queueing.
  390: 	 */
  391: 	devstat_add_entry(&softc->device_stats, "ch",
  392: 			  periph->unit_number, 0,
  393: 			  DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
  394: 			  SID_TYPE(&cgd->inq_data)| DEVSTAT_TYPE_IF_SCSI,
  395: 			  DEVSTAT_PRIORITY_OTHER);
  396: 
  397: 	/* Register the device */
  398: 	softc->dev = make_dev(&ch_cdevsw, periph->unit_number, UID_ROOT,
  399: 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
  400: 			      periph->unit_number);
  401: 
  402: 	/*
  403: 	 * Add an async callback so that we get
  404: 	 * notified if this device goes away.
  405: 	 */
  406: 	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
  407: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  408: 	csa.event_enable = AC_LOST_DEVICE;
  409: 	csa.callback = chasync;
  410: 	csa.callback_arg = periph;
  411: 	xpt_action((union ccb *)&csa);
  412: 
  413: 	/*
  414: 	 * Lock this peripheral until we are setup.
  415: 	 * This first call can't block
  416: 	 */
  417: 	(void)cam_periph_lock(periph, 0);
  418: 	xpt_schedule(periph, /*priority*/5);
  419: 
  420: 	return(CAM_REQ_CMP);
  421: }
  422: 
  423: static int
  424: chopen(dev_t dev, int flags, int fmt, struct thread *td)
  425: {
  426: 	struct cam_periph *periph;
  427: 	struct ch_softc *softc;
  428: 	int unit, error;
  429: 	int s;
  430: 
  431: 	unit = CHUNIT(dev);
  432: 	periph = cam_extend_get(chperiphs, unit);
  433: 
  434: 	if (periph == NULL)
  435: 		return(ENXIO);
  436: 
  437: 	softc = (struct ch_softc *)periph->softc;
  438: 
  439: 	s = splsoftcam();
  440: 	if (softc->flags & CH_FLAG_INVALID) {
  441: 		splx(s);
  442: 		return(ENXIO);
  443: 	}
  444: 
  445: 	if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
  446: 		splx(s);
  447: 		return (error);
  448: 	}
  449: 	
  450: 	splx(s);
  451: 
  452: 	if ((softc->flags & CH_FLAG_OPEN) == 0) {
  453: 		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  454: 			return(ENXIO);
  455: 		softc->flags |= CH_FLAG_OPEN;
  456: 	}
  457: 
  458: 	/*
  459: 	 * Load information about this changer device into the softc.
  460: 	 */
  461: 	if ((error = chgetparams(periph)) != 0) {
  462: 		softc->flags &= ~CH_FLAG_OPEN;
  463: 		cam_periph_unlock(periph);
  464: 		cam_periph_release(periph);
  465: 		return(error);
  466: 	}
  467: 
  468: 	cam_periph_unlock(periph);
  469: 
  470: 	return(error);
  471: }
  472: 
  473: static int
  474: chclose(dev_t dev, int flag, int fmt, struct thread *td)
  475: {
  476: 	struct	cam_periph *periph;
  477: 	struct	ch_softc *softc;
  478: 	int	unit, error;
  479: 
  480: 	error = 0;
  481: 
  482: 	unit = CHUNIT(dev);
  483: 	periph = cam_extend_get(chperiphs, unit);
  484: 	if (periph == NULL)
  485: 		return(ENXIO);
  486: 
  487: 	softc = (struct ch_softc *)periph->softc;
  488: 
  489: 	if ((error = cam_periph_lock(periph, 0)) != 0)
  490: 		return(error);
  491: 
  492: 	softc->flags &= ~CH_FLAG_OPEN;
  493: 
  494: 	cam_periph_unlock(periph);
  495: 	cam_periph_release(periph);
  496: 
  497: 	return(0);
  498: }
  499: 
  500: static void
  501: chstart(struct cam_periph *periph, union ccb *start_ccb)
  502: {
  503: 	struct ch_softc *softc;
  504: 	int s;
  505: 
  506: 	softc = (struct ch_softc *)periph->softc;
  507: 
  508: 	switch (softc->state) {
  509: 	case CH_STATE_NORMAL:
  510: 	{
  511: 		s = splbio();
  512: 		if (periph->immediate_priority <= periph->pinfo.priority){
  513: 			start_ccb->ccb_h.ccb_state = CH_CCB_WAITING;
  514: 
  515: 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
  516: 					  periph_links.sle);
  517: 			periph->immediate_priority = CAM_PRIORITY_NONE;
  518: 			splx(s);
  519: 			wakeup(&periph->ccb_list);
  520: 		} else
  521: 			splx(s);
  522: 		break;
  523: 	}
  524: 	case CH_STATE_PROBE:
  525: 	{
  526: 		int mode_buffer_len;
  527: 		void *mode_buffer;
  528: 
  529: 		/*
  530: 		 * Include the block descriptor when calculating the mode
  531: 		 * buffer length,
  532: 		 */
  533: 		mode_buffer_len = sizeof(struct scsi_mode_header_6) +
  534: 				  sizeof(struct scsi_mode_blk_desc) +
  535: 				 sizeof(struct page_element_address_assignment);
  536: 
  537: 		mode_buffer = malloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO);
  538: 		/*
  539: 		 * Get the element address assignment page.
  540: 		 */
  541: 		scsi_mode_sense(&start_ccb->csio,
  542: 				/* retries */ 1,
  543: 				/* cbfcnp */ chdone,
  544: 				/* tag_action */ MSG_SIMPLE_Q_TAG,
  545: 				/* dbd */ (softc->quirks & CH_Q_NO_DBD) ?
  546: 					FALSE : TRUE,
  547: 				/* page_code */ SMS_PAGE_CTRL_CURRENT,
  548: 				/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
  549: 				/* param_buf */ (u_int8_t *)mode_buffer,
  550: 				/* param_len */ mode_buffer_len,
  551: 				/* sense_len */ SSD_FULL_SIZE,
  552: 				/* timeout */ CH_TIMEOUT_MODE_SENSE);
  553: 
  554: 		start_ccb->ccb_h.ccb_bp = NULL;
  555: 		start_ccb->ccb_h.ccb_state = CH_CCB_PROBE;
  556: 		xpt_action(start_ccb);
  557: 		break;
  558: 	}
  559: 	}
  560: }
  561: 
  562: static void
  563: chdone(struct cam_periph *periph, union ccb *done_ccb)
  564: {
  565: 	struct ch_softc *softc;
  566: 	struct ccb_scsiio *csio;
  567: 
  568: 	softc = (struct ch_softc *)periph->softc;
  569: 	csio = &done_ccb->csio;
  570: 
  571: 	switch(done_ccb->ccb_h.ccb_state) {
  572: 	case CH_CCB_PROBE:
  573: 	{
  574: 		struct scsi_mode_header_6 *mode_header;
  575: 		struct page_element_address_assignment *ea;
  576: 		char announce_buf[80];
  577: 
  578: 
  579: 		mode_header = (struct scsi_mode_header_6 *)csio->data_ptr;
  580: 
  581: 		ea = (struct page_element_address_assignment *)
  582: 			find_mode_page_6(mode_header);
  583: 
  584: 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){
  585: 			
  586: 			softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
  587: 			softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
  588: 			softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
  589: 			softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
  590: 			softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
  591: 			softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
  592: 			softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
  593: 			softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
  594: 			softc->sc_picker = softc->sc_firsts[CHET_MT];
  595: 
  596: #define PLURAL(c)	(c) == 1 ? "" : "s"
  597: 			snprintf(announce_buf, sizeof(announce_buf),
  598: 				"%d slot%s, %d drive%s, "
  599: 				"%d picker%s, %d portal%s",
  600: 		    		softc->sc_counts[CHET_ST],
  601: 				PLURAL(softc->sc_counts[CHET_ST]),
  602: 		    		softc->sc_counts[CHET_DT],
  603: 				PLURAL(softc->sc_counts[CHET_DT]),
  604: 		    		softc->sc_counts[CHET_MT],
  605: 				PLURAL(softc->sc_counts[CHET_MT]),
  606: 		    		softc->sc_counts[CHET_IE],
  607: 				PLURAL(softc->sc_counts[CHET_IE]));
  608: #undef PLURAL
  609: 		} else {
  610: 			int error;
  611: 
  612: 			error = cherror(done_ccb, 0, SF_RETRY_UA |
  613: 					SF_NO_PRINT | SF_RETRY_SELTO);
  614: 			/*
  615: 			 * Retry any UNIT ATTENTION type errors.  They
  616: 			 * are expected at boot.
  617: 			 */
  618: 			if (error == ERESTART) {
  619: 				/*
  620: 				 * A retry was scheuled, so
  621: 				 * just return.
  622: 				 */
  623: 				return;
  624: 			} else if (error != 0) {
  625: 				int retry_scheduled;
  626: 				struct scsi_mode_sense_6 *sms;
  627: 
  628: 				sms = (struct scsi_mode_sense_6 *)
  629: 					done_ccb->csio.cdb_io.cdb_bytes;
  630: 
  631: 				/*
  632: 				 * Check to see if block descriptors were
  633: 				 * disabled.  Some devices don't like that.
  634: 				 * We're taking advantage of the fact that
  635: 				 * the first few bytes of the 6 and 10 byte
  636: 				 * mode sense commands are the same.  If
  637: 				 * block descriptors were disabled, enable
  638: 				 * them and re-send the command.
  639: 				 */
  640: 				if (sms->byte2 & SMS_DBD) {
  641: 					sms->byte2 &= ~SMS_DBD;
  642: 					xpt_action(done_ccb);
  643: 					softc->quirks |= CH_Q_NO_DBD;
  644: 					retry_scheduled = 1;
  645: 				} else
  646: 					retry_scheduled = 0;
  647: 
  648: 				/* Don't wedge this device's queue */
  649: 				cam_release_devq(done_ccb->ccb_h.path,
  650: 						 /*relsim_flags*/0,
  651: 						 /*reduction*/0,
  652: 						 /*timeout*/0,
  653: 						 /*getcount_only*/0);
  654: 
  655: 				if (retry_scheduled)
  656: 					return;
  657: 
  658: 				if ((done_ccb->ccb_h.status & CAM_STATUS_MASK)
  659: 				    == CAM_SCSI_STATUS_ERROR) 
  660: 					scsi_sense_print(&done_ccb->csio);
  661: 				else {
  662: 					xpt_print_path(periph->path);
  663: 					printf("got CAM status %#x\n",
  664: 					       done_ccb->ccb_h.status);
  665: 				}
  666: 				xpt_print_path(periph->path);
  667: 				printf("fatal error, failed to attach to"
  668: 				       " device\n");
  669: 
  670: 				cam_periph_invalidate(periph);
  671: 
  672: 				announce_buf[0] = '\0';
  673: 			}
  674: 		}
  675: 		if (announce_buf[0] != '\0')
  676: 			xpt_announce_periph(periph, announce_buf);
  677: 		softc->state = CH_STATE_NORMAL;
  678: 		free(mode_header, M_TEMP);
  679: 		/*
  680: 		 * Since our peripheral may be invalidated by an error
  681: 		 * above or an external event, we must release our CCB
  682: 		 * before releasing the probe lock on the peripheral.
  683: 		 * The peripheral will only go away once the last lock
  684: 		 * is removed, and we need it around for the CCB release
  685: 		 * operation.
  686: 		 */
  687: 		xpt_release_ccb(done_ccb);
  688: 		cam_periph_unlock(periph);
  689: 		return;
  690: 	}
  691: 	case CH_CCB_WAITING:
  692: 	{
  693: 		/* Caller will release the CCB */
  694: 		wakeup(&done_ccb->ccb_h.cbfcnp);
  695: 		return;
  696: 	}
  697: 	default:
  698: 		break;
  699: 	}
  700: 	xpt_release_ccb(done_ccb);
  701: }
  702: 
  703: static int
  704: cherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  705: {
  706: 	struct ch_softc *softc;
  707: 	struct cam_periph *periph;
  708: 
  709: 	periph = xpt_path_periph(ccb->ccb_h.path);
  710: 	softc = (struct ch_softc *)periph->softc;
  711: 
  712: 	return (cam_periph_error(ccb, cam_flags, sense_flags,
  713: 				 &softc->saved_ccb));
  714: }
  715: 
  716: static int
  717: chioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  718: {
  719: 	struct cam_periph *periph;
  720: 	struct ch_softc *softc;
  721: 	u_int8_t unit;
  722: 	int error;
  723: 
  724: 	unit = CHUNIT(dev);
  725: 
  726: 	periph = cam_extend_get(chperiphs, unit);
  727: 	if (periph == NULL)
  728: 		return(ENXIO);
  729: 
  730: 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n"));
  731: 
  732: 	softc = (struct ch_softc *)periph->softc;
  733: 
  734: 	error = 0;
  735: 
  736: 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
  737: 		  ("trying to do ioctl %#lx\n", cmd));
  738: 
  739: 	/*
  740: 	 * If this command can change the device's state, we must
  741: 	 * have the device open for writing.
  742: 	 */
  743: 	switch (cmd) {
  744: 	case CHIOGPICKER:
  745: 	case CHIOGPARAMS:
  746: 	case CHIOGSTATUS:
  747: 		break;
  748: 
  749: 	default:
  750: 		if ((flag & FWRITE) == 0)
  751: 			return (EBADF);
  752: 	}
  753: 
  754: 	switch (cmd) {
  755: 	case CHIOMOVE:
  756: 		error = chmove(periph, (struct changer_move *)addr);
  757: 		break;
  758: 
  759: 	case CHIOEXCHANGE:
  760: 		error = chexchange(periph, (struct changer_exchange *)addr);
  761: 		break;
  762: 
  763: 	case CHIOPOSITION:
  764: 		error = chposition(periph, (struct changer_position *)addr);
  765: 		break;
  766: 
  767: 	case CHIOGPICKER:
  768: 		*(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT];
  769: 		break;
  770: 
  771: 	case CHIOSPICKER:
  772: 	{
  773: 		int new_picker = *(int *)addr;
  774: 
  775: 		if (new_picker > (softc->sc_counts[CHET_MT] - 1))
  776: 			return (EINVAL);
  777: 		softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker;
  778: 		break;
  779: 	}
  780: 	case CHIOGPARAMS:
  781: 	{
  782: 		struct changer_params *cp = (struct changer_params *)addr;
  783: 
  784: 		cp->cp_npickers = softc->sc_counts[CHET_MT];
  785: 		cp->cp_nslots = softc->sc_counts[CHET_ST];
  786: 		cp->cp_nportals = softc->sc_counts[CHET_IE];
  787: 		cp->cp_ndrives = softc->sc_counts[CHET_DT];
  788: 		break;
  789: 	}
  790: 	case CHIOIELEM:
  791: 		error = chielem(periph, *(unsigned int *)addr);
  792: 		break;
  793: 
  794: 	case CHIOGSTATUS:
  795: 	{
  796: 		error = chgetelemstatus(periph,
  797: 			       (struct changer_element_status_request *) addr);
  798: 		break;
  799: 	}
  800: 
  801: 	case CHIOSETVOLTAG:
  802: 	{
  803: 		error = chsetvoltag(periph,
  804: 				    (struct changer_set_voltag_request *) addr);
  805: 		break;
  806: 	}
  807: 
  808: 	/* Implement prevent/allow? */
  809: 
  810: 	default:
  811: 		error = cam_periph_ioctl(periph, cmd, addr, cherror);
  812: 		break;
  813: 	}
  814: 
  815: 	return (error);
  816: }
  817: 
  818: static int
  819: chmove(struct cam_periph *periph, struct changer_move *cm)
  820: {
  821: 	struct ch_softc *softc;
  822: 	u_int16_t fromelem, toelem;
  823: 	union ccb *ccb;
  824: 	int error;
  825: 
  826: 	error = 0;
  827: 	softc = (struct ch_softc *)periph->softc;
  828: 
  829: 	/*
  830: 	 * Check arguments.
  831: 	 */
  832: 	if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  833: 		return (EINVAL);
  834: 	if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) ||
  835: 	    (cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1)))
  836: 		return (ENODEV);
  837: 
  838: 	/*
  839: 	 * Check the request against the changer's capabilities.
  840: 	 */
  841: 	if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  842: 		return (ENODEV);
  843: 
  844: 	/*
  845: 	 * Calculate the source and destination elements.
  846: 	 */
  847: 	fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  848: 	toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  849: 
  850: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
  851: 
  852: 	scsi_move_medium(&ccb->csio,
  853: 			 /* retries */ 1,
  854: 			 /* cbfcnp */ chdone,
  855: 			 /* tag_action */ MSG_SIMPLE_Q_TAG,
  856: 			 /* tea */ softc->sc_picker,
  857: 			 /* src */ fromelem,
  858: 			 /* dst */ toelem,
  859: 			 /* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE,
  860: 			 /* sense_len */ SSD_FULL_SIZE,
  861: 			 /* timeout */ CH_TIMEOUT_MOVE_MEDIUM);
  862: 
  863: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/0,
  864: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
  865: 				  &softc->device_stats);
  866: 
  867: 	xpt_release_ccb(ccb);
  868: 
  869: 	return(error);
  870: }
  871: 
  872: static int
  873: chexchange(struct cam_periph *periph, struct changer_exchange *ce)
  874: {
  875: 	struct ch_softc *softc;
  876: 	u_int16_t src, dst1, dst2;
  877: 	union ccb *ccb;
  878: 	int error;
  879: 
  880: 	error = 0;
  881: 	softc = (struct ch_softc *)periph->softc;
  882: 	/*
  883: 	 * Check arguments.
  884: 	 */
  885: 	if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  886: 	    (ce->ce_sdsttype > CHET_DT))
  887: 		return (EINVAL);
  888: 	if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) ||
  889: 	    (ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) ||
  890: 	    (ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1)))
  891: 		return (ENODEV);
  892: 
  893: 	/*
  894: 	 * Check the request against the changer's capabilities.
  895: 	 */
  896: 	if (((softc->sc_exchangemask[ce->ce_srctype] &
  897: 	     (1 << ce->ce_fdsttype)) == 0) ||
  898: 	    ((softc->sc_exchangemask[ce->ce_fdsttype] &
  899: 	     (1 << ce->ce_sdsttype)) == 0))
  900: 		return (ENODEV);
  901: 
  902: 	/*
  903: 	 * Calculate the source and destination elements.
  904: 	 */
  905: 	src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  906: 	dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  907: 	dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  908: 
  909: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
  910: 
  911: 	scsi_exchange_medium(&ccb->csio,
  912: 			     /* retries */ 1,
  913: 			     /* cbfcnp */ chdone,
  914: 			     /* tag_action */ MSG_SIMPLE_Q_TAG,
  915: 			     /* tea */ softc->sc_picker,
  916: 			     /* src */ src,
  917: 			     /* dst1 */ dst1,
  918: 			     /* dst2 */ dst2,
  919: 			     /* invert1 */ (ce->ce_flags & CE_INVERT1) ?
  920: 			                   TRUE : FALSE,
  921: 			     /* invert2 */ (ce->ce_flags & CE_INVERT2) ?
  922: 			                   TRUE : FALSE,
  923: 			     /* sense_len */ SSD_FULL_SIZE,
  924: 			     /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM);
  925: 
  926: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/0,
  927: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
  928: 				  &softc->device_stats);
  929: 
  930: 	xpt_release_ccb(ccb);
  931: 
  932: 	return(error);
  933: }
  934: 
  935: static int
  936: chposition(struct cam_periph *periph, struct changer_position *cp)
  937: {
  938: 	struct ch_softc *softc;
  939: 	u_int16_t dst;
  940: 	union ccb *ccb;
  941: 	int error;
  942: 
  943: 	error = 0;
  944: 	softc = (struct ch_softc *)periph->softc;
  945: 
  946: 	/*
  947: 	 * Check arguments.
  948: 	 */
  949: 	if (cp->cp_type > CHET_DT)
  950: 		return (EINVAL);
  951: 	if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1))
  952: 		return (ENODEV);
  953: 
  954: 	/*
  955: 	 * Calculate the destination element.
  956: 	 */
  957: 	dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit;
  958: 
  959: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
  960: 
  961: 	scsi_position_to_element(&ccb->csio,
  962: 				 /* retries */ 1,
  963: 				 /* cbfcnp */ chdone,
  964: 				 /* tag_action */ MSG_SIMPLE_Q_TAG,
  965: 				 /* tea */ softc->sc_picker,
  966: 				 /* dst */ dst,
  967: 				 /* invert */ (cp->cp_flags & CP_INVERT) ?
  968: 					      TRUE : FALSE,
  969: 				 /* sense_len */ SSD_FULL_SIZE,
  970: 				 /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT);
  971: 
  972: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
  973: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
  974: 				  &softc->device_stats);
  975: 
  976: 	xpt_release_ccb(ccb);
  977: 
  978: 	return(error);
  979: }
  980: 
  981: /*
  982:  * Copy a volume tag to a volume_tag struct, converting SCSI byte order
  983:  * to host native byte order in the volume serial number.  The volume
  984:  * label as returned by the changer is transferred to user mode as
  985:  * nul-terminated string.  Volume labels are truncated at the first
  986:  * space, as suggested by SCSI-2.
  987:  */
  988: static	void
  989: copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
  990: {
  991: 	int i;
  992: 	for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
  993: 		char c = voltag->vif[i];
  994: 		if (c && c != ' ')
  995: 			uvoltag->cv_volid[i] = c;
  996: 	        else
  997: 			break;
  998: 	}
  999: 	uvoltag->cv_serial = scsi_2btoul(voltag->vsn);
 1000: }
 1001: 
 1002: /*
 1003:  * Copy an an element status descriptor to a user-mode
 1004:  * changer_element_status structure.
 1005:  */
 1006: 
 1007: static	void
 1008: copy_element_status(struct ch_softc *softc,
 1009: 		    u_int16_t flags,
 1010: 		    struct read_element_status_descriptor *desc,
 1011: 		    struct changer_element_status *ces)
 1012: {
 1013: 	u_int16_t eaddr = scsi_2btoul(desc->eaddr);
 1014: 	u_int16_t et;
 1015: 
 1016: 	ces->ces_int_addr = eaddr;
 1017: 	/* set up logical address in element status */
 1018: 	for (et = CHET_MT; et <= CHET_DT; et++) {
 1019: 		if ((softc->sc_firsts[et] <= eaddr)
 1020: 		    && ((softc->sc_firsts[et] + softc->sc_counts[et])
 1021: 			> eaddr)) {
 1022: 			ces->ces_addr = eaddr - softc->sc_firsts[et];
 1023: 			ces->ces_type = et;
 1024: 			break;
 1025: 		}
 1026: 	}
 1027: 
 1028: 	ces->ces_flags = desc->flags1;
 1029: 
 1030: 	ces->ces_sensecode = desc->sense_code;
 1031: 	ces->ces_sensequal = desc->sense_qual;
 1032: 
 1033: 	if (desc->flags2 & READ_ELEMENT_STATUS_INVERT)
 1034: 		ces->ces_flags |= CES_INVERT;
 1035: 
 1036: 	if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
 1037: 
 1038: 		eaddr = scsi_2btoul(desc->ssea);
 1039: 
 1040: 		/* convert source address to logical format */
 1041: 		for (et = CHET_MT; et <= CHET_DT; et++) {
 1042: 			if ((softc->sc_firsts[et] <= eaddr)
 1043: 			    && ((softc->sc_firsts[et] + softc->sc_counts[et])
 1044: 				> eaddr)) {
 1045: 				ces->ces_source_addr = 
 1046: 					eaddr - softc->sc_firsts[et];
 1047: 				ces->ces_source_type = et;
 1048: 				ces->ces_flags |= CES_SOURCE_VALID;
 1049: 				break;
 1050: 			}
 1051: 		}
 1052: 
 1053: 		if (!(ces->ces_flags & CES_SOURCE_VALID))
 1054: 			printf("ch: warning: could not map element source "
 1055: 			       "address %ud to a valid element type\n",
 1056: 			       eaddr);
 1057: 	}
 1058: 			
 1059: 
 1060: 	if (flags & READ_ELEMENT_STATUS_PVOLTAG)
 1061: 		copy_voltag(&(ces->ces_pvoltag), &(desc->pvoltag));
 1062: 	if (flags & READ_ELEMENT_STATUS_AVOLTAG)
 1063: 		copy_voltag(&(ces->ces_avoltag), &(desc->avoltag));
 1064: 
 1065: 	if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) {
 1066: 		ces->ces_flags |= CES_SCSIID_VALID;
 1067: 		ces->ces_scsi_id = desc->dt_scsi_addr;
 1068: 	}
 1069: 
 1070: 	if (desc->dt_scsi_addr & READ_ELEMENT_STATUS_DT_LUVALID) {
 1071: 		ces->ces_flags |= CES_LUN_VALID;
 1072: 		ces->ces_scsi_lun = 
 1073: 			desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUNMASK;
 1074: 	}
 1075: }
 1076: 
 1077: static int
 1078: chgetelemstatus(struct cam_periph *periph, 
 1079: 		struct changer_element_status_request *cesr)
 1080: {
 1081: 	struct read_element_status_header *st_hdr;
 1082: 	struct read_element_status_page_header *pg_hdr;
 1083: 	struct read_element_status_descriptor *desc;
 1084: 	caddr_t data = NULL;
 1085: 	size_t size, desclen;
 1086: 	int avail, i, error = 0;
 1087: 	struct changer_element_status *user_data = NULL;
 1088: 	struct ch_softc *softc;
 1089: 	union ccb *ccb;
 1090: 	int chet = cesr->cesr_element_type;
 1091: 	int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
 1092: 
 1093: 	softc = (struct ch_softc *)periph->softc;
 1094: 
 1095: 	/* perform argument checking */
 1096: 
 1097: 	/*
 1098: 	 * Perform a range check on the cesr_element_{base,count}
 1099: 	 * request argument fields.
 1100: 	 */
 1101: 	if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0
 1102: 	    || (cesr->cesr_element_base + cesr->cesr_element_count)
 1103: 	        > softc->sc_counts[chet])
 1104: 		return (EINVAL);
 1105: 
 1106: 	/*
 1107: 	 * Request one descriptor for the given element type.  This
 1108: 	 * is used to determine the size of the descriptor so that
 1109: 	 * we can allocate enough storage for all of them.  We assume
 1110: 	 * that the first one can fit into 1k.
 1111: 	 */
 1112: 	data = (caddr_t)malloc(1024, M_DEVBUF, M_INTWAIT);
 1113: 
 1114: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
 1115: 
 1116: 	scsi_read_element_status(&ccb->csio,
 1117: 				 /* retries */ 1,
 1118: 				 /* cbfcnp */ chdone,
 1119: 				 /* tag_action */ MSG_SIMPLE_Q_TAG,
 1120: 				 /* voltag */ want_voltags,
 1121: 				 /* sea */ softc->sc_firsts[chet],
 1122: 				 /* count */ 1,
 1123: 				 /* data_ptr */ data,
 1124: 				 /* dxfer_len */ 1024,
 1125: 				 /* sense_len */ SSD_FULL_SIZE,
 1126: 				 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
 1127: 
 1128: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1129: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
 1130: 				  &softc->device_stats);
 1131: 
 1132: 	if (error)
 1133: 		goto done;
 1134: 
 1135: 	st_hdr = (struct read_element_status_header *)data;
 1136: 	pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
 1137: 		  sizeof(struct read_element_status_header));
 1138: 	desclen = scsi_2btoul(pg_hdr->edl);
 1139: 
 1140: 	size = sizeof(struct read_element_status_header) +
 1141: 	       sizeof(struct read_element_status_page_header) +
 1142: 	       (desclen * cesr->cesr_element_count);
 1143: 
 1144: 	/*
 1145: 	 * Reallocate storage for descriptors and get them from the
 1146: 	 * device.
 1147: 	 */
 1148: 	free(data, M_DEVBUF);
 1149: 	data = (caddr_t)malloc(size, M_DEVBUF, M_INTWAIT);
 1150: 
 1151: 	scsi_read_element_status(&ccb->csio,
 1152: 				 /* retries */ 1,
 1153: 				 /* cbfcnp */ chdone,
 1154: 				 /* tag_action */ MSG_SIMPLE_Q_TAG,
 1155: 				 /* voltag */ want_voltags,
 1156: 				 /* sea */ softc->sc_firsts[chet]
 1157: 				 + cesr->cesr_element_base,
 1158: 				 /* count */ cesr->cesr_element_count,
 1159: 				 /* data_ptr */ data,
 1160: 				 /* dxfer_len */ size,
 1161: 				 /* sense_len */ SSD_FULL_SIZE,
 1162: 				 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
 1163: 	
 1164: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1165: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
 1166: 				  &softc->device_stats);
 1167: 
 1168: 	if (error)
 1169: 		goto done;
 1170: 
 1171: 	/*
 1172: 	 * Fill in the user status array.
 1173: 	 */
 1174: 	st_hdr = (struct read_element_status_header *)data;
 1175: 	avail = scsi_2btoul(st_hdr->count);
 1176: 
 1177: 	if (avail != cesr->cesr_element_count) {
 1178: 		xpt_print_path(periph->path);
 1179: 		printf("warning, READ ELEMENT STATUS avail != count\n");
 1180: 	}
 1181: 
 1182: 	user_data = (struct changer_element_status *)
 1183: 		malloc(avail * sizeof(struct changer_element_status),
 1184: 		       M_DEVBUF, M_INTWAIT | M_ZERO);
 1185: 
 1186: 	desc = (struct read_element_status_descriptor *)((uintptr_t)data +
 1187: 		sizeof(struct read_element_status_header) +
 1188: 		sizeof(struct read_element_status_page_header));
 1189: 	/*
 1190: 	 * Set up the individual element status structures
 1191: 	 */
 1192: 	for (i = 0; i < avail; ++i) {
 1193: 		struct changer_element_status *ces = &(user_data[i]);
 1194: 
 1195: 		copy_element_status(softc, pg_hdr->flags, desc, ces);
 1196: 
 1197: 		desc = (struct read_element_status_descriptor *)
 1198: 		       ((uintptr_t)desc + desclen);
 1199: 	}
 1200: 
 1201: 	/* Copy element status structures out to userspace. */
 1202: 	error = copyout(user_data,
 1203: 			cesr->cesr_element_status,
 1204: 			avail * sizeof(struct changer_element_status));
 1205: 
 1206:  done:
 1207: 	xpt_release_ccb(ccb);
 1208: 
 1209: 	if (data != NULL)
 1210: 		free(data, M_DEVBUF);
 1211: 	if (user_data != NULL)
 1212: 		free(user_data, M_DEVBUF);
 1213: 
 1214: 	return (error);
 1215: }
 1216: 
 1217: static int
 1218: chielem(struct cam_periph *periph,
 1219: 	unsigned int timeout)
 1220: {
 1221: 	union ccb *ccb;
 1222: 	struct ch_softc *softc;
 1223: 	int error;
 1224: 
 1225: 	if (!timeout) {
 1226: 		timeout = CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS;
 1227: 	} else {
 1228: 		timeout *= 1000;
 1229: 	}
 1230: 
 1231: 	error = 0;
 1232: 	softc = (struct ch_softc *)periph->softc;
 1233: 
 1234: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
 1235: 
 1236: 	scsi_initialize_element_status(&ccb->csio,
 1237: 				      /* retries */ 1,
 1238: 				      /* cbfcnp */ chdone,
 1239: 				      /* tag_action */ MSG_SIMPLE_Q_TAG,
 1240: 				      /* sense_len */ SSD_FULL_SIZE,
 1241: 				      /* timeout */ timeout);
 1242: 
 1243: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1244: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
 1245: 				  &softc->device_stats);
 1246: 
 1247: 	xpt_release_ccb(ccb);
 1248: 
 1249: 	return(error);
 1250: }
 1251: 
 1252: static int
 1253: chsetvoltag(struct cam_periph *periph,
 1254: 	    struct changer_set_voltag_request *csvr)
 1255: {
 1256: 	union ccb *ccb;
 1257: 	struct ch_softc *softc;
 1258: 	u_int16_t ea;
 1259: 	u_int8_t sac;
 1260: 	struct scsi_send_volume_tag_parameters ssvtp;
 1261: 	int error;
 1262: 	int i;
 1263: 
 1264: 	error = 0;
 1265: 	softc = (struct ch_softc *)periph->softc;
 1266: 
 1267: 	bzero(&ssvtp, sizeof(ssvtp));
 1268: 	for (i=0; i<sizeof(ssvtp.vitf); i++) {
 1269: 		ssvtp.vitf[i] = ' ';
 1270: 	}
 1271: 
 1272: 	/*
 1273: 	 * Check arguments.
 1274: 	 */
 1275: 	if (csvr->csvr_type > CHET_DT)
 1276: 		return EINVAL;
 1277: 	if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1))
 1278: 		return ENODEV;
 1279: 
 1280: 	ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr;
 1281: 
 1282: 	if (csvr->csvr_flags & CSVR_ALTERNATE) {
 1283: 		switch (csvr->csvr_flags & CSVR_MODE_MASK) {
 1284: 		case CSVR_MODE_SET:
 1285: 			sac = SEND_VOLUME_TAG_ASSERT_ALTERNATE;
 1286: 			break;
 1287: 		case CSVR_MODE_REPLACE:
 1288: 			sac = SEND_VOLUME_TAG_REPLACE_ALTERNATE;
 1289: 			break;
 1290: 		case CSVR_MODE_CLEAR:
 1291: 			sac = SEND_VOLUME_TAG_UNDEFINED_ALTERNATE;
 1292: 			break;
 1293: 		default:
 1294: 			error = EINVAL;
 1295: 			goto out;
 1296: 		}
 1297: 	} else {
 1298: 		switch (csvr->csvr_flags & CSVR_MODE_MASK) {
 1299: 		case CSVR_MODE_SET:
 1300: 			sac = SEND_VOLUME_TAG_ASSERT_PRIMARY;
 1301: 			break;
 1302: 		case CSVR_MODE_REPLACE:
 1303: 			sac = SEND_VOLUME_TAG_REPLACE_PRIMARY;
 1304: 			break;
 1305: 		case CSVR_MODE_CLEAR:
 1306: 			sac = SEND_VOLUME_TAG_UNDEFINED_PRIMARY;
 1307: 			break;
 1308: 		default:
 1309: 			error = EINVAL;
 1310: 			goto out;
 1311: 		}
 1312: 	}
 1313: 
 1314: 	memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid,
 1315: 	       min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf)));
 1316: 	scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn);
 1317: 
 1318: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
 1319: 
 1320: 	scsi_send_volume_tag(&ccb->csio,
 1321: 			     /* retries */ 1,
 1322: 			     /* cbfcnp */ chdone,
 1323: 			     /* tag_action */ MSG_SIMPLE_Q_TAG,
 1324: 			     /* element_address */ ea,
 1325: 			     /* send_action_code */ sac,
 1326: 			     /* parameters */ &ssvtp,
 1327: 			     /* sense_len */ SSD_FULL_SIZE,
 1328: 			     /* timeout */ CH_TIMEOUT_SEND_VOLTAG);
 1329: 	
 1330: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1331: 				  /*sense_flags*/ SF_RETRY_UA | SF_RETRY_SELTO,
 1332: 				  &softc->device_stats);
 1333: 
 1334: 	xpt_release_ccb(ccb);
 1335: 
 1336:  out:
 1337: 	return error;
 1338: }
 1339: 
 1340: static int
 1341: chgetparams(struct cam_periph *periph)
 1342: {
 1343: 	union ccb *ccb;
 1344: 	struct ch_softc *softc;
 1345: 	void *mode_buffer;
 1346: 	int mode_buffer_len;
 1347: 	struct page_element_address_assignment *ea;
 1348: 	struct page_device_capabilities *cap;
 1349: 	int error, from, dbd;
 1350: 	u_int8_t *moves, *exchanges;
 1351: 
 1352: 	error = 0;
 1353: 
 1354: 	softc = (struct ch_softc *)periph->softc;
 1355: 
 1356: 	ccb = cam_periph_getccb(periph, /*priority*/ 1);
 1357: 
 1358: 	/*
 1359: 	 * The scsi_mode_sense_data structure is just a convenience
 1360: 	 * structure that allows us to easily calculate the worst-case
 1361: 	 * storage size of the mode sense buffer.
 1362: 	 */
 1363: 	mode_buffer_len = sizeof(struct scsi_mode_sense_data);
 1364: 
 1365: 	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO);
 1366: 
 1367: 	if (softc->quirks & CH_Q_NO_DBD)
 1368: 		dbd = FALSE;
 1369: 	else
 1370: 		dbd = TRUE;
 1371: 
 1372: 	/*
 1373: 	 * Get the element address assignment page.
 1374: 	 */
 1375: 	scsi_mode_sense(&ccb->csio,
 1376: 			/* retries */ 1,
 1377: 			/* cbfcnp */ chdone,
 1378: 			/* tag_action */ MSG_SIMPLE_Q_TAG,
 1379: 			/* dbd */ dbd,
 1380: 			/* page_code */ SMS_PAGE_CTRL_CURRENT,
 1381: 			/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
 1382: 			/* param_buf */ (u_int8_t *)mode_buffer,
 1383: 			/* param_len */ mode_buffer_len,
 1384: 			/* sense_len */ SSD_FULL_SIZE,
 1385: 			/* timeout */ CH_TIMEOUT_MODE_SENSE);
 1386: 
 1387: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1388: 				  /* sense_flags */ SF_RETRY_UA |
 1389: 				  SF_NO_PRINT | SF_RETRY_SELTO,
 1390: 				  &softc->device_stats);
 1391: 
 1392: 	if (error) {
 1393: 		if (dbd) {
 1394: 			struct scsi_mode_sense_6 *sms;
 1395: 
 1396: 			sms = (struct scsi_mode_sense_6 *)
 1397: 				ccb->csio.cdb_io.cdb_bytes;
 1398: 
 1399: 			sms->byte2 &= ~SMS_DBD;
 1400: 			error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1401: 				  		  /*sense_flags*/ SF_RETRY_UA |
 1402: 						  SF_RETRY_SELTO,
 1403: 						  &softc->device_stats);
 1404: 		} else {
 1405: 			/*
 1406: 			 * Since we disabled sense printing above, print
 1407: 			 * out the sense here since we got an error.
 1408: 			 */
 1409: 			scsi_sense_print(&ccb->csio);
 1410: 		}
 1411: 
 1412: 		if (error) {
 1413: 			xpt_print_path(periph->path);
 1414: 			printf("chgetparams: error getting element "
 1415: 			       "address page\n");
 1416: 			xpt_release_ccb(ccb);
 1417: 			free(mode_buffer, M_TEMP);
 1418: 			return(error);
 1419: 		}
 1420: 	}
 1421: 
 1422: 	ea = (struct page_element_address_assignment *)
 1423: 		find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
 1424: 
 1425: 	softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
 1426: 	softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
 1427: 	softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
 1428: 	softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
 1429: 	softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
 1430: 	softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
 1431: 	softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
 1432: 	softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
 1433: 
 1434: 	bzero(mode_buffer, mode_buffer_len);
 1435: 
 1436: 	/*
 1437: 	 * Now get the device capabilities page.
 1438: 	 */
 1439: 	scsi_mode_sense(&ccb->csio,
 1440: 			/* retries */ 1,
 1441: 			/* cbfcnp */ chdone,
 1442: 			/* tag_action */ MSG_SIMPLE_Q_TAG,
 1443: 			/* dbd */ dbd,
 1444: 			/* page_code */ SMS_PAGE_CTRL_CURRENT,
 1445: 			/* page */ CH_DEVICE_CAP_PAGE,
 1446: 			/* param_buf */ (u_int8_t *)mode_buffer,
 1447: 			/* param_len */ mode_buffer_len,
 1448: 			/* sense_len */ SSD_FULL_SIZE,
 1449: 			/* timeout */ CH_TIMEOUT_MODE_SENSE);
 1450: 	
 1451: 	error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1452: 				  /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT |
 1453: 				  SF_RETRY_SELTO, &softc->device_stats);
 1454: 
 1455: 	if (error) {
 1456: 		if (dbd) {
 1457: 			struct scsi_mode_sense_6 *sms;
 1458: 
 1459: 			sms = (struct scsi_mode_sense_6 *)
 1460: 				ccb->csio.cdb_io.cdb_bytes;
 1461: 
 1462: 			sms->byte2 &= ~SMS_DBD;
 1463: 			error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
 1464: 				  		  /*sense_flags*/ SF_RETRY_UA |
 1465: 						  SF_RETRY_SELTO,
 1466: 						  &softc->device_stats);
 1467: 		} else {
 1468: 			/*
 1469: 			 * Since we disabled sense printing above, print
 1470: 			 * out the sense here since we got an error.
 1471: 			 */
 1472: 			scsi_sense_print(&ccb->csio);
 1473: 		}
 1474: 
 1475: 		if (error) {
 1476: 			xpt_print_path(periph->path);
 1477: 			printf("chgetparams: error getting device "
 1478: 			       "capabilities page\n");
 1479: 			xpt_release_ccb(ccb);
 1480: 			free(mode_buffer, M_TEMP);
 1481: 			return(error);
 1482: 		}
 1483: 	}
 1484: 
 1485: 	xpt_release_ccb(ccb);
 1486: 
 1487: 	cap = (struct page_device_capabilities *)
 1488: 		find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
 1489: 
 1490: 	bzero(softc->sc_movemask, sizeof(softc->sc_movemask));
 1491: 	bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask));
 1492: 	moves = &cap->move_from_mt;
 1493: 	exchanges = &cap->exchange_with_mt;
 1494: 	for (from = CHET_MT; from <= CHET_DT; ++from) {
 1495: 		softc->sc_movemask[from] = moves[from];
 1496: 		softc->sc_exchangemask[from] = exchanges[from];
 1497: 	}
 1498: 
 1499: 	free(mode_buffer, M_TEMP);
 1500: 
 1501: 	return(error);
 1502: }
 1503: 
 1504: void
 1505: scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
 1506: 		 void (*cbfcnp)(struct cam_periph *, union ccb *),
 1507: 		 u_int8_t tag_action, u_int32_t tea, u_int32_t src,
 1508: 		 u_int32_t dst, int invert, u_int8_t sense_len,
 1509: 		 u_int32_t timeout)
 1510: {
 1511: 	struct scsi_move_medium *scsi_cmd;
 1512: 
 1513: 	scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes;
 1514: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1515: 
 1516: 	scsi_cmd->opcode = MOVE_MEDIUM;
 1517: 
 1518: 	scsi_ulto2b(tea, scsi_cmd->tea);
 1519: 	scsi_ulto2b(src, scsi_cmd->src);
 1520: 	scsi_ulto2b(dst, scsi_cmd->dst);
 1521: 
 1522: 	if (invert)
 1523: 		scsi_cmd->invert |= MOVE_MEDIUM_INVERT;
 1524: 
 1525: 	cam_fill_csio(csio,
 1526: 		      retries,
 1527: 		      cbfcnp,
 1528: 		      /*flags*/ CAM_DIR_NONE,
 1529: 		      tag_action,
 1530: 		      /*data_ptr*/ NULL,
 1531: 		      /*dxfer_len*/ 0,
 1532: 		      sense_len,
 1533: 		      sizeof(*scsi_cmd),
 1534: 		      timeout);
 1535: }
 1536: 
 1537: void
 1538: scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries,
 1539: 		     void (*cbfcnp)(struct cam_periph *, union ccb *),
 1540: 		     u_int8_t tag_action, u_int32_t tea, u_int32_t src,
 1541: 		     u_int32_t dst1, u_int32_t dst2, int invert1,
 1542: 		     int invert2, u_int8_t sense_len, u_int32_t timeout)
 1543: {
 1544: 	struct scsi_exchange_medium *scsi_cmd;
 1545: 
 1546: 	scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes;
 1547: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1548: 
 1549: 	scsi_cmd->opcode = EXCHANGE_MEDIUM;
 1550: 
 1551: 	scsi_ulto2b(tea, scsi_cmd->tea);
 1552: 	scsi_ulto2b(src, scsi_cmd->src);
 1553: 	scsi_ulto2b(dst1, scsi_cmd->fdst);
 1554: 	scsi_ulto2b(dst2, scsi_cmd->sdst);
 1555: 
 1556: 	if (invert1)
 1557: 		scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1;
 1558: 
 1559: 	if (invert2)
 1560: 		scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2;
 1561: 
 1562: 	cam_fill_csio(csio,
 1563: 		      retries,
 1564: 		      cbfcnp,
 1565: 		      /*flags*/ CAM_DIR_NONE,
 1566: 		      tag_action,
 1567: 		      /*data_ptr*/ NULL,
 1568: 		      /*dxfer_len*/ 0,
 1569: 		      sense_len,
 1570: 		      sizeof(*scsi_cmd),
 1571: 		      timeout);
 1572: }
 1573: 
 1574: void
 1575: scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
 1576: 			 void (*cbfcnp)(struct cam_periph *, union ccb *),
 1577: 			 u_int8_t tag_action, u_int32_t tea, u_int32_t dst,
 1578: 			 int invert, u_int8_t sense_len, u_int32_t timeout)
 1579: {
 1580: 	struct scsi_position_to_element *scsi_cmd;
 1581: 
 1582: 	scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes;
 1583: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1584: 
 1585: 	scsi_cmd->opcode = POSITION_TO_ELEMENT;
 1586: 
 1587: 	scsi_ulto2b(tea, scsi_cmd->tea);
 1588: 	scsi_ulto2b(dst, scsi_cmd->dst);
 1589: 
 1590: 	if (invert)
 1591: 		scsi_cmd->invert |= POSITION_TO_ELEMENT_INVERT;
 1592: 
 1593: 	cam_fill_csio(csio,
 1594: 		      retries,
 1595: 		      cbfcnp,
 1596: 		      /*flags*/ CAM_DIR_NONE,
 1597: 		      tag_action,
 1598: 		      /*data_ptr*/ NULL,
 1599: 		      /*dxfer_len*/ 0,
 1600: 		      sense_len,
 1601: 		      sizeof(*scsi_cmd),
 1602: 		      timeout);
 1603: }
 1604: 
 1605: void
 1606: scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 1607: 			 void (*cbfcnp)(struct cam_periph *, union ccb *),
 1608: 			 u_int8_t tag_action, int voltag, u_int32_t sea,
 1609: 			 u_int32_t count, u_int8_t *data_ptr,
 1610: 			 u_int32_t dxfer_len, u_int8_t sense_len,
 1611: 			 u_int32_t timeout)
 1612: {
 1613: 	struct scsi_read_element_status *scsi_cmd;
 1614: 
 1615: 	scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes;
 1616: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1617: 
 1618: 	scsi_cmd->opcode = READ_ELEMENT_STATUS;
 1619: 
 1620: 	scsi_ulto2b(sea, scsi_cmd->sea);
 1621: 	scsi_ulto2b(count, scsi_cmd->count);
 1622: 	scsi_ulto3b(dxfer_len, scsi_cmd->len);
 1623: 
 1624: 	if (voltag)
 1625: 		scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;
 1626: 
 1627: 	cam_fill_csio(csio,
 1628: 		      retries,
 1629: 		      cbfcnp,
 1630: 		      /*flags*/ CAM_DIR_IN,
 1631: 		      tag_action,
 1632: 		      data_ptr,
 1633: 		      dxfer_len,
 1634: 		      sense_len,
 1635: 		      sizeof(*scsi_cmd),
 1636: 		      timeout);
 1637: }
 1638: 
 1639: void
 1640: scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 1641: 			       void (*cbfcnp)(struct cam_periph *, union ccb *),
 1642: 			       u_int8_t tag_action, u_int8_t sense_len,
 1643: 			       u_int32_t timeout)
 1644: {
 1645: 	struct scsi_initialize_element_status *scsi_cmd;
 1646: 
 1647: 	scsi_cmd = (struct scsi_initialize_element_status *)
 1648: 		    &csio->cdb_io.cdb_bytes;
 1649: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1650: 
 1651: 	scsi_cmd->opcode = INITIALIZE_ELEMENT_STATUS;
 1652: 
 1653: 	cam_fill_csio(csio,
 1654: 		      retries,
 1655: 		      cbfcnp,
 1656: 		      /*flags*/ CAM_DIR_NONE,
 1657: 		      tag_action,
 1658: 		      /* data_ptr */ NULL,
 1659: 		      /* dxfer_len */ 0,
 1660: 		      sense_len,
 1661: 		      sizeof(*scsi_cmd),
 1662: 		      timeout);
 1663: }
 1664: 
 1665: void
 1666: scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries,
 1667: 		     void (*cbfcnp)(struct cam_periph *, union ccb *),
 1668: 		     u_int8_t tag_action, 
 1669: 		     u_int16_t element_address,
 1670: 		     u_int8_t send_action_code,
 1671: 		     struct scsi_send_volume_tag_parameters *parameters,
 1672: 		     u_int8_t sense_len, u_int32_t timeout)
 1673: {
 1674: 	struct scsi_send_volume_tag *scsi_cmd;
 1675: 
 1676: 	scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes;
 1677: 	bzero(scsi_cmd, sizeof(*scsi_cmd));
 1678: 
 1679: 	scsi_cmd->opcode = SEND_VOLUME_TAG;
 1680: 	scsi_ulto2b(element_address, scsi_cmd->ea);
 1681: 	scsi_cmd->sac = send_action_code;
 1682: 	scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll);
 1683: 
 1684: 	cam_fill_csio(csio,
 1685: 		      retries,
 1686: 		      cbfcnp,
 1687: 		      /*flags*/ CAM_DIR_OUT,
 1688: 		      tag_action,
 1689: 		      /* data_ptr */ (u_int8_t *) parameters,
 1690: 		      sizeof(*parameters),
 1691: 		      sense_len,
 1692: 		      sizeof(*scsi_cmd),
 1693: 		      timeout);
 1694: }