File:  [DragonFly] / src / sys / bus / cam / scsi / scsi_pass.c
Revision 1.11: download - view: text, annotated - select for diffs
Thu May 13 23:49:11 2004 UTC (10 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * Copyright (c) 1997, 1998 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_pass.c,v 1.19 2000/01/17 06:27:37 mjacob Exp $
   28:  * $DragonFly: src/sys/bus/cam/scsi/scsi_pass.c,v 1.11 2004/05/13 23:49:11 dillon Exp $
   29:  */
   30: 
   31: #include <sys/param.h>
   32: #include <sys/systm.h>
   33: #include <sys/kernel.h>
   34: #include <sys/types.h>
   35: #include <sys/buf.h>
   36: #include <sys/malloc.h>
   37: #include <sys/fcntl.h>
   38: #include <sys/stat.h>
   39: #include <sys/conf.h>
   40: #include <sys/buf.h>
   41: #include <sys/proc.h>
   42: #include <sys/errno.h>
   43: #include <sys/devicestat.h>
   44: #include <sys/proc.h>
   45: #include <sys/buf2.h>
   46: 
   47: #include "../cam.h"
   48: #include "../cam_ccb.h"
   49: #include "../cam_extend.h"
   50: #include "../cam_periph.h"
   51: #include "../cam_xpt_periph.h"
   52: #include "../cam_debug.h"
   53: 
   54: #include "scsi_all.h"
   55: #include "scsi_message.h"
   56: #include "scsi_da.h"
   57: #include "scsi_pass.h"
   58: 
   59: typedef enum {
   60: 	PASS_FLAG_OPEN			= 0x01,
   61: 	PASS_FLAG_LOCKED		= 0x02,
   62: 	PASS_FLAG_INVALID		= 0x04
   63: } pass_flags;
   64: 
   65: typedef enum {
   66: 	PASS_STATE_NORMAL
   67: } pass_state;
   68: 
   69: typedef enum {
   70: 	PASS_CCB_BUFFER_IO,
   71: 	PASS_CCB_WAITING
   72: } pass_ccb_types;
   73: 
   74: #define ccb_type	ppriv_field0
   75: #define ccb_bp		ppriv_ptr1
   76: 
   77: struct pass_softc {
   78: 	pass_state	state;
   79: 	pass_flags	flags;
   80: 	u_int8_t	pd_type;
   81: 	struct		buf_queue_head buf_queue;
   82: 	union ccb	saved_ccb;
   83: 	struct devstat	device_stats;
   84: 	dev_t		dev;
   85: };
   86: 
   87: #define PASS_CDEV_MAJOR 31
   88: 
   89: static	d_open_t	passopen;
   90: static	d_close_t	passclose;
   91: static	d_ioctl_t	passioctl;
   92: static	d_strategy_t	passstrategy;
   93: 
   94: static	periph_init_t	passinit;
   95: static	periph_ctor_t	passregister;
   96: static	periph_oninv_t	passoninvalidate;
   97: static	periph_dtor_t	passcleanup;
   98: static	periph_start_t	passstart;
   99: static	void		passasync(void *callback_arg, u_int32_t code,
  100: 				  struct cam_path *path, void *arg);
  101: static	void		passdone(struct cam_periph *periph, 
  102: 				 union ccb *done_ccb);
  103: static	int		passerror(union ccb *ccb, u_int32_t cam_flags, 
  104: 				  u_int32_t sense_flags);
  105: static 	int		passsendccb(struct cam_periph *periph, union ccb *ccb,
  106: 				    union ccb *inccb);
  107: 
  108: static struct periph_driver passdriver =
  109: {
  110: 	passinit, "pass",
  111: 	TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
  112: };
  113: 
  114: DATA_SET(periphdriver_set, passdriver);
  115: 
  116: static struct cdevsw pass_cdevsw = {
  117: 	/* name */	"pass",
  118: 	/* maj */	PASS_CDEV_MAJOR,
  119: 	/* flags */	0,
  120: 	/* port */      NULL,
  121: 	/* clone */     NULL,
  122: 
  123: 	/* open */	passopen,
  124: 	/* close */	passclose,
  125: 	/* read */	physread,
  126: 	/* write */	physwrite,
  127: 	/* ioctl */	passioctl,
  128: 	/* poll */	nopoll,
  129: 	/* mmap */	nommap,
  130: 	/* strategy */	passstrategy,
  131: 	/* dump */	nodump,
  132: 	/* psize */	nopsize
  133: };
  134: 
  135: static struct extend_array *passperiphs;
  136: 
  137: static void
  138: passinit(void)
  139: {
  140: 	cam_status status;
  141: 	struct cam_path *path;
  142: 
  143: 	/*
  144: 	 * Create our extend array for storing the devices we attach to.
  145: 	 */
  146: 	passperiphs = cam_extend_new();
  147: 	if (passperiphs == NULL) {
  148: 		printf("passm: Failed to alloc extend array!\n");
  149: 		return;
  150: 	}
  151: 
  152: 	/*
  153: 	 * Install a global async callback.  This callback will
  154: 	 * receive async callbacks like "new device found".
  155: 	 */
  156: 	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
  157: 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  158: 
  159: 	if (status == CAM_REQ_CMP) {
  160: 		struct ccb_setasync csa;
  161: 
  162:                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
  163:                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  164:                 csa.event_enable = AC_FOUND_DEVICE;
  165:                 csa.callback = passasync;
  166:                 csa.callback_arg = NULL;
  167:                 xpt_action((union ccb *)&csa);
  168: 		status = csa.ccb_h.status;
  169:                 xpt_free_path(path);
  170:         }
  171: 
  172: 	if (status != CAM_REQ_CMP) {
  173: 		printf("pass: Failed to attach master async callback "
  174: 		       "due to status 0x%x!\n", status);
  175: 	}
  176: 	
  177: }
  178: 
  179: static void
  180: passoninvalidate(struct cam_periph *periph)
  181: {
  182: 	int s;
  183: 	struct pass_softc *softc;
  184: 	struct buf *q_bp;
  185: 	struct ccb_setasync csa;
  186: 
  187: 	softc = (struct pass_softc *)periph->softc;
  188: 
  189: 	/*
  190: 	 * De-register any async callbacks.
  191: 	 */
  192: 	xpt_setup_ccb(&csa.ccb_h, periph->path,
  193: 		      /* priority */ 5);
  194: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  195: 	csa.event_enable = 0;
  196: 	csa.callback = passasync;
  197: 	csa.callback_arg = periph;
  198: 	xpt_action((union ccb *)&csa);
  199: 
  200: 	softc->flags |= PASS_FLAG_INVALID;
  201: 
  202: 	/*
  203: 	 * Although the oninvalidate() routines are always called at
  204: 	 * splsoftcam, we need to be at splbio() here to keep the buffer
  205: 	 * queue from being modified while we traverse it.
  206: 	 */
  207: 	s = splbio();
  208: 
  209: 	/*
  210: 	 * Return all queued I/O with ENXIO.
  211: 	 * XXX Handle any transactions queued to the card
  212: 	 *     with XPT_ABORT_CCB.
  213: 	 */
  214: 	while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
  215: 		bufq_remove(&softc->buf_queue, q_bp);
  216: 		q_bp->b_resid = q_bp->b_bcount;
  217: 		q_bp->b_error = ENXIO;
  218: 		q_bp->b_flags |= B_ERROR;
  219: 		biodone(q_bp);
  220: 	}
  221: 	splx(s);
  222: 
  223: 	if (bootverbose) {
  224: 		xpt_print_path(periph->path);
  225: 		printf("lost device\n");
  226: 	}
  227: 
  228: }
  229: 
  230: static void
  231: passcleanup(struct cam_periph *periph)
  232: {
  233: 	struct pass_softc *softc;
  234: 
  235: 	softc = (struct pass_softc *)periph->softc;
  236: 
  237: 	devstat_remove_entry(&softc->device_stats);
  238: 
  239: 	destroy_dev(softc->dev);
  240: 
  241: 	cam_extend_release(passperiphs, periph->unit_number);
  242: 
  243: 	if (bootverbose) {
  244: 		xpt_print_path(periph->path);
  245: 		printf("removing device entry\n");
  246: 	}
  247: 	free(softc, M_DEVBUF);
  248: }
  249: 
  250: static void
  251: passasync(void *callback_arg, u_int32_t code,
  252: 	  struct cam_path *path, void *arg)
  253: {
  254: 	struct cam_periph *periph;
  255: 
  256: 	periph = (struct cam_periph *)callback_arg;
  257: 
  258: 	switch (code) {
  259: 	case AC_FOUND_DEVICE:
  260: 	{
  261: 		struct ccb_getdev *cgd;
  262: 		cam_status status;
  263:  
  264: 		cgd = (struct ccb_getdev *)arg;
  265: 
  266: 		/*
  267: 		 * Allocate a peripheral instance for
  268: 		 * this device and start the probe
  269: 		 * process.
  270: 		 */
  271: 		status = cam_periph_alloc(passregister, passoninvalidate,
  272: 					  passcleanup, passstart, "pass",
  273: 					  CAM_PERIPH_BIO, cgd->ccb_h.path,
  274: 					  passasync, AC_FOUND_DEVICE, cgd);
  275: 
  276: 		if (status != CAM_REQ_CMP
  277: 		 && status != CAM_REQ_INPROG)
  278: 			printf("passasync: Unable to attach new device "
  279: 				"due to status 0x%x\n", status);
  280: 
  281: 		break;
  282: 	}
  283: 	default:
  284: 		cam_periph_async(periph, code, path, arg);
  285: 		break;
  286: 	}
  287: }
  288: 
  289: static cam_status
  290: passregister(struct cam_periph *periph, void *arg)
  291: {
  292: 	struct pass_softc *softc;
  293: 	struct ccb_setasync csa;
  294: 	struct ccb_getdev *cgd;
  295: 
  296: 	cgd = (struct ccb_getdev *)arg;
  297: 	if (periph == NULL) {
  298: 		printf("passregister: periph was NULL!!\n");
  299: 		return(CAM_REQ_CMP_ERR);
  300: 	}
  301: 
  302: 	if (cgd == NULL) {
  303: 		printf("passregister: no getdev CCB, can't register device\n");
  304: 		return(CAM_REQ_CMP_ERR);
  305: 	}
  306: 
  307: 	softc = malloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
  308: 	softc->state = PASS_STATE_NORMAL;
  309: 	softc->pd_type = SID_TYPE(&cgd->inq_data);
  310: 	bufq_init(&softc->buf_queue);
  311: 
  312: 	periph->softc = softc;
  313: 
  314: 	cam_extend_set(passperiphs, periph->unit_number, periph);
  315: 	/*
  316: 	 * We pass in 0 for a blocksize, since we don't 
  317: 	 * know what the blocksize of this device is, if 
  318: 	 * it even has a blocksize.
  319: 	 */
  320: 	devstat_add_entry(&softc->device_stats, "pass", periph->unit_number,
  321: 			  0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
  322: 			  softc->pd_type |
  323: 			  DEVSTAT_TYPE_IF_SCSI |
  324: 			  DEVSTAT_TYPE_PASS,
  325: 			  DEVSTAT_PRIORITY_PASS);
  326: 
  327: 	/* Register the device */
  328: 	softc->dev = make_dev(&pass_cdevsw, periph->unit_number, UID_ROOT,
  329: 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
  330: 			      periph->unit_number);
  331: 
  332: 	/*
  333: 	 * Add an async callback so that we get
  334: 	 * notified if this device goes away.
  335: 	 */
  336: 	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
  337: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  338: 	csa.event_enable = AC_LOST_DEVICE;
  339: 	csa.callback = passasync;
  340: 	csa.callback_arg = periph;
  341: 	xpt_action((union ccb *)&csa);
  342: 
  343: 	if (bootverbose)
  344: 		xpt_announce_periph(periph, NULL);
  345: 
  346: 	return(CAM_REQ_CMP);
  347: }
  348: 
  349: static int
  350: passopen(dev_t dev, int flags, int fmt, struct thread *td)
  351: {
  352: 	struct cam_periph *periph;
  353: 	struct pass_softc *softc;
  354: 	int unit, error;
  355: 	int s;
  356: 
  357: 	error = 0; /* default to no error */
  358: 
  359: 	/* unit = dkunit(dev); */
  360: 	/* XXX KDM fix this */
  361: 	unit = minor(dev) & 0xff;
  362: 
  363: 	periph = cam_extend_get(passperiphs, unit);
  364: 
  365: 	if (periph == NULL)
  366: 		return (ENXIO);
  367: 
  368: 	softc = (struct pass_softc *)periph->softc;
  369: 
  370: 	s = splsoftcam();
  371: 	if (softc->flags & PASS_FLAG_INVALID) {
  372: 		splx(s);
  373: 		return(ENXIO);
  374: 	}
  375: 
  376: 	/*
  377: 	 * Don't allow access when we're running at a high securelvel.
  378: 	 */
  379: 	if (securelevel > 1) {
  380: 		splx(s);
  381: 		return(EPERM);
  382: 	}
  383: 
  384: 	/*
  385: 	 * Only allow read-write access.
  386: 	 */
  387: 	if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
  388: 		splx(s);
  389: 		return(EPERM);
  390: 	}
  391: 
  392: 	/*
  393: 	 * We don't allow nonblocking access.
  394: 	 */
  395: 	if ((flags & O_NONBLOCK) != 0) {
  396: 		xpt_print_path(periph->path);
  397: 		printf("can't do nonblocking accesss\n");
  398: 		splx(s);
  399: 		return(EINVAL);
  400: 	}
  401: 
  402: 	if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
  403: 		splx(s);
  404: 		return (error);
  405: 	}
  406: 
  407: 	splx(s);
  408: 
  409: 	if ((softc->flags & PASS_FLAG_OPEN) == 0) {
  410: 		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  411: 			return(ENXIO);
  412: 		softc->flags |= PASS_FLAG_OPEN;
  413: 	}
  414: 
  415: 	cam_periph_unlock(periph);
  416: 
  417: 	return (error);
  418: }
  419: 
  420: static int
  421: passclose(dev_t dev, int flag, int fmt, struct thread *td)
  422: {
  423: 	struct 	cam_periph *periph;
  424: 	struct	pass_softc *softc;
  425: 	int	unit, error;
  426: 
  427: 	/* unit = dkunit(dev); */
  428: 	/* XXX KDM fix this */
  429: 	unit = minor(dev) & 0xff;
  430: 
  431: 	periph = cam_extend_get(passperiphs, unit);
  432: 	if (periph == NULL)
  433: 		return (ENXIO);	
  434: 
  435: 	softc = (struct pass_softc *)periph->softc;
  436: 
  437: 	if ((error = cam_periph_lock(periph, 0)) != 0)
  438: 		return (error);
  439: 
  440: 	softc->flags &= ~PASS_FLAG_OPEN;
  441: 
  442: 	cam_periph_unlock(periph);
  443: 	cam_periph_release(periph);
  444: 
  445: 	return (0);
  446: }
  447: 
  448: /*
  449:  * Actually translate the requested transfer into one the physical driver
  450:  * can understand.  The transfer is described by a buf and will include
  451:  * only one physical transfer.
  452:  */
  453: static void
  454: passstrategy(struct buf *bp)
  455: {
  456: 	struct cam_periph *periph;
  457: 	struct pass_softc *softc;
  458: 	u_int  unit;
  459: 	int    s;
  460: 
  461: 	/*
  462: 	 * The read/write interface for the passthrough driver doesn't
  463: 	 * really work right now.  So, we just pass back EINVAL to tell the
  464: 	 * user to go away.
  465: 	 */
  466: 	bp->b_error = EINVAL;
  467: 	goto bad;
  468: 
  469: 	/* unit = dkunit(bp->b_dev); */
  470: 	/* XXX KDM fix this */
  471: 	unit = minor(bp->b_dev) & 0xff;
  472: 
  473: 	periph = cam_extend_get(passperiphs, unit);
  474: 	if (periph == NULL) {
  475: 		bp->b_error = ENXIO;
  476: 		goto bad;
  477: 	}
  478: 	softc = (struct pass_softc *)periph->softc;
  479: 
  480: 	/*
  481: 	 * Odd number of bytes or negative offset
  482: 	 */
  483: 	/* valid request?  */
  484: 	if (bp->b_blkno < 0) {
  485: 		bp->b_error = EINVAL;
  486: 		goto bad;
  487:         }
  488: 	
  489: 	/*
  490: 	 * Mask interrupts so that the pack cannot be invalidated until
  491: 	 * after we are in the queue.  Otherwise, we might not properly
  492: 	 * clean up one of the buffers.
  493: 	 */
  494: 	s = splbio();
  495: 	
  496: 	bufq_insert_tail(&softc->buf_queue, bp);
  497: 
  498: 	splx(s);
  499: 	
  500: 	/*
  501: 	 * Schedule ourselves for performing the work.
  502: 	 */
  503: 	xpt_schedule(periph, /* XXX priority */1);
  504: 
  505: 	return;
  506: bad:
  507: 	bp->b_flags |= B_ERROR;
  508: 
  509: 	/*
  510: 	 * Correctly set the buf to indicate a completed xfer
  511: 	 */
  512: 	bp->b_resid = bp->b_bcount;
  513: 	biodone(bp);
  514: 	return;
  515: }
  516: 
  517: static void
  518: passstart(struct cam_periph *periph, union ccb *start_ccb)
  519: {
  520: 	struct pass_softc *softc;
  521: 	int s;
  522: 
  523: 	softc = (struct pass_softc *)periph->softc;
  524: 
  525: 	switch (softc->state) {
  526: 	case PASS_STATE_NORMAL:
  527: 	{
  528: 		struct buf *bp;
  529: 
  530: 		s = splbio();
  531: 		bp = bufq_first(&softc->buf_queue);
  532: 		if (periph->immediate_priority <= periph->pinfo.priority) {
  533: 			start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING;			
  534: 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
  535: 					  periph_links.sle);
  536: 			periph->immediate_priority = CAM_PRIORITY_NONE;
  537: 			splx(s);
  538: 			wakeup(&periph->ccb_list);
  539: 		} else if (bp == NULL) {
  540: 			splx(s);
  541: 			xpt_release_ccb(start_ccb);
  542: 		} else {
  543: 
  544: 			bufq_remove(&softc->buf_queue, bp);
  545: 
  546: 			devstat_start_transaction(&softc->device_stats);
  547: 
  548: 			/*
  549: 			 * XXX JGibbs -
  550: 			 * Interpret the contents of the bp as a CCB
  551: 			 * and pass it to a routine shared by our ioctl
  552: 			 * code and passtart.
  553: 			 * For now, just biodone it with EIO so we don't
  554: 			 * hang.
  555: 			 */
  556: 			bp->b_error = EIO;
  557: 			bp->b_flags |= B_ERROR;
  558: 			bp->b_resid = bp->b_bcount;
  559: 			biodone(bp);
  560: 			bp = bufq_first(&softc->buf_queue);
  561: 			splx(s);
  562:   
  563: 			xpt_action(start_ccb);
  564: 
  565: 		}
  566: 		if (bp != NULL) {
  567: 			/* Have more work to do, so ensure we stay scheduled */
  568: 			xpt_schedule(periph, /* XXX priority */1);
  569: 		}
  570: 		break;
  571: 	}
  572: 	}
  573: }
  574: static void
  575: passdone(struct cam_periph *periph, union ccb *done_ccb)
  576: { 
  577: 	struct pass_softc *softc;
  578: 	struct ccb_scsiio *csio;
  579: 
  580: 	softc = (struct pass_softc *)periph->softc;
  581: 	csio = &done_ccb->csio;
  582: 	switch (csio->ccb_h.ccb_type) {
  583: 	case PASS_CCB_BUFFER_IO:
  584: 	{
  585: 		struct buf		*bp;
  586: 		cam_status		status;
  587: 		u_int8_t		scsi_status;
  588: 		devstat_trans_flags	ds_flags;
  589: 
  590: 		status = done_ccb->ccb_h.status;
  591: 		scsi_status = done_ccb->csio.scsi_status;
  592: 		bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
  593: 		/* XXX handle errors */
  594: 		if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP)
  595: 		  && (scsi_status == SCSI_STATUS_OK))) {
  596: 			int error;
  597: 			
  598: 			if ((error = passerror(done_ccb, 0, 0)) == ERESTART) {
  599: 				/*
  600: 				 * A retry was scheuled, so
  601: 				 * just return.
  602: 				 */
  603: 				return;
  604: 			}
  605: 
  606: 			/*
  607: 			 * XXX unfreeze the queue after we complete
  608: 			 * the abort process
  609: 			 */
  610: 			bp->b_error = error;
  611: 			bp->b_flags |= B_ERROR;
  612: 		}
  613: 
  614: 		if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
  615: 			ds_flags = DEVSTAT_READ;
  616: 		else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
  617: 			ds_flags = DEVSTAT_WRITE;
  618: 		else
  619: 			ds_flags = DEVSTAT_NO_DATA;
  620: 
  621: 		devstat_end_transaction_buf(&softc->device_stats, bp);
  622: 		biodone(bp);
  623: 		break;
  624: 	}
  625: 	case PASS_CCB_WAITING:
  626: 	{
  627: 		/* Caller will release the CCB */
  628: 		wakeup(&done_ccb->ccb_h.cbfcnp);
  629: 		return;
  630: 	}
  631: 	}
  632: 	xpt_release_ccb(done_ccb);
  633: }
  634: 
  635: static int
  636: passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  637: {
  638: 	struct 	cam_periph *periph;
  639: 	struct	pass_softc *softc;
  640: 	u_int8_t unit;
  641: 	int      error;
  642: 
  643: 
  644: 	/* unit = dkunit(dev); */
  645: 	/* XXX KDM fix this */
  646: 	unit = minor(dev) & 0xff;
  647: 
  648: 	periph = cam_extend_get(passperiphs, unit);
  649: 
  650: 	if (periph == NULL)
  651: 		return(ENXIO);
  652: 
  653: 	softc = (struct pass_softc *)periph->softc;
  654: 
  655: 	error = 0;
  656: 
  657: 	switch (cmd) {
  658: 
  659: 	case CAMIOCOMMAND:
  660: 	{
  661: 		union ccb *inccb;
  662: 		union ccb *ccb;
  663: 		int ccb_malloced;
  664: 
  665: 		inccb = (union ccb *)addr;
  666: 
  667: 		/*
  668: 		 * Some CCB types, like scan bus and scan lun can only go
  669: 		 * through the transport layer device.
  670: 		 */
  671: 		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
  672: 			xpt_print_path(periph->path);
  673: 			printf("CCB function code %#x is restricted to the "
  674: 			       "XPT device\n", inccb->ccb_h.func_code);
  675: 			error = ENODEV;
  676: 			break;
  677: 		}
  678: 
  679: 		/*
  680: 		 * Non-immediate CCBs need a CCB from the per-device pool
  681: 		 * of CCBs, which is scheduled by the transport layer.
  682: 		 * Immediate CCBs and user-supplied CCBs should just be
  683: 		 * malloced.
  684: 		 */
  685: 		if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
  686: 		 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
  687: 			ccb = cam_periph_getccb(periph,
  688: 						inccb->ccb_h.pinfo.priority);
  689: 			ccb_malloced = 0;
  690: 		} else {
  691: 			ccb = xpt_alloc_ccb();
  692: 
  693: 			if (ccb != NULL)
  694: 				xpt_setup_ccb(&ccb->ccb_h, periph->path,
  695: 					      inccb->ccb_h.pinfo.priority);
  696: 			ccb_malloced = 1;
  697: 		}
  698: 
  699: 		if (ccb == NULL) {
  700: 			xpt_print_path(periph->path);
  701: 			printf("unable to allocate CCB\n");
  702: 			error = ENOMEM;
  703: 			break;
  704: 		}
  705: 
  706: 		error = passsendccb(periph, ccb, inccb);
  707: 
  708: 		if (ccb_malloced)
  709: 			xpt_free_ccb(ccb);
  710: 		else
  711: 			xpt_release_ccb(ccb);
  712: 
  713: 		break;
  714: 	}
  715: 	default:
  716: 		error = cam_periph_ioctl(periph, cmd, addr, passerror);
  717: 		break;
  718: 	}
  719: 
  720: 	return(error);
  721: }
  722: 
  723: /*
  724:  * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
  725:  * should be the CCB that is copied in from the user.
  726:  */
  727: static int
  728: passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
  729: {
  730: 	struct pass_softc *softc;
  731: 	struct cam_periph_map_info mapinfo;
  732: 	int error, need_unmap;
  733: 
  734: 	softc = (struct pass_softc *)periph->softc;
  735: 
  736: 	need_unmap = 0;
  737: 
  738: 	/*
  739: 	 * There are some fields in the CCB header that need to be
  740: 	 * preserved, the rest we get from the user.
  741: 	 */
  742: 	xpt_merge_ccb(ccb, inccb);
  743: 
  744: 	/*
  745: 	 * There's no way for the user to have a completion
  746: 	 * function, so we put our own completion function in here.
  747: 	 */
  748: 	ccb->ccb_h.cbfcnp = passdone;
  749: 
  750: 	/*
  751: 	 * We only attempt to map the user memory into kernel space
  752: 	 * if they haven't passed in a physical memory pointer,
  753: 	 * and if there is actually an I/O operation to perform.
  754: 	 * Right now cam_periph_mapmem() only supports SCSI and device
  755: 	 * match CCBs.  For the SCSI CCBs, we only pass the CCB in if
  756: 	 * there's actually data to map.  cam_periph_mapmem() will do the
  757: 	 * right thing, even if there isn't data to map, but since CCBs
  758: 	 * without data are a reasonably common occurance (e.g. test unit
  759: 	 * ready), it will save a few cycles if we check for it here.
  760: 	 */
  761: 	if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
  762: 	 && (((ccb->ccb_h.func_code == XPT_SCSI_IO)
  763: 	    && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
  764: 	  || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {
  765: 
  766: 		bzero(&mapinfo, sizeof(mapinfo));
  767: 
  768: 		error = cam_periph_mapmem(ccb, &mapinfo); 
  769: 
  770: 		/*
  771: 		 * cam_periph_mapmem returned an error, we can't continue.
  772: 		 * Return the error to the user.
  773: 		 */
  774: 		if (error)
  775: 			return(error);
  776: 
  777: 		/*
  778: 		 * We successfully mapped the memory in, so we need to
  779: 		 * unmap it when the transaction is done.
  780: 		 */
  781: 		need_unmap = 1;
  782: 	}
  783: 
  784: 	/*
  785: 	 * If the user wants us to perform any error recovery, then honor
  786: 	 * that request.  Otherwise, it's up to the user to perform any
  787: 	 * error recovery.
  788: 	 */
  789: 	error = cam_periph_runccb(ccb,
  790: 				  (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
  791: 				  passerror : NULL,
  792: 				  /* cam_flags */ 0,
  793: 				  /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO,
  794: 				  &softc->device_stats);
  795: 
  796: 	if (need_unmap != 0)
  797: 		cam_periph_unmapmem(ccb, &mapinfo);
  798: 
  799: 	ccb->ccb_h.cbfcnp = NULL;
  800: 	ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
  801: 	bcopy(ccb, inccb, sizeof(union ccb));
  802: 
  803: 	return(error);
  804: }
  805: 
  806: static int
  807: passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  808: {
  809: 	struct cam_periph *periph;
  810: 	struct pass_softc *softc;
  811: 
  812: 	periph = xpt_path_periph(ccb->ccb_h.path);
  813: 	softc = (struct pass_softc *)periph->softc;
  814: 	
  815: 	return(cam_periph_error(ccb, cam_flags, sense_flags, 
  816: 				 &softc->saved_ccb));
  817: }