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$");
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_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;
85130585Sphk	struct cdev *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
11947625Sphkstatic struct cdevsw pt_cdevsw = {
120126080Sphk	.d_version =	D_VERSION,
121168752Sscottl	.d_flags =	0,
122111815Sphk	.d_open =	ptopen,
123111815Sphk	.d_close =	ptclose,
124111815Sphk	.d_read =	physread,
125111815Sphk	.d_write =	physwrite,
126111815Sphk	.d_ioctl =	ptioctl,
127111815Sphk	.d_strategy =	ptstrategy,
128111815Sphk	.d_name =	"pt",
12939213Sgibbs};
13039213Sgibbs
13150073Sken#ifndef SCSI_PT_DEFAULT_TIMEOUT
13250073Sken#define SCSI_PT_DEFAULT_TIMEOUT		60
13350073Sken#endif
13450073Sken
13539213Sgibbsstatic int
136130585Sphkptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
13739213Sgibbs{
13839213Sgibbs	struct cam_periph *periph;
13939213Sgibbs	struct pt_softc *softc;
140168752Sscottl	int error = 0;
14139213Sgibbs
142101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
143168752Sscottl	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
14439213Sgibbs		return (ENXIO);
14539213Sgibbs
14639213Sgibbs	softc = (struct pt_softc *)periph->softc;
14739213Sgibbs
148168752Sscottl	cam_periph_lock(periph);
14940603Sken	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
150236138Sken		cam_periph_release_locked(periph);
151168752Sscottl		cam_periph_unlock(periph);
15240603Sken		return(ENXIO);
15340603Sken	}
15440603Sken
155168752Sscottl	if ((softc->flags & PT_FLAG_OPEN) == 0)
156168752Sscottl		softc->flags |= PT_FLAG_OPEN;
157168752Sscottl	else {
158168752Sscottl		error = EBUSY;
159168752Sscottl		cam_periph_release(periph);
16041297Sken	}
16139213Sgibbs
162168752Sscottl	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
163168752Sscottl	    ("ptopen: dev=%s\n", devtoname(dev)));
16441297Sken
16539213Sgibbs	cam_periph_unlock(periph);
16639213Sgibbs	return (error);
16739213Sgibbs}
16839213Sgibbs
16939213Sgibbsstatic int
170130585Sphkptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
17139213Sgibbs{
17239213Sgibbs	struct	cam_periph *periph;
17339213Sgibbs	struct	pt_softc *softc;
17439213Sgibbs
175101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
17639213Sgibbs	softc = (struct pt_softc *)periph->softc;
17739213Sgibbs
178168752Sscottl	cam_periph_lock(periph);
17939213Sgibbs
18039213Sgibbs	softc->flags &= ~PT_FLAG_OPEN;
181236138Sken	cam_periph_release_locked(periph);
18239213Sgibbs	cam_periph_unlock(periph);
18339213Sgibbs	return (0);
18439213Sgibbs}
18539213Sgibbs
18639213Sgibbs/*
18739213Sgibbs * Actually translate the requested transfer into one the physical driver
18839213Sgibbs * can understand.  The transfer is described by a buf and will include
18939213Sgibbs * only one physical transfer.
19039213Sgibbs */
19139213Sgibbsstatic void
19259249Sphkptstrategy(struct bio *bp)
19339213Sgibbs{
19439213Sgibbs	struct cam_periph *periph;
19539213Sgibbs	struct pt_softc *softc;
19639213Sgibbs
197101940Snjl	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
19876362Sphk	bp->bio_resid = bp->bio_bcount;
19939213Sgibbs	if (periph == NULL) {
20076362Sphk		biofinish(bp, NULL, ENXIO);
20176362Sphk		return;
20239213Sgibbs	}
203168752Sscottl	cam_periph_lock(periph);
20439213Sgibbs	softc = (struct pt_softc *)periph->softc;
20539213Sgibbs
20639213Sgibbs	/*
20739213Sgibbs	 * If the device has been made invalid, error out
20839213Sgibbs	 */
20939213Sgibbs	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
210168752Sscottl		cam_periph_unlock(periph);
21176362Sphk		biofinish(bp, NULL, ENXIO);
21276362Sphk		return;
21339213Sgibbs	}
21439213Sgibbs
21539213Sgibbs	/*
21639213Sgibbs	 * Place it in the queue of disk activities for this disk
21739213Sgibbs	 */
21859249Sphk	bioq_insert_tail(&softc->bio_queue, bp);
21939213Sgibbs
22039213Sgibbs	/*
22139213Sgibbs	 * Schedule ourselves for performing the work.
22239213Sgibbs	 */
223198382Smav	xpt_schedule(periph, CAM_PRIORITY_NORMAL);
224168752Sscottl	cam_periph_unlock(periph);
22539213Sgibbs
22639213Sgibbs	return;
22739213Sgibbs}
22839213Sgibbs
22939213Sgibbsstatic void
23039213Sgibbsptinit(void)
23139213Sgibbs{
23239213Sgibbs	cam_status status;
23339213Sgibbs
23439213Sgibbs	/*
23539213Sgibbs	 * Install a global async callback.  This callback will
23639213Sgibbs	 * receive async callbacks like "new device found".
23739213Sgibbs	 */
238169605Sscottl	status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
23939213Sgibbs
24039213Sgibbs	if (status != CAM_REQ_CMP) {
24139213Sgibbs		printf("pt: Failed to attach master async callback "
24239213Sgibbs		       "due to status 0x%x!\n", status);
24339213Sgibbs	}
24439213Sgibbs}
24539213Sgibbs
24639213Sgibbsstatic cam_status
24739213Sgibbsptctor(struct cam_periph *periph, void *arg)
24839213Sgibbs{
24939213Sgibbs	struct pt_softc *softc;
25039213Sgibbs	struct ccb_getdev *cgd;
251220644Smav	struct ccb_pathinq cpi;
252294978Skib	struct make_dev_args args;
253294978Skib	int error;
25439213Sgibbs
25539213Sgibbs	cgd = (struct ccb_getdev *)arg;
25639213Sgibbs	if (cgd == NULL) {
25739213Sgibbs		printf("ptregister: no getdev CCB, can't register device\n");
25839213Sgibbs		return(CAM_REQ_CMP_ERR);
25939213Sgibbs	}
26039213Sgibbs
26139213Sgibbs	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
26239213Sgibbs
26339213Sgibbs	if (softc == NULL) {
26439213Sgibbs		printf("daregister: Unable to probe new device. "
26539213Sgibbs		       "Unable to allocate softc\n");
26639213Sgibbs		return(CAM_REQ_CMP_ERR);
26739213Sgibbs	}
26839213Sgibbs
26939213Sgibbs	bzero(softc, sizeof(*softc));
27039213Sgibbs	LIST_INIT(&softc->pending_ccbs);
27139213Sgibbs	softc->state = PT_STATE_NORMAL;
27259249Sphk	bioq_init(&softc->bio_queue);
27339213Sgibbs
27450073Sken	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
27550073Sken
27639213Sgibbs	periph->softc = softc;
277220644Smav
278220644Smav	bzero(&cpi, sizeof(cpi));
279220644Smav	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
280220644Smav	cpi.ccb_h.func_code = XPT_PATH_INQ;
281220644Smav	xpt_action((union ccb *)&cpi);
282220644Smav
283169605Sscottl	cam_periph_unlock(periph);
284294978Skib
285294978Skib	make_dev_args_init(&args);
286294978Skib	args.mda_devsw = &pt_cdevsw;
287294978Skib	args.mda_unit = periph->unit_number;
288294978Skib	args.mda_uid = UID_ROOT;
289294978Skib	args.mda_gid = GID_OPERATOR;
290294978Skib	args.mda_mode = 0600;
291294978Skib	args.mda_si_drv1 = periph;
292294978Skib	error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
293294978Skib	    periph->unit_number);
294294978Skib	if (error != 0) {
295294978Skib		cam_periph_lock(periph);
296294978Skib		return (CAM_REQ_CMP_ERR);
297294978Skib	}
298294978Skib
299112006Sphk	softc->device_stats = devstat_new_entry("pt",
30039213Sgibbs			  periph->unit_number, 0,
30139213Sgibbs			  DEVSTAT_NO_BLOCKSIZE,
302220644Smav			  SID_TYPE(&cgd->inq_data) |
303220644Smav			  XPORT_DEVSTAT_TYPE(cpi.transport),
30443819Sken			  DEVSTAT_PRIORITY_OTHER);
30539213Sgibbs
306168872Sscottl	cam_periph_lock(periph);
307101940Snjl
30839213Sgibbs	/*
30939213Sgibbs	 * Add async callbacks for bus reset and
31039213Sgibbs	 * bus device reset calls.  I don't bother
31139213Sgibbs	 * checking if this fails as, in most cases,
31239213Sgibbs	 * the system will function just fine without
31339213Sgibbs	 * them and the only alternative would be to
31439213Sgibbs	 * not attach the device on failure.
31539213Sgibbs	 */
316169605Sscottl	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
317169605Sscottl			   ptasync, periph, periph->path);
31839213Sgibbs
31939213Sgibbs	/* Tell the user we've attached to the device */
32039213Sgibbs	xpt_announce_periph(periph, NULL);
32139213Sgibbs
32239213Sgibbs	return(CAM_REQ_CMP);
32339213Sgibbs}
32439213Sgibbs
32539213Sgibbsstatic void
32640603Skenptoninvalidate(struct cam_periph *periph)
32740603Sken{
32840603Sken	struct pt_softc *softc;
32940603Sken
33040603Sken	softc = (struct pt_softc *)periph->softc;
33140603Sken
33240603Sken	/*
33340603Sken	 * De-register any async callbacks.
33440603Sken	 */
335169605Sscottl	xpt_register_async(0, ptasync, periph, periph->path);
33640603Sken
33740603Sken	softc->flags |= PT_FLAG_DEVICE_INVALID;
33840603Sken
33940603Sken	/*
34040603Sken	 * Return all queued I/O with ENXIO.
34140603Sken	 * XXX Handle any transactions queued to the card
34240603Sken	 *     with XPT_ABORT_CCB.
34340603Sken	 */
344112946Sphk	bioq_flush(&softc->bio_queue, NULL, ENXIO);
34540603Sken}
34640603Sken
34740603Skenstatic void
34839213Sgibbsptdtor(struct cam_periph *periph)
34939213Sgibbs{
35040603Sken	struct pt_softc *softc;
35140603Sken
35240603Sken	softc = (struct pt_softc *)periph->softc;
35340603Sken
354112006Sphk	devstat_remove_entry(softc->device_stats);
355187028Strasz	cam_periph_unlock(periph);
35653257Sken	destroy_dev(softc->dev);
357187028Strasz	cam_periph_lock(periph);
35840603Sken	free(softc, M_DEVBUF);
35939213Sgibbs}
36039213Sgibbs
36139213Sgibbsstatic void
36239213Sgibbsptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
36339213Sgibbs{
36439213Sgibbs	struct cam_periph *periph;
36539213Sgibbs
36639213Sgibbs	periph = (struct cam_periph *)callback_arg;
36739213Sgibbs	switch (code) {
36839213Sgibbs	case AC_FOUND_DEVICE:
36939213Sgibbs	{
37039213Sgibbs		struct ccb_getdev *cgd;
37139213Sgibbs		cam_status status;
37239213Sgibbs
37339213Sgibbs		cgd = (struct ccb_getdev *)arg;
37479177Smjacob		if (cgd == NULL)
37579177Smjacob			break;
37639213Sgibbs
377195534Sscottl		if (cgd->protocol != PROTO_SCSI)
378195534Sscottl			break;
379288338Smav		if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
380288338Smav			break;
38156148Smjacob		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
38239213Sgibbs			break;
38339213Sgibbs
38439213Sgibbs		/*
38539213Sgibbs		 * Allocate a peripheral instance for
38639213Sgibbs		 * this device and start the probe
38739213Sgibbs		 * process.
38839213Sgibbs		 */
38940603Sken		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
39040603Sken					  ptstart, "pt", CAM_PERIPH_BIO,
391260387Sscottl					  path, ptasync,
39240603Sken					  AC_FOUND_DEVICE, cgd);
39339213Sgibbs
39439213Sgibbs		if (status != CAM_REQ_CMP
39539213Sgibbs		 && status != CAM_REQ_INPROG)
39639213Sgibbs			printf("ptasync: Unable to attach to new device "
39739213Sgibbs				"due to status 0x%x\n", status);
39839213Sgibbs		break;
39939213Sgibbs	}
40039213Sgibbs	case AC_SENT_BDR:
40139213Sgibbs	case AC_BUS_RESET:
40239213Sgibbs	{
40339213Sgibbs		struct pt_softc *softc;
40439213Sgibbs		struct ccb_hdr *ccbh;
40539213Sgibbs
40639213Sgibbs		softc = (struct pt_softc *)periph->softc;
40739213Sgibbs		/*
40839213Sgibbs		 * Don't fail on the expected unit attention
40939213Sgibbs		 * that will occur.
41039213Sgibbs		 */
41139213Sgibbs		softc->flags |= PT_FLAG_RETRY_UA;
41271999Sphk		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
41339213Sgibbs			ccbh->ccb_state |= PT_CCB_RETRY_UA;
41439213Sgibbs	}
415115562Sphk	/* FALLTHROUGH */
41639213Sgibbs	default:
41747413Sgibbs		cam_periph_async(periph, code, path, arg);
41839213Sgibbs		break;
41939213Sgibbs	}
42039213Sgibbs}
42139213Sgibbs
42239213Sgibbsstatic void
42339213Sgibbsptstart(struct cam_periph *periph, union ccb *start_ccb)
42439213Sgibbs{
42539213Sgibbs	struct pt_softc *softc;
42659249Sphk	struct bio *bp;
42739213Sgibbs
42839213Sgibbs	softc = (struct pt_softc *)periph->softc;
42939213Sgibbs
430236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
431236602Smav
43239213Sgibbs	/*
43339213Sgibbs	 * See if there is a buf with work for us to do..
43439213Sgibbs	 */
43559249Sphk	bp = bioq_first(&softc->bio_queue);
436260387Sscottl	if (bp == NULL) {
43739213Sgibbs		xpt_release_ccb(start_ccb);
43839213Sgibbs	} else {
43959249Sphk		bioq_remove(&softc->bio_queue, bp);
44039213Sgibbs
441112260Sphk		devstat_start_transaction_bio(softc->device_stats, bp);
44239213Sgibbs
44339213Sgibbs		scsi_send_receive(&start_ccb->csio,
44439213Sgibbs				  /*retries*/4,
44539213Sgibbs				  ptdone,
44639213Sgibbs				  MSG_SIMPLE_Q_TAG,
44759249Sphk				  bp->bio_cmd == BIO_READ,
44839213Sgibbs				  /*byte2*/0,
44959249Sphk				  bp->bio_bcount,
45059249Sphk				  bp->bio_data,
45139213Sgibbs				  /*sense_len*/SSD_FULL_SIZE,
45250073Sken				  /*timeout*/softc->io_timeout);
45339213Sgibbs
45476192Sken		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
45539213Sgibbs
45639213Sgibbs		/*
457250460Seadler		 * Block out any asynchronous callbacks
45839213Sgibbs		 * while we touch the pending ccb list.
45939213Sgibbs		 */
46039213Sgibbs		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
46139213Sgibbs				 periph_links.le);
46239213Sgibbs
46339213Sgibbs		start_ccb->ccb_h.ccb_bp = bp;
46459249Sphk		bp = bioq_first(&softc->bio_queue);
46539213Sgibbs
46639213Sgibbs		xpt_action(start_ccb);
46739213Sgibbs
46839213Sgibbs		if (bp != NULL) {
46939213Sgibbs			/* Have more work to do, so ensure we stay scheduled */
470198382Smav			xpt_schedule(periph, CAM_PRIORITY_NORMAL);
47139213Sgibbs		}
47239213Sgibbs	}
47339213Sgibbs}
47439213Sgibbs
47539213Sgibbsstatic void
47639213Sgibbsptdone(struct cam_periph *periph, union ccb *done_ccb)
47739213Sgibbs{
47839213Sgibbs	struct pt_softc *softc;
47939213Sgibbs	struct ccb_scsiio *csio;
48039213Sgibbs
48139213Sgibbs	softc = (struct pt_softc *)periph->softc;
482236602Smav
483236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
484236602Smav
48539213Sgibbs	csio = &done_ccb->csio;
48639213Sgibbs	switch (csio->ccb_h.ccb_state) {
48739213Sgibbs	case PT_CCB_BUFFER_IO:
48839213Sgibbs	case PT_CCB_BUFFER_IO_UA:
48939213Sgibbs	{
49059249Sphk		struct bio *bp;
49139213Sgibbs
49259249Sphk		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
49339213Sgibbs		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
49439213Sgibbs			int error;
49539213Sgibbs			int sf;
49639213Sgibbs
49739213Sgibbs			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
49839213Sgibbs				sf = SF_RETRY_UA;
49939213Sgibbs			else
50039213Sgibbs				sf = 0;
50139213Sgibbs
50274840Sken			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
50374840Sken			if (error == ERESTART) {
50439213Sgibbs				/*
50539213Sgibbs				 * A retry was scheuled, so
50639213Sgibbs				 * just return.
50739213Sgibbs				 */
50839213Sgibbs				return;
50939213Sgibbs			}
51039213Sgibbs			if (error != 0) {
51139213Sgibbs				if (error == ENXIO) {
51239213Sgibbs					/*
51339213Sgibbs					 * Catastrophic error.  Mark our device
51439213Sgibbs					 * as invalid.
51539213Sgibbs					 */
516164906Smjacob					xpt_print(periph->path,
517164906Smjacob					    "Invalidating device\n");
51839213Sgibbs					softc->flags |= PT_FLAG_DEVICE_INVALID;
51939213Sgibbs				}
52039213Sgibbs
52139213Sgibbs				/*
52239213Sgibbs				 * return all queued I/O with EIO, so that
52339213Sgibbs				 * the client can retry these I/Os in the
52439213Sgibbs				 * proper order should it attempt to recover.
52539213Sgibbs				 */
526112946Sphk				bioq_flush(&softc->bio_queue, NULL, EIO);
52759249Sphk				bp->bio_error = error;
52859249Sphk				bp->bio_resid = bp->bio_bcount;
52959249Sphk				bp->bio_flags |= BIO_ERROR;
53039213Sgibbs			} else {
53159249Sphk				bp->bio_resid = csio->resid;
53259249Sphk				bp->bio_error = 0;
53359249Sphk				if (bp->bio_resid != 0) {
53439213Sgibbs					/* Short transfer ??? */
53559249Sphk					bp->bio_flags |= BIO_ERROR;
53639213Sgibbs				}
53739213Sgibbs			}
53839213Sgibbs			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
53939213Sgibbs				cam_release_devq(done_ccb->ccb_h.path,
54039213Sgibbs						 /*relsim_flags*/0,
54139213Sgibbs						 /*reduction*/0,
54239213Sgibbs						 /*timeout*/0,
54339213Sgibbs						 /*getcount_only*/0);
54439213Sgibbs		} else {
54559249Sphk			bp->bio_resid = csio->resid;
54659249Sphk			if (bp->bio_resid != 0)
54759249Sphk				bp->bio_flags |= BIO_ERROR;
54839213Sgibbs		}
54939213Sgibbs
55039213Sgibbs		/*
551250460Seadler		 * Block out any asynchronous callbacks
55239213Sgibbs		 * while we touch the pending ccb list.
55339213Sgibbs		 */
55439213Sgibbs		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
55539213Sgibbs
556112006Sphk		biofinish(bp, softc->device_stats, 0);
55739213Sgibbs		break;
55839213Sgibbs	}
55939213Sgibbs	}
56039213Sgibbs	xpt_release_ccb(done_ccb);
56139213Sgibbs}
56239213Sgibbs
56339213Sgibbsstatic int
56439213Sgibbspterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
56539213Sgibbs{
56639213Sgibbs	struct pt_softc	  *softc;
56739213Sgibbs	struct cam_periph *periph;
56839213Sgibbs
56939213Sgibbs	periph = xpt_path_periph(ccb->ccb_h.path);
57039213Sgibbs	softc = (struct pt_softc *)periph->softc;
57139213Sgibbs
57239213Sgibbs	return(cam_periph_error(ccb, cam_flags, sense_flags,
57339213Sgibbs				&softc->saved_ccb));
57439213Sgibbs}
57539213Sgibbs
57650073Skenstatic int
577130585Sphkptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
57850073Sken{
57950073Sken	struct cam_periph *periph;
58050073Sken	struct pt_softc *softc;
581168752Sscottl	int error = 0;
58250073Sken
583101940Snjl	periph = (struct cam_periph *)dev->si_drv1;
58450073Sken	softc = (struct pt_softc *)periph->softc;
58550073Sken
586168752Sscottl	cam_periph_lock(periph);
58750073Sken
58850073Sken	switch(cmd) {
58950073Sken	case PTIOCGETTIMEOUT:
59050073Sken		if (softc->io_timeout >= 1000)
59150073Sken			*(int *)addr = softc->io_timeout / 1000;
59250073Sken		else
59350073Sken			*(int *)addr = 0;
59450073Sken		break;
59550073Sken	case PTIOCSETTIMEOUT:
59650073Sken		if (*(int *)addr < 1) {
59750073Sken			error = EINVAL;
59850073Sken			break;
59950073Sken		}
60050073Sken
60150073Sken		softc->io_timeout = *(int *)addr * 1000;
60250073Sken
60350073Sken		break;
60450073Sken	default:
60550073Sken		error = cam_periph_ioctl(periph, cmd, addr, pterror);
60650073Sken		break;
60750073Sken	}
60850073Sken
60950073Sken	cam_periph_unlock(periph);
61050073Sken
61150073Sken	return(error);
61250073Sken}
61350073Sken
61439213Sgibbsvoid
61539213Sgibbsscsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
61639213Sgibbs		  void (*cbfcnp)(struct cam_periph *, union ccb *),
61739213Sgibbs		  u_int tag_action, int readop, u_int byte2,
61839213Sgibbs		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
61939213Sgibbs		  u_int32_t timeout)
62039213Sgibbs{
62139213Sgibbs	struct scsi_send_receive *scsi_cmd;
62239213Sgibbs
62339213Sgibbs	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
62439213Sgibbs	scsi_cmd->opcode = readop ? RECEIVE : SEND;
62539213Sgibbs	scsi_cmd->byte2 = byte2;
62639213Sgibbs	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
62739213Sgibbs	scsi_cmd->control = 0;
62839213Sgibbs
62939213Sgibbs	cam_fill_csio(csio,
63039213Sgibbs		      retries,
63139213Sgibbs		      cbfcnp,
63239213Sgibbs		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
63339213Sgibbs		      tag_action,
63439213Sgibbs		      data_ptr,
63539213Sgibbs		      xfer_len,
63639213Sgibbs		      sense_len,
63739213Sgibbs		      sizeof(*scsi_cmd),
63839213Sgibbs		      timeout);
63939213Sgibbs}
640