scsi_pt.c revision 41297
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 *
2841297Sken *      $Id: scsi_pt.c,v 1.3 1998/10/22 22:16:56 ken Exp $
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>
3639213Sgibbs#include <sys/buf.h>
3739213Sgibbs#include <sys/devicestat.h>
3839213Sgibbs#include <sys/malloc.h>
3939213Sgibbs#include <sys/conf.h>
4039213Sgibbs
4139213Sgibbs#include <cam/cam.h>
4239213Sgibbs#include <cam/cam_ccb.h>
4339213Sgibbs#include <cam/cam_extend.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
5239213Sgibbstypedef enum {
5339213Sgibbs	PT_STATE_PROBE,
5439213Sgibbs	PT_STATE_NORMAL
5539213Sgibbs} pt_state;
5639213Sgibbs
5739213Sgibbstypedef enum {
5839213Sgibbs	PT_FLAG_NONE		= 0x00,
5939213Sgibbs	PT_FLAG_OPEN		= 0x01,
6039213Sgibbs	PT_FLAG_DEVICE_INVALID	= 0x02,
6139213Sgibbs	PT_FLAG_RETRY_UA	= 0x04
6239213Sgibbs} pt_flags;
6339213Sgibbs
6439213Sgibbstypedef enum {
6539213Sgibbs	PT_CCB_BUFFER_IO	= 0x01,
6639213Sgibbs	PT_CCB_WAITING		= 0x02,
6739213Sgibbs	PT_CCB_RETRY_UA		= 0x04,
6839213Sgibbs	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
6939213Sgibbs} pt_ccb_state;
7039213Sgibbs
7139213Sgibbs/* Offsets into our private area for storing information */
7239213Sgibbs#define ccb_state	ppriv_field0
7339213Sgibbs#define ccb_bp		ppriv_ptr1
7439213Sgibbs
7539213Sgibbsstruct pt_softc {
7639213Sgibbs	struct	 buf_queue_head buf_queue;
7739213Sgibbs	struct	 devstat device_stats;
7839213Sgibbs	LIST_HEAD(, ccb_hdr) pending_ccbs;
7939213Sgibbs	pt_state state;
8039213Sgibbs	pt_flags flags;
8139213Sgibbs	union	 ccb saved_ccb;
8239213Sgibbs};
8339213Sgibbs
8439213Sgibbsstatic	d_open_t	ptopen;
8539213Sgibbsstatic	d_read_t	ptread;
8639213Sgibbsstatic	d_write_t	ptwrite;
8739213Sgibbsstatic	d_close_t	ptclose;
8839213Sgibbsstatic	d_strategy_t	ptstrategy;
8939213Sgibbsstatic	periph_init_t	ptinit;
9039213Sgibbsstatic	void		ptasync(void *callback_arg, u_int32_t code,
9139213Sgibbs				struct cam_path *path, void *arg);
9239213Sgibbsstatic	periph_ctor_t	ptctor;
9340603Skenstatic	periph_oninv_t	ptoninvalidate;
9439213Sgibbsstatic	periph_dtor_t	ptdtor;
9539213Sgibbsstatic	periph_start_t	ptstart;
9639213Sgibbsstatic	void		ptdone(struct cam_periph *periph,
9739213Sgibbs			       union ccb *done_ccb);
9839213Sgibbsstatic  int		pterror(union ccb *ccb, u_int32_t cam_flags,
9939213Sgibbs				u_int32_t sense_flags);
10039213Sgibbs
10139213Sgibbsvoid	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
10239213Sgibbs			  void (*cbfcnp)(struct cam_periph *, union ccb *),
10339213Sgibbs			  u_int tag_action, int readop, u_int byte2,
10439213Sgibbs			  u_int32_t xfer_len, u_int8_t *data_ptr,
10539213Sgibbs			  u_int8_t sense_len, u_int32_t timeout);
10639213Sgibbs
10739213Sgibbsstatic struct periph_driver ptdriver =
10839213Sgibbs{
10939213Sgibbs	ptinit, "pt",
11039213Sgibbs	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11139213Sgibbs};
11239213Sgibbs
11339213SgibbsDATA_SET(periphdriver_set, ptdriver);
11439213Sgibbs
11539213Sgibbs#define PT_CDEV_MAJOR 61
11639213Sgibbs
11739213Sgibbsstatic struct cdevsw pt_cdevsw =
11839213Sgibbs{
11939213Sgibbs	/*d_open*/	ptopen,
12039213Sgibbs	/*d_close*/	ptclose,
12139213Sgibbs	/*d_read*/	ptread,
12239213Sgibbs	/*d_write*/	ptwrite,
12339213Sgibbs	/*d_ioctl*/	noioctl,
12439213Sgibbs	/*d_stop*/	nostop,
12539213Sgibbs	/*d_reset*/	noreset,
12639213Sgibbs	/*d_devtotty*/	nodevtotty,
12739213Sgibbs	/*d_poll*/	seltrue,
12839213Sgibbs	/*d_mmap*/	nommap,
12939213Sgibbs	/*d_strategy*/	ptstrategy,
13039213Sgibbs	/*d_name*/	"pt",
13139213Sgibbs	/*d_spare*/	NULL,
13239213Sgibbs	/*d_maj*/	-1,
13339213Sgibbs	/*d_dump*/	nodump,
13439213Sgibbs	/*d_psize*/	nopsize,
13539213Sgibbs	/*d_flags*/	0,
13639213Sgibbs	/*d_maxio*/	0,
13739213Sgibbs	/*b_maj*/	-1
13839213Sgibbs};
13939213Sgibbs
14039213Sgibbsstatic struct extend_array *ptperiphs;
14139213Sgibbs
14239213Sgibbsstatic int
14339213Sgibbsptopen(dev_t dev, int flags, int fmt, struct proc *p)
14439213Sgibbs{
14539213Sgibbs	struct cam_periph *periph;
14639213Sgibbs	struct pt_softc *softc;
14739213Sgibbs	int unit;
14839213Sgibbs	int error;
14940603Sken	int s;
15039213Sgibbs
15139213Sgibbs	unit = minor(dev);
15239213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
15339213Sgibbs	if (periph == NULL)
15439213Sgibbs		return (ENXIO);
15539213Sgibbs
15639213Sgibbs	softc = (struct pt_softc *)periph->softc;
15739213Sgibbs
15840603Sken	s = splsoftcam();
15940603Sken	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
16040603Sken		splx(s);
16140603Sken		return(ENXIO);
16240603Sken	}
16340603Sken
16439213Sgibbs	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
16539213Sgibbs	    ("ptopen: dev=0x%x (unit %d)\n", dev, unit));
16639213Sgibbs
16741297Sken	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
16841297Sken		splx(s);
16939213Sgibbs		return (error); /* error code from tsleep */
17041297Sken	}
17139213Sgibbs
17241297Sken	splx(s);
17341297Sken
17439213Sgibbs	if ((softc->flags & PT_FLAG_OPEN) == 0) {
17539213Sgibbs		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
17639213Sgibbs			error = ENXIO;
17739213Sgibbs		else
17839213Sgibbs			softc->flags |= PT_FLAG_OPEN;
17939213Sgibbs	} else
18039213Sgibbs		error = EBUSY;
18139213Sgibbs
18239213Sgibbs	cam_periph_unlock(periph);
18339213Sgibbs	return (error);
18439213Sgibbs}
18539213Sgibbs
18639213Sgibbsstatic int
18739213Sgibbsptclose(dev_t dev, int flag, int fmt, struct proc *p)
18839213Sgibbs{
18939213Sgibbs	struct	cam_periph *periph;
19039213Sgibbs	struct	pt_softc *softc;
19139213Sgibbs	int	unit;
19239213Sgibbs	int	error;
19339213Sgibbs
19439213Sgibbs	unit = minor(dev);
19539213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
19639213Sgibbs	if (periph == NULL)
19739213Sgibbs		return (ENXIO);
19839213Sgibbs
19939213Sgibbs	softc = (struct pt_softc *)periph->softc;
20039213Sgibbs
20139213Sgibbs	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
20239213Sgibbs		return (error); /* error code from tsleep */
20339213Sgibbs
20439213Sgibbs	softc->flags &= ~PT_FLAG_OPEN;
20539213Sgibbs	cam_periph_unlock(periph);
20639213Sgibbs	cam_periph_release(periph);
20739213Sgibbs	return (0);
20839213Sgibbs}
20939213Sgibbs
21039213Sgibbsstatic int
21139213Sgibbsptread(dev_t dev, struct uio *uio, int ioflag)
21239213Sgibbs{
21339213Sgibbs	return(physio(ptstrategy, NULL, dev, 1, minphys, uio));
21439213Sgibbs}
21539213Sgibbs
21639213Sgibbsstatic int
21739213Sgibbsptwrite(dev_t dev, struct uio *uio, int ioflag)
21839213Sgibbs{
21939213Sgibbs	return(physio(ptstrategy, NULL, dev, 0, minphys, uio));
22039213Sgibbs}
22139213Sgibbs
22239213Sgibbs/*
22339213Sgibbs * Actually translate the requested transfer into one the physical driver
22439213Sgibbs * can understand.  The transfer is described by a buf and will include
22539213Sgibbs * only one physical transfer.
22639213Sgibbs */
22739213Sgibbsstatic void
22839213Sgibbsptstrategy(struct buf *bp)
22939213Sgibbs{
23039213Sgibbs	struct cam_periph *periph;
23139213Sgibbs	struct pt_softc *softc;
23239213Sgibbs	u_int  unit;
23339213Sgibbs	int    s;
23439213Sgibbs
23539213Sgibbs	unit = minor(bp->b_dev);
23639213Sgibbs	periph = cam_extend_get(ptperiphs, unit);
23739213Sgibbs	if (periph == NULL) {
23839213Sgibbs		bp->b_error = ENXIO;
23939213Sgibbs		goto bad;
24039213Sgibbs	}
24139213Sgibbs	softc = (struct pt_softc *)periph->softc;
24239213Sgibbs
24339213Sgibbs	/*
24439213Sgibbs	 * Mask interrupts so that the pack cannot be invalidated until
24539213Sgibbs	 * after we are in the queue.  Otherwise, we might not properly
24639213Sgibbs	 * clean up one of the buffers.
24739213Sgibbs	 */
24839213Sgibbs	s = splbio();
24939213Sgibbs
25039213Sgibbs	/*
25139213Sgibbs	 * If the device has been made invalid, error out
25239213Sgibbs	 */
25339213Sgibbs	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
25439213Sgibbs		splx(s);
25539213Sgibbs		bp->b_error = ENXIO;
25639213Sgibbs		goto bad;
25739213Sgibbs	}
25839213Sgibbs
25939213Sgibbs	/*
26039213Sgibbs	 * Place it in the queue of disk activities for this disk
26139213Sgibbs	 */
26239213Sgibbs	bufq_insert_tail(&softc->buf_queue, bp);
26339213Sgibbs
26439213Sgibbs	splx(s);
26539213Sgibbs
26639213Sgibbs	/*
26739213Sgibbs	 * Schedule ourselves for performing the work.
26839213Sgibbs	 */
26939213Sgibbs	xpt_schedule(periph, /* XXX priority */1);
27039213Sgibbs
27139213Sgibbs	return;
27239213Sgibbsbad:
27339213Sgibbs	bp->b_flags |= B_ERROR;
27439213Sgibbs
27539213Sgibbs	/*
27639213Sgibbs	 * Correctly set the buf to indicate a completed xfer
27739213Sgibbs	 */
27839213Sgibbs	bp->b_resid = bp->b_bcount;
27939213Sgibbs	biodone(bp);
28039213Sgibbs}
28139213Sgibbs
28239213Sgibbsstatic void
28339213Sgibbsptinit(void)
28439213Sgibbs{
28539213Sgibbs	cam_status status;
28639213Sgibbs	struct cam_path *path;
28739213Sgibbs
28839213Sgibbs	/*
28939213Sgibbs	 * Create our extend array for storing the devices we attach to.
29039213Sgibbs	 */
29139213Sgibbs	ptperiphs = cam_extend_new();
29239213Sgibbs	if (ptperiphs == NULL) {
29339213Sgibbs		printf("pt: Failed to alloc extend array!\n");
29439213Sgibbs		return;
29539213Sgibbs	}
29639213Sgibbs
29739213Sgibbs	/*
29839213Sgibbs	 * Install a global async callback.  This callback will
29939213Sgibbs	 * receive async callbacks like "new device found".
30039213Sgibbs	 */
30139213Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
30239213Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
30339213Sgibbs
30439213Sgibbs	if (status == CAM_REQ_CMP) {
30539213Sgibbs		struct ccb_setasync csa;
30639213Sgibbs
30739213Sgibbs                xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
30839213Sgibbs                csa.ccb_h.func_code = XPT_SASYNC_CB;
30939213Sgibbs                csa.event_enable = AC_FOUND_DEVICE;
31039213Sgibbs                csa.callback = ptasync;
31139213Sgibbs                csa.callback_arg = NULL;
31239213Sgibbs                xpt_action((union ccb *)&csa);
31339213Sgibbs		status = csa.ccb_h.status;
31439213Sgibbs                xpt_free_path(path);
31539213Sgibbs        }
31639213Sgibbs
31739213Sgibbs	if (status != CAM_REQ_CMP) {
31839213Sgibbs		printf("pt: Failed to attach master async callback "
31939213Sgibbs		       "due to status 0x%x!\n", status);
32039213Sgibbs	} else {
32139213Sgibbs		/* If we were successfull, register our devsw */
32239213Sgibbs		dev_t dev;
32339213Sgibbs
32439213Sgibbs		dev = makedev(PT_CDEV_MAJOR, 0);
32539213Sgibbs		cdevsw_add(&dev,&pt_cdevsw, NULL);
32639213Sgibbs	}
32739213Sgibbs}
32839213Sgibbs
32939213Sgibbsstatic cam_status
33039213Sgibbsptctor(struct cam_periph *periph, void *arg)
33139213Sgibbs{
33239213Sgibbs	struct pt_softc *softc;
33339213Sgibbs	struct ccb_setasync csa;
33439213Sgibbs	struct ccb_getdev *cgd;
33539213Sgibbs
33639213Sgibbs	cgd = (struct ccb_getdev *)arg;
33739213Sgibbs	if (periph == NULL) {
33839213Sgibbs		printf("ptregister: periph was NULL!!\n");
33939213Sgibbs		return(CAM_REQ_CMP_ERR);
34039213Sgibbs	}
34139213Sgibbs
34239213Sgibbs	if (cgd == NULL) {
34339213Sgibbs		printf("ptregister: no getdev CCB, can't register device\n");
34439213Sgibbs		return(CAM_REQ_CMP_ERR);
34539213Sgibbs	}
34639213Sgibbs
34739213Sgibbs	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
34839213Sgibbs
34939213Sgibbs	if (softc == NULL) {
35039213Sgibbs		printf("daregister: Unable to probe new device. "
35139213Sgibbs		       "Unable to allocate softc\n");
35239213Sgibbs		return(CAM_REQ_CMP_ERR);
35339213Sgibbs	}
35439213Sgibbs
35539213Sgibbs	bzero(softc, sizeof(*softc));
35639213Sgibbs	LIST_INIT(&softc->pending_ccbs);
35739213Sgibbs	softc->state = PT_STATE_NORMAL;
35839213Sgibbs	bufq_init(&softc->buf_queue);
35939213Sgibbs
36039213Sgibbs	periph->softc = softc;
36139213Sgibbs
36239213Sgibbs	cam_extend_set(ptperiphs, periph->unit_number, periph);
36339213Sgibbs
36439213Sgibbs	/*
36539213Sgibbs	 * The DA driver supports a blocksize, but
36639213Sgibbs	 * we don't know the blocksize until we do
36739213Sgibbs	 * a read capacity.  So, set a flag to
36839213Sgibbs	 * indicate that the blocksize is
36939213Sgibbs	 * unavailable right now.  We'll clear the
37039213Sgibbs	 * flag as soon as we've done a read capacity.
37139213Sgibbs	 */
37239213Sgibbs	devstat_add_entry(&softc->device_stats, "pt",
37339213Sgibbs			  periph->unit_number, 0,
37439213Sgibbs			  DEVSTAT_NO_BLOCKSIZE,
37539213Sgibbs			  cgd->pd_type | DEVSTAT_TYPE_IF_SCSI);
37639213Sgibbs
37739213Sgibbs	/*
37839213Sgibbs	 * Add async callbacks for bus reset and
37939213Sgibbs	 * bus device reset calls.  I don't bother
38039213Sgibbs	 * checking if this fails as, in most cases,
38139213Sgibbs	 * the system will function just fine without
38239213Sgibbs	 * them and the only alternative would be to
38339213Sgibbs	 * not attach the device on failure.
38439213Sgibbs	 */
38539213Sgibbs	xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
38639213Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
38739213Sgibbs	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
38839213Sgibbs	csa.callback = ptasync;
38939213Sgibbs	csa.callback_arg = periph;
39039213Sgibbs	xpt_action((union ccb *)&csa);
39139213Sgibbs
39239213Sgibbs	/* Tell the user we've attached to the device */
39339213Sgibbs	xpt_announce_periph(periph, NULL);
39439213Sgibbs
39539213Sgibbs	return(CAM_REQ_CMP);
39639213Sgibbs}
39739213Sgibbs
39839213Sgibbsstatic void
39940603Skenptoninvalidate(struct cam_periph *periph)
40040603Sken{
40140603Sken	int s;
40240603Sken	struct pt_softc *softc;
40340603Sken	struct buf *q_bp;
40440603Sken	struct ccb_setasync csa;
40540603Sken
40640603Sken	softc = (struct pt_softc *)periph->softc;
40740603Sken
40840603Sken	/*
40940603Sken	 * De-register any async callbacks.
41040603Sken	 */
41140603Sken	xpt_setup_ccb(&csa.ccb_h, periph->path,
41240603Sken		      /* priority */ 5);
41340603Sken	csa.ccb_h.func_code = XPT_SASYNC_CB;
41440603Sken	csa.event_enable = 0;
41540603Sken	csa.callback = ptasync;
41640603Sken	csa.callback_arg = periph;
41740603Sken	xpt_action((union ccb *)&csa);
41840603Sken
41940603Sken	softc->flags |= PT_FLAG_DEVICE_INVALID;
42040603Sken
42140603Sken	/*
42240603Sken	 * Although the oninvalidate() routines are always called at
42340603Sken	 * splsoftcam, we need to be at splbio() here to keep the buffer
42440603Sken	 * queue from being modified while we traverse it.
42540603Sken	 */
42640603Sken	s = splbio();
42740603Sken
42840603Sken	/*
42940603Sken	 * Return all queued I/O with ENXIO.
43040603Sken	 * XXX Handle any transactions queued to the card
43140603Sken	 *     with XPT_ABORT_CCB.
43240603Sken	 */
43340603Sken	while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
43440603Sken		bufq_remove(&softc->buf_queue, q_bp);
43540603Sken		q_bp->b_resid = q_bp->b_bcount;
43640603Sken		q_bp->b_error = ENXIO;
43740603Sken		q_bp->b_flags |= B_ERROR;
43840603Sken		biodone(q_bp);
43940603Sken	}
44040603Sken
44140603Sken	splx(s);
44240603Sken
44340603Sken	xpt_print_path(periph->path);
44440603Sken	printf("lost device\n");
44540603Sken}
44640603Sken
44740603Skenstatic void
44839213Sgibbsptdtor(struct cam_periph *periph)
44939213Sgibbs{
45040603Sken	struct pt_softc *softc;
45140603Sken
45240603Sken	softc = (struct pt_softc *)periph->softc;
45340603Sken
45440603Sken	devstat_remove_entry(&softc->device_stats);
45540603Sken
45639213Sgibbs	cam_extend_release(ptperiphs, periph->unit_number);
45739213Sgibbs	xpt_print_path(periph->path);
45839213Sgibbs	printf("removing device entry\n");
45940603Sken	free(softc, M_DEVBUF);
46039213Sgibbs}
46139213Sgibbs
46239213Sgibbsstatic void
46339213Sgibbsptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
46439213Sgibbs{
46539213Sgibbs	struct cam_periph *periph;
46639213Sgibbs
46739213Sgibbs	periph = (struct cam_periph *)callback_arg;
46839213Sgibbs	switch (code) {
46939213Sgibbs	case AC_FOUND_DEVICE:
47039213Sgibbs	{
47139213Sgibbs		struct ccb_getdev *cgd;
47239213Sgibbs		cam_status status;
47339213Sgibbs
47439213Sgibbs		cgd = (struct ccb_getdev *)arg;
47539213Sgibbs
47639213Sgibbs		if (cgd->pd_type != T_PROCESSOR)
47739213Sgibbs			break;
47839213Sgibbs
47939213Sgibbs		/*
48039213Sgibbs		 * Allocate a peripheral instance for
48139213Sgibbs		 * this device and start the probe
48239213Sgibbs		 * process.
48339213Sgibbs		 */
48440603Sken		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
48540603Sken					  ptstart, "pt", CAM_PERIPH_BIO,
48640603Sken					  cgd->ccb_h.path, ptasync,
48740603Sken					  AC_FOUND_DEVICE, cgd);
48839213Sgibbs
48939213Sgibbs		if (status != CAM_REQ_CMP
49039213Sgibbs		 && status != CAM_REQ_INPROG)
49139213Sgibbs			printf("ptasync: Unable to attach to new device "
49239213Sgibbs				"due to status 0x%x\n", status);
49339213Sgibbs		break;
49439213Sgibbs	}
49539213Sgibbs	case AC_LOST_DEVICE:
49639213Sgibbs	{
49739213Sgibbs		cam_periph_invalidate(periph);
49839213Sgibbs		break;
49939213Sgibbs	}
50039213Sgibbs	case AC_SENT_BDR:
50139213Sgibbs	case AC_BUS_RESET:
50239213Sgibbs	{
50339213Sgibbs		struct pt_softc *softc;
50439213Sgibbs		struct ccb_hdr *ccbh;
50539213Sgibbs		int s;
50639213Sgibbs
50739213Sgibbs		softc = (struct pt_softc *)periph->softc;
50839213Sgibbs		s = splsoftcam();
50939213Sgibbs		/*
51039213Sgibbs		 * Don't fail on the expected unit attention
51139213Sgibbs		 * that will occur.
51239213Sgibbs		 */
51339213Sgibbs		softc->flags |= PT_FLAG_RETRY_UA;
51439213Sgibbs		for (ccbh = LIST_FIRST(&softc->pending_ccbs);
51539213Sgibbs		     ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le))
51639213Sgibbs			ccbh->ccb_state |= PT_CCB_RETRY_UA;
51739213Sgibbs		splx(s);
51839213Sgibbs		break;
51939213Sgibbs	}
52039213Sgibbs	case AC_TRANSFER_NEG:
52139213Sgibbs	case AC_SCSI_AEN:
52239213Sgibbs	case AC_UNSOL_RESEL:
52339213Sgibbs	default:
52439213Sgibbs		break;
52539213Sgibbs	}
52639213Sgibbs}
52739213Sgibbs
52839213Sgibbsstatic void
52939213Sgibbsptstart(struct cam_periph *periph, union ccb *start_ccb)
53039213Sgibbs{
53139213Sgibbs	struct pt_softc *softc;
53239213Sgibbs	struct buf *bp;
53339213Sgibbs	int s;
53439213Sgibbs
53539213Sgibbs	softc = (struct pt_softc *)periph->softc;
53639213Sgibbs
53739213Sgibbs	/*
53839213Sgibbs	 * See if there is a buf with work for us to do..
53939213Sgibbs	 */
54039213Sgibbs	s = splbio();
54139213Sgibbs	bp = bufq_first(&softc->buf_queue);
54239213Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
54339213Sgibbs		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
54439213Sgibbs				("queuing for immediate ccb\n"));
54539213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
54639213Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
54739213Sgibbs				  periph_links.sle);
54839213Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
54939213Sgibbs		splx(s);
55039213Sgibbs		wakeup(&periph->ccb_list);
55139213Sgibbs	} else if (bp == NULL) {
55239213Sgibbs		splx(s);
55339213Sgibbs		xpt_release_ccb(start_ccb);
55439213Sgibbs	} else {
55539213Sgibbs		int oldspl;
55639213Sgibbs
55739213Sgibbs		bufq_remove(&softc->buf_queue, bp);
55839213Sgibbs
55939213Sgibbs		devstat_start_transaction(&softc->device_stats);
56039213Sgibbs
56139213Sgibbs		scsi_send_receive(&start_ccb->csio,
56239213Sgibbs				  /*retries*/4,
56339213Sgibbs				  ptdone,
56439213Sgibbs				  MSG_SIMPLE_Q_TAG,
56539213Sgibbs				  bp->b_flags & B_READ,
56639213Sgibbs				  /*byte2*/0,
56739213Sgibbs				  bp->b_bcount,
56839213Sgibbs				  bp->b_data,
56939213Sgibbs				  /*sense_len*/SSD_FULL_SIZE,
57039213Sgibbs				  /*timeout*/10000);
57139213Sgibbs
57239213Sgibbs		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO;
57339213Sgibbs
57439213Sgibbs		/*
57539213Sgibbs		 * Block out any asyncronous callbacks
57639213Sgibbs		 * while we touch the pending ccb list.
57739213Sgibbs		 */
57839213Sgibbs		oldspl = splcam();
57939213Sgibbs		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
58039213Sgibbs				 periph_links.le);
58139213Sgibbs		splx(oldspl);
58239213Sgibbs
58339213Sgibbs		start_ccb->ccb_h.ccb_bp = bp;
58439213Sgibbs		bp = bufq_first(&softc->buf_queue);
58539213Sgibbs		splx(s);
58639213Sgibbs
58739213Sgibbs		xpt_action(start_ccb);
58839213Sgibbs
58939213Sgibbs		if (bp != NULL) {
59039213Sgibbs			/* Have more work to do, so ensure we stay scheduled */
59139213Sgibbs			xpt_schedule(periph, /* XXX priority */1);
59239213Sgibbs		}
59339213Sgibbs	}
59439213Sgibbs}
59539213Sgibbs
59639213Sgibbsstatic void
59739213Sgibbsptdone(struct cam_periph *periph, union ccb *done_ccb)
59839213Sgibbs{
59939213Sgibbs	struct pt_softc *softc;
60039213Sgibbs	struct ccb_scsiio *csio;
60139213Sgibbs
60239213Sgibbs	softc = (struct pt_softc *)periph->softc;
60339213Sgibbs	csio = &done_ccb->csio;
60439213Sgibbs	switch (csio->ccb_h.ccb_state) {
60539213Sgibbs	case PT_CCB_BUFFER_IO:
60639213Sgibbs	case PT_CCB_BUFFER_IO_UA:
60739213Sgibbs	{
60839213Sgibbs		struct buf *bp;
60939213Sgibbs		int    oldspl;
61039213Sgibbs
61139213Sgibbs		bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
61239213Sgibbs		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
61339213Sgibbs			int error;
61439213Sgibbs			int s;
61539213Sgibbs			int sf;
61639213Sgibbs
61739213Sgibbs			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
61839213Sgibbs				sf = SF_RETRY_UA;
61939213Sgibbs			else
62039213Sgibbs				sf = 0;
62139213Sgibbs
62239213Sgibbs			if ((error = pterror(done_ccb, 0, sf)) == ERESTART) {
62339213Sgibbs				/*
62439213Sgibbs				 * A retry was scheuled, so
62539213Sgibbs				 * just return.
62639213Sgibbs				 */
62739213Sgibbs				return;
62839213Sgibbs			}
62939213Sgibbs			if (error != 0) {
63039213Sgibbs				struct buf *q_bp;
63139213Sgibbs
63239213Sgibbs				s = splbio();
63339213Sgibbs
63439213Sgibbs				if (error == ENXIO) {
63539213Sgibbs					/*
63639213Sgibbs					 * Catastrophic error.  Mark our device
63739213Sgibbs					 * as invalid.
63839213Sgibbs					 */
63939213Sgibbs					xpt_print_path(periph->path);
64039213Sgibbs					printf("Invalidating device\n");
64139213Sgibbs					softc->flags |= PT_FLAG_DEVICE_INVALID;
64239213Sgibbs				}
64339213Sgibbs
64439213Sgibbs				/*
64539213Sgibbs				 * return all queued I/O with EIO, so that
64639213Sgibbs				 * the client can retry these I/Os in the
64739213Sgibbs				 * proper order should it attempt to recover.
64839213Sgibbs				 */
64939213Sgibbs				while ((q_bp = bufq_first(&softc->buf_queue))
65039213Sgibbs					!= NULL) {
65139213Sgibbs					bufq_remove(&softc->buf_queue, q_bp);
65239213Sgibbs					q_bp->b_resid = q_bp->b_bcount;
65339213Sgibbs					q_bp->b_error = EIO;
65439213Sgibbs					q_bp->b_flags |= B_ERROR;
65539213Sgibbs					biodone(q_bp);
65639213Sgibbs				}
65739213Sgibbs				splx(s);
65839213Sgibbs				bp->b_error = error;
65939213Sgibbs				bp->b_resid = bp->b_bcount;
66039213Sgibbs				bp->b_flags |= B_ERROR;
66139213Sgibbs			} else {
66239213Sgibbs				bp->b_resid = csio->resid;
66339213Sgibbs				bp->b_error = 0;
66439213Sgibbs				if (bp->b_resid != 0) {
66539213Sgibbs					/* Short transfer ??? */
66639213Sgibbs					bp->b_flags |= B_ERROR;
66739213Sgibbs				}
66839213Sgibbs			}
66939213Sgibbs			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
67039213Sgibbs				cam_release_devq(done_ccb->ccb_h.path,
67139213Sgibbs						 /*relsim_flags*/0,
67239213Sgibbs						 /*reduction*/0,
67339213Sgibbs						 /*timeout*/0,
67439213Sgibbs						 /*getcount_only*/0);
67539213Sgibbs		} else {
67639213Sgibbs			bp->b_resid = csio->resid;
67739213Sgibbs			if (bp->b_resid != 0)
67839213Sgibbs				bp->b_flags |= B_ERROR;
67939213Sgibbs		}
68039213Sgibbs
68139213Sgibbs		/*
68239213Sgibbs		 * Block out any asyncronous callbacks
68339213Sgibbs		 * while we touch the pending ccb list.
68439213Sgibbs		 */
68539213Sgibbs		oldspl = splcam();
68639213Sgibbs		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
68739213Sgibbs		splx(oldspl);
68839213Sgibbs
68939213Sgibbs		devstat_end_transaction(&softc->device_stats,
69039213Sgibbs					bp->b_bcount - bp->b_resid,
69139213Sgibbs					done_ccb->csio.tag_action & 0xf,
69239213Sgibbs					(bp->b_flags & B_READ) ? DEVSTAT_READ
69339213Sgibbs							       : DEVSTAT_WRITE);
69439213Sgibbs
69539213Sgibbs		biodone(bp);
69639213Sgibbs		break;
69739213Sgibbs	}
69839213Sgibbs	case PT_CCB_WAITING:
69939213Sgibbs		/* Caller will release the CCB */
70039213Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
70139213Sgibbs		return;
70239213Sgibbs	}
70339213Sgibbs	xpt_release_ccb(done_ccb);
70439213Sgibbs}
70539213Sgibbs
70639213Sgibbsstatic int
70739213Sgibbspterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
70839213Sgibbs{
70939213Sgibbs	struct pt_softc	  *softc;
71039213Sgibbs	struct cam_periph *periph;
71139213Sgibbs
71239213Sgibbs	periph = xpt_path_periph(ccb->ccb_h.path);
71339213Sgibbs	softc = (struct pt_softc *)periph->softc;
71439213Sgibbs
71539213Sgibbs	return(cam_periph_error(ccb, cam_flags, sense_flags,
71639213Sgibbs				&softc->saved_ccb));
71739213Sgibbs}
71839213Sgibbs
71939213Sgibbsvoid
72039213Sgibbsscsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
72139213Sgibbs		  void (*cbfcnp)(struct cam_periph *, union ccb *),
72239213Sgibbs		  u_int tag_action, int readop, u_int byte2,
72339213Sgibbs		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
72439213Sgibbs		  u_int32_t timeout)
72539213Sgibbs{
72639213Sgibbs	struct scsi_send_receive *scsi_cmd;
72739213Sgibbs
72839213Sgibbs	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
72939213Sgibbs	scsi_cmd->opcode = readop ? RECEIVE : SEND;
73039213Sgibbs	scsi_cmd->byte2 = byte2;
73139213Sgibbs	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
73239213Sgibbs	scsi_cmd->control = 0;
73339213Sgibbs
73439213Sgibbs	cam_fill_csio(csio,
73539213Sgibbs		      retries,
73639213Sgibbs		      cbfcnp,
73739213Sgibbs		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
73839213Sgibbs		      tag_action,
73939213Sgibbs		      data_ptr,
74039213Sgibbs		      xfer_len,
74139213Sgibbs		      sense_len,
74239213Sgibbs		      sizeof(*scsi_cmd),
74339213Sgibbs		      timeout);
74439213Sgibbs}
745