File:  [DragonFly] / src / sys / bus / cam / scsi / scsi_pt.c
Revision 1.8: download - view: text, annotated - select for diffs
Fri Mar 12 03:23:19 2004 UTC (10 years, 1 month ago) by dillon
Branches: MAIN
CVS tags: HEAD
Change M_NOWAIT to M_INTWAIT or M_WAITOK.  CAM does a mediocre job checking
for NULL returns from malloc() and even when it does it generally causes
the device operation to fail instead of retrying, resulting in unacceptable
behavior.  M_NOWAIT semantics allow NULL to be returned during normal system
operation.  This is especially true in DragonFly.

Also remove much of the code that previously checked for NULL.  By using
M_INTWAIT or M_WAITOK, malloc() will panic rather then return NULL.  Only
the addition of M_NULLOK allows a blocking malloc() to return NULL, and we
do not use that flag in CAM.

Add M_ZERO to a number of malloc()'s and remove subsequent bzero()'s, and
add M_ZERO to a few mallocs (primarily for the read capacity data structure)
that did not bother zeroing out the structure before.  While the data is
supposed to be overwritten read-capacity is often quite fragile due to the
SCSI simulation layer, so we do not take any chances.

    1: /*
    2:  * Implementation of SCSI Processor Target Peripheral driver for CAM.
    3:  *
    4:  * Copyright (c) 1998 Justin T. Gibbs.
    5:  * All rights reserved.
    6:  *
    7:  * Redistribution and use in source and binary forms, with or without
    8:  * modification, are permitted provided that the following conditions
    9:  * are met:
   10:  * 1. Redistributions of source code must retain the above copyright
   11:  *    notice, this list of conditions, and the following disclaimer,
   12:  *    without modification, immediately at the beginning of the file.
   13:  * 2. The name of the author may not be used to endorse or promote products
   14:  *    derived from this software without specific prior written permission.
   15:  *
   16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26:  * SUCH DAMAGE.
   27:  *
   28:  * $FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.17 2000/01/17 06:27:37 mjacob Exp $
   29:  * $DragonFly: src/sys/bus/cam/scsi/scsi_pt.c,v 1.8 2004/03/12 03:23:19 dillon Exp $
   30:  */
   31: 
   32: #include <sys/param.h>
   33: #include <sys/queue.h>
   34: #include <sys/systm.h>
   35: #include <sys/kernel.h>
   36: #include <sys/types.h>
   37: #include <sys/buf.h>
   38: #include <sys/devicestat.h>
   39: #include <sys/malloc.h>
   40: #include <sys/conf.h>
   41: #include <sys/ptio.h>
   42: #include <sys/buf2.h>
   43: 
   44: #include "../cam.h"
   45: #include "../cam_ccb.h"
   46: #include "../cam_extend.h"
   47: #include "../cam_periph.h"
   48: #include "../cam_xpt_periph.h"
   49: #include "../cam_debug.h"
   50: 
   51: #include "scsi_all.h"
   52: #include "scsi_message.h"
   53: #include "scsi_pt.h"
   54: 
   55: #include "opt_pt.h"
   56: 
   57: typedef enum {
   58: 	PT_STATE_PROBE,
   59: 	PT_STATE_NORMAL
   60: } pt_state;
   61: 
   62: typedef enum {
   63: 	PT_FLAG_NONE		= 0x00,
   64: 	PT_FLAG_OPEN		= 0x01,
   65: 	PT_FLAG_DEVICE_INVALID	= 0x02,
   66: 	PT_FLAG_RETRY_UA	= 0x04
   67: } pt_flags;
   68: 
   69: typedef enum {
   70: 	PT_CCB_BUFFER_IO	= 0x01,
   71: 	PT_CCB_WAITING		= 0x02,
   72: 	PT_CCB_RETRY_UA		= 0x04,
   73: 	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
   74: } pt_ccb_state;
   75: 
   76: /* Offsets into our private area for storing information */
   77: #define ccb_state	ppriv_field0
   78: #define ccb_bp		ppriv_ptr1
   79: 
   80: struct pt_softc {
   81: 	struct	 buf_queue_head buf_queue;
   82: 	struct	 devstat device_stats;
   83: 	LIST_HEAD(, ccb_hdr) pending_ccbs;
   84: 	pt_state state;
   85: 	pt_flags flags;	
   86: 	union	 ccb saved_ccb;
   87: 	int	 io_timeout;
   88: 	dev_t	 dev;
   89: };
   90: 
   91: static	d_open_t	ptopen;
   92: static	d_close_t	ptclose;
   93: static	d_strategy_t	ptstrategy;
   94: static	periph_init_t	ptinit;
   95: static	void		ptasync(void *callback_arg, u_int32_t code,
   96: 				struct cam_path *path, void *arg);
   97: static	periph_ctor_t	ptctor;
   98: static	periph_oninv_t	ptoninvalidate;
   99: static	periph_dtor_t	ptdtor;
  100: static	periph_start_t	ptstart;
  101: static	void		ptdone(struct cam_periph *periph,
  102: 			       union ccb *done_ccb);
  103: static	d_ioctl_t	ptioctl;
  104: static  int		pterror(union ccb *ccb, u_int32_t cam_flags,
  105: 				u_int32_t sense_flags);
  106: 
  107: void	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
  108: 			  void (*cbfcnp)(struct cam_periph *, union ccb *),
  109: 			  u_int tag_action, int readop, u_int byte2,
  110: 			  u_int32_t xfer_len, u_int8_t *data_ptr,
  111: 			  u_int8_t sense_len, u_int32_t timeout);
  112: 
  113: static struct periph_driver ptdriver =
  114: {
  115: 	ptinit, "pt",
  116: 	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
  117: };
  118: 
  119: DATA_SET(periphdriver_set, ptdriver);
  120: 
  121: #define PT_CDEV_MAJOR 61
  122: 
  123: static struct cdevsw pt_cdevsw = {
  124: 	/* name */	"pt",
  125: 	/* maj */	PT_CDEV_MAJOR,
  126: 	/* flags */	0,
  127: 	/* port */	NULL,
  128: 	/* autoq */	0,
  129: 
  130: 	/* open */	ptopen,
  131: 	/* close */	ptclose,
  132: 	/* read */	physread,
  133: 	/* write */	physwrite,
  134: 	/* ioctl */	ptioctl,
  135: 	/* poll */	nopoll,
  136: 	/* mmap */	nommap,
  137: 	/* strategy */	ptstrategy,
  138: 	/* dump */	nodump,
  139: 	/* psize */	nopsize
  140: };
  141: 
  142: static struct extend_array *ptperiphs;
  143: 
  144: #ifndef SCSI_PT_DEFAULT_TIMEOUT
  145: #define SCSI_PT_DEFAULT_TIMEOUT		60
  146: #endif
  147: 
  148: static int
  149: ptopen(dev_t dev, int flags, int fmt, struct thread *td)
  150: {
  151: 	struct cam_periph *periph;
  152: 	struct pt_softc *softc;
  153: 	int unit;
  154: 	int error;
  155: 	int s;
  156: 
  157: 	unit = minor(dev);
  158: 	periph = cam_extend_get(ptperiphs, unit);
  159: 	if (periph == NULL)
  160: 		return (ENXIO);	
  161: 
  162: 	softc = (struct pt_softc *)periph->softc;
  163: 
  164: 	s = splsoftcam();
  165: 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
  166: 		splx(s);
  167: 		return(ENXIO);
  168: 	}
  169: 
  170: 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  171: 	    ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
  172: 
  173: 	if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
  174: 		splx(s);
  175: 		return (error); /* error code from tsleep */
  176: 	}
  177: 
  178: 	splx(s);
  179: 
  180: 	if ((softc->flags & PT_FLAG_OPEN) == 0) {
  181: 		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  182: 			error = ENXIO;
  183: 		else
  184: 			softc->flags |= PT_FLAG_OPEN;
  185: 	} else
  186: 		error = EBUSY;
  187: 
  188: 	cam_periph_unlock(periph);
  189: 	return (error);
  190: }
  191: 
  192: static int
  193: ptclose(dev_t dev, int flag, int fmt, struct thread *td)
  194: {
  195: 	struct	cam_periph *periph;
  196: 	struct	pt_softc *softc;
  197: 	int	unit;
  198: 	int	error;
  199: 
  200: 	unit = minor(dev);
  201: 	periph = cam_extend_get(ptperiphs, unit);
  202: 	if (periph == NULL)
  203: 		return (ENXIO);	
  204: 
  205: 	softc = (struct pt_softc *)periph->softc;
  206: 
  207: 	if ((error = cam_periph_lock(periph, 0)) != 0)
  208: 		return (error); /* error code from tsleep */
  209: 
  210: 	softc->flags &= ~PT_FLAG_OPEN;
  211: 	cam_periph_unlock(periph);
  212: 	cam_periph_release(periph);
  213: 	return (0);
  214: }
  215: 
  216: /*
  217:  * Actually translate the requested transfer into one the physical driver
  218:  * can understand.  The transfer is described by a buf and will include
  219:  * only one physical transfer.
  220:  */
  221: static void
  222: ptstrategy(struct buf *bp)
  223: {
  224: 	struct cam_periph *periph;
  225: 	struct pt_softc *softc;
  226: 	u_int  unit;
  227: 	int    s;
  228: 	
  229: 	unit = minor(bp->b_dev);
  230: 	periph = cam_extend_get(ptperiphs, unit);
  231: 	if (periph == NULL) {
  232: 		bp->b_error = ENXIO;
  233: 		goto bad;		
  234: 	}
  235: 	softc = (struct pt_softc *)periph->softc;
  236: 
  237: 	/*
  238: 	 * Mask interrupts so that the pack cannot be invalidated until
  239: 	 * after we are in the queue.  Otherwise, we might not properly
  240: 	 * clean up one of the buffers.
  241: 	 */
  242: 	s = splbio();
  243: 	
  244: 	/*
  245: 	 * If the device has been made invalid, error out
  246: 	 */
  247: 	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
  248: 		splx(s);
  249: 		bp->b_error = ENXIO;
  250: 		goto bad;
  251: 	}
  252: 	
  253: 	/*
  254: 	 * Place it in the queue of disk activities for this disk
  255: 	 */
  256: 	bufq_insert_tail(&softc->buf_queue, bp);
  257: 
  258: 	splx(s);
  259: 	
  260: 	/*
  261: 	 * Schedule ourselves for performing the work.
  262: 	 */
  263: 	xpt_schedule(periph, /* XXX priority */1);
  264: 
  265: 	return;
  266: bad:
  267: 	bp->b_flags |= B_ERROR;
  268: 
  269: 	/*
  270: 	 * Correctly set the buf to indicate a completed xfer
  271: 	 */
  272: 	bp->b_resid = bp->b_bcount;
  273: 	biodone(bp);
  274: }
  275: 
  276: static void
  277: ptinit(void)
  278: {
  279: 	cam_status status;
  280: 	struct cam_path *path;
  281: 
  282: 	/*
  283: 	 * Create our extend array for storing the devices we attach to.
  284: 	 */
  285: 	ptperiphs = cam_extend_new();
  286: 	if (ptperiphs == NULL) {
  287: 		printf("pt: Failed to alloc extend array!\n");
  288: 		return;
  289: 	}
  290: 	
  291: 	/*
  292: 	 * Install a global async callback.  This callback will
  293: 	 * receive async callbacks like "new device found".
  294: 	 */
  295: 	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
  296: 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  297: 
  298: 	if (status == CAM_REQ_CMP) {
  299: 		struct ccb_setasync csa;
  300: 
  301:                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
  302:                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  303:                 csa.event_enable = AC_FOUND_DEVICE;
  304:                 csa.callback = ptasync;
  305:                 csa.callback_arg = NULL;
  306:                 xpt_action((union ccb *)&csa);
  307: 		status = csa.ccb_h.status;
  308:                 xpt_free_path(path);
  309:         }
  310: 
  311: 	if (status != CAM_REQ_CMP) {
  312: 		printf("pt: Failed to attach master async callback "
  313: 		       "due to status 0x%x!\n", status);
  314: 	}
  315: }
  316: 
  317: static cam_status
  318: ptctor(struct cam_periph *periph, void *arg)
  319: {
  320: 	struct pt_softc *softc;
  321: 	struct ccb_setasync csa;
  322: 	struct ccb_getdev *cgd;
  323: 
  324: 	cgd = (struct ccb_getdev *)arg;
  325: 	if (periph == NULL) {
  326: 		printf("ptregister: periph was NULL!!\n");
  327: 		return(CAM_REQ_CMP_ERR);
  328: 	}
  329: 
  330: 	if (cgd == NULL) {
  331: 		printf("ptregister: no getdev CCB, can't register device\n");
  332: 		return(CAM_REQ_CMP_ERR);
  333: 	}
  334: 
  335: 	softc = malloc(sizeof(*softc), M_DEVBUF, M_WAITOK | M_ZERO);
  336: 	LIST_INIT(&softc->pending_ccbs);
  337: 	softc->state = PT_STATE_NORMAL;
  338: 	bufq_init(&softc->buf_queue);
  339: 
  340: 	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
  341: 
  342: 	periph->softc = softc;
  343: 	
  344: 	cam_extend_set(ptperiphs, periph->unit_number, periph);
  345: 
  346: 	devstat_add_entry(&softc->device_stats, "pt",
  347: 			  periph->unit_number, 0,
  348: 			  DEVSTAT_NO_BLOCKSIZE,
  349: 			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
  350: 			  DEVSTAT_PRIORITY_OTHER);
  351: 
  352: 	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
  353: 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
  354: 			      periph->unit_number);
  355: 	/*
  356: 	 * Add async callbacks for bus reset and
  357: 	 * bus device reset calls.  I don't bother
  358: 	 * checking if this fails as, in most cases,
  359: 	 * the system will function just fine without
  360: 	 * them and the only alternative would be to
  361: 	 * not attach the device on failure.
  362: 	 */
  363: 	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
  364: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  365: 	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
  366: 	csa.callback = ptasync;
  367: 	csa.callback_arg = periph;
  368: 	xpt_action((union ccb *)&csa);
  369: 
  370: 	/* Tell the user we've attached to the device */
  371: 	xpt_announce_periph(periph, NULL);
  372: 
  373: 	return(CAM_REQ_CMP);
  374: }
  375: 
  376: static void
  377: ptoninvalidate(struct cam_periph *periph)
  378: {
  379: 	int s;
  380: 	struct pt_softc *softc;
  381: 	struct buf *q_bp;
  382: 	struct ccb_setasync csa;
  383: 
  384: 	softc = (struct pt_softc *)periph->softc;
  385: 
  386: 	/*
  387: 	 * De-register any async callbacks.
  388: 	 */
  389: 	xpt_setup_ccb(&csa.ccb_h, periph->path,
  390: 		      /* priority */ 5);
  391: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  392: 	csa.event_enable = 0;
  393: 	csa.callback = ptasync;
  394: 	csa.callback_arg = periph;
  395: 	xpt_action((union ccb *)&csa);
  396: 
  397: 	softc->flags |= PT_FLAG_DEVICE_INVALID;
  398: 
  399: 	/*
  400: 	 * Although the oninvalidate() routines are always called at
  401: 	 * splsoftcam, we need to be at splbio() here to keep the buffer
  402: 	 * queue from being modified while we traverse it.
  403: 	 */
  404: 	s = splbio();
  405: 
  406: 	/*
  407: 	 * Return all queued I/O with ENXIO.
  408: 	 * XXX Handle any transactions queued to the card
  409: 	 *     with XPT_ABORT_CCB.
  410: 	 */
  411: 	while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
  412: 		bufq_remove(&softc->buf_queue, q_bp);
  413: 		q_bp->b_resid = q_bp->b_bcount;
  414: 		q_bp->b_error = ENXIO;
  415: 		q_bp->b_flags |= B_ERROR;
  416: 		biodone(q_bp);
  417: 	}
  418: 
  419: 	splx(s);
  420: 
  421: 	xpt_print_path(periph->path);
  422: 	printf("lost device\n");
  423: }
  424: 
  425: static void
  426: ptdtor(struct cam_periph *periph)
  427: {
  428: 	struct pt_softc *softc;
  429: 
  430: 	softc = (struct pt_softc *)periph->softc;
  431: 
  432: 	devstat_remove_entry(&softc->device_stats);
  433: 
  434: 	destroy_dev(softc->dev);
  435: 
  436: 	cam_extend_release(ptperiphs, periph->unit_number);
  437: 	xpt_print_path(periph->path);
  438: 	printf("removing device entry\n");
  439: 	free(softc, M_DEVBUF);
  440: }
  441: 
  442: static void
  443: ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  444: {
  445: 	struct cam_periph *periph;
  446: 
  447: 	periph = (struct cam_periph *)callback_arg;
  448: 	switch (code) {
  449: 	case AC_FOUND_DEVICE:
  450: 	{
  451: 		struct ccb_getdev *cgd;
  452: 		cam_status status;
  453:  
  454: 		cgd = (struct ccb_getdev *)arg;
  455: 
  456: 		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
  457: 			break;
  458: 
  459: 		/*
  460: 		 * Allocate a peripheral instance for
  461: 		 * this device and start the probe
  462: 		 * process.
  463: 		 */
  464: 		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
  465: 					  ptstart, "pt", CAM_PERIPH_BIO,
  466: 					  cgd->ccb_h.path, ptasync,
  467: 					  AC_FOUND_DEVICE, cgd);
  468: 
  469: 		if (status != CAM_REQ_CMP
  470: 		 && status != CAM_REQ_INPROG)
  471: 			printf("ptasync: Unable to attach to new device "
  472: 				"due to status 0x%x\n", status);
  473: 		break;
  474: 	}
  475: 	case AC_SENT_BDR:
  476: 	case AC_BUS_RESET:
  477: 	{
  478: 		struct pt_softc *softc;
  479: 		struct ccb_hdr *ccbh;
  480: 		int s;
  481: 
  482: 		softc = (struct pt_softc *)periph->softc;
  483: 		s = splsoftcam();
  484: 		/*
  485: 		 * Don't fail on the expected unit attention
  486: 		 * that will occur.
  487: 		 */
  488: 		softc->flags |= PT_FLAG_RETRY_UA;
  489: 		for (ccbh = LIST_FIRST(&softc->pending_ccbs);
  490: 		     ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le))
  491: 			ccbh->ccb_state |= PT_CCB_RETRY_UA;
  492: 		splx(s);
  493: 		/* FALLTHROUGH */
  494: 	}
  495: 	default:
  496: 		cam_periph_async(periph, code, path, arg);
  497: 		break;
  498: 	}
  499: }
  500: 
  501: static void
  502: ptstart(struct cam_periph *periph, union ccb *start_ccb)
  503: {
  504: 	struct pt_softc *softc;
  505: 	struct buf *bp;
  506: 	int s;
  507: 
  508: 	softc = (struct pt_softc *)periph->softc;
  509: 
  510: 	/*
  511: 	 * See if there is a buf with work for us to do..
  512: 	 */
  513: 	s = splbio();
  514: 	bp = bufq_first(&softc->buf_queue);
  515: 	if (periph->immediate_priority <= periph->pinfo.priority) {
  516: 		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
  517: 				("queuing for immediate ccb\n"));
  518: 		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
  519: 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
  520: 				  periph_links.sle);
  521: 		periph->immediate_priority = CAM_PRIORITY_NONE;
  522: 		splx(s);
  523: 		wakeup(&periph->ccb_list);
  524: 	} else if (bp == NULL) {
  525: 		splx(s);
  526: 		xpt_release_ccb(start_ccb);
  527: 	} else {
  528: 		int oldspl;
  529: 
  530: 		bufq_remove(&softc->buf_queue, bp);
  531: 
  532: 		devstat_start_transaction(&softc->device_stats);
  533: 
  534: 		scsi_send_receive(&start_ccb->csio,
  535: 				  /*retries*/4,
  536: 				  ptdone,
  537: 				  MSG_SIMPLE_Q_TAG,
  538: 				  bp->b_flags & B_READ,
  539: 				  /*byte2*/0,
  540: 				  bp->b_bcount,
  541: 				  bp->b_data,
  542: 				  /*sense_len*/SSD_FULL_SIZE,
  543: 				  /*timeout*/softc->io_timeout);
  544: 
  545: 		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO;
  546: 
  547: 		/*
  548: 		 * Block out any asyncronous callbacks
  549: 		 * while we touch the pending ccb list.
  550: 		 */
  551: 		oldspl = splcam();
  552: 		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
  553: 				 periph_links.le);
  554: 		splx(oldspl);
  555: 
  556: 		start_ccb->ccb_h.ccb_bp = bp;
  557: 		bp = bufq_first(&softc->buf_queue);
  558: 		splx(s);
  559: 
  560: 		xpt_action(start_ccb);
  561: 		
  562: 		if (bp != NULL) {
  563: 			/* Have more work to do, so ensure we stay scheduled */
  564: 			xpt_schedule(periph, /* XXX priority */1);
  565: 		}
  566: 	}
  567: }
  568: 
  569: static void
  570: ptdone(struct cam_periph *periph, union ccb *done_ccb)
  571: {
  572: 	struct pt_softc *softc;
  573: 	struct ccb_scsiio *csio;
  574: 
  575: 	softc = (struct pt_softc *)periph->softc;
  576: 	csio = &done_ccb->csio;
  577: 	switch (csio->ccb_h.ccb_state) {
  578: 	case PT_CCB_BUFFER_IO:
  579: 	case PT_CCB_BUFFER_IO_UA:
  580: 	{
  581: 		struct buf *bp;
  582: 		int    oldspl;
  583: 
  584: 		bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
  585: 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  586: 			int error;
  587: 			int s;
  588: 			int sf;
  589: 			
  590: 			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
  591: 				sf = SF_RETRY_UA;
  592: 			else
  593: 				sf = 0;
  594: 
  595: 			sf |= SF_RETRY_SELTO;
  596: 
  597: 			if ((error = pterror(done_ccb, 0, sf)) == ERESTART) {
  598: 				/*
  599: 				 * A retry was scheuled, so
  600: 				 * just return.
  601: 				 */
  602: 				return;
  603: 			}
  604: 			if (error != 0) {
  605: 				struct buf *q_bp;
  606: 
  607: 				s = splbio();
  608: 
  609: 				if (error == ENXIO) {
  610: 					/*
  611: 					 * Catastrophic error.  Mark our device
  612: 					 * as invalid.
  613: 					 */
  614: 					xpt_print_path(periph->path);
  615: 					printf("Invalidating device\n");
  616: 					softc->flags |= PT_FLAG_DEVICE_INVALID;
  617: 				}
  618: 
  619: 				/*
  620: 				 * return all queued I/O with EIO, so that
  621: 				 * the client can retry these I/Os in the
  622: 				 * proper order should it attempt to recover.
  623: 				 */
  624: 				while ((q_bp = bufq_first(&softc->buf_queue))
  625: 					!= NULL) {
  626: 					bufq_remove(&softc->buf_queue, q_bp);
  627: 					q_bp->b_resid = q_bp->b_bcount;
  628: 					q_bp->b_error = EIO;
  629: 					q_bp->b_flags |= B_ERROR;
  630: 					biodone(q_bp);
  631: 				}
  632: 				splx(s);
  633: 				bp->b_error = error;
  634: 				bp->b_resid = bp->b_bcount;
  635: 				bp->b_flags |= B_ERROR;
  636: 			} else {
  637: 				bp->b_resid = csio->resid;
  638: 				bp->b_error = 0;
  639: 				if (bp->b_resid != 0) {
  640: 					/* Short transfer ??? */
  641: 					bp->b_flags |= B_ERROR;
  642: 				}
  643: 			}
  644: 			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
  645: 				cam_release_devq(done_ccb->ccb_h.path,
  646: 						 /*relsim_flags*/0,
  647: 						 /*reduction*/0,
  648: 						 /*timeout*/0,
  649: 						 /*getcount_only*/0);
  650: 		} else {
  651: 			bp->b_resid = csio->resid;
  652: 			if (bp->b_resid != 0)
  653: 				bp->b_flags |= B_ERROR;
  654: 		}
  655: 
  656: 		/*
  657: 		 * Block out any asyncronous callbacks
  658: 		 * while we touch the pending ccb list.
  659: 		 */
  660: 		oldspl = splcam();
  661: 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
  662: 		splx(oldspl);
  663: 
  664: 		devstat_end_transaction_buf(&softc->device_stats, bp);
  665: 		biodone(bp);
  666: 		break;
  667: 	}
  668: 	case PT_CCB_WAITING:
  669: 		/* Caller will release the CCB */
  670: 		wakeup(&done_ccb->ccb_h.cbfcnp);
  671: 		return;
  672: 	}
  673: 	xpt_release_ccb(done_ccb);
  674: }
  675: 
  676: static int
  677: pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  678: {
  679: 	struct pt_softc	  *softc;
  680: 	struct cam_periph *periph;
  681: 
  682: 	periph = xpt_path_periph(ccb->ccb_h.path);
  683: 	softc = (struct pt_softc *)periph->softc;
  684: 
  685: 	return(cam_periph_error(ccb, cam_flags, sense_flags,
  686: 				&softc->saved_ccb));
  687: }
  688: 
  689: static int
  690: ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  691: {
  692: 	struct cam_periph *periph;
  693: 	struct pt_softc *softc;
  694: 	int unit;
  695: 	int error;
  696: 
  697: 	unit = minor(dev);
  698: 	periph = cam_extend_get(ptperiphs, unit);
  699: 
  700: 	if (periph == NULL)
  701: 		return(ENXIO);
  702: 
  703: 	softc = (struct pt_softc *)periph->softc;
  704: 
  705: 	if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
  706: 		return (error); /* error code from tsleep */
  707: 	}	
  708: 
  709: 	switch(cmd) {
  710: 	case PTIOCGETTIMEOUT:
  711: 		if (softc->io_timeout >= 1000)
  712: 			*(int *)addr = softc->io_timeout / 1000;
  713: 		else
  714: 			*(int *)addr = 0;
  715: 		break;
  716: 	case PTIOCSETTIMEOUT:
  717: 	{
  718: 		int s;
  719: 
  720: 		if (*(int *)addr < 1) {
  721: 			error = EINVAL;
  722: 			break;
  723: 		}
  724: 
  725: 		s = splsoftcam();
  726: 		softc->io_timeout = *(int *)addr * 1000;
  727: 		splx(s);
  728: 
  729: 		break;
  730: 	}
  731: 	default:
  732: 		error = cam_periph_ioctl(periph, cmd, addr, pterror);
  733: 		break;
  734: 	}
  735: 
  736: 	cam_periph_unlock(periph);
  737: 
  738: 	return(error);
  739: }
  740: 
  741: void
  742: scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
  743: 		  void (*cbfcnp)(struct cam_periph *, union ccb *),
  744: 		  u_int tag_action, int readop, u_int byte2,
  745: 		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
  746: 		  u_int32_t timeout)
  747: {
  748: 	struct scsi_send_receive *scsi_cmd;
  749: 
  750: 	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
  751: 	scsi_cmd->opcode = readop ? RECEIVE : SEND;
  752: 	scsi_cmd->byte2 = byte2;
  753: 	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
  754: 	scsi_cmd->control = 0;
  755: 
  756: 	cam_fill_csio(csio,
  757: 		      retries,
  758: 		      cbfcnp,
  759: 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
  760: 		      tag_action,
  761: 		      data_ptr,
  762: 		      xfer_len,
  763: 		      sense_len,
  764: 		      sizeof(*scsi_cmd),
  765: 		      timeout);
  766: }