scsi_pt.c revision 168752
1139743Simp/*-
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 */
2839213Sgibbs
29116162Sobrien#include <sys/cdefs.h>
30116162Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pt.c 168752 2007-04-15 08:49:19Z scottl $");
31116162Sobrien
3239213Sgibbs#include <sys/param.h>
3339213Sgibbs#include <sys/queue.h>
3439213Sgibbs#include <sys/systm.h>
3539213Sgibbs#include <sys/kernel.h>
3639213Sgibbs#include <sys/types.h>
3760041Sphk#include <sys/bio.h>
3839213Sgibbs#include <sys/devicestat.h>
3939213Sgibbs#include <sys/malloc.h>
4039213Sgibbs#include <sys/conf.h>
4150073Sken#include <sys/ptio.h>
4239213Sgibbs
4339213Sgibbs#include <cam/cam.h>
4439213Sgibbs#include <cam/cam_ccb.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;
80112006Sphk	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;
86130585Sphk	struct cdev *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
12047625Sphkstatic struct cdevsw pt_cdevsw = {
121126080Sphk	.d_version =	D_VERSION,
122168752Sscottl	.d_flags =	0,
123111815Sphk	.d_open =	ptopen,
124111815Sphk	.d_close =	ptclose,
125111815Sphk	.d_read =	physread,
126111815Sphk	.d_write =	physwrite,
127111815Sphk	.d_ioctl =	ptioctl,
128111815Sphk	.d_strategy =	ptstrategy,
129111815Sphk	.d_name =	"pt",
13039213Sgibbs};
13139213Sgibbs
13250073Sken#ifndef SCSI_PT_DEFAULT_TIMEOUT
13350073Sken#define SCSI_PT_DEFAULT_TIMEOUT		60
13450073Sken#endif
13550073Sken
13639213Sgibbsstatic int
137130585Sphkptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
13839213Sgibbs{
13939213Sgibbs	struct cam_periph *periph;
14039213Sgibbs	struct pt_softc *softc;
141168752Sscottl	int error = 0;
14239213Sgibbs
143101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
144168752Sscottl	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
14539213Sgibbs		return (ENXIO);
14639213Sgibbs
14739213Sgibbs	softc = (struct pt_softc *)periph->softc;
14839213Sgibbs
149168752Sscottl	cam_periph_lock(periph);
15040603Sken	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
151168752Sscottl		cam_periph_unlock(periph);
152168752Sscottl		cam_periph_release(periph);
15340603Sken		return(ENXIO);
15440603Sken	}
15540603Sken
156168752Sscottl	if ((softc->flags & PT_FLAG_OPEN) == 0)
157168752Sscottl		softc->flags |= PT_FLAG_OPEN;
158168752Sscottl	else {
159168752Sscottl		error = EBUSY;
160168752Sscottl		cam_periph_release(periph);
16141297Sken	}
16239213Sgibbs
163168752Sscottl	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
164168752Sscottl	    ("ptopen: dev=%s\n", devtoname(dev)));
16541297Sken
16639213Sgibbs	cam_periph_unlock(periph);
16739213Sgibbs	return (error);
16839213Sgibbs}
16939213Sgibbs
17039213Sgibbsstatic int
171130585Sphkptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
17239213Sgibbs{
17339213Sgibbs	struct	cam_periph *periph;
17439213Sgibbs	struct	pt_softc *softc;
17539213Sgibbs
176101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
17739213Sgibbs	if (periph == NULL)
17839213Sgibbs		return (ENXIO);
17939213Sgibbs
18039213Sgibbs	softc = (struct pt_softc *)periph->softc;
18139213Sgibbs
182168752Sscottl	cam_periph_lock(periph);
18339213Sgibbs
18439213Sgibbs	softc->flags &= ~PT_FLAG_OPEN;
18539213Sgibbs	cam_periph_unlock(periph);
18639213Sgibbs	cam_periph_release(periph);
18739213Sgibbs	return (0);
18839213Sgibbs}
18939213Sgibbs
19039213Sgibbs/*
19139213Sgibbs * Actually translate the requested transfer into one the physical driver
19239213Sgibbs * can understand.  The transfer is described by a buf and will include
19339213Sgibbs * only one physical transfer.
19439213Sgibbs */
19539213Sgibbsstatic void
19659249Sphkptstrategy(struct bio *bp)
19739213Sgibbs{
19839213Sgibbs	struct cam_periph *periph;
19939213Sgibbs	struct pt_softc *softc;
20039213Sgibbs
201101940Snjl	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
20276362Sphk	bp->bio_resid = bp->bio_bcount;
20339213Sgibbs	if (periph == NULL) {
20476362Sphk		biofinish(bp, NULL, ENXIO);
20576362Sphk		return;
20639213Sgibbs	}
207168752Sscottl	cam_periph_lock(periph);
20839213Sgibbs	softc = (struct pt_softc *)periph->softc;
20939213Sgibbs
21039213Sgibbs	/*
21139213Sgibbs	 * If the device has been made invalid, error out
21239213Sgibbs	 */
21339213Sgibbs	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
214168752Sscottl		cam_periph_unlock(periph);
21576362Sphk		biofinish(bp, NULL, ENXIO);
21676362Sphk		return;
21739213Sgibbs	}
21839213Sgibbs
21939213Sgibbs	/*
22039213Sgibbs	 * Place it in the queue of disk activities for this disk
22139213Sgibbs	 */
22259249Sphk	bioq_insert_tail(&softc->bio_queue, bp);
22339213Sgibbs
22439213Sgibbs	/*
22539213Sgibbs	 * Schedule ourselves for performing the work.
22639213Sgibbs	 */
22739213Sgibbs	xpt_schedule(periph, /* XXX priority */1);
228168752Sscottl	cam_periph_unlock(periph);
22939213Sgibbs
23039213Sgibbs	return;
23139213Sgibbs}
23239213Sgibbs
23339213Sgibbsstatic void
23439213Sgibbsptinit(void)
23539213Sgibbs{
23639213Sgibbs	cam_status status;
23739213Sgibbs	struct cam_path *path;
23839213Sgibbs
23939213Sgibbs	/*
24039213Sgibbs	 * Install a global async callback.  This callback will
24139213Sgibbs	 * receive async callbacks like "new device found".
24239213Sgibbs	 */
24339213Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
24439213Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
24539213Sgibbs
24639213Sgibbs	if (status == CAM_REQ_CMP) {
24739213Sgibbs		struct ccb_setasync csa;
24839213Sgibbs
24939213Sgibbs                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
25039213Sgibbs                csa.ccb_h.func_code = XPT_SASYNC_CB;
25139213Sgibbs                csa.event_enable = AC_FOUND_DEVICE;
25239213Sgibbs                csa.callback = ptasync;
25339213Sgibbs                csa.callback_arg = NULL;
25439213Sgibbs                xpt_action((union ccb *)&csa);
25539213Sgibbs		status = csa.ccb_h.status;
25639213Sgibbs                xpt_free_path(path);
25739213Sgibbs        }
25839213Sgibbs
25939213Sgibbs	if (status != CAM_REQ_CMP) {
26039213Sgibbs		printf("pt: Failed to attach master async callback "
26139213Sgibbs		       "due to status 0x%x!\n", status);
26239213Sgibbs	}
26339213Sgibbs}
26439213Sgibbs
26539213Sgibbsstatic cam_status
26639213Sgibbsptctor(struct cam_periph *periph, void *arg)
26739213Sgibbs{
26839213Sgibbs	struct pt_softc *softc;
26939213Sgibbs	struct ccb_setasync csa;
27039213Sgibbs	struct ccb_getdev *cgd;
27139213Sgibbs
27239213Sgibbs	cgd = (struct ccb_getdev *)arg;
27339213Sgibbs	if (periph == NULL) {
27439213Sgibbs		printf("ptregister: periph was NULL!!\n");
27539213Sgibbs		return(CAM_REQ_CMP_ERR);
27639213Sgibbs	}
27739213Sgibbs
27839213Sgibbs	if (cgd == NULL) {
27939213Sgibbs		printf("ptregister: no getdev CCB, can't register device\n");
28039213Sgibbs		return(CAM_REQ_CMP_ERR);
28139213Sgibbs	}
28239213Sgibbs
28339213Sgibbs	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
28439213Sgibbs
28539213Sgibbs	if (softc == NULL) {
28639213Sgibbs		printf("daregister: Unable to probe new device. "
28739213Sgibbs		       "Unable to allocate softc\n");
28839213Sgibbs		return(CAM_REQ_CMP_ERR);
28939213Sgibbs	}
29039213Sgibbs
29139213Sgibbs	bzero(softc, sizeof(*softc));
29239213Sgibbs	LIST_INIT(&softc->pending_ccbs);
29339213Sgibbs	softc->state = PT_STATE_NORMAL;
29459249Sphk	bioq_init(&softc->bio_queue);
29539213Sgibbs
29650073Sken	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
29750073Sken
29839213Sgibbs	periph->softc = softc;
29939213Sgibbs
300112006Sphk	softc->device_stats = devstat_new_entry("pt",
30139213Sgibbs			  periph->unit_number, 0,
30239213Sgibbs			  DEVSTAT_NO_BLOCKSIZE,
30356148Smjacob			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
30443819Sken			  DEVSTAT_PRIORITY_OTHER);
30539213Sgibbs
30653257Sken	softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
30753257Sken			      GID_OPERATOR, 0600, "%s%d", periph->periph_name,
30853257Sken			      periph->unit_number);
309101940Snjl	softc->dev->si_drv1 = periph;
310101940Snjl
31139213Sgibbs	/*
31239213Sgibbs	 * Add async callbacks for bus reset and
31339213Sgibbs	 * bus device reset calls.  I don't bother
31439213Sgibbs	 * checking if this fails as, in most cases,
31539213Sgibbs	 * the system will function just fine without
31639213Sgibbs	 * them and the only alternative would be to
31739213Sgibbs	 * not attach the device on failure.
31839213Sgibbs	 */
31939213Sgibbs	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
32039213Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
32139213Sgibbs	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
32239213Sgibbs	csa.callback = ptasync;
32339213Sgibbs	csa.callback_arg = periph;
32439213Sgibbs	xpt_action((union ccb *)&csa);
32539213Sgibbs
32639213Sgibbs	/* Tell the user we've attached to the device */
32739213Sgibbs	xpt_announce_periph(periph, NULL);
32839213Sgibbs
32939213Sgibbs	return(CAM_REQ_CMP);
33039213Sgibbs}
33139213Sgibbs
33239213Sgibbsstatic void
33340603Skenptoninvalidate(struct cam_periph *periph)
33440603Sken{
33540603Sken	struct pt_softc *softc;
33640603Sken	struct ccb_setasync csa;
33740603Sken
33840603Sken	softc = (struct pt_softc *)periph->softc;
33940603Sken
34040603Sken	/*
34140603Sken	 * De-register any async callbacks.
34240603Sken	 */
34340603Sken	xpt_setup_ccb(&csa.ccb_h, periph->path,
34440603Sken		      /* priority */ 5);
34540603Sken	csa.ccb_h.func_code = XPT_SASYNC_CB;
34640603Sken	csa.event_enable = 0;
34740603Sken	csa.callback = ptasync;
34840603Sken	csa.callback_arg = periph;
34940603Sken	xpt_action((union ccb *)&csa);
35040603Sken
35140603Sken	softc->flags |= PT_FLAG_DEVICE_INVALID;
35240603Sken
35340603Sken	/*
35440603Sken	 * Return all queued I/O with ENXIO.
35540603Sken	 * XXX Handle any transactions queued to the card
35640603Sken	 *     with XPT_ABORT_CCB.
35740603Sken	 */
358112946Sphk	bioq_flush(&softc->bio_queue, NULL, ENXIO);
35940603Sken
360164906Smjacob	xpt_print(periph->path, "lost device\n");
36140603Sken}
36240603Sken
36340603Skenstatic void
36439213Sgibbsptdtor(struct cam_periph *periph)
36539213Sgibbs{
36640603Sken	struct pt_softc *softc;
36740603Sken
36840603Sken	softc = (struct pt_softc *)periph->softc;
36940603Sken
370112006Sphk	devstat_remove_entry(softc->device_stats);
37140603Sken
37253257Sken	destroy_dev(softc->dev);
37353257Sken
374164906Smjacob	xpt_print(periph->path, "removing device entry\n");
37540603Sken	free(softc, M_DEVBUF);
37639213Sgibbs}
37739213Sgibbs
37839213Sgibbsstatic void
37939213Sgibbsptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
38039213Sgibbs{
38139213Sgibbs	struct cam_periph *periph;
38239213Sgibbs
38339213Sgibbs	periph = (struct cam_periph *)callback_arg;
38439213Sgibbs	switch (code) {
38539213Sgibbs	case AC_FOUND_DEVICE:
38639213Sgibbs	{
38739213Sgibbs		struct ccb_getdev *cgd;
38839213Sgibbs		cam_status status;
38939213Sgibbs
39039213Sgibbs		cgd = (struct ccb_getdev *)arg;
39179177Smjacob		if (cgd == NULL)
39279177Smjacob			break;
39339213Sgibbs
39456148Smjacob		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
39539213Sgibbs			break;
39639213Sgibbs
39739213Sgibbs		/*
39839213Sgibbs		 * Allocate a peripheral instance for
39939213Sgibbs		 * this device and start the probe
40039213Sgibbs		 * process.
40139213Sgibbs		 */
40240603Sken		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
40340603Sken					  ptstart, "pt", CAM_PERIPH_BIO,
40440603Sken					  cgd->ccb_h.path, ptasync,
40540603Sken					  AC_FOUND_DEVICE, cgd);
40639213Sgibbs
40739213Sgibbs		if (status != CAM_REQ_CMP
40839213Sgibbs		 && status != CAM_REQ_INPROG)
40939213Sgibbs			printf("ptasync: Unable to attach to new device "
41039213Sgibbs				"due to status 0x%x\n", status);
41139213Sgibbs		break;
41239213Sgibbs	}
41339213Sgibbs	case AC_SENT_BDR:
41439213Sgibbs	case AC_BUS_RESET:
41539213Sgibbs	{
41639213Sgibbs		struct pt_softc *softc;
41739213Sgibbs		struct ccb_hdr *ccbh;
41839213Sgibbs
41939213Sgibbs		softc = (struct pt_softc *)periph->softc;
42039213Sgibbs		/*
42139213Sgibbs		 * Don't fail on the expected unit attention
42239213Sgibbs		 * that will occur.
42339213Sgibbs		 */
42439213Sgibbs		softc->flags |= PT_FLAG_RETRY_UA;
42571999Sphk		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
42639213Sgibbs			ccbh->ccb_state |= PT_CCB_RETRY_UA;
42739213Sgibbs	}
428115562Sphk	/* FALLTHROUGH */
42939213Sgibbs	default:
43047413Sgibbs		cam_periph_async(periph, code, path, arg);
43139213Sgibbs		break;
43239213Sgibbs	}
43339213Sgibbs}
43439213Sgibbs
43539213Sgibbsstatic void
43639213Sgibbsptstart(struct cam_periph *periph, union ccb *start_ccb)
43739213Sgibbs{
43839213Sgibbs	struct pt_softc *softc;
43959249Sphk	struct bio *bp;
44039213Sgibbs
44139213Sgibbs	softc = (struct pt_softc *)periph->softc;
44239213Sgibbs
44339213Sgibbs	/*
44439213Sgibbs	 * See if there is a buf with work for us to do..
44539213Sgibbs	 */
44659249Sphk	bp = bioq_first(&softc->bio_queue);
44739213Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
44839213Sgibbs		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
44939213Sgibbs				("queuing for immediate ccb\n"));
45039213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
45139213Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
45239213Sgibbs				  periph_links.sle);
45339213Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
45439213Sgibbs		wakeup(&periph->ccb_list);
45539213Sgibbs	} else if (bp == NULL) {
45639213Sgibbs		xpt_release_ccb(start_ccb);
45739213Sgibbs	} else {
45859249Sphk		bioq_remove(&softc->bio_queue, bp);
45939213Sgibbs
460112260Sphk		devstat_start_transaction_bio(softc->device_stats, bp);
46139213Sgibbs
46239213Sgibbs		scsi_send_receive(&start_ccb->csio,
46339213Sgibbs				  /*retries*/4,
46439213Sgibbs				  ptdone,
46539213Sgibbs				  MSG_SIMPLE_Q_TAG,
46659249Sphk				  bp->bio_cmd == BIO_READ,
46739213Sgibbs				  /*byte2*/0,
46859249Sphk				  bp->bio_bcount,
46959249Sphk				  bp->bio_data,
47039213Sgibbs				  /*sense_len*/SSD_FULL_SIZE,
47150073Sken				  /*timeout*/softc->io_timeout);
47239213Sgibbs
47376192Sken		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
47439213Sgibbs
47539213Sgibbs		/*
47639213Sgibbs		 * Block out any asyncronous callbacks
47739213Sgibbs		 * while we touch the pending ccb list.
47839213Sgibbs		 */
47939213Sgibbs		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
48039213Sgibbs				 periph_links.le);
48139213Sgibbs
48239213Sgibbs		start_ccb->ccb_h.ccb_bp = bp;
48359249Sphk		bp = bioq_first(&softc->bio_queue);
48439213Sgibbs
48539213Sgibbs		xpt_action(start_ccb);
48639213Sgibbs
48739213Sgibbs		if (bp != NULL) {
48839213Sgibbs			/* Have more work to do, so ensure we stay scheduled */
48939213Sgibbs			xpt_schedule(periph, /* XXX priority */1);
49039213Sgibbs		}
49139213Sgibbs	}
49239213Sgibbs}
49339213Sgibbs
49439213Sgibbsstatic void
49539213Sgibbsptdone(struct cam_periph *periph, union ccb *done_ccb)
49639213Sgibbs{
49739213Sgibbs	struct pt_softc *softc;
49839213Sgibbs	struct ccb_scsiio *csio;
49939213Sgibbs
50039213Sgibbs	softc = (struct pt_softc *)periph->softc;
50139213Sgibbs	csio = &done_ccb->csio;
50239213Sgibbs	switch (csio->ccb_h.ccb_state) {
50339213Sgibbs	case PT_CCB_BUFFER_IO:
50439213Sgibbs	case PT_CCB_BUFFER_IO_UA:
50539213Sgibbs	{
50659249Sphk		struct bio *bp;
50739213Sgibbs
50859249Sphk		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
50939213Sgibbs		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
51039213Sgibbs			int error;
51139213Sgibbs			int sf;
51239213Sgibbs
51339213Sgibbs			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
51439213Sgibbs				sf = SF_RETRY_UA;
51539213Sgibbs			else
51639213Sgibbs				sf = 0;
51739213Sgibbs
51874840Sken			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
51974840Sken			if (error == ERESTART) {
52039213Sgibbs				/*
52139213Sgibbs				 * A retry was scheuled, so
52239213Sgibbs				 * just return.
52339213Sgibbs				 */
52439213Sgibbs				return;
52539213Sgibbs			}
52639213Sgibbs			if (error != 0) {
52739213Sgibbs				if (error == ENXIO) {
52839213Sgibbs					/*
52939213Sgibbs					 * Catastrophic error.  Mark our device
53039213Sgibbs					 * as invalid.
53139213Sgibbs					 */
532164906Smjacob					xpt_print(periph->path,
533164906Smjacob					    "Invalidating device\n");
53439213Sgibbs					softc->flags |= PT_FLAG_DEVICE_INVALID;
53539213Sgibbs				}
53639213Sgibbs
53739213Sgibbs				/*
53839213Sgibbs				 * return all queued I/O with EIO, so that
53939213Sgibbs				 * the client can retry these I/Os in the
54039213Sgibbs				 * proper order should it attempt to recover.
54139213Sgibbs				 */
542112946Sphk				bioq_flush(&softc->bio_queue, NULL, EIO);
54359249Sphk				bp->bio_error = error;
54459249Sphk				bp->bio_resid = bp->bio_bcount;
54559249Sphk				bp->bio_flags |= BIO_ERROR;
54639213Sgibbs			} else {
54759249Sphk				bp->bio_resid = csio->resid;
54859249Sphk				bp->bio_error = 0;
54959249Sphk				if (bp->bio_resid != 0) {
55039213Sgibbs					/* Short transfer ??? */
55159249Sphk					bp->bio_flags |= BIO_ERROR;
55239213Sgibbs				}
55339213Sgibbs			}
55439213Sgibbs			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
55539213Sgibbs				cam_release_devq(done_ccb->ccb_h.path,
55639213Sgibbs						 /*relsim_flags*/0,
55739213Sgibbs						 /*reduction*/0,
55839213Sgibbs						 /*timeout*/0,
55939213Sgibbs						 /*getcount_only*/0);
56039213Sgibbs		} else {
56159249Sphk			bp->bio_resid = csio->resid;
56259249Sphk			if (bp->bio_resid != 0)
56359249Sphk				bp->bio_flags |= BIO_ERROR;
56439213Sgibbs		}
56539213Sgibbs
56639213Sgibbs		/*
56739213Sgibbs		 * Block out any asyncronous callbacks
56839213Sgibbs		 * while we touch the pending ccb list.
56939213Sgibbs		 */
57039213Sgibbs		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
57139213Sgibbs
572112006Sphk		biofinish(bp, softc->device_stats, 0);
57339213Sgibbs		break;
57439213Sgibbs	}
57539213Sgibbs	case PT_CCB_WAITING:
57639213Sgibbs		/* Caller will release the CCB */
57739213Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
57839213Sgibbs		return;
57939213Sgibbs	}
58039213Sgibbs	xpt_release_ccb(done_ccb);
58139213Sgibbs}
58239213Sgibbs
58339213Sgibbsstatic int
58439213Sgibbspterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
58539213Sgibbs{
58639213Sgibbs	struct pt_softc	  *softc;
58739213Sgibbs	struct cam_periph *periph;
58839213Sgibbs
58939213Sgibbs	periph = xpt_path_periph(ccb->ccb_h.path);
59039213Sgibbs	softc = (struct pt_softc *)periph->softc;
59139213Sgibbs
59239213Sgibbs	return(cam_periph_error(ccb, cam_flags, sense_flags,
59339213Sgibbs				&softc->saved_ccb));
59439213Sgibbs}
59539213Sgibbs
59650073Skenstatic int
597130585Sphkptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
59850073Sken{
59950073Sken	struct cam_periph *periph;
60050073Sken	struct pt_softc *softc;
601168752Sscottl	int error = 0;
60250073Sken
603101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
60450073Sken	if (periph == NULL)
60550073Sken		return(ENXIO);
60650073Sken
60750073Sken	softc = (struct pt_softc *)periph->softc;
60850073Sken
609168752Sscottl	cam_periph_lock(periph);
61050073Sken
61150073Sken	switch(cmd) {
61250073Sken	case PTIOCGETTIMEOUT:
61350073Sken		if (softc->io_timeout >= 1000)
61450073Sken			*(int *)addr = softc->io_timeout / 1000;
61550073Sken		else
61650073Sken			*(int *)addr = 0;
61750073Sken		break;
61850073Sken	case PTIOCSETTIMEOUT:
61950073Sken		if (*(int *)addr < 1) {
62050073Sken			error = EINVAL;
62150073Sken			break;
62250073Sken		}
62350073Sken
62450073Sken		softc->io_timeout = *(int *)addr * 1000;
62550073Sken
62650073Sken		break;
62750073Sken	default:
62850073Sken		error = cam_periph_ioctl(periph, cmd, addr, pterror);
62950073Sken		break;
63050073Sken	}
63150073Sken
63250073Sken	cam_periph_unlock(periph);
63350073Sken
63450073Sken	return(error);
63550073Sken}
63650073Sken
63739213Sgibbsvoid
63839213Sgibbsscsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
63939213Sgibbs		  void (*cbfcnp)(struct cam_periph *, union ccb *),
64039213Sgibbs		  u_int tag_action, int readop, u_int byte2,
64139213Sgibbs		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
64239213Sgibbs		  u_int32_t timeout)
64339213Sgibbs{
64439213Sgibbs	struct scsi_send_receive *scsi_cmd;
64539213Sgibbs
64639213Sgibbs	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
64739213Sgibbs	scsi_cmd->opcode = readop ? RECEIVE : SEND;
64839213Sgibbs	scsi_cmd->byte2 = byte2;
64939213Sgibbs	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
65039213Sgibbs	scsi_cmd->control = 0;
65139213Sgibbs
65239213Sgibbs	cam_fill_csio(csio,
65339213Sgibbs		      retries,
65439213Sgibbs		      cbfcnp,
65539213Sgibbs		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
65639213Sgibbs		      tag_action,
65739213Sgibbs		      data_ptr,
65839213Sgibbs		      xfer_len,
65939213Sgibbs		      sense_len,
66039213Sgibbs		      sizeof(*scsi_cmd),
66139213Sgibbs		      timeout);
66239213Sgibbs}
663