xref: /freebsd/sys/cam/scsi/scsi_pt.c (revision 898b0535b73b62baaf1d386b169e4d215194a012)
1898b0535SWarner Losh /*-
276babe50SJustin T. Gibbs  * Implementation of SCSI Processor Target Peripheral driver for CAM.
376babe50SJustin T. Gibbs  *
476babe50SJustin T. Gibbs  * Copyright (c) 1998 Justin T. Gibbs.
576babe50SJustin T. Gibbs  * All rights reserved.
676babe50SJustin T. Gibbs  *
776babe50SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
876babe50SJustin T. Gibbs  * modification, are permitted provided that the following conditions
976babe50SJustin T. Gibbs  * are met:
1076babe50SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
1176babe50SJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
1276babe50SJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
1376babe50SJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
1476babe50SJustin T. Gibbs  *    derived from this software without specific prior written permission.
1576babe50SJustin T. Gibbs  *
1676babe50SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1776babe50SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1876babe50SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1976babe50SJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2076babe50SJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2176babe50SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2276babe50SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2376babe50SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2476babe50SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2576babe50SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2676babe50SJustin T. Gibbs  * SUCH DAMAGE.
2776babe50SJustin T. Gibbs  */
2876babe50SJustin T. Gibbs 
29ee709e70SDavid E. O'Brien #include <sys/cdefs.h>
30ee709e70SDavid E. O'Brien __FBSDID("$FreeBSD$");
31ee709e70SDavid E. O'Brien 
3276babe50SJustin T. Gibbs #include <sys/param.h>
3376babe50SJustin T. Gibbs #include <sys/queue.h>
3476babe50SJustin T. Gibbs #include <sys/systm.h>
3576babe50SJustin T. Gibbs #include <sys/kernel.h>
3676babe50SJustin T. Gibbs #include <sys/types.h>
379626b608SPoul-Henning Kamp #include <sys/bio.h>
3876babe50SJustin T. Gibbs #include <sys/devicestat.h>
3976babe50SJustin T. Gibbs #include <sys/malloc.h>
4076babe50SJustin T. Gibbs #include <sys/conf.h>
413ece1bd2SKenneth D. Merry #include <sys/ptio.h>
4276babe50SJustin T. Gibbs 
4376babe50SJustin T. Gibbs #include <cam/cam.h>
4476babe50SJustin T. Gibbs #include <cam/cam_ccb.h>
4576babe50SJustin T. Gibbs #include <cam/cam_periph.h>
4676babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h>
4776babe50SJustin T. Gibbs #include <cam/cam_debug.h>
4876babe50SJustin T. Gibbs 
4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h>
5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h>
5176babe50SJustin T. Gibbs #include <cam/scsi/scsi_pt.h>
5276babe50SJustin T. Gibbs 
533ece1bd2SKenneth D. Merry #include "opt_pt.h"
543ece1bd2SKenneth D. Merry 
5576babe50SJustin T. Gibbs typedef enum {
5676babe50SJustin T. Gibbs 	PT_STATE_PROBE,
5776babe50SJustin T. Gibbs 	PT_STATE_NORMAL
5876babe50SJustin T. Gibbs } pt_state;
5976babe50SJustin T. Gibbs 
6076babe50SJustin T. Gibbs typedef enum {
6176babe50SJustin T. Gibbs 	PT_FLAG_NONE		= 0x00,
6276babe50SJustin T. Gibbs 	PT_FLAG_OPEN		= 0x01,
6376babe50SJustin T. Gibbs 	PT_FLAG_DEVICE_INVALID	= 0x02,
6476babe50SJustin T. Gibbs 	PT_FLAG_RETRY_UA	= 0x04
6576babe50SJustin T. Gibbs } pt_flags;
6676babe50SJustin T. Gibbs 
6776babe50SJustin T. Gibbs typedef enum {
6876babe50SJustin T. Gibbs 	PT_CCB_BUFFER_IO	= 0x01,
6976babe50SJustin T. Gibbs 	PT_CCB_WAITING		= 0x02,
7076babe50SJustin T. Gibbs 	PT_CCB_RETRY_UA		= 0x04,
7176babe50SJustin T. Gibbs 	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
7276babe50SJustin T. Gibbs } pt_ccb_state;
7376babe50SJustin T. Gibbs 
7476babe50SJustin T. Gibbs /* Offsets into our private area for storing information */
7576babe50SJustin T. Gibbs #define ccb_state	ppriv_field0
7676babe50SJustin T. Gibbs #define ccb_bp		ppriv_ptr1
7776babe50SJustin T. Gibbs 
7876babe50SJustin T. Gibbs struct pt_softc {
798177437dSPoul-Henning Kamp 	struct	 bio_queue_head bio_queue;
80a9d2245eSPoul-Henning Kamp 	struct	 devstat *device_stats;
81e3975643SJake Burkholder 	LIST_HEAD(, ccb_hdr) pending_ccbs;
8276babe50SJustin T. Gibbs 	pt_state state;
8376babe50SJustin T. Gibbs 	pt_flags flags;
8476babe50SJustin T. Gibbs 	union	 ccb saved_ccb;
853ece1bd2SKenneth D. Merry 	int	 io_timeout;
8689c9c53dSPoul-Henning Kamp 	struct cdev *dev;
8776babe50SJustin T. Gibbs };
8876babe50SJustin T. Gibbs 
8976babe50SJustin T. Gibbs static	d_open_t	ptopen;
9076babe50SJustin T. Gibbs static	d_close_t	ptclose;
9176babe50SJustin T. Gibbs static	d_strategy_t	ptstrategy;
9276babe50SJustin T. Gibbs static	periph_init_t	ptinit;
9376babe50SJustin T. Gibbs static	void		ptasync(void *callback_arg, u_int32_t code,
9476babe50SJustin T. Gibbs 				struct cam_path *path, void *arg);
9576babe50SJustin T. Gibbs static	periph_ctor_t	ptctor;
96ee9c90c7SKenneth D. Merry static	periph_oninv_t	ptoninvalidate;
9776babe50SJustin T. Gibbs static	periph_dtor_t	ptdtor;
9876babe50SJustin T. Gibbs static	periph_start_t	ptstart;
9976babe50SJustin T. Gibbs static	void		ptdone(struct cam_periph *periph,
10076babe50SJustin T. Gibbs 			       union ccb *done_ccb);
1013ece1bd2SKenneth D. Merry static	d_ioctl_t	ptioctl;
10276babe50SJustin T. Gibbs static  int		pterror(union ccb *ccb, u_int32_t cam_flags,
10376babe50SJustin T. Gibbs 				u_int32_t sense_flags);
10476babe50SJustin T. Gibbs 
10576babe50SJustin T. Gibbs void	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
10676babe50SJustin T. Gibbs 			  void (*cbfcnp)(struct cam_periph *, union ccb *),
10776babe50SJustin T. Gibbs 			  u_int tag_action, int readop, u_int byte2,
10876babe50SJustin T. Gibbs 			  u_int32_t xfer_len, u_int8_t *data_ptr,
10976babe50SJustin T. Gibbs 			  u_int8_t sense_len, u_int32_t timeout);
11076babe50SJustin T. Gibbs 
11176babe50SJustin T. Gibbs static struct periph_driver ptdriver =
11276babe50SJustin T. Gibbs {
11376babe50SJustin T. Gibbs 	ptinit, "pt",
11476babe50SJustin T. Gibbs 	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11576babe50SJustin T. Gibbs };
11676babe50SJustin T. Gibbs 
1170b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pt, ptdriver);
11876babe50SJustin T. Gibbs 
11976babe50SJustin T. Gibbs 
1204e2f199eSPoul-Henning Kamp static struct cdevsw pt_cdevsw = {
121dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
122dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1237ac40f5fSPoul-Henning Kamp 	.d_open =	ptopen,
1247ac40f5fSPoul-Henning Kamp 	.d_close =	ptclose,
1257ac40f5fSPoul-Henning Kamp 	.d_read =	physread,
1267ac40f5fSPoul-Henning Kamp 	.d_write =	physwrite,
1277ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ptioctl,
1287ac40f5fSPoul-Henning Kamp 	.d_strategy =	ptstrategy,
1297ac40f5fSPoul-Henning Kamp 	.d_name =	"pt",
13076babe50SJustin T. Gibbs };
13176babe50SJustin T. Gibbs 
1323ece1bd2SKenneth D. Merry #ifndef SCSI_PT_DEFAULT_TIMEOUT
1333ece1bd2SKenneth D. Merry #define SCSI_PT_DEFAULT_TIMEOUT		60
1343ece1bd2SKenneth D. Merry #endif
1353ece1bd2SKenneth D. Merry 
13676babe50SJustin T. Gibbs static int
13789c9c53dSPoul-Henning Kamp ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
13876babe50SJustin T. Gibbs {
13976babe50SJustin T. Gibbs 	struct cam_periph *periph;
14076babe50SJustin T. Gibbs 	struct pt_softc *softc;
14176babe50SJustin T. Gibbs 	int unit;
14276babe50SJustin T. Gibbs 	int error;
143ee9c90c7SKenneth D. Merry 	int s;
14476babe50SJustin T. Gibbs 
14576babe50SJustin T. Gibbs 	unit = minor(dev);
146e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
14776babe50SJustin T. Gibbs 	if (periph == NULL)
14876babe50SJustin T. Gibbs 		return (ENXIO);
14976babe50SJustin T. Gibbs 
15076babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
15176babe50SJustin T. Gibbs 
152ee9c90c7SKenneth D. Merry 	s = splsoftcam();
153ee9c90c7SKenneth D. Merry 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
154ee9c90c7SKenneth D. Merry 		splx(s);
155ee9c90c7SKenneth D. Merry 		return(ENXIO);
156ee9c90c7SKenneth D. Merry 	}
157ee9c90c7SKenneth D. Merry 
15876babe50SJustin T. Gibbs 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
159b8e49f68SBill Fumerola 	    ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
16076babe50SJustin T. Gibbs 
16122b9c86cSKenneth D. Merry 	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
16222b9c86cSKenneth D. Merry 		splx(s);
16376babe50SJustin T. Gibbs 		return (error); /* error code from tsleep */
16422b9c86cSKenneth D. Merry 	}
16522b9c86cSKenneth D. Merry 
16622b9c86cSKenneth D. Merry 	splx(s);
16776babe50SJustin T. Gibbs 
16876babe50SJustin T. Gibbs 	if ((softc->flags & PT_FLAG_OPEN) == 0) {
16976babe50SJustin T. Gibbs 		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
17076babe50SJustin T. Gibbs 			error = ENXIO;
17176babe50SJustin T. Gibbs 		else
17276babe50SJustin T. Gibbs 			softc->flags |= PT_FLAG_OPEN;
17376babe50SJustin T. Gibbs 	} else
17476babe50SJustin T. Gibbs 		error = EBUSY;
17576babe50SJustin T. Gibbs 
17676babe50SJustin T. Gibbs 	cam_periph_unlock(periph);
17776babe50SJustin T. Gibbs 	return (error);
17876babe50SJustin T. Gibbs }
17976babe50SJustin T. Gibbs 
18076babe50SJustin T. Gibbs static int
18189c9c53dSPoul-Henning Kamp ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
18276babe50SJustin T. Gibbs {
18376babe50SJustin T. Gibbs 	struct	cam_periph *periph;
18476babe50SJustin T. Gibbs 	struct	pt_softc *softc;
18576babe50SJustin T. Gibbs 	int	error;
18676babe50SJustin T. Gibbs 
187e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
18876babe50SJustin T. Gibbs 	if (periph == NULL)
18976babe50SJustin T. Gibbs 		return (ENXIO);
19076babe50SJustin T. Gibbs 
19176babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
19276babe50SJustin T. Gibbs 
19376babe50SJustin T. Gibbs 	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
19476babe50SJustin T. Gibbs 		return (error); /* error code from tsleep */
19576babe50SJustin T. Gibbs 
19676babe50SJustin T. Gibbs 	softc->flags &= ~PT_FLAG_OPEN;
19776babe50SJustin T. Gibbs 	cam_periph_unlock(periph);
19876babe50SJustin T. Gibbs 	cam_periph_release(periph);
19976babe50SJustin T. Gibbs 	return (0);
20076babe50SJustin T. Gibbs }
20176babe50SJustin T. Gibbs 
20276babe50SJustin T. Gibbs /*
20376babe50SJustin T. Gibbs  * Actually translate the requested transfer into one the physical driver
20476babe50SJustin T. Gibbs  * can understand.  The transfer is described by a buf and will include
20576babe50SJustin T. Gibbs  * only one physical transfer.
20676babe50SJustin T. Gibbs  */
20776babe50SJustin T. Gibbs static void
2088177437dSPoul-Henning Kamp ptstrategy(struct bio *bp)
20976babe50SJustin T. Gibbs {
21076babe50SJustin T. Gibbs 	struct cam_periph *periph;
21176babe50SJustin T. Gibbs 	struct pt_softc *softc;
21276babe50SJustin T. Gibbs 	int    s;
21376babe50SJustin T. Gibbs 
214e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
215b63170f8SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount;
21676babe50SJustin T. Gibbs 	if (periph == NULL) {
217b63170f8SPoul-Henning Kamp 		biofinish(bp, NULL, ENXIO);
218b63170f8SPoul-Henning Kamp 		return;
21976babe50SJustin T. Gibbs 	}
22076babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
22176babe50SJustin T. Gibbs 
22276babe50SJustin T. Gibbs 	/*
22376babe50SJustin T. Gibbs 	 * Mask interrupts so that the pack cannot be invalidated until
22476babe50SJustin T. Gibbs 	 * after we are in the queue.  Otherwise, we might not properly
22576babe50SJustin T. Gibbs 	 * clean up one of the buffers.
22676babe50SJustin T. Gibbs 	 */
22776babe50SJustin T. Gibbs 	s = splbio();
22876babe50SJustin T. Gibbs 
22976babe50SJustin T. Gibbs 	/*
23076babe50SJustin T. Gibbs 	 * If the device has been made invalid, error out
23176babe50SJustin T. Gibbs 	 */
23276babe50SJustin T. Gibbs 	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
23376babe50SJustin T. Gibbs 		splx(s);
234b63170f8SPoul-Henning Kamp 		biofinish(bp, NULL, ENXIO);
235b63170f8SPoul-Henning Kamp 		return;
23676babe50SJustin T. Gibbs 	}
23776babe50SJustin T. Gibbs 
23876babe50SJustin T. Gibbs 	/*
23976babe50SJustin T. Gibbs 	 * Place it in the queue of disk activities for this disk
24076babe50SJustin T. Gibbs 	 */
2418177437dSPoul-Henning Kamp 	bioq_insert_tail(&softc->bio_queue, bp);
24276babe50SJustin T. Gibbs 
24376babe50SJustin T. Gibbs 	splx(s);
24476babe50SJustin T. Gibbs 
24576babe50SJustin T. Gibbs 	/*
24676babe50SJustin T. Gibbs 	 * Schedule ourselves for performing the work.
24776babe50SJustin T. Gibbs 	 */
24876babe50SJustin T. Gibbs 	xpt_schedule(periph, /* XXX priority */1);
24976babe50SJustin T. Gibbs 
25076babe50SJustin T. Gibbs 	return;
25176babe50SJustin T. Gibbs }
25276babe50SJustin T. Gibbs 
25376babe50SJustin T. Gibbs static void
25476babe50SJustin T. Gibbs ptinit(void)
25576babe50SJustin T. Gibbs {
25676babe50SJustin T. Gibbs 	cam_status status;
25776babe50SJustin T. Gibbs 	struct cam_path *path;
25876babe50SJustin T. Gibbs 
25976babe50SJustin T. Gibbs 	/*
26076babe50SJustin T. Gibbs 	 * Install a global async callback.  This callback will
26176babe50SJustin T. Gibbs 	 * receive async callbacks like "new device found".
26276babe50SJustin T. Gibbs 	 */
26376babe50SJustin T. Gibbs 	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
26476babe50SJustin T. Gibbs 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
26576babe50SJustin T. Gibbs 
26676babe50SJustin T. Gibbs 	if (status == CAM_REQ_CMP) {
26776babe50SJustin T. Gibbs 		struct ccb_setasync csa;
26876babe50SJustin T. Gibbs 
26976babe50SJustin T. Gibbs                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
27076babe50SJustin T. Gibbs                 csa.ccb_h.func_code = XPT_SASYNC_CB;
27176babe50SJustin T. Gibbs                 csa.event_enable = AC_FOUND_DEVICE;
27276babe50SJustin T. Gibbs                 csa.callback = ptasync;
27376babe50SJustin T. Gibbs                 csa.callback_arg = NULL;
27476babe50SJustin T. Gibbs                 xpt_action((union ccb *)&csa);
27576babe50SJustin T. Gibbs 		status = csa.ccb_h.status;
27676babe50SJustin T. Gibbs                 xpt_free_path(path);
27776babe50SJustin T. Gibbs         }
27876babe50SJustin T. Gibbs 
27976babe50SJustin T. Gibbs 	if (status != CAM_REQ_CMP) {
28076babe50SJustin T. Gibbs 		printf("pt: Failed to attach master async callback "
28176babe50SJustin T. Gibbs 		       "due to status 0x%x!\n", status);
28276babe50SJustin T. Gibbs 	}
28376babe50SJustin T. Gibbs }
28476babe50SJustin T. Gibbs 
28576babe50SJustin T. Gibbs static cam_status
28676babe50SJustin T. Gibbs ptctor(struct cam_periph *periph, void *arg)
28776babe50SJustin T. Gibbs {
28876babe50SJustin T. Gibbs 	struct pt_softc *softc;
28976babe50SJustin T. Gibbs 	struct ccb_setasync csa;
29076babe50SJustin T. Gibbs 	struct ccb_getdev *cgd;
29176babe50SJustin T. Gibbs 
29276babe50SJustin T. Gibbs 	cgd = (struct ccb_getdev *)arg;
29376babe50SJustin T. Gibbs 	if (periph == NULL) {
29476babe50SJustin T. Gibbs 		printf("ptregister: periph was NULL!!\n");
29576babe50SJustin T. Gibbs 		return(CAM_REQ_CMP_ERR);
29676babe50SJustin T. Gibbs 	}
29776babe50SJustin T. Gibbs 
29876babe50SJustin T. Gibbs 	if (cgd == NULL) {
29976babe50SJustin T. Gibbs 		printf("ptregister: no getdev CCB, can't register device\n");
30076babe50SJustin T. Gibbs 		return(CAM_REQ_CMP_ERR);
30176babe50SJustin T. Gibbs 	}
30276babe50SJustin T. Gibbs 
30376babe50SJustin T. Gibbs 	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
30476babe50SJustin T. Gibbs 
30576babe50SJustin T. Gibbs 	if (softc == NULL) {
30676babe50SJustin T. Gibbs 		printf("daregister: Unable to probe new device. "
30776babe50SJustin T. Gibbs 		       "Unable to allocate softc\n");
30876babe50SJustin T. Gibbs 		return(CAM_REQ_CMP_ERR);
30976babe50SJustin T. Gibbs 	}
31076babe50SJustin T. Gibbs 
31176babe50SJustin T. Gibbs 	bzero(softc, sizeof(*softc));
31276babe50SJustin T. Gibbs 	LIST_INIT(&softc->pending_ccbs);
31376babe50SJustin T. Gibbs 	softc->state = PT_STATE_NORMAL;
3148177437dSPoul-Henning Kamp 	bioq_init(&softc->bio_queue);
31576babe50SJustin T. Gibbs 
3163ece1bd2SKenneth D. Merry 	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
3173ece1bd2SKenneth D. Merry 
31876babe50SJustin T. Gibbs 	periph->softc = softc;
31976babe50SJustin T. Gibbs 
320a9d2245eSPoul-Henning Kamp 	softc->device_stats = devstat_new_entry("pt",
32176babe50SJustin T. Gibbs 			  periph->unit_number, 0,
32276babe50SJustin T. Gibbs 			  DEVSTAT_NO_BLOCKSIZE,
32310b6172aSMatt Jacob 			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
3242a888f93SKenneth D. Merry 			  DEVSTAT_PRIORITY_OTHER);
32576babe50SJustin T. Gibbs 
32673d26919SKenneth D. Merry 	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
32773d26919SKenneth D. Merry 			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
32873d26919SKenneth D. Merry 			      periph->unit_number);
329e2a5fdf9SNate Lawson 	softc->dev->si_drv1 = periph;
330e2a5fdf9SNate Lawson 
33176babe50SJustin T. Gibbs 	/*
33276babe50SJustin T. Gibbs 	 * Add async callbacks for bus reset and
33376babe50SJustin T. Gibbs 	 * bus device reset calls.  I don't bother
33476babe50SJustin T. Gibbs 	 * checking if this fails as, in most cases,
33576babe50SJustin T. Gibbs 	 * the system will function just fine without
33676babe50SJustin T. Gibbs 	 * them and the only alternative would be to
33776babe50SJustin T. Gibbs 	 * not attach the device on failure.
33876babe50SJustin T. Gibbs 	 */
33976babe50SJustin T. Gibbs 	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
34076babe50SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
34176babe50SJustin T. Gibbs 	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
34276babe50SJustin T. Gibbs 	csa.callback = ptasync;
34376babe50SJustin T. Gibbs 	csa.callback_arg = periph;
34476babe50SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
34576babe50SJustin T. Gibbs 
34676babe50SJustin T. Gibbs 	/* Tell the user we've attached to the device */
34776babe50SJustin T. Gibbs 	xpt_announce_periph(periph, NULL);
34876babe50SJustin T. Gibbs 
34976babe50SJustin T. Gibbs 	return(CAM_REQ_CMP);
35076babe50SJustin T. Gibbs }
35176babe50SJustin T. Gibbs 
35276babe50SJustin T. Gibbs static void
353ee9c90c7SKenneth D. Merry ptoninvalidate(struct cam_periph *periph)
354ee9c90c7SKenneth D. Merry {
355ee9c90c7SKenneth D. Merry 	int s;
356ee9c90c7SKenneth D. Merry 	struct pt_softc *softc;
357ee9c90c7SKenneth D. Merry 	struct ccb_setasync csa;
358ee9c90c7SKenneth D. Merry 
359ee9c90c7SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
360ee9c90c7SKenneth D. Merry 
361ee9c90c7SKenneth D. Merry 	/*
362ee9c90c7SKenneth D. Merry 	 * De-register any async callbacks.
363ee9c90c7SKenneth D. Merry 	 */
364ee9c90c7SKenneth D. Merry 	xpt_setup_ccb(&csa.ccb_h, periph->path,
365ee9c90c7SKenneth D. Merry 		      /* priority */ 5);
366ee9c90c7SKenneth D. Merry 	csa.ccb_h.func_code = XPT_SASYNC_CB;
367ee9c90c7SKenneth D. Merry 	csa.event_enable = 0;
368ee9c90c7SKenneth D. Merry 	csa.callback = ptasync;
369ee9c90c7SKenneth D. Merry 	csa.callback_arg = periph;
370ee9c90c7SKenneth D. Merry 	xpt_action((union ccb *)&csa);
371ee9c90c7SKenneth D. Merry 
372ee9c90c7SKenneth D. Merry 	softc->flags |= PT_FLAG_DEVICE_INVALID;
373ee9c90c7SKenneth D. Merry 
374ee9c90c7SKenneth D. Merry 	/*
375ee9c90c7SKenneth D. Merry 	 * Although the oninvalidate() routines are always called at
376ee9c90c7SKenneth D. Merry 	 * splsoftcam, we need to be at splbio() here to keep the buffer
377ee9c90c7SKenneth D. Merry 	 * queue from being modified while we traverse it.
378ee9c90c7SKenneth D. Merry 	 */
379ee9c90c7SKenneth D. Merry 	s = splbio();
380ee9c90c7SKenneth D. Merry 
381ee9c90c7SKenneth D. Merry 	/*
382ee9c90c7SKenneth D. Merry 	 * Return all queued I/O with ENXIO.
383ee9c90c7SKenneth D. Merry 	 * XXX Handle any transactions queued to the card
384ee9c90c7SKenneth D. Merry 	 *     with XPT_ABORT_CCB.
385ee9c90c7SKenneth D. Merry 	 */
386891619a6SPoul-Henning Kamp 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
387ee9c90c7SKenneth D. Merry 
388ee9c90c7SKenneth D. Merry 	splx(s);
389ee9c90c7SKenneth D. Merry 
390ee9c90c7SKenneth D. Merry 	xpt_print_path(periph->path);
391ee9c90c7SKenneth D. Merry 	printf("lost device\n");
392ee9c90c7SKenneth D. Merry }
393ee9c90c7SKenneth D. Merry 
394ee9c90c7SKenneth D. Merry static void
39576babe50SJustin T. Gibbs ptdtor(struct cam_periph *periph)
39676babe50SJustin T. Gibbs {
397ee9c90c7SKenneth D. Merry 	struct pt_softc *softc;
398ee9c90c7SKenneth D. Merry 
399ee9c90c7SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
400ee9c90c7SKenneth D. Merry 
401a9d2245eSPoul-Henning Kamp 	devstat_remove_entry(softc->device_stats);
402ee9c90c7SKenneth D. Merry 
40373d26919SKenneth D. Merry 	destroy_dev(softc->dev);
40473d26919SKenneth D. Merry 
40576babe50SJustin T. Gibbs 	xpt_print_path(periph->path);
40676babe50SJustin T. Gibbs 	printf("removing device entry\n");
407ee9c90c7SKenneth D. Merry 	free(softc, M_DEVBUF);
40876babe50SJustin T. Gibbs }
40976babe50SJustin T. Gibbs 
41076babe50SJustin T. Gibbs static void
41176babe50SJustin T. Gibbs ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
41276babe50SJustin T. Gibbs {
41376babe50SJustin T. Gibbs 	struct cam_periph *periph;
41476babe50SJustin T. Gibbs 
41576babe50SJustin T. Gibbs 	periph = (struct cam_periph *)callback_arg;
41676babe50SJustin T. Gibbs 	switch (code) {
41776babe50SJustin T. Gibbs 	case AC_FOUND_DEVICE:
41876babe50SJustin T. Gibbs 	{
41976babe50SJustin T. Gibbs 		struct ccb_getdev *cgd;
42076babe50SJustin T. Gibbs 		cam_status status;
42176babe50SJustin T. Gibbs 
42276babe50SJustin T. Gibbs 		cgd = (struct ccb_getdev *)arg;
423c5ff3b2fSMatt Jacob 		if (cgd == NULL)
424c5ff3b2fSMatt Jacob 			break;
42576babe50SJustin T. Gibbs 
42610b6172aSMatt Jacob 		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
42776babe50SJustin T. Gibbs 			break;
42876babe50SJustin T. Gibbs 
42976babe50SJustin T. Gibbs 		/*
43076babe50SJustin T. Gibbs 		 * Allocate a peripheral instance for
43176babe50SJustin T. Gibbs 		 * this device and start the probe
43276babe50SJustin T. Gibbs 		 * process.
43376babe50SJustin T. Gibbs 		 */
434ee9c90c7SKenneth D. Merry 		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
435ee9c90c7SKenneth D. Merry 					  ptstart, "pt", CAM_PERIPH_BIO,
436ee9c90c7SKenneth D. Merry 					  cgd->ccb_h.path, ptasync,
437ee9c90c7SKenneth D. Merry 					  AC_FOUND_DEVICE, cgd);
43876babe50SJustin T. Gibbs 
43976babe50SJustin T. Gibbs 		if (status != CAM_REQ_CMP
44076babe50SJustin T. Gibbs 		 && status != CAM_REQ_INPROG)
44176babe50SJustin T. Gibbs 			printf("ptasync: Unable to attach to new device "
44276babe50SJustin T. Gibbs 				"due to status 0x%x\n", status);
44376babe50SJustin T. Gibbs 		break;
44476babe50SJustin T. Gibbs 	}
44576babe50SJustin T. Gibbs 	case AC_SENT_BDR:
44676babe50SJustin T. Gibbs 	case AC_BUS_RESET:
44776babe50SJustin T. Gibbs 	{
44876babe50SJustin T. Gibbs 		struct pt_softc *softc;
44976babe50SJustin T. Gibbs 		struct ccb_hdr *ccbh;
45076babe50SJustin T. Gibbs 		int s;
45176babe50SJustin T. Gibbs 
45276babe50SJustin T. Gibbs 		softc = (struct pt_softc *)periph->softc;
45376babe50SJustin T. Gibbs 		s = splsoftcam();
45476babe50SJustin T. Gibbs 		/*
45576babe50SJustin T. Gibbs 		 * Don't fail on the expected unit attention
45676babe50SJustin T. Gibbs 		 * that will occur.
45776babe50SJustin T. Gibbs 		 */
45876babe50SJustin T. Gibbs 		softc->flags |= PT_FLAG_RETRY_UA;
459fc2ffbe6SPoul-Henning Kamp 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
46076babe50SJustin T. Gibbs 			ccbh->ccb_state |= PT_CCB_RETRY_UA;
46176babe50SJustin T. Gibbs 		splx(s);
46276babe50SJustin T. Gibbs 	}
46307c6eac9SPoul-Henning Kamp 	/* FALLTHROUGH */
46476babe50SJustin T. Gibbs 	default:
465516871c6SJustin T. Gibbs 		cam_periph_async(periph, code, path, arg);
46676babe50SJustin T. Gibbs 		break;
46776babe50SJustin T. Gibbs 	}
46876babe50SJustin T. Gibbs }
46976babe50SJustin T. Gibbs 
47076babe50SJustin T. Gibbs static void
47176babe50SJustin T. Gibbs ptstart(struct cam_periph *periph, union ccb *start_ccb)
47276babe50SJustin T. Gibbs {
47376babe50SJustin T. Gibbs 	struct pt_softc *softc;
4748177437dSPoul-Henning Kamp 	struct bio *bp;
47576babe50SJustin T. Gibbs 	int s;
47676babe50SJustin T. Gibbs 
47776babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
47876babe50SJustin T. Gibbs 
47976babe50SJustin T. Gibbs 	/*
48076babe50SJustin T. Gibbs 	 * See if there is a buf with work for us to do..
48176babe50SJustin T. Gibbs 	 */
48276babe50SJustin T. Gibbs 	s = splbio();
4838177437dSPoul-Henning Kamp 	bp = bioq_first(&softc->bio_queue);
48476babe50SJustin T. Gibbs 	if (periph->immediate_priority <= periph->pinfo.priority) {
48576babe50SJustin T. Gibbs 		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
48676babe50SJustin T. Gibbs 				("queuing for immediate ccb\n"));
48776babe50SJustin T. Gibbs 		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
48876babe50SJustin T. Gibbs 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
48976babe50SJustin T. Gibbs 				  periph_links.sle);
49076babe50SJustin T. Gibbs 		periph->immediate_priority = CAM_PRIORITY_NONE;
49176babe50SJustin T. Gibbs 		splx(s);
49276babe50SJustin T. Gibbs 		wakeup(&periph->ccb_list);
49376babe50SJustin T. Gibbs 	} else if (bp == NULL) {
49476babe50SJustin T. Gibbs 		splx(s);
49576babe50SJustin T. Gibbs 		xpt_release_ccb(start_ccb);
49676babe50SJustin T. Gibbs 	} else {
49776babe50SJustin T. Gibbs 		int oldspl;
49876babe50SJustin T. Gibbs 
4998177437dSPoul-Henning Kamp 		bioq_remove(&softc->bio_queue, bp);
50076babe50SJustin T. Gibbs 
5011ecc485cSPoul-Henning Kamp 		devstat_start_transaction_bio(softc->device_stats, bp);
50276babe50SJustin T. Gibbs 
50376babe50SJustin T. Gibbs 		scsi_send_receive(&start_ccb->csio,
50476babe50SJustin T. Gibbs 				  /*retries*/4,
50576babe50SJustin T. Gibbs 				  ptdone,
50676babe50SJustin T. Gibbs 				  MSG_SIMPLE_Q_TAG,
5078177437dSPoul-Henning Kamp 				  bp->bio_cmd == BIO_READ,
50876babe50SJustin T. Gibbs 				  /*byte2*/0,
5098177437dSPoul-Henning Kamp 				  bp->bio_bcount,
5108177437dSPoul-Henning Kamp 				  bp->bio_data,
51176babe50SJustin T. Gibbs 				  /*sense_len*/SSD_FULL_SIZE,
5123ece1bd2SKenneth D. Merry 				  /*timeout*/softc->io_timeout);
51376babe50SJustin T. Gibbs 
5149c6a0920SKenneth D. Merry 		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
51576babe50SJustin T. Gibbs 
51676babe50SJustin T. Gibbs 		/*
51776babe50SJustin T. Gibbs 		 * Block out any asyncronous callbacks
51876babe50SJustin T. Gibbs 		 * while we touch the pending ccb list.
51976babe50SJustin T. Gibbs 		 */
52076babe50SJustin T. Gibbs 		oldspl = splcam();
52176babe50SJustin T. Gibbs 		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
52276babe50SJustin T. Gibbs 				 periph_links.le);
52376babe50SJustin T. Gibbs 		splx(oldspl);
52476babe50SJustin T. Gibbs 
52576babe50SJustin T. Gibbs 		start_ccb->ccb_h.ccb_bp = bp;
5268177437dSPoul-Henning Kamp 		bp = bioq_first(&softc->bio_queue);
52776babe50SJustin T. Gibbs 		splx(s);
52876babe50SJustin T. Gibbs 
52976babe50SJustin T. Gibbs 		xpt_action(start_ccb);
53076babe50SJustin T. Gibbs 
53176babe50SJustin T. Gibbs 		if (bp != NULL) {
53276babe50SJustin T. Gibbs 			/* Have more work to do, so ensure we stay scheduled */
53376babe50SJustin T. Gibbs 			xpt_schedule(periph, /* XXX priority */1);
53476babe50SJustin T. Gibbs 		}
53576babe50SJustin T. Gibbs 	}
53676babe50SJustin T. Gibbs }
53776babe50SJustin T. Gibbs 
53876babe50SJustin T. Gibbs static void
53976babe50SJustin T. Gibbs ptdone(struct cam_periph *periph, union ccb *done_ccb)
54076babe50SJustin T. Gibbs {
54176babe50SJustin T. Gibbs 	struct pt_softc *softc;
54276babe50SJustin T. Gibbs 	struct ccb_scsiio *csio;
54376babe50SJustin T. Gibbs 
54476babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
54576babe50SJustin T. Gibbs 	csio = &done_ccb->csio;
54676babe50SJustin T. Gibbs 	switch (csio->ccb_h.ccb_state) {
54776babe50SJustin T. Gibbs 	case PT_CCB_BUFFER_IO:
54876babe50SJustin T. Gibbs 	case PT_CCB_BUFFER_IO_UA:
54976babe50SJustin T. Gibbs 	{
5508177437dSPoul-Henning Kamp 		struct bio *bp;
55176babe50SJustin T. Gibbs 		int    oldspl;
55276babe50SJustin T. Gibbs 
5538177437dSPoul-Henning Kamp 		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
55476babe50SJustin T. Gibbs 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
55576babe50SJustin T. Gibbs 			int error;
55676babe50SJustin T. Gibbs 			int s;
55776babe50SJustin T. Gibbs 			int sf;
55876babe50SJustin T. Gibbs 
55976babe50SJustin T. Gibbs 			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
56076babe50SJustin T. Gibbs 				sf = SF_RETRY_UA;
56176babe50SJustin T. Gibbs 			else
56276babe50SJustin T. Gibbs 				sf = 0;
56376babe50SJustin T. Gibbs 
5643393f8daSKenneth D. Merry 			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
5653393f8daSKenneth D. Merry 			if (error == ERESTART) {
56676babe50SJustin T. Gibbs 				/*
56776babe50SJustin T. Gibbs 				 * A retry was scheuled, so
56876babe50SJustin T. Gibbs 				 * just return.
56976babe50SJustin T. Gibbs 				 */
57076babe50SJustin T. Gibbs 				return;
57176babe50SJustin T. Gibbs 			}
57276babe50SJustin T. Gibbs 			if (error != 0) {
57376babe50SJustin T. Gibbs 				s = splbio();
57476babe50SJustin T. Gibbs 
57576babe50SJustin T. Gibbs 				if (error == ENXIO) {
57676babe50SJustin T. Gibbs 					/*
57776babe50SJustin T. Gibbs 					 * Catastrophic error.  Mark our device
57876babe50SJustin T. Gibbs 					 * as invalid.
57976babe50SJustin T. Gibbs 					 */
58076babe50SJustin T. Gibbs 					xpt_print_path(periph->path);
58176babe50SJustin T. Gibbs 					printf("Invalidating device\n");
58276babe50SJustin T. Gibbs 					softc->flags |= PT_FLAG_DEVICE_INVALID;
58376babe50SJustin T. Gibbs 				}
58476babe50SJustin T. Gibbs 
58576babe50SJustin T. Gibbs 				/*
58676babe50SJustin T. Gibbs 				 * return all queued I/O with EIO, so that
58776babe50SJustin T. Gibbs 				 * the client can retry these I/Os in the
58876babe50SJustin T. Gibbs 				 * proper order should it attempt to recover.
58976babe50SJustin T. Gibbs 				 */
590891619a6SPoul-Henning Kamp 				bioq_flush(&softc->bio_queue, NULL, EIO);
59176babe50SJustin T. Gibbs 				splx(s);
5928177437dSPoul-Henning Kamp 				bp->bio_error = error;
5938177437dSPoul-Henning Kamp 				bp->bio_resid = bp->bio_bcount;
5948177437dSPoul-Henning Kamp 				bp->bio_flags |= BIO_ERROR;
59576babe50SJustin T. Gibbs 			} else {
5968177437dSPoul-Henning Kamp 				bp->bio_resid = csio->resid;
5978177437dSPoul-Henning Kamp 				bp->bio_error = 0;
5988177437dSPoul-Henning Kamp 				if (bp->bio_resid != 0) {
59976babe50SJustin T. Gibbs 					/* Short transfer ??? */
6008177437dSPoul-Henning Kamp 					bp->bio_flags |= BIO_ERROR;
60176babe50SJustin T. Gibbs 				}
60276babe50SJustin T. Gibbs 			}
60376babe50SJustin T. Gibbs 			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
60476babe50SJustin T. Gibbs 				cam_release_devq(done_ccb->ccb_h.path,
60576babe50SJustin T. Gibbs 						 /*relsim_flags*/0,
60676babe50SJustin T. Gibbs 						 /*reduction*/0,
60776babe50SJustin T. Gibbs 						 /*timeout*/0,
60876babe50SJustin T. Gibbs 						 /*getcount_only*/0);
60976babe50SJustin T. Gibbs 		} else {
6108177437dSPoul-Henning Kamp 			bp->bio_resid = csio->resid;
6118177437dSPoul-Henning Kamp 			if (bp->bio_resid != 0)
6128177437dSPoul-Henning Kamp 				bp->bio_flags |= BIO_ERROR;
61376babe50SJustin T. Gibbs 		}
61476babe50SJustin T. Gibbs 
61576babe50SJustin T. Gibbs 		/*
61676babe50SJustin T. Gibbs 		 * Block out any asyncronous callbacks
61776babe50SJustin T. Gibbs 		 * while we touch the pending ccb list.
61876babe50SJustin T. Gibbs 		 */
61976babe50SJustin T. Gibbs 		oldspl = splcam();
62076babe50SJustin T. Gibbs 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
62176babe50SJustin T. Gibbs 		splx(oldspl);
62276babe50SJustin T. Gibbs 
623a9d2245eSPoul-Henning Kamp 		biofinish(bp, softc->device_stats, 0);
62476babe50SJustin T. Gibbs 		break;
62576babe50SJustin T. Gibbs 	}
62676babe50SJustin T. Gibbs 	case PT_CCB_WAITING:
62776babe50SJustin T. Gibbs 		/* Caller will release the CCB */
62876babe50SJustin T. Gibbs 		wakeup(&done_ccb->ccb_h.cbfcnp);
62976babe50SJustin T. Gibbs 		return;
63076babe50SJustin T. Gibbs 	}
63176babe50SJustin T. Gibbs 	xpt_release_ccb(done_ccb);
63276babe50SJustin T. Gibbs }
63376babe50SJustin T. Gibbs 
63476babe50SJustin T. Gibbs static int
63576babe50SJustin T. Gibbs pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
63676babe50SJustin T. Gibbs {
63776babe50SJustin T. Gibbs 	struct pt_softc	  *softc;
63876babe50SJustin T. Gibbs 	struct cam_periph *periph;
63976babe50SJustin T. Gibbs 
64076babe50SJustin T. Gibbs 	periph = xpt_path_periph(ccb->ccb_h.path);
64176babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
64276babe50SJustin T. Gibbs 
64376babe50SJustin T. Gibbs 	return(cam_periph_error(ccb, cam_flags, sense_flags,
64476babe50SJustin T. Gibbs 				&softc->saved_ccb));
64576babe50SJustin T. Gibbs }
64676babe50SJustin T. Gibbs 
6473ece1bd2SKenneth D. Merry static int
64889c9c53dSPoul-Henning Kamp ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
6493ece1bd2SKenneth D. Merry {
6503ece1bd2SKenneth D. Merry 	struct cam_periph *periph;
6513ece1bd2SKenneth D. Merry 	struct pt_softc *softc;
6523ece1bd2SKenneth D. Merry 	int error;
6533ece1bd2SKenneth D. Merry 
654e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
6553ece1bd2SKenneth D. Merry 	if (periph == NULL)
6563ece1bd2SKenneth D. Merry 		return(ENXIO);
6573ece1bd2SKenneth D. Merry 
6583ece1bd2SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
6593ece1bd2SKenneth D. Merry 
6603ece1bd2SKenneth D. Merry 	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
6613ece1bd2SKenneth D. Merry 		return (error); /* error code from tsleep */
6623ece1bd2SKenneth D. Merry 	}
6633ece1bd2SKenneth D. Merry 
6643ece1bd2SKenneth D. Merry 	switch(cmd) {
6653ece1bd2SKenneth D. Merry 	case PTIOCGETTIMEOUT:
6663ece1bd2SKenneth D. Merry 		if (softc->io_timeout >= 1000)
6673ece1bd2SKenneth D. Merry 			*(int *)addr = softc->io_timeout / 1000;
6683ece1bd2SKenneth D. Merry 		else
6693ece1bd2SKenneth D. Merry 			*(int *)addr = 0;
6703ece1bd2SKenneth D. Merry 		break;
6713ece1bd2SKenneth D. Merry 	case PTIOCSETTIMEOUT:
6723ece1bd2SKenneth D. Merry 	{
6733ece1bd2SKenneth D. Merry 		int s;
6743ece1bd2SKenneth D. Merry 
6753ece1bd2SKenneth D. Merry 		if (*(int *)addr < 1) {
6763ece1bd2SKenneth D. Merry 			error = EINVAL;
6773ece1bd2SKenneth D. Merry 			break;
6783ece1bd2SKenneth D. Merry 		}
6793ece1bd2SKenneth D. Merry 
6803ece1bd2SKenneth D. Merry 		s = splsoftcam();
6813ece1bd2SKenneth D. Merry 		softc->io_timeout = *(int *)addr * 1000;
6823ece1bd2SKenneth D. Merry 		splx(s);
6833ece1bd2SKenneth D. Merry 
6843ece1bd2SKenneth D. Merry 		break;
6853ece1bd2SKenneth D. Merry 	}
6863ece1bd2SKenneth D. Merry 	default:
6873ece1bd2SKenneth D. Merry 		error = cam_periph_ioctl(periph, cmd, addr, pterror);
6883ece1bd2SKenneth D. Merry 		break;
6893ece1bd2SKenneth D. Merry 	}
6903ece1bd2SKenneth D. Merry 
6913ece1bd2SKenneth D. Merry 	cam_periph_unlock(periph);
6923ece1bd2SKenneth D. Merry 
6933ece1bd2SKenneth D. Merry 	return(error);
6943ece1bd2SKenneth D. Merry }
6953ece1bd2SKenneth D. Merry 
69676babe50SJustin T. Gibbs void
69776babe50SJustin T. Gibbs scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
69876babe50SJustin T. Gibbs 		  void (*cbfcnp)(struct cam_periph *, union ccb *),
69976babe50SJustin T. Gibbs 		  u_int tag_action, int readop, u_int byte2,
70076babe50SJustin T. Gibbs 		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
70176babe50SJustin T. Gibbs 		  u_int32_t timeout)
70276babe50SJustin T. Gibbs {
70376babe50SJustin T. Gibbs 	struct scsi_send_receive *scsi_cmd;
70476babe50SJustin T. Gibbs 
70576babe50SJustin T. Gibbs 	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
70676babe50SJustin T. Gibbs 	scsi_cmd->opcode = readop ? RECEIVE : SEND;
70776babe50SJustin T. Gibbs 	scsi_cmd->byte2 = byte2;
70876babe50SJustin T. Gibbs 	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
70976babe50SJustin T. Gibbs 	scsi_cmd->control = 0;
71076babe50SJustin T. Gibbs 
71176babe50SJustin T. Gibbs 	cam_fill_csio(csio,
71276babe50SJustin T. Gibbs 		      retries,
71376babe50SJustin T. Gibbs 		      cbfcnp,
71476babe50SJustin T. Gibbs 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
71576babe50SJustin T. Gibbs 		      tag_action,
71676babe50SJustin T. Gibbs 		      data_ptr,
71776babe50SJustin T. Gibbs 		      xfer_len,
71876babe50SJustin T. Gibbs 		      sense_len,
71976babe50SJustin T. Gibbs 		      sizeof(*scsi_cmd),
72076babe50SJustin T. Gibbs 		      timeout);
72176babe50SJustin T. Gibbs }
722