scsi_pt.c revision 112006
139213Sgibbs/*
239213Sgibbs * Implementation of SCSI Processor Target Peripheral driver for CAM.
339213Sgibbs *
439213Sgibbs * Copyright (c) 1998 Justin T. Gibbs.
539213Sgibbs * All rights reserved.
639213Sgibbs *
739213Sgibbs * Redistribution and use in source and binary forms, with or without
839213Sgibbs * modification, are permitted provided that the following conditions
939213Sgibbs * are met:
1039213Sgibbs * 1. Redistributions of source code must retain the above copyright
1139213Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239213Sgibbs *    without modification, immediately at the beginning of the file.
1339213Sgibbs * 2. The name of the author may not be used to endorse or promote products
1439213Sgibbs *    derived from this software without specific prior written permission.
1539213Sgibbs *
1639213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2039213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639213Sgibbs * SUCH DAMAGE.
2739213Sgibbs *
2850477Speter * $FreeBSD: head/sys/cam/scsi/scsi_pt.c 112006 2003-03-08 21:44:46Z phk $
2939213Sgibbs */
3039213Sgibbs
3139213Sgibbs#include <sys/param.h>
3239213Sgibbs#include <sys/queue.h>
3339213Sgibbs#include <sys/systm.h>
3439213Sgibbs#include <sys/kernel.h>
3539213Sgibbs#include <sys/types.h>
3660041Sphk#include <sys/bio.h>
3739213Sgibbs#include <sys/devicestat.h>
3839213Sgibbs#include <sys/malloc.h>
3939213Sgibbs#include <sys/conf.h>
4050073Sken#include <sys/ptio.h>
4139213Sgibbs
4239213Sgibbs#include <cam/cam.h>
4339213Sgibbs#include <cam/cam_ccb.h>
4439213Sgibbs#include <cam/cam_periph.h>
4539213Sgibbs#include <cam/cam_xpt_periph.h>
4639213Sgibbs#include <cam/cam_debug.h>
4739213Sgibbs
4839213Sgibbs#include <cam/scsi/scsi_all.h>
4939213Sgibbs#include <cam/scsi/scsi_message.h>
5039213Sgibbs#include <cam/scsi/scsi_pt.h>
5139213Sgibbs
5250073Sken#include "opt_pt.h"
5350073Sken
5439213Sgibbstypedef enum {
5539213Sgibbs	PT_STATE_PROBE,
5639213Sgibbs	PT_STATE_NORMAL
5739213Sgibbs} pt_state;
5839213Sgibbs
5939213Sgibbstypedef enum {
6039213Sgibbs	PT_FLAG_NONE		= 0x00,
6139213Sgibbs	PT_FLAG_OPEN		= 0x01,
6239213Sgibbs	PT_FLAG_DEVICE_INVALID	= 0x02,
6339213Sgibbs	PT_FLAG_RETRY_UA	= 0x04
6439213Sgibbs} pt_flags;
6539213Sgibbs
6639213Sgibbstypedef enum {
6739213Sgibbs	PT_CCB_BUFFER_IO	= 0x01,
6839213Sgibbs	PT_CCB_WAITING		= 0x02,
6939213Sgibbs	PT_CCB_RETRY_UA		= 0x04,
7039213Sgibbs	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
7139213Sgibbs} pt_ccb_state;
7239213Sgibbs
7339213Sgibbs/* Offsets into our private area for storing information */
7439213Sgibbs#define ccb_state	ppriv_field0
7539213Sgibbs#define ccb_bp		ppriv_ptr1
7639213Sgibbs
7739213Sgibbsstruct pt_softc {
7859249Sphk	struct	 bio_queue_head bio_queue;
79112006Sphk	struct	 devstat *device_stats;
8060938Sjake	LIST_HEAD(, ccb_hdr) pending_ccbs;
8139213Sgibbs	pt_state state;
8239213Sgibbs	pt_flags flags;
8339213Sgibbs	union	 ccb saved_ccb;
8450073Sken	int	 io_timeout;
8553257Sken	dev_t	 dev;
8639213Sgibbs};
8739213Sgibbs
8839213Sgibbsstatic	d_open_t	ptopen;
8939213Sgibbsstatic	d_close_t	ptclose;
9039213Sgibbsstatic	d_strategy_t	ptstrategy;
9139213Sgibbsstatic	periph_init_t	ptinit;
9239213Sgibbsstatic	void		ptasync(void *callback_arg, u_int32_t code,
9339213Sgibbs				struct cam_path *path, void *arg);
9439213Sgibbsstatic	periph_ctor_t	ptctor;
9540603Skenstatic	periph_oninv_t	ptoninvalidate;
9639213Sgibbsstatic	periph_dtor_t	ptdtor;
9739213Sgibbsstatic	periph_start_t	ptstart;
9839213Sgibbsstatic	void		ptdone(struct cam_periph *periph,
9939213Sgibbs			       union ccb *done_ccb);
10050073Skenstatic	d_ioctl_t	ptioctl;
10139213Sgibbsstatic  int		pterror(union ccb *ccb, u_int32_t cam_flags,
10239213Sgibbs				u_int32_t sense_flags);
10339213Sgibbs
10439213Sgibbsvoid	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
10539213Sgibbs			  void (*cbfcnp)(struct cam_periph *, union ccb *),
10639213Sgibbs			  u_int tag_action, int readop, u_int byte2,
10739213Sgibbs			  u_int32_t xfer_len, u_int8_t *data_ptr,
10839213Sgibbs			  u_int8_t sense_len, u_int32_t timeout);
10939213Sgibbs
11039213Sgibbsstatic struct periph_driver ptdriver =
11139213Sgibbs{
11239213Sgibbs	ptinit, "pt",
11339213Sgibbs	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11439213Sgibbs};
11539213Sgibbs
11672119SpeterPERIPHDRIVER_DECLARE(pt, ptdriver);
11739213Sgibbs
11839213Sgibbs#define PT_CDEV_MAJOR 61
11939213Sgibbs
12047625Sphkstatic struct cdevsw pt_cdevsw = {
121111815Sphk	.d_open =	ptopen,
122111815Sphk	.d_close =	ptclose,
123111815Sphk	.d_read =	physread,
124111815Sphk	.d_write =	physwrite,
125111815Sphk	.d_ioctl =	ptioctl,
126111815Sphk	.d_strategy =	ptstrategy,
127111815Sphk	.d_name =	"pt",
128111815Sphk	.d_maj =	PT_CDEV_MAJOR,
12939213Sgibbs};
13039213Sgibbs
13150073Sken#ifndef SCSI_PT_DEFAULT_TIMEOUT
13250073Sken#define SCSI_PT_DEFAULT_TIMEOUT		60
13350073Sken#endif
13450073Sken
13539213Sgibbsstatic int
13683366Sjulianptopen(dev_t dev, int flags, int fmt, struct thread *td)
13739213Sgibbs{
13839213Sgibbs	struct cam_periph *periph;
13939213Sgibbs	struct pt_softc *softc;
14039213Sgibbs	int unit;
14139213Sgibbs	int error;
14240603Sken	int s;
14339213Sgibbs
14439213Sgibbs	unit = minor(dev);
145101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
14639213Sgibbs	if (periph == NULL)
14739213Sgibbs		return (ENXIO);
14839213Sgibbs
14939213Sgibbs	softc = (struct pt_softc *)periph->softc;
15039213Sgibbs
15140603Sken	s = splsoftcam();
15240603Sken	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
15340603Sken		splx(s);
15440603Sken		return(ENXIO);
15540603Sken	}
15640603Sken
15739213Sgibbs	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
15849982Sbillf	    ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
15939213Sgibbs
16041297Sken	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
16141297Sken		splx(s);
16239213Sgibbs		return (error); /* error code from tsleep */
16341297Sken	}
16439213Sgibbs
16541297Sken	splx(s);
16641297Sken
16739213Sgibbs	if ((softc->flags & PT_FLAG_OPEN) == 0) {
16839213Sgibbs		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
16939213Sgibbs			error = ENXIO;
17039213Sgibbs		else
17139213Sgibbs			softc->flags |= PT_FLAG_OPEN;
17239213Sgibbs	} else
17339213Sgibbs		error = EBUSY;
17439213Sgibbs
17539213Sgibbs	cam_periph_unlock(periph);
17639213Sgibbs	return (error);
17739213Sgibbs}
17839213Sgibbs
17939213Sgibbsstatic int
18083366Sjulianptclose(dev_t dev, int flag, int fmt, struct thread *td)
18139213Sgibbs{
18239213Sgibbs	struct	cam_periph *periph;
18339213Sgibbs	struct	pt_softc *softc;
18439213Sgibbs	int	error;
18539213Sgibbs
186101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
18739213Sgibbs	if (periph == NULL)
18839213Sgibbs		return (ENXIO);
18939213Sgibbs
19039213Sgibbs	softc = (struct pt_softc *)periph->softc;
19139213Sgibbs
19239213Sgibbs	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
19339213Sgibbs		return (error); /* error code from tsleep */
19439213Sgibbs
19539213Sgibbs	softc->flags &= ~PT_FLAG_OPEN;
19639213Sgibbs	cam_periph_unlock(periph);
19739213Sgibbs	cam_periph_release(periph);
19839213Sgibbs	return (0);
19939213Sgibbs}
20039213Sgibbs
20139213Sgibbs/*
20239213Sgibbs * Actually translate the requested transfer into one the physical driver
20339213Sgibbs * can understand.  The transfer is described by a buf and will include
20439213Sgibbs * only one physical transfer.
20539213Sgibbs */
20639213Sgibbsstatic void
20759249Sphkptstrategy(struct bio *bp)
20839213Sgibbs{
20939213Sgibbs	struct cam_periph *periph;
21039213Sgibbs	struct pt_softc *softc;
21139213Sgibbs	int    s;
21239213Sgibbs
213101940Snjl	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
21476362Sphk	bp->bio_resid = bp->bio_bcount;
21539213Sgibbs	if (periph == NULL) {
21676362Sphk		biofinish(bp, NULL, ENXIO);
21776362Sphk		return;
21839213Sgibbs	}
21939213Sgibbs	softc = (struct pt_softc *)periph->softc;
22039213Sgibbs
22139213Sgibbs	/*
22239213Sgibbs	 * Mask interrupts so that the pack cannot be invalidated until
22339213Sgibbs	 * after we are in the queue.  Otherwise, we might not properly
22439213Sgibbs	 * clean up one of the buffers.
22539213Sgibbs	 */
22639213Sgibbs	s = splbio();
22739213Sgibbs
22839213Sgibbs	/*
22939213Sgibbs	 * If the device has been made invalid, error out
23039213Sgibbs	 */
23139213Sgibbs	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
23239213Sgibbs		splx(s);
23376362Sphk		biofinish(bp, NULL, ENXIO);
23476362Sphk		return;
23539213Sgibbs	}
23639213Sgibbs
23739213Sgibbs	/*
23839213Sgibbs	 * Place it in the queue of disk activities for this disk
23939213Sgibbs	 */
24059249Sphk	bioq_insert_tail(&softc->bio_queue, bp);
24139213Sgibbs
24239213Sgibbs	splx(s);
24339213Sgibbs
24439213Sgibbs	/*
24539213Sgibbs	 * Schedule ourselves for performing the work.
24639213Sgibbs	 */
24739213Sgibbs	xpt_schedule(periph, /* XXX priority */1);
24839213Sgibbs
24939213Sgibbs	return;
25039213Sgibbs}
25139213Sgibbs
25239213Sgibbsstatic void
25339213Sgibbsptinit(void)
25439213Sgibbs{
25539213Sgibbs	cam_status status;
25639213Sgibbs	struct cam_path *path;
25739213Sgibbs
25839213Sgibbs	/*
25939213Sgibbs	 * Install a global async callback.  This callback will
26039213Sgibbs	 * receive async callbacks like "new device found".
26139213Sgibbs	 */
26239213Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
26339213Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
26439213Sgibbs
26539213Sgibbs	if (status == CAM_REQ_CMP) {
26639213Sgibbs		struct ccb_setasync csa;
26739213Sgibbs
26839213Sgibbs                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
26939213Sgibbs                csa.ccb_h.func_code = XPT_SASYNC_CB;
27039213Sgibbs                csa.event_enable = AC_FOUND_DEVICE;
27139213Sgibbs                csa.callback = ptasync;
27239213Sgibbs                csa.callback_arg = NULL;
27339213Sgibbs                xpt_action((union ccb *)&csa);
27439213Sgibbs		status = csa.ccb_h.status;
27539213Sgibbs                xpt_free_path(path);
27639213Sgibbs        }
27739213Sgibbs
27839213Sgibbs	if (status != CAM_REQ_CMP) {
27939213Sgibbs		printf("pt: Failed to attach master async callback "
28039213Sgibbs		       "due to status 0x%x!\n", status);
28139213Sgibbs	}
28239213Sgibbs}
28339213Sgibbs
28439213Sgibbsstatic cam_status
28539213Sgibbsptctor(struct cam_periph *periph, void *arg)
28639213Sgibbs{
28739213Sgibbs	struct pt_softc *softc;
28839213Sgibbs	struct ccb_setasync csa;
28939213Sgibbs	struct ccb_getdev *cgd;
29039213Sgibbs
29139213Sgibbs	cgd = (struct ccb_getdev *)arg;
29239213Sgibbs	if (periph == NULL) {
29339213Sgibbs		printf("ptregister: periph was NULL!!\n");
29439213Sgibbs		return(CAM_REQ_CMP_ERR);
29539213Sgibbs	}
29639213Sgibbs
29739213Sgibbs	if (cgd == NULL) {
29839213Sgibbs		printf("ptregister: no getdev CCB, can't register device\n");
29939213Sgibbs		return(CAM_REQ_CMP_ERR);
30039213Sgibbs	}
30139213Sgibbs
30239213Sgibbs	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
30339213Sgibbs
30439213Sgibbs	if (softc == NULL) {
30539213Sgibbs		printf("daregister: Unable to probe new device. "
30639213Sgibbs		       "Unable to allocate softc\n");
30739213Sgibbs		return(CAM_REQ_CMP_ERR);
30839213Sgibbs	}
30939213Sgibbs
31039213Sgibbs	bzero(softc, sizeof(*softc));
31139213Sgibbs	LIST_INIT(&softc->pending_ccbs);
31239213Sgibbs	softc->state = PT_STATE_NORMAL;
31359249Sphk	bioq_init(&softc->bio_queue);
31439213Sgibbs
31550073Sken	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
31650073Sken
31739213Sgibbs	periph->softc = softc;
31839213Sgibbs
319112006Sphk	softc->device_stats = devstat_new_entry("pt",
32039213Sgibbs			  periph->unit_number, 0,
32139213Sgibbs			  DEVSTAT_NO_BLOCKSIZE,
32256148Smjacob			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
32343819Sken			  DEVSTAT_PRIORITY_OTHER);
32439213Sgibbs
32553257Sken	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
32653257Sken			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
32753257Sken			      periph->unit_number);
328101940Snjl	softc->dev->si_drv1 = periph;
329101940Snjl
33039213Sgibbs	/*
33139213Sgibbs	 * Add async callbacks for bus reset and
33239213Sgibbs	 * bus device reset calls.  I don't bother
33339213Sgibbs	 * checking if this fails as, in most cases,
33439213Sgibbs	 * the system will function just fine without
33539213Sgibbs	 * them and the only alternative would be to
33639213Sgibbs	 * not attach the device on failure.
33739213Sgibbs	 */
33839213Sgibbs	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
33939213Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
34039213Sgibbs	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
34139213Sgibbs	csa.callback = ptasync;
34239213Sgibbs	csa.callback_arg = periph;
34339213Sgibbs	xpt_action((union ccb *)&csa);
34439213Sgibbs
34539213Sgibbs	/* Tell the user we've attached to the device */
34639213Sgibbs	xpt_announce_periph(periph, NULL);
34739213Sgibbs
34839213Sgibbs	return(CAM_REQ_CMP);
34939213Sgibbs}
35039213Sgibbs
35139213Sgibbsstatic void
35240603Skenptoninvalidate(struct cam_periph *periph)
35340603Sken{
35440603Sken	int s;
35540603Sken	struct pt_softc *softc;
35659249Sphk	struct bio *q_bp;
35740603Sken	struct ccb_setasync csa;
35840603Sken
35940603Sken	softc = (struct pt_softc *)periph->softc;
36040603Sken
36140603Sken	/*
36240603Sken	 * De-register any async callbacks.
36340603Sken	 */
36440603Sken	xpt_setup_ccb(&csa.ccb_h, periph->path,
36540603Sken		      /* priority */ 5);
36640603Sken	csa.ccb_h.func_code = XPT_SASYNC_CB;
36740603Sken	csa.event_enable = 0;
36840603Sken	csa.callback = ptasync;
36940603Sken	csa.callback_arg = periph;
37040603Sken	xpt_action((union ccb *)&csa);
37140603Sken
37240603Sken	softc->flags |= PT_FLAG_DEVICE_INVALID;
37340603Sken
37440603Sken	/*
37540603Sken	 * Although the oninvalidate() routines are always called at
37640603Sken	 * splsoftcam, we need to be at splbio() here to keep the buffer
37740603Sken	 * queue from being modified while we traverse it.
37840603Sken	 */
37940603Sken	s = splbio();
38040603Sken
38140603Sken	/*
38240603Sken	 * Return all queued I/O with ENXIO.
38340603Sken	 * XXX Handle any transactions queued to the card
38440603Sken	 *     with XPT_ABORT_CCB.
38540603Sken	 */
38659249Sphk	while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){
38759249Sphk		bioq_remove(&softc->bio_queue, q_bp);
38859249Sphk		q_bp->bio_resid = q_bp->bio_bcount;
38976322Sphk		biofinish(q_bp, NULL, ENXIO);
39040603Sken	}
39140603Sken
39240603Sken	splx(s);
39340603Sken
39440603Sken	xpt_print_path(periph->path);
39540603Sken	printf("lost device\n");
39640603Sken}
39740603Sken
39840603Skenstatic void
39939213Sgibbsptdtor(struct cam_periph *periph)
40039213Sgibbs{
40140603Sken	struct pt_softc *softc;
40240603Sken
40340603Sken	softc = (struct pt_softc *)periph->softc;
40440603Sken
405112006Sphk	devstat_remove_entry(softc->device_stats);
40640603Sken
40753257Sken	destroy_dev(softc->dev);
40853257Sken
40939213Sgibbs	xpt_print_path(periph->path);
41039213Sgibbs	printf("removing device entry\n");
41140603Sken	free(softc, M_DEVBUF);
41239213Sgibbs}
41339213Sgibbs
41439213Sgibbsstatic void
41539213Sgibbsptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
41639213Sgibbs{
41739213Sgibbs	struct cam_periph *periph;
41839213Sgibbs
41939213Sgibbs	periph = (struct cam_periph *)callback_arg;
42039213Sgibbs	switch (code) {
42139213Sgibbs	case AC_FOUND_DEVICE:
42239213Sgibbs	{
42339213Sgibbs		struct ccb_getdev *cgd;
42439213Sgibbs		cam_status status;
42539213Sgibbs
42639213Sgibbs		cgd = (struct ccb_getdev *)arg;
42779177Smjacob		if (cgd == NULL)
42879177Smjacob			break;
42939213Sgibbs
43056148Smjacob		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
43139213Sgibbs			break;
43239213Sgibbs
43339213Sgibbs		/*
43439213Sgibbs		 * Allocate a peripheral instance for
43539213Sgibbs		 * this device and start the probe
43639213Sgibbs		 * process.
43739213Sgibbs		 */
43840603Sken		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
43940603Sken					  ptstart, "pt", CAM_PERIPH_BIO,
44040603Sken					  cgd->ccb_h.path, ptasync,
44140603Sken					  AC_FOUND_DEVICE, cgd);
44239213Sgibbs
44339213Sgibbs		if (status != CAM_REQ_CMP
44439213Sgibbs		 && status != CAM_REQ_INPROG)
44539213Sgibbs			printf("ptasync: Unable to attach to new device "
44639213Sgibbs				"due to status 0x%x\n", status);
44739213Sgibbs		break;
44839213Sgibbs	}
44939213Sgibbs	case AC_SENT_BDR:
45039213Sgibbs	case AC_BUS_RESET:
45139213Sgibbs	{
45239213Sgibbs		struct pt_softc *softc;
45339213Sgibbs		struct ccb_hdr *ccbh;
45439213Sgibbs		int s;
45539213Sgibbs
45639213Sgibbs		softc = (struct pt_softc *)periph->softc;
45739213Sgibbs		s = splsoftcam();
45839213Sgibbs		/*
45939213Sgibbs		 * Don't fail on the expected unit attention
46039213Sgibbs		 * that will occur.
46139213Sgibbs		 */
46239213Sgibbs		softc->flags |= PT_FLAG_RETRY_UA;
46371999Sphk		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
46439213Sgibbs			ccbh->ccb_state |= PT_CCB_RETRY_UA;
46539213Sgibbs		splx(s);
46647413Sgibbs		/* FALLTHROUGH */
46739213Sgibbs	}
46839213Sgibbs	default:
46947413Sgibbs		cam_periph_async(periph, code, path, arg);
47039213Sgibbs		break;
47139213Sgibbs	}
47239213Sgibbs}
47339213Sgibbs
47439213Sgibbsstatic void
47539213Sgibbsptstart(struct cam_periph *periph, union ccb *start_ccb)
47639213Sgibbs{
47739213Sgibbs	struct pt_softc *softc;
47859249Sphk	struct bio *bp;
47939213Sgibbs	int s;
48039213Sgibbs
48139213Sgibbs	softc = (struct pt_softc *)periph->softc;
48239213Sgibbs
48339213Sgibbs	/*
48439213Sgibbs	 * See if there is a buf with work for us to do..
48539213Sgibbs	 */
48639213Sgibbs	s = splbio();
48759249Sphk	bp = bioq_first(&softc->bio_queue);
48839213Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
48939213Sgibbs		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
49039213Sgibbs				("queuing for immediate ccb\n"));
49139213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
49239213Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
49339213Sgibbs				  periph_links.sle);
49439213Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
49539213Sgibbs		splx(s);
49639213Sgibbs		wakeup(&periph->ccb_list);
49739213Sgibbs	} else if (bp == NULL) {
49839213Sgibbs		splx(s);
49939213Sgibbs		xpt_release_ccb(start_ccb);
50039213Sgibbs	} else {
50139213Sgibbs		int oldspl;
50239213Sgibbs
50359249Sphk		bioq_remove(&softc->bio_queue, bp);
50439213Sgibbs
505112006Sphk		devstat_start_transaction(softc->device_stats);
50639213Sgibbs
50739213Sgibbs		scsi_send_receive(&start_ccb->csio,
50839213Sgibbs				  /*retries*/4,
50939213Sgibbs				  ptdone,
51039213Sgibbs				  MSG_SIMPLE_Q_TAG,
51159249Sphk				  bp->bio_cmd == BIO_READ,
51239213Sgibbs				  /*byte2*/0,
51359249Sphk				  bp->bio_bcount,
51459249Sphk				  bp->bio_data,
51539213Sgibbs				  /*sense_len*/SSD_FULL_SIZE,
51650073Sken				  /*timeout*/softc->io_timeout);
51739213Sgibbs
51876192Sken		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
51939213Sgibbs
52039213Sgibbs		/*
52139213Sgibbs		 * Block out any asyncronous callbacks
52239213Sgibbs		 * while we touch the pending ccb list.
52339213Sgibbs		 */
52439213Sgibbs		oldspl = splcam();
52539213Sgibbs		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
52639213Sgibbs				 periph_links.le);
52739213Sgibbs		splx(oldspl);
52839213Sgibbs
52939213Sgibbs		start_ccb->ccb_h.ccb_bp = bp;
53059249Sphk		bp = bioq_first(&softc->bio_queue);
53139213Sgibbs		splx(s);
53239213Sgibbs
53339213Sgibbs		xpt_action(start_ccb);
53439213Sgibbs
53539213Sgibbs		if (bp != NULL) {
53639213Sgibbs			/* Have more work to do, so ensure we stay scheduled */
53739213Sgibbs			xpt_schedule(periph, /* XXX priority */1);
53839213Sgibbs		}
53939213Sgibbs	}
54039213Sgibbs}
54139213Sgibbs
54239213Sgibbsstatic void
54339213Sgibbsptdone(struct cam_periph *periph, union ccb *done_ccb)
54439213Sgibbs{
54539213Sgibbs	struct pt_softc *softc;
54639213Sgibbs	struct ccb_scsiio *csio;
54739213Sgibbs
54839213Sgibbs	softc = (struct pt_softc *)periph->softc;
54939213Sgibbs	csio = &done_ccb->csio;
55039213Sgibbs	switch (csio->ccb_h.ccb_state) {
55139213Sgibbs	case PT_CCB_BUFFER_IO:
55239213Sgibbs	case PT_CCB_BUFFER_IO_UA:
55339213Sgibbs	{
55459249Sphk		struct bio *bp;
55539213Sgibbs		int    oldspl;
55639213Sgibbs
55759249Sphk		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
55839213Sgibbs		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
55939213Sgibbs			int error;
56039213Sgibbs			int s;
56139213Sgibbs			int sf;
56239213Sgibbs
56339213Sgibbs			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
56439213Sgibbs				sf = SF_RETRY_UA;
56539213Sgibbs			else
56639213Sgibbs				sf = 0;
56739213Sgibbs
56874840Sken			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
56974840Sken			if (error == ERESTART) {
57039213Sgibbs				/*
57139213Sgibbs				 * A retry was scheuled, so
57239213Sgibbs				 * just return.
57339213Sgibbs				 */
57439213Sgibbs				return;
57539213Sgibbs			}
57639213Sgibbs			if (error != 0) {
57759249Sphk				struct bio *q_bp;
57839213Sgibbs
57939213Sgibbs				s = splbio();
58039213Sgibbs
58139213Sgibbs				if (error == ENXIO) {
58239213Sgibbs					/*
58339213Sgibbs					 * Catastrophic error.  Mark our device
58439213Sgibbs					 * as invalid.
58539213Sgibbs					 */
58639213Sgibbs					xpt_print_path(periph->path);
58739213Sgibbs					printf("Invalidating device\n");
58839213Sgibbs					softc->flags |= PT_FLAG_DEVICE_INVALID;
58939213Sgibbs				}
59039213Sgibbs
59139213Sgibbs				/*
59239213Sgibbs				 * return all queued I/O with EIO, so that
59339213Sgibbs				 * the client can retry these I/Os in the
59439213Sgibbs				 * proper order should it attempt to recover.
59539213Sgibbs				 */
59659249Sphk				while ((q_bp = bioq_first(&softc->bio_queue))
59739213Sgibbs					!= NULL) {
59859249Sphk					bioq_remove(&softc->bio_queue, q_bp);
59959249Sphk					q_bp->bio_resid = q_bp->bio_bcount;
60076322Sphk					biofinish(q_bp, NULL, EIO);
60139213Sgibbs				}
60239213Sgibbs				splx(s);
60359249Sphk				bp->bio_error = error;
60459249Sphk				bp->bio_resid = bp->bio_bcount;
60559249Sphk				bp->bio_flags |= BIO_ERROR;
60639213Sgibbs			} else {
60759249Sphk				bp->bio_resid = csio->resid;
60859249Sphk				bp->bio_error = 0;
60959249Sphk				if (bp->bio_resid != 0) {
61039213Sgibbs					/* Short transfer ??? */
61159249Sphk					bp->bio_flags |= BIO_ERROR;
61239213Sgibbs				}
61339213Sgibbs			}
61439213Sgibbs			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
61539213Sgibbs				cam_release_devq(done_ccb->ccb_h.path,
61639213Sgibbs						 /*relsim_flags*/0,
61739213Sgibbs						 /*reduction*/0,
61839213Sgibbs						 /*timeout*/0,
61939213Sgibbs						 /*getcount_only*/0);
62039213Sgibbs		} else {
62159249Sphk			bp->bio_resid = csio->resid;
62259249Sphk			if (bp->bio_resid != 0)
62359249Sphk				bp->bio_flags |= BIO_ERROR;
62439213Sgibbs		}
62539213Sgibbs
62639213Sgibbs		/*
62739213Sgibbs		 * Block out any asyncronous callbacks
62839213Sgibbs		 * while we touch the pending ccb list.
62939213Sgibbs		 */
63039213Sgibbs		oldspl = splcam();
63139213Sgibbs		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
63239213Sgibbs		splx(oldspl);
63339213Sgibbs
634112006Sphk		biofinish(bp, softc->device_stats, 0);
63539213Sgibbs		break;
63639213Sgibbs	}
63739213Sgibbs	case PT_CCB_WAITING:
63839213Sgibbs		/* Caller will release the CCB */
63939213Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
64039213Sgibbs		return;
64139213Sgibbs	}
64239213Sgibbs	xpt_release_ccb(done_ccb);
64339213Sgibbs}
64439213Sgibbs
64539213Sgibbsstatic int
64639213Sgibbspterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
64739213Sgibbs{
64839213Sgibbs	struct pt_softc	  *softc;
64939213Sgibbs	struct cam_periph *periph;
65039213Sgibbs
65139213Sgibbs	periph = xpt_path_periph(ccb->ccb_h.path);
65239213Sgibbs	softc = (struct pt_softc *)periph->softc;
65339213Sgibbs
65439213Sgibbs	return(cam_periph_error(ccb, cam_flags, sense_flags,
65539213Sgibbs				&softc->saved_ccb));
65639213Sgibbs}
65739213Sgibbs
65850073Skenstatic int
65983366Sjulianptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
66050073Sken{
66150073Sken	struct cam_periph *periph;
66250073Sken	struct pt_softc *softc;
66350073Sken	int error;
66450073Sken
665101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
66650073Sken	if (periph == NULL)
66750073Sken		return(ENXIO);
66850073Sken
66950073Sken	softc = (struct pt_softc *)periph->softc;
67050073Sken
67150073Sken	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
67250073Sken		return (error); /* error code from tsleep */
67350073Sken	}
67450073Sken
67550073Sken	switch(cmd) {
67650073Sken	case PTIOCGETTIMEOUT:
67750073Sken		if (softc->io_timeout >= 1000)
67850073Sken			*(int *)addr = softc->io_timeout / 1000;
67950073Sken		else
68050073Sken			*(int *)addr = 0;
68150073Sken		break;
68250073Sken	case PTIOCSETTIMEOUT:
68350073Sken	{
68450073Sken		int s;
68550073Sken
68650073Sken		if (*(int *)addr < 1) {
68750073Sken			error = EINVAL;
68850073Sken			break;
68950073Sken		}
69050073Sken
69150073Sken		s = splsoftcam();
69250073Sken		softc->io_timeout = *(int *)addr * 1000;
69350073Sken		splx(s);
69450073Sken
69550073Sken		break;
69650073Sken	}
69750073Sken	default:
69850073Sken		error = cam_periph_ioctl(periph, cmd, addr, pterror);
69950073Sken		break;
70050073Sken	}
70150073Sken
70250073Sken	cam_periph_unlock(periph);
70350073Sken
70450073Sken	return(error);
70550073Sken}
70650073Sken
70739213Sgibbsvoid
70839213Sgibbsscsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
70939213Sgibbs		  void (*cbfcnp)(struct cam_periph *, union ccb *),
71039213Sgibbs		  u_int tag_action, int readop, u_int byte2,
71139213Sgibbs		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
71239213Sgibbs		  u_int32_t timeout)
71339213Sgibbs{
71439213Sgibbs	struct scsi_send_receive *scsi_cmd;
71539213Sgibbs
71639213Sgibbs	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
71739213Sgibbs	scsi_cmd->opcode = readop ? RECEIVE : SEND;
71839213Sgibbs	scsi_cmd->byte2 = byte2;
71939213Sgibbs	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
72039213Sgibbs	scsi_cmd->control = 0;
72139213Sgibbs
72239213Sgibbs	cam_fill_csio(csio,
72339213Sgibbs		      retries,
72439213Sgibbs		      cbfcnp,
72539213Sgibbs		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
72639213Sgibbs		      tag_action,
72739213Sgibbs		      data_ptr,
72839213Sgibbs		      xfer_len,
72939213Sgibbs		      sense_len,
73039213Sgibbs		      sizeof(*scsi_cmd),
73139213Sgibbs		      timeout);
73239213Sgibbs}
733