scsi_pt.c revision 72119
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 72119 2001-02-07 07:05:59Z peter $
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_extend.h>
4539213Sgibbs#include <cam/cam_periph.h>
4639213Sgibbs#include <cam/cam_xpt_periph.h>
4739213Sgibbs#include <cam/cam_debug.h>
4839213Sgibbs
4939213Sgibbs#include <cam/scsi/scsi_all.h>
5039213Sgibbs#include <cam/scsi/scsi_message.h>
5139213Sgibbs#include <cam/scsi/scsi_pt.h>
5239213Sgibbs
5350073Sken#include "opt_pt.h"
5450073Sken
5539213Sgibbstypedef enum {
5639213Sgibbs	PT_STATE_PROBE,
5739213Sgibbs	PT_STATE_NORMAL
5839213Sgibbs} pt_state;
5939213Sgibbs
6039213Sgibbstypedef enum {
6139213Sgibbs	PT_FLAG_NONE		= 0x00,
6239213Sgibbs	PT_FLAG_OPEN		= 0x01,
6339213Sgibbs	PT_FLAG_DEVICE_INVALID	= 0x02,
6439213Sgibbs	PT_FLAG_RETRY_UA	= 0x04
6539213Sgibbs} pt_flags;
6639213Sgibbs
6739213Sgibbstypedef enum {
6839213Sgibbs	PT_CCB_BUFFER_IO	= 0x01,
6939213Sgibbs	PT_CCB_WAITING		= 0x02,
7039213Sgibbs	PT_CCB_RETRY_UA		= 0x04,
7139213Sgibbs	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
7239213Sgibbs} pt_ccb_state;
7339213Sgibbs
7439213Sgibbs/* Offsets into our private area for storing information */
7539213Sgibbs#define ccb_state	ppriv_field0
7639213Sgibbs#define ccb_bp		ppriv_ptr1
7739213Sgibbs
7839213Sgibbsstruct pt_softc {
7959249Sphk	struct	 bio_queue_head bio_queue;
8039213Sgibbs	struct	 devstat device_stats;
8160938Sjake	LIST_HEAD(, ccb_hdr) pending_ccbs;
8239213Sgibbs	pt_state state;
8339213Sgibbs	pt_flags flags;
8439213Sgibbs	union	 ccb saved_ccb;
8550073Sken	int	 io_timeout;
8653257Sken	dev_t	 dev;
8739213Sgibbs};
8839213Sgibbs
8939213Sgibbsstatic	d_open_t	ptopen;
9039213Sgibbsstatic	d_close_t	ptclose;
9139213Sgibbsstatic	d_strategy_t	ptstrategy;
9239213Sgibbsstatic	periph_init_t	ptinit;
9339213Sgibbsstatic	void		ptasync(void *callback_arg, u_int32_t code,
9439213Sgibbs				struct cam_path *path, void *arg);
9539213Sgibbsstatic	periph_ctor_t	ptctor;
9640603Skenstatic	periph_oninv_t	ptoninvalidate;
9739213Sgibbsstatic	periph_dtor_t	ptdtor;
9839213Sgibbsstatic	periph_start_t	ptstart;
9939213Sgibbsstatic	void		ptdone(struct cam_periph *periph,
10039213Sgibbs			       union ccb *done_ccb);
10150073Skenstatic	d_ioctl_t	ptioctl;
10239213Sgibbsstatic  int		pterror(union ccb *ccb, u_int32_t cam_flags,
10339213Sgibbs				u_int32_t sense_flags);
10439213Sgibbs
10539213Sgibbsvoid	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
10639213Sgibbs			  void (*cbfcnp)(struct cam_periph *, union ccb *),
10739213Sgibbs			  u_int tag_action, int readop, u_int byte2,
10839213Sgibbs			  u_int32_t xfer_len, u_int8_t *data_ptr,
10939213Sgibbs			  u_int8_t sense_len, u_int32_t timeout);
11039213Sgibbs
11139213Sgibbsstatic struct periph_driver ptdriver =
11239213Sgibbs{
11339213Sgibbs	ptinit, "pt",
11439213Sgibbs	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11539213Sgibbs};
11639213Sgibbs
11772119SpeterPERIPHDRIVER_DECLARE(pt, ptdriver);
11839213Sgibbs
11939213Sgibbs#define PT_CDEV_MAJOR 61
12039213Sgibbs
12147625Sphkstatic struct cdevsw pt_cdevsw = {
12247625Sphk	/* open */	ptopen,
12347625Sphk	/* close */	ptclose,
12447625Sphk	/* read */	physread,
12547625Sphk	/* write */	physwrite,
12650073Sken	/* ioctl */	ptioctl,
12747625Sphk	/* poll */	nopoll,
12847625Sphk	/* mmap */	nommap,
12947625Sphk	/* strategy */	ptstrategy,
13047625Sphk	/* name */	"pt",
13147625Sphk	/* maj */	PT_CDEV_MAJOR,
13247625Sphk	/* dump */	nodump,
13347625Sphk	/* psize */	nopsize,
13447625Sphk	/* flags */	0,
13547625Sphk	/* bmaj */	-1
13639213Sgibbs};
13739213Sgibbs
13839213Sgibbsstatic struct extend_array *ptperiphs;
13939213Sgibbs
14050073Sken#ifndef SCSI_PT_DEFAULT_TIMEOUT
14150073Sken#define SCSI_PT_DEFAULT_TIMEOUT		60
14250073Sken#endif
14350073Sken
14439213Sgibbsstatic int
14539213Sgibbsptopen(dev_t dev, int flags, int fmt, struct proc *p)
14639213Sgibbs{
14739213Sgibbs	struct cam_periph *periph;
14839213Sgibbs	struct pt_softc *softc;
14939213Sgibbs	int unit;
15039213Sgibbs	int error;
15140603Sken	int s;
15239213Sgibbs
15339213Sgibbs	unit = minor(dev);
15439213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
15539213Sgibbs	if (periph == NULL)
15639213Sgibbs		return (ENXIO);
15739213Sgibbs
15839213Sgibbs	softc = (struct pt_softc *)periph->softc;
15939213Sgibbs
16040603Sken	s = splsoftcam();
16140603Sken	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
16240603Sken		splx(s);
16340603Sken		return(ENXIO);
16440603Sken	}
16540603Sken
16639213Sgibbs	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
16749982Sbillf	    ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
16839213Sgibbs
16941297Sken	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
17041297Sken		splx(s);
17139213Sgibbs		return (error); /* error code from tsleep */
17241297Sken	}
17339213Sgibbs
17441297Sken	splx(s);
17541297Sken
17639213Sgibbs	if ((softc->flags & PT_FLAG_OPEN) == 0) {
17739213Sgibbs		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
17839213Sgibbs			error = ENXIO;
17939213Sgibbs		else
18039213Sgibbs			softc->flags |= PT_FLAG_OPEN;
18139213Sgibbs	} else
18239213Sgibbs		error = EBUSY;
18339213Sgibbs
18439213Sgibbs	cam_periph_unlock(periph);
18539213Sgibbs	return (error);
18639213Sgibbs}
18739213Sgibbs
18839213Sgibbsstatic int
18939213Sgibbsptclose(dev_t dev, int flag, int fmt, struct proc *p)
19039213Sgibbs{
19139213Sgibbs	struct	cam_periph *periph;
19239213Sgibbs	struct	pt_softc *softc;
19339213Sgibbs	int	unit;
19439213Sgibbs	int	error;
19539213Sgibbs
19639213Sgibbs	unit = minor(dev);
19739213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
19839213Sgibbs	if (periph == NULL)
19939213Sgibbs		return (ENXIO);
20039213Sgibbs
20139213Sgibbs	softc = (struct pt_softc *)periph->softc;
20239213Sgibbs
20339213Sgibbs	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
20439213Sgibbs		return (error); /* error code from tsleep */
20539213Sgibbs
20639213Sgibbs	softc->flags &= ~PT_FLAG_OPEN;
20739213Sgibbs	cam_periph_unlock(periph);
20839213Sgibbs	cam_periph_release(periph);
20939213Sgibbs	return (0);
21039213Sgibbs}
21139213Sgibbs
21239213Sgibbs/*
21339213Sgibbs * Actually translate the requested transfer into one the physical driver
21439213Sgibbs * can understand.  The transfer is described by a buf and will include
21539213Sgibbs * only one physical transfer.
21639213Sgibbs */
21739213Sgibbsstatic void
21859249Sphkptstrategy(struct bio *bp)
21939213Sgibbs{
22039213Sgibbs	struct cam_periph *periph;
22139213Sgibbs	struct pt_softc *softc;
22239213Sgibbs	u_int  unit;
22339213Sgibbs	int    s;
22439213Sgibbs
22559249Sphk	unit = minor(bp->bio_dev);
22639213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
22739213Sgibbs	if (periph == NULL) {
22859249Sphk		bp->bio_error = ENXIO;
22939213Sgibbs		goto bad;
23039213Sgibbs	}
23139213Sgibbs	softc = (struct pt_softc *)periph->softc;
23239213Sgibbs
23339213Sgibbs	/*
23439213Sgibbs	 * Mask interrupts so that the pack cannot be invalidated until
23539213Sgibbs	 * after we are in the queue.  Otherwise, we might not properly
23639213Sgibbs	 * clean up one of the buffers.
23739213Sgibbs	 */
23839213Sgibbs	s = splbio();
23939213Sgibbs
24039213Sgibbs	/*
24139213Sgibbs	 * If the device has been made invalid, error out
24239213Sgibbs	 */
24339213Sgibbs	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
24439213Sgibbs		splx(s);
24559249Sphk		bp->bio_error = ENXIO;
24639213Sgibbs		goto bad;
24739213Sgibbs	}
24839213Sgibbs
24939213Sgibbs	/*
25039213Sgibbs	 * Place it in the queue of disk activities for this disk
25139213Sgibbs	 */
25259249Sphk	bioq_insert_tail(&softc->bio_queue, bp);
25339213Sgibbs
25439213Sgibbs	splx(s);
25539213Sgibbs
25639213Sgibbs	/*
25739213Sgibbs	 * Schedule ourselves for performing the work.
25839213Sgibbs	 */
25939213Sgibbs	xpt_schedule(periph, /* XXX priority */1);
26039213Sgibbs
26139213Sgibbs	return;
26239213Sgibbsbad:
26359249Sphk	bp->bio_flags |= BIO_ERROR;
26439213Sgibbs
26539213Sgibbs	/*
26639213Sgibbs	 * Correctly set the buf to indicate a completed xfer
26739213Sgibbs	 */
26859249Sphk	bp->bio_resid = bp->bio_bcount;
26939213Sgibbs	biodone(bp);
27039213Sgibbs}
27139213Sgibbs
27239213Sgibbsstatic void
27339213Sgibbsptinit(void)
27439213Sgibbs{
27539213Sgibbs	cam_status status;
27639213Sgibbs	struct cam_path *path;
27739213Sgibbs
27839213Sgibbs	/*
27939213Sgibbs	 * Create our extend array for storing the devices we attach to.
28039213Sgibbs	 */
28139213Sgibbs	ptperiphs = cam_extend_new();
28239213Sgibbs	if (ptperiphs == NULL) {
28339213Sgibbs		printf("pt: Failed to alloc extend array!\n");
28439213Sgibbs		return;
28539213Sgibbs	}
28639213Sgibbs
28739213Sgibbs	/*
28839213Sgibbs	 * Install a global async callback.  This callback will
28939213Sgibbs	 * receive async callbacks like "new device found".
29039213Sgibbs	 */
29139213Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
29239213Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
29339213Sgibbs
29439213Sgibbs	if (status == CAM_REQ_CMP) {
29539213Sgibbs		struct ccb_setasync csa;
29639213Sgibbs
29739213Sgibbs                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
29839213Sgibbs                csa.ccb_h.func_code = XPT_SASYNC_CB;
29939213Sgibbs                csa.event_enable = AC_FOUND_DEVICE;
30039213Sgibbs                csa.callback = ptasync;
30139213Sgibbs                csa.callback_arg = NULL;
30239213Sgibbs                xpt_action((union ccb *)&csa);
30339213Sgibbs		status = csa.ccb_h.status;
30439213Sgibbs                xpt_free_path(path);
30539213Sgibbs        }
30639213Sgibbs
30739213Sgibbs	if (status != CAM_REQ_CMP) {
30839213Sgibbs		printf("pt: Failed to attach master async callback "
30939213Sgibbs		       "due to status 0x%x!\n", status);
31039213Sgibbs	}
31139213Sgibbs}
31239213Sgibbs
31339213Sgibbsstatic cam_status
31439213Sgibbsptctor(struct cam_periph *periph, void *arg)
31539213Sgibbs{
31639213Sgibbs	struct pt_softc *softc;
31739213Sgibbs	struct ccb_setasync csa;
31839213Sgibbs	struct ccb_getdev *cgd;
31939213Sgibbs
32039213Sgibbs	cgd = (struct ccb_getdev *)arg;
32139213Sgibbs	if (periph == NULL) {
32239213Sgibbs		printf("ptregister: periph was NULL!!\n");
32339213Sgibbs		return(CAM_REQ_CMP_ERR);
32439213Sgibbs	}
32539213Sgibbs
32639213Sgibbs	if (cgd == NULL) {
32739213Sgibbs		printf("ptregister: no getdev CCB, can't register device\n");
32839213Sgibbs		return(CAM_REQ_CMP_ERR);
32939213Sgibbs	}
33039213Sgibbs
33139213Sgibbs	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
33239213Sgibbs
33339213Sgibbs	if (softc == NULL) {
33439213Sgibbs		printf("daregister: Unable to probe new device. "
33539213Sgibbs		       "Unable to allocate softc\n");
33639213Sgibbs		return(CAM_REQ_CMP_ERR);
33739213Sgibbs	}
33839213Sgibbs
33939213Sgibbs	bzero(softc, sizeof(*softc));
34039213Sgibbs	LIST_INIT(&softc->pending_ccbs);
34139213Sgibbs	softc->state = PT_STATE_NORMAL;
34259249Sphk	bioq_init(&softc->bio_queue);
34339213Sgibbs
34450073Sken	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
34550073Sken
34639213Sgibbs	periph->softc = softc;
34739213Sgibbs
34839213Sgibbs	cam_extend_set(ptperiphs, periph->unit_number, periph);
34939213Sgibbs
35039213Sgibbs	devstat_add_entry(&softc->device_stats, "pt",
35139213Sgibbs			  periph->unit_number, 0,
35239213Sgibbs			  DEVSTAT_NO_BLOCKSIZE,
35356148Smjacob			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
35443819Sken			  DEVSTAT_PRIORITY_OTHER);
35539213Sgibbs
35653257Sken	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
35753257Sken			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
35853257Sken			      periph->unit_number);
35939213Sgibbs	/*
36039213Sgibbs	 * Add async callbacks for bus reset and
36139213Sgibbs	 * bus device reset calls.  I don't bother
36239213Sgibbs	 * checking if this fails as, in most cases,
36339213Sgibbs	 * the system will function just fine without
36439213Sgibbs	 * them and the only alternative would be to
36539213Sgibbs	 * not attach the device on failure.
36639213Sgibbs	 */
36739213Sgibbs	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
36839213Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
36939213Sgibbs	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
37039213Sgibbs	csa.callback = ptasync;
37139213Sgibbs	csa.callback_arg = periph;
37239213Sgibbs	xpt_action((union ccb *)&csa);
37339213Sgibbs
37439213Sgibbs	/* Tell the user we've attached to the device */
37539213Sgibbs	xpt_announce_periph(periph, NULL);
37639213Sgibbs
37739213Sgibbs	return(CAM_REQ_CMP);
37839213Sgibbs}
37939213Sgibbs
38039213Sgibbsstatic void
38140603Skenptoninvalidate(struct cam_periph *periph)
38240603Sken{
38340603Sken	int s;
38440603Sken	struct pt_softc *softc;
38559249Sphk	struct bio *q_bp;
38640603Sken	struct ccb_setasync csa;
38740603Sken
38840603Sken	softc = (struct pt_softc *)periph->softc;
38940603Sken
39040603Sken	/*
39140603Sken	 * De-register any async callbacks.
39240603Sken	 */
39340603Sken	xpt_setup_ccb(&csa.ccb_h, periph->path,
39440603Sken		      /* priority */ 5);
39540603Sken	csa.ccb_h.func_code = XPT_SASYNC_CB;
39640603Sken	csa.event_enable = 0;
39740603Sken	csa.callback = ptasync;
39840603Sken	csa.callback_arg = periph;
39940603Sken	xpt_action((union ccb *)&csa);
40040603Sken
40140603Sken	softc->flags |= PT_FLAG_DEVICE_INVALID;
40240603Sken
40340603Sken	/*
40440603Sken	 * Although the oninvalidate() routines are always called at
40540603Sken	 * splsoftcam, we need to be at splbio() here to keep the buffer
40640603Sken	 * queue from being modified while we traverse it.
40740603Sken	 */
40840603Sken	s = splbio();
40940603Sken
41040603Sken	/*
41140603Sken	 * Return all queued I/O with ENXIO.
41240603Sken	 * XXX Handle any transactions queued to the card
41340603Sken	 *     with XPT_ABORT_CCB.
41440603Sken	 */
41559249Sphk	while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){
41659249Sphk		bioq_remove(&softc->bio_queue, q_bp);
41759249Sphk		q_bp->bio_resid = q_bp->bio_bcount;
41859249Sphk		q_bp->bio_error = ENXIO;
41959249Sphk		q_bp->bio_flags |= BIO_ERROR;
42040603Sken		biodone(q_bp);
42140603Sken	}
42240603Sken
42340603Sken	splx(s);
42440603Sken
42540603Sken	xpt_print_path(periph->path);
42640603Sken	printf("lost device\n");
42740603Sken}
42840603Sken
42940603Skenstatic void
43039213Sgibbsptdtor(struct cam_periph *periph)
43139213Sgibbs{
43240603Sken	struct pt_softc *softc;
43340603Sken
43440603Sken	softc = (struct pt_softc *)periph->softc;
43540603Sken
43640603Sken	devstat_remove_entry(&softc->device_stats);
43740603Sken
43853257Sken	destroy_dev(softc->dev);
43953257Sken
44039213Sgibbs	cam_extend_release(ptperiphs, periph->unit_number);
44139213Sgibbs	xpt_print_path(periph->path);
44239213Sgibbs	printf("removing device entry\n");
44340603Sken	free(softc, M_DEVBUF);
44439213Sgibbs}
44539213Sgibbs
44639213Sgibbsstatic void
44739213Sgibbsptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
44839213Sgibbs{
44939213Sgibbs	struct cam_periph *periph;
45039213Sgibbs
45139213Sgibbs	periph = (struct cam_periph *)callback_arg;
45239213Sgibbs	switch (code) {
45339213Sgibbs	case AC_FOUND_DEVICE:
45439213Sgibbs	{
45539213Sgibbs		struct ccb_getdev *cgd;
45639213Sgibbs		cam_status status;
45739213Sgibbs
45839213Sgibbs		cgd = (struct ccb_getdev *)arg;
45939213Sgibbs
46056148Smjacob		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
46139213Sgibbs			break;
46239213Sgibbs
46339213Sgibbs		/*
46439213Sgibbs		 * Allocate a peripheral instance for
46539213Sgibbs		 * this device and start the probe
46639213Sgibbs		 * process.
46739213Sgibbs		 */
46840603Sken		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
46940603Sken					  ptstart, "pt", CAM_PERIPH_BIO,
47040603Sken					  cgd->ccb_h.path, ptasync,
47140603Sken					  AC_FOUND_DEVICE, cgd);
47239213Sgibbs
47339213Sgibbs		if (status != CAM_REQ_CMP
47439213Sgibbs		 && status != CAM_REQ_INPROG)
47539213Sgibbs			printf("ptasync: Unable to attach to new device "
47639213Sgibbs				"due to status 0x%x\n", status);
47739213Sgibbs		break;
47839213Sgibbs	}
47939213Sgibbs	case AC_SENT_BDR:
48039213Sgibbs	case AC_BUS_RESET:
48139213Sgibbs	{
48239213Sgibbs		struct pt_softc *softc;
48339213Sgibbs		struct ccb_hdr *ccbh;
48439213Sgibbs		int s;
48539213Sgibbs
48639213Sgibbs		softc = (struct pt_softc *)periph->softc;
48739213Sgibbs		s = splsoftcam();
48839213Sgibbs		/*
48939213Sgibbs		 * Don't fail on the expected unit attention
49039213Sgibbs		 * that will occur.
49139213Sgibbs		 */
49239213Sgibbs		softc->flags |= PT_FLAG_RETRY_UA;
49371999Sphk		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
49439213Sgibbs			ccbh->ccb_state |= PT_CCB_RETRY_UA;
49539213Sgibbs		splx(s);
49647413Sgibbs		/* FALLTHROUGH */
49739213Sgibbs	}
49839213Sgibbs	default:
49947413Sgibbs		cam_periph_async(periph, code, path, arg);
50039213Sgibbs		break;
50139213Sgibbs	}
50239213Sgibbs}
50339213Sgibbs
50439213Sgibbsstatic void
50539213Sgibbsptstart(struct cam_periph *periph, union ccb *start_ccb)
50639213Sgibbs{
50739213Sgibbs	struct pt_softc *softc;
50859249Sphk	struct bio *bp;
50939213Sgibbs	int s;
51039213Sgibbs
51139213Sgibbs	softc = (struct pt_softc *)periph->softc;
51239213Sgibbs
51339213Sgibbs	/*
51439213Sgibbs	 * See if there is a buf with work for us to do..
51539213Sgibbs	 */
51639213Sgibbs	s = splbio();
51759249Sphk	bp = bioq_first(&softc->bio_queue);
51839213Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
51939213Sgibbs		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
52039213Sgibbs				("queuing for immediate ccb\n"));
52139213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
52239213Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
52339213Sgibbs				  periph_links.sle);
52439213Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
52539213Sgibbs		splx(s);
52639213Sgibbs		wakeup(&periph->ccb_list);
52739213Sgibbs	} else if (bp == NULL) {
52839213Sgibbs		splx(s);
52939213Sgibbs		xpt_release_ccb(start_ccb);
53039213Sgibbs	} else {
53139213Sgibbs		int oldspl;
53239213Sgibbs
53359249Sphk		bioq_remove(&softc->bio_queue, bp);
53439213Sgibbs
53539213Sgibbs		devstat_start_transaction(&softc->device_stats);
53639213Sgibbs
53739213Sgibbs		scsi_send_receive(&start_ccb->csio,
53839213Sgibbs				  /*retries*/4,
53939213Sgibbs				  ptdone,
54039213Sgibbs				  MSG_SIMPLE_Q_TAG,
54159249Sphk				  bp->bio_cmd == BIO_READ,
54239213Sgibbs				  /*byte2*/0,
54359249Sphk				  bp->bio_bcount,
54459249Sphk				  bp->bio_data,
54539213Sgibbs				  /*sense_len*/SSD_FULL_SIZE,
54650073Sken				  /*timeout*/softc->io_timeout);
54739213Sgibbs
54839213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO;
54939213Sgibbs
55039213Sgibbs		/*
55139213Sgibbs		 * Block out any asyncronous callbacks
55239213Sgibbs		 * while we touch the pending ccb list.
55339213Sgibbs		 */
55439213Sgibbs		oldspl = splcam();
55539213Sgibbs		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
55639213Sgibbs				 periph_links.le);
55739213Sgibbs		splx(oldspl);
55839213Sgibbs
55939213Sgibbs		start_ccb->ccb_h.ccb_bp = bp;
56059249Sphk		bp = bioq_first(&softc->bio_queue);
56139213Sgibbs		splx(s);
56239213Sgibbs
56339213Sgibbs		xpt_action(start_ccb);
56439213Sgibbs
56539213Sgibbs		if (bp != NULL) {
56639213Sgibbs			/* Have more work to do, so ensure we stay scheduled */
56739213Sgibbs			xpt_schedule(periph, /* XXX priority */1);
56839213Sgibbs		}
56939213Sgibbs	}
57039213Sgibbs}
57139213Sgibbs
57239213Sgibbsstatic void
57339213Sgibbsptdone(struct cam_periph *periph, union ccb *done_ccb)
57439213Sgibbs{
57539213Sgibbs	struct pt_softc *softc;
57639213Sgibbs	struct ccb_scsiio *csio;
57739213Sgibbs
57839213Sgibbs	softc = (struct pt_softc *)periph->softc;
57939213Sgibbs	csio = &done_ccb->csio;
58039213Sgibbs	switch (csio->ccb_h.ccb_state) {
58139213Sgibbs	case PT_CCB_BUFFER_IO:
58239213Sgibbs	case PT_CCB_BUFFER_IO_UA:
58339213Sgibbs	{
58459249Sphk		struct bio *bp;
58539213Sgibbs		int    oldspl;
58639213Sgibbs
58759249Sphk		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
58839213Sgibbs		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
58939213Sgibbs			int error;
59039213Sgibbs			int s;
59139213Sgibbs			int sf;
59239213Sgibbs
59339213Sgibbs			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
59439213Sgibbs				sf = SF_RETRY_UA;
59539213Sgibbs			else
59639213Sgibbs				sf = 0;
59739213Sgibbs
59846747Sken			sf |= SF_RETRY_SELTO;
59946747Sken
60039213Sgibbs			if ((error = pterror(done_ccb, 0, sf)) == ERESTART) {
60139213Sgibbs				/*
60239213Sgibbs				 * A retry was scheuled, so
60339213Sgibbs				 * just return.
60439213Sgibbs				 */
60539213Sgibbs				return;
60639213Sgibbs			}
60739213Sgibbs			if (error != 0) {
60859249Sphk				struct bio *q_bp;
60939213Sgibbs
61039213Sgibbs				s = splbio();
61139213Sgibbs
61239213Sgibbs				if (error == ENXIO) {
61339213Sgibbs					/*
61439213Sgibbs					 * Catastrophic error.  Mark our device
61539213Sgibbs					 * as invalid.
61639213Sgibbs					 */
61739213Sgibbs					xpt_print_path(periph->path);
61839213Sgibbs					printf("Invalidating device\n");
61939213Sgibbs					softc->flags |= PT_FLAG_DEVICE_INVALID;
62039213Sgibbs				}
62139213Sgibbs
62239213Sgibbs				/*
62339213Sgibbs				 * return all queued I/O with EIO, so that
62439213Sgibbs				 * the client can retry these I/Os in the
62539213Sgibbs				 * proper order should it attempt to recover.
62639213Sgibbs				 */
62759249Sphk				while ((q_bp = bioq_first(&softc->bio_queue))
62839213Sgibbs					!= NULL) {
62959249Sphk					bioq_remove(&softc->bio_queue, q_bp);
63059249Sphk					q_bp->bio_resid = q_bp->bio_bcount;
63159249Sphk					q_bp->bio_error = EIO;
63259249Sphk					q_bp->bio_flags |= BIO_ERROR;
63339213Sgibbs					biodone(q_bp);
63439213Sgibbs				}
63539213Sgibbs				splx(s);
63659249Sphk				bp->bio_error = error;
63759249Sphk				bp->bio_resid = bp->bio_bcount;
63859249Sphk				bp->bio_flags |= BIO_ERROR;
63939213Sgibbs			} else {
64059249Sphk				bp->bio_resid = csio->resid;
64159249Sphk				bp->bio_error = 0;
64259249Sphk				if (bp->bio_resid != 0) {
64339213Sgibbs					/* Short transfer ??? */
64459249Sphk					bp->bio_flags |= BIO_ERROR;
64539213Sgibbs				}
64639213Sgibbs			}
64739213Sgibbs			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
64839213Sgibbs				cam_release_devq(done_ccb->ccb_h.path,
64939213Sgibbs						 /*relsim_flags*/0,
65039213Sgibbs						 /*reduction*/0,
65139213Sgibbs						 /*timeout*/0,
65239213Sgibbs						 /*getcount_only*/0);
65339213Sgibbs		} else {
65459249Sphk			bp->bio_resid = csio->resid;
65559249Sphk			if (bp->bio_resid != 0)
65659249Sphk				bp->bio_flags |= BIO_ERROR;
65739213Sgibbs		}
65839213Sgibbs
65939213Sgibbs		/*
66039213Sgibbs		 * Block out any asyncronous callbacks
66139213Sgibbs		 * while we touch the pending ccb list.
66239213Sgibbs		 */
66339213Sgibbs		oldspl = splcam();
66439213Sgibbs		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
66539213Sgibbs		splx(oldspl);
66639213Sgibbs
66759249Sphk		devstat_end_transaction_bio(&softc->device_stats, bp);
66839213Sgibbs		biodone(bp);
66939213Sgibbs		break;
67039213Sgibbs	}
67139213Sgibbs	case PT_CCB_WAITING:
67239213Sgibbs		/* Caller will release the CCB */
67339213Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
67439213Sgibbs		return;
67539213Sgibbs	}
67639213Sgibbs	xpt_release_ccb(done_ccb);
67739213Sgibbs}
67839213Sgibbs
67939213Sgibbsstatic int
68039213Sgibbspterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
68139213Sgibbs{
68239213Sgibbs	struct pt_softc	  *softc;
68339213Sgibbs	struct cam_periph *periph;
68439213Sgibbs
68539213Sgibbs	periph = xpt_path_periph(ccb->ccb_h.path);
68639213Sgibbs	softc = (struct pt_softc *)periph->softc;
68739213Sgibbs
68839213Sgibbs	return(cam_periph_error(ccb, cam_flags, sense_flags,
68939213Sgibbs				&softc->saved_ccb));
69039213Sgibbs}
69139213Sgibbs
69250073Skenstatic int
69350073Skenptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
69450073Sken{
69550073Sken	struct cam_periph *periph;
69650073Sken	struct pt_softc *softc;
69750073Sken	int unit;
69850073Sken	int error;
69950073Sken
70050073Sken	unit = minor(dev);
70150073Sken	periph = cam_extend_get(ptperiphs, unit);
70250073Sken
70350073Sken	if (periph == NULL)
70450073Sken		return(ENXIO);
70550073Sken
70650073Sken	softc = (struct pt_softc *)periph->softc;
70750073Sken
70850073Sken	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
70950073Sken		return (error); /* error code from tsleep */
71050073Sken	}
71150073Sken
71250073Sken	switch(cmd) {
71350073Sken	case PTIOCGETTIMEOUT:
71450073Sken		if (softc->io_timeout >= 1000)
71550073Sken			*(int *)addr = softc->io_timeout / 1000;
71650073Sken		else
71750073Sken			*(int *)addr = 0;
71850073Sken		break;
71950073Sken	case PTIOCSETTIMEOUT:
72050073Sken	{
72150073Sken		int s;
72250073Sken
72350073Sken		if (*(int *)addr < 1) {
72450073Sken			error = EINVAL;
72550073Sken			break;
72650073Sken		}
72750073Sken
72850073Sken		s = splsoftcam();
72950073Sken		softc->io_timeout = *(int *)addr * 1000;
73050073Sken		splx(s);
73150073Sken
73250073Sken		break;
73350073Sken	}
73450073Sken	default:
73550073Sken		error = cam_periph_ioctl(periph, cmd, addr, pterror);
73650073Sken		break;
73750073Sken	}
73850073Sken
73950073Sken	cam_periph_unlock(periph);
74050073Sken
74150073Sken	return(error);
74250073Sken}
74350073Sken
74439213Sgibbsvoid
74539213Sgibbsscsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
74639213Sgibbs		  void (*cbfcnp)(struct cam_periph *, union ccb *),
74739213Sgibbs		  u_int tag_action, int readop, u_int byte2,
74839213Sgibbs		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
74939213Sgibbs		  u_int32_t timeout)
75039213Sgibbs{
75139213Sgibbs	struct scsi_send_receive *scsi_cmd;
75239213Sgibbs
75339213Sgibbs	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
75439213Sgibbs	scsi_cmd->opcode = readop ? RECEIVE : SEND;
75539213Sgibbs	scsi_cmd->byte2 = byte2;
75639213Sgibbs	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
75739213Sgibbs	scsi_cmd->control = 0;
75839213Sgibbs
75939213Sgibbs	cam_fill_csio(csio,
76039213Sgibbs		      retries,
76139213Sgibbs		      cbfcnp,
76239213Sgibbs		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
76339213Sgibbs		      tag_action,
76439213Sgibbs		      data_ptr,
76539213Sgibbs		      xfer_len,
76639213Sgibbs		      sense_len,
76739213Sgibbs		      sizeof(*scsi_cmd),
76839213Sgibbs		      timeout);
76939213Sgibbs}
770