xref: /freebsd/sys/cam/scsi/scsi_pt.c (revision 2ffd30f7ee15c87ee092cbac6a4438bcb3af923c)
1898b0535SWarner Losh /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3bec9534dSPedro F. Giffuni  *
476babe50SJustin T. Gibbs  * Implementation of SCSI Processor Target Peripheral driver for CAM.
576babe50SJustin T. Gibbs  *
676babe50SJustin T. Gibbs  * Copyright (c) 1998 Justin T. Gibbs.
776babe50SJustin T. Gibbs  * All rights reserved.
876babe50SJustin T. Gibbs  *
976babe50SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
1076babe50SJustin T. Gibbs  * modification, are permitted provided that the following conditions
1176babe50SJustin T. Gibbs  * are met:
1276babe50SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
1376babe50SJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
1476babe50SJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
1576babe50SJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
1676babe50SJustin T. Gibbs  *    derived from this software without specific prior written permission.
1776babe50SJustin T. Gibbs  *
1876babe50SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1976babe50SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2076babe50SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2176babe50SJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2276babe50SJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2376babe50SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2476babe50SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2576babe50SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2676babe50SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2776babe50SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2876babe50SJustin T. Gibbs  * SUCH DAMAGE.
2976babe50SJustin T. Gibbs  */
3076babe50SJustin T. Gibbs 
3176babe50SJustin T. Gibbs #include <sys/param.h>
3276babe50SJustin T. Gibbs #include <sys/queue.h>
3376babe50SJustin T. Gibbs #include <sys/systm.h>
3476babe50SJustin T. Gibbs #include <sys/kernel.h>
3576babe50SJustin T. Gibbs #include <sys/types.h>
369626b608SPoul-Henning Kamp #include <sys/bio.h>
3776babe50SJustin T. Gibbs #include <sys/devicestat.h>
3876babe50SJustin T. Gibbs #include <sys/malloc.h>
3976babe50SJustin T. Gibbs #include <sys/conf.h>
403ece1bd2SKenneth D. Merry #include <sys/ptio.h>
4176babe50SJustin T. Gibbs 
4276babe50SJustin T. Gibbs #include <cam/cam.h>
4376babe50SJustin T. Gibbs #include <cam/cam_ccb.h>
4476babe50SJustin T. Gibbs #include <cam/cam_periph.h>
4576babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h>
4676babe50SJustin T. Gibbs #include <cam/cam_debug.h>
4776babe50SJustin T. Gibbs 
4876babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h>
4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h>
5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_pt.h>
5176babe50SJustin T. Gibbs 
523ece1bd2SKenneth D. Merry #include "opt_pt.h"
533ece1bd2SKenneth D. Merry 
5476babe50SJustin T. Gibbs typedef enum {
5576babe50SJustin T. Gibbs 	PT_STATE_PROBE,
5676babe50SJustin T. Gibbs 	PT_STATE_NORMAL
5776babe50SJustin T. Gibbs } pt_state;
5876babe50SJustin T. Gibbs 
5976babe50SJustin T. Gibbs typedef enum {
6076babe50SJustin T. Gibbs 	PT_FLAG_NONE		= 0x00,
6176babe50SJustin T. Gibbs 	PT_FLAG_OPEN		= 0x01,
6276babe50SJustin T. Gibbs 	PT_FLAG_DEVICE_INVALID	= 0x02,
6376babe50SJustin T. Gibbs 	PT_FLAG_RETRY_UA	= 0x04
6476babe50SJustin T. Gibbs } pt_flags;
6576babe50SJustin T. Gibbs 
6676babe50SJustin T. Gibbs typedef enum {
6776babe50SJustin T. Gibbs 	PT_CCB_BUFFER_IO	= 0x01,
6876babe50SJustin T. Gibbs 	PT_CCB_RETRY_UA		= 0x04,
6976babe50SJustin T. Gibbs 	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
7076babe50SJustin T. Gibbs } pt_ccb_state;
7176babe50SJustin T. Gibbs 
7276babe50SJustin T. Gibbs /* Offsets into our private area for storing information */
7376babe50SJustin T. Gibbs #define ccb_state	ppriv_field0
7476babe50SJustin T. Gibbs #define ccb_bp		ppriv_ptr1
7576babe50SJustin T. Gibbs 
7676babe50SJustin T. Gibbs struct pt_softc {
778177437dSPoul-Henning Kamp 	struct	 bio_queue_head bio_queue;
78a9d2245eSPoul-Henning Kamp 	struct	 devstat *device_stats;
79e3975643SJake Burkholder 	LIST_HEAD(, ccb_hdr) pending_ccbs;
8076babe50SJustin T. Gibbs 	pt_state state;
8176babe50SJustin T. Gibbs 	pt_flags flags;
823ece1bd2SKenneth D. Merry 	int	 io_timeout;
8389c9c53dSPoul-Henning Kamp 	struct cdev *dev;
8476babe50SJustin T. Gibbs };
8576babe50SJustin T. Gibbs 
8676babe50SJustin T. Gibbs static	d_open_t	ptopen;
8776babe50SJustin T. Gibbs static	d_close_t	ptclose;
8876babe50SJustin T. Gibbs static	d_strategy_t	ptstrategy;
8976babe50SJustin T. Gibbs static	periph_init_t	ptinit;
90*7c5d20a6SWarner Losh static	void		ptasync(void *callback_arg, uint32_t code,
9176babe50SJustin T. Gibbs 				struct cam_path *path, void *arg);
9276babe50SJustin T. Gibbs static	periph_ctor_t	ptctor;
93ee9c90c7SKenneth D. Merry static	periph_oninv_t	ptoninvalidate;
9476babe50SJustin T. Gibbs static	periph_dtor_t	ptdtor;
9576babe50SJustin T. Gibbs static	periph_start_t	ptstart;
9676babe50SJustin T. Gibbs static	void		ptdone(struct cam_periph *periph,
9776babe50SJustin T. Gibbs 			       union ccb *done_ccb);
983ece1bd2SKenneth D. Merry static	d_ioctl_t	ptioctl;
99*7c5d20a6SWarner Losh static  int		pterror(union ccb *ccb, uint32_t cam_flags,
100*7c5d20a6SWarner Losh 				uint32_t sense_flags);
10176babe50SJustin T. Gibbs 
102*7c5d20a6SWarner Losh void	scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
10376babe50SJustin T. Gibbs 			  void (*cbfcnp)(struct cam_periph *, union ccb *),
10476babe50SJustin T. Gibbs 			  u_int tag_action, int readop, u_int byte2,
105*7c5d20a6SWarner Losh 			  uint32_t xfer_len, uint8_t *data_ptr,
106*7c5d20a6SWarner Losh 			  uint8_t sense_len, uint32_t timeout);
10776babe50SJustin T. Gibbs 
10876babe50SJustin T. Gibbs static struct periph_driver ptdriver =
10976babe50SJustin T. Gibbs {
11076babe50SJustin T. Gibbs 	ptinit, "pt",
11176babe50SJustin T. Gibbs 	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11276babe50SJustin T. Gibbs };
11376babe50SJustin T. Gibbs 
1140b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pt, ptdriver);
11576babe50SJustin T. Gibbs 
1164e2f199eSPoul-Henning Kamp static struct cdevsw pt_cdevsw = {
117dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
1182b83592fSScott Long 	.d_flags =	0,
1197ac40f5fSPoul-Henning Kamp 	.d_open =	ptopen,
1207ac40f5fSPoul-Henning Kamp 	.d_close =	ptclose,
1217ac40f5fSPoul-Henning Kamp 	.d_read =	physread,
1227ac40f5fSPoul-Henning Kamp 	.d_write =	physwrite,
1237ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ptioctl,
1247ac40f5fSPoul-Henning Kamp 	.d_strategy =	ptstrategy,
1257ac40f5fSPoul-Henning Kamp 	.d_name =	"pt",
12676babe50SJustin T. Gibbs };
12776babe50SJustin T. Gibbs 
1283ece1bd2SKenneth D. Merry #ifndef SCSI_PT_DEFAULT_TIMEOUT
1293ece1bd2SKenneth D. Merry #define SCSI_PT_DEFAULT_TIMEOUT		60
1303ece1bd2SKenneth D. Merry #endif
1313ece1bd2SKenneth D. Merry 
13276babe50SJustin T. Gibbs static int
ptopen(struct cdev * dev,int flags,int fmt,struct thread * td)13389c9c53dSPoul-Henning Kamp ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
13476babe50SJustin T. Gibbs {
13576babe50SJustin T. Gibbs 	struct cam_periph *periph;
13676babe50SJustin T. Gibbs 	struct pt_softc *softc;
1372b83592fSScott Long 	int error = 0;
13876babe50SJustin T. Gibbs 
139e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
14099e7a4adSScott Long 	if (cam_periph_acquire(periph) != 0)
14176babe50SJustin T. Gibbs 		return (ENXIO);
14276babe50SJustin T. Gibbs 
14376babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
14476babe50SJustin T. Gibbs 
1452b83592fSScott Long 	cam_periph_lock(periph);
146ee9c90c7SKenneth D. Merry 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
147c552ebe1SKenneth D. Merry 		cam_periph_release_locked(periph);
1482b83592fSScott Long 		cam_periph_unlock(periph);
149ee9c90c7SKenneth D. Merry 		return(ENXIO);
150ee9c90c7SKenneth D. Merry 	}
151ee9c90c7SKenneth D. Merry 
1522b83592fSScott Long 	if ((softc->flags & PT_FLAG_OPEN) == 0)
1532b83592fSScott Long 		softc->flags |= PT_FLAG_OPEN;
1542b83592fSScott Long 	else {
1552b83592fSScott Long 		error = EBUSY;
1562b83592fSScott Long 		cam_periph_release(periph);
15722b9c86cSKenneth D. Merry 	}
15822b9c86cSKenneth D. Merry 
1592b83592fSScott Long 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1602b83592fSScott Long 	    ("ptopen: dev=%s\n", devtoname(dev)));
16176babe50SJustin T. Gibbs 
16276babe50SJustin T. Gibbs 	cam_periph_unlock(periph);
16376babe50SJustin T. Gibbs 	return (error);
16476babe50SJustin T. Gibbs }
16576babe50SJustin T. Gibbs 
16676babe50SJustin T. Gibbs static int
ptclose(struct cdev * dev,int flag,int fmt,struct thread * td)16789c9c53dSPoul-Henning Kamp ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
16876babe50SJustin T. Gibbs {
16976babe50SJustin T. Gibbs 	struct	cam_periph *periph;
17076babe50SJustin T. Gibbs 	struct	pt_softc *softc;
17176babe50SJustin T. Gibbs 
172e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
17376babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
17476babe50SJustin T. Gibbs 
1752b83592fSScott Long 	cam_periph_lock(periph);
17676babe50SJustin T. Gibbs 
17776babe50SJustin T. Gibbs 	softc->flags &= ~PT_FLAG_OPEN;
178c552ebe1SKenneth D. Merry 	cam_periph_release_locked(periph);
17976babe50SJustin T. Gibbs 	cam_periph_unlock(periph);
18076babe50SJustin T. Gibbs 	return (0);
18176babe50SJustin T. Gibbs }
18276babe50SJustin T. Gibbs 
18376babe50SJustin T. Gibbs /*
18476babe50SJustin T. Gibbs  * Actually translate the requested transfer into one the physical driver
18576babe50SJustin T. Gibbs  * can understand.  The transfer is described by a buf and will include
18676babe50SJustin T. Gibbs  * only one physical transfer.
18776babe50SJustin T. Gibbs  */
18876babe50SJustin T. Gibbs static void
ptstrategy(struct bio * bp)1898177437dSPoul-Henning Kamp ptstrategy(struct bio *bp)
19076babe50SJustin T. Gibbs {
19176babe50SJustin T. Gibbs 	struct cam_periph *periph;
19276babe50SJustin T. Gibbs 	struct pt_softc *softc;
19376babe50SJustin T. Gibbs 
194e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)bp->bio_dev->si_drv1;
195b63170f8SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount;
19676babe50SJustin T. Gibbs 	if (periph == NULL) {
197b63170f8SPoul-Henning Kamp 		biofinish(bp, NULL, ENXIO);
198b63170f8SPoul-Henning Kamp 		return;
19976babe50SJustin T. Gibbs 	}
2002b83592fSScott Long 	cam_periph_lock(periph);
20176babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
20276babe50SJustin T. Gibbs 
20376babe50SJustin T. Gibbs 	/*
20476babe50SJustin T. Gibbs 	 * If the device has been made invalid, error out
20576babe50SJustin T. Gibbs 	 */
20676babe50SJustin T. Gibbs 	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
2072b83592fSScott Long 		cam_periph_unlock(periph);
208b63170f8SPoul-Henning Kamp 		biofinish(bp, NULL, ENXIO);
209b63170f8SPoul-Henning Kamp 		return;
21076babe50SJustin T. Gibbs 	}
21176babe50SJustin T. Gibbs 
21276babe50SJustin T. Gibbs 	/*
21376babe50SJustin T. Gibbs 	 * Place it in the queue of disk activities for this disk
21476babe50SJustin T. Gibbs 	 */
2158177437dSPoul-Henning Kamp 	bioq_insert_tail(&softc->bio_queue, bp);
21676babe50SJustin T. Gibbs 
21776babe50SJustin T. Gibbs 	/*
21876babe50SJustin T. Gibbs 	 * Schedule ourselves for performing the work.
21976babe50SJustin T. Gibbs 	 */
220bbfa4aa1SAlexander Motin 	xpt_schedule(periph, CAM_PRIORITY_NORMAL);
2212b83592fSScott Long 	cam_periph_unlock(periph);
22276babe50SJustin T. Gibbs 
22376babe50SJustin T. Gibbs 	return;
22476babe50SJustin T. Gibbs }
22576babe50SJustin T. Gibbs 
22676babe50SJustin T. Gibbs static void
ptinit(void)22776babe50SJustin T. Gibbs ptinit(void)
22876babe50SJustin T. Gibbs {
22976babe50SJustin T. Gibbs 	cam_status status;
23076babe50SJustin T. Gibbs 
23176babe50SJustin T. Gibbs 	/*
23276babe50SJustin T. Gibbs 	 * Install a global async callback.  This callback will
23376babe50SJustin T. Gibbs 	 * receive async callbacks like "new device found".
23476babe50SJustin T. Gibbs 	 */
23585d92640SScott Long 	status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
23676babe50SJustin T. Gibbs 
23776babe50SJustin T. Gibbs 	if (status != CAM_REQ_CMP) {
23876babe50SJustin T. Gibbs 		printf("pt: Failed to attach master async callback "
23976babe50SJustin T. Gibbs 		       "due to status 0x%x!\n", status);
24076babe50SJustin T. Gibbs 	}
24176babe50SJustin T. Gibbs }
24276babe50SJustin T. Gibbs 
24376babe50SJustin T. Gibbs static cam_status
ptctor(struct cam_periph * periph,void * arg)24476babe50SJustin T. Gibbs ptctor(struct cam_periph *periph, void *arg)
24576babe50SJustin T. Gibbs {
24676babe50SJustin T. Gibbs 	struct pt_softc *softc;
24776babe50SJustin T. Gibbs 	struct ccb_getdev *cgd;
248b8b6b5d3SAlexander Motin 	struct ccb_pathinq cpi;
249ee198893SKonstantin Belousov 	struct make_dev_args args;
250ee198893SKonstantin Belousov 	int error;
25176babe50SJustin T. Gibbs 
25276babe50SJustin T. Gibbs 	cgd = (struct ccb_getdev *)arg;
25376babe50SJustin T. Gibbs 	if (cgd == NULL) {
25476babe50SJustin T. Gibbs 		printf("ptregister: no getdev CCB, can't register device\n");
25576babe50SJustin T. Gibbs 		return(CAM_REQ_CMP_ERR);
25676babe50SJustin T. Gibbs 	}
25776babe50SJustin T. Gibbs 
25876babe50SJustin T. Gibbs 	softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
25976babe50SJustin T. Gibbs 
26076babe50SJustin T. Gibbs 	if (softc == NULL) {
26176babe50SJustin T. Gibbs 		printf("daregister: Unable to probe new device. "
26276babe50SJustin T. Gibbs 		       "Unable to allocate softc\n");
26376babe50SJustin T. Gibbs 		return(CAM_REQ_CMP_ERR);
26476babe50SJustin T. Gibbs 	}
26576babe50SJustin T. Gibbs 
26676babe50SJustin T. Gibbs 	bzero(softc, sizeof(*softc));
26776babe50SJustin T. Gibbs 	LIST_INIT(&softc->pending_ccbs);
26876babe50SJustin T. Gibbs 	softc->state = PT_STATE_NORMAL;
2698177437dSPoul-Henning Kamp 	bioq_init(&softc->bio_queue);
27076babe50SJustin T. Gibbs 
2713ece1bd2SKenneth D. Merry 	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
2723ece1bd2SKenneth D. Merry 
27376babe50SJustin T. Gibbs 	periph->softc = softc;
27476babe50SJustin T. Gibbs 
275762a7f4fSWarner Losh 	xpt_path_inq(&cpi, periph->path);
276b8b6b5d3SAlexander Motin 
27785d92640SScott Long 	cam_periph_unlock(periph);
278ee198893SKonstantin Belousov 
279ee198893SKonstantin Belousov 	make_dev_args_init(&args);
280ee198893SKonstantin Belousov 	args.mda_devsw = &pt_cdevsw;
281ee198893SKonstantin Belousov 	args.mda_unit = periph->unit_number;
282ee198893SKonstantin Belousov 	args.mda_uid = UID_ROOT;
283ee198893SKonstantin Belousov 	args.mda_gid = GID_OPERATOR;
284ee198893SKonstantin Belousov 	args.mda_mode = 0600;
285ee198893SKonstantin Belousov 	args.mda_si_drv1 = periph;
286ee198893SKonstantin Belousov 	error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
287ee198893SKonstantin Belousov 	    periph->unit_number);
288ee198893SKonstantin Belousov 	if (error != 0) {
289ee198893SKonstantin Belousov 		cam_periph_lock(periph);
290ee198893SKonstantin Belousov 		return (CAM_REQ_CMP_ERR);
291ee198893SKonstantin Belousov 	}
292ee198893SKonstantin Belousov 
293a9d2245eSPoul-Henning Kamp 	softc->device_stats = devstat_new_entry("pt",
29476babe50SJustin T. Gibbs 			  periph->unit_number, 0,
29576babe50SJustin T. Gibbs 			  DEVSTAT_NO_BLOCKSIZE,
296b8b6b5d3SAlexander Motin 			  SID_TYPE(&cgd->inq_data) |
297b8b6b5d3SAlexander Motin 			  XPORT_DEVSTAT_TYPE(cpi.transport),
2982a888f93SKenneth D. Merry 			  DEVSTAT_PRIORITY_OTHER);
29976babe50SJustin T. Gibbs 
30058b0b144SScott Long 	cam_periph_lock(periph);
301e2a5fdf9SNate Lawson 
30276babe50SJustin T. Gibbs 	/*
30376babe50SJustin T. Gibbs 	 * Add async callbacks for bus reset and
30476babe50SJustin T. Gibbs 	 * bus device reset calls.  I don't bother
30576babe50SJustin T. Gibbs 	 * checking if this fails as, in most cases,
30676babe50SJustin T. Gibbs 	 * the system will function just fine without
30776babe50SJustin T. Gibbs 	 * them and the only alternative would be to
30876babe50SJustin T. Gibbs 	 * not attach the device on failure.
30976babe50SJustin T. Gibbs 	 */
31085d92640SScott Long 	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
31185d92640SScott Long 			   ptasync, periph, periph->path);
31276babe50SJustin T. Gibbs 
31376babe50SJustin T. Gibbs 	/* Tell the user we've attached to the device */
31476babe50SJustin T. Gibbs 	xpt_announce_periph(periph, NULL);
31576babe50SJustin T. Gibbs 
31676babe50SJustin T. Gibbs 	return(CAM_REQ_CMP);
31776babe50SJustin T. Gibbs }
31876babe50SJustin T. Gibbs 
31976babe50SJustin T. Gibbs static void
ptoninvalidate(struct cam_periph * periph)320ee9c90c7SKenneth D. Merry ptoninvalidate(struct cam_periph *periph)
321ee9c90c7SKenneth D. Merry {
322ee9c90c7SKenneth D. Merry 	struct pt_softc *softc;
323ee9c90c7SKenneth D. Merry 
324ee9c90c7SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
325ee9c90c7SKenneth D. Merry 
326ee9c90c7SKenneth D. Merry 	/*
327ee9c90c7SKenneth D. Merry 	 * De-register any async callbacks.
328ee9c90c7SKenneth D. Merry 	 */
32985d92640SScott Long 	xpt_register_async(0, ptasync, periph, periph->path);
330ee9c90c7SKenneth D. Merry 
331ee9c90c7SKenneth D. Merry 	softc->flags |= PT_FLAG_DEVICE_INVALID;
332ee9c90c7SKenneth D. Merry 
333ee9c90c7SKenneth D. Merry 	/*
334ee9c90c7SKenneth D. Merry 	 * Return all queued I/O with ENXIO.
335ee9c90c7SKenneth D. Merry 	 * XXX Handle any transactions queued to the card
336ee9c90c7SKenneth D. Merry 	 *     with XPT_ABORT_CCB.
337ee9c90c7SKenneth D. Merry 	 */
338891619a6SPoul-Henning Kamp 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
339ee9c90c7SKenneth D. Merry }
340ee9c90c7SKenneth D. Merry 
341ee9c90c7SKenneth D. Merry static void
ptdtor(struct cam_periph * periph)34276babe50SJustin T. Gibbs ptdtor(struct cam_periph *periph)
34376babe50SJustin T. Gibbs {
344ee9c90c7SKenneth D. Merry 	struct pt_softc *softc;
345ee9c90c7SKenneth D. Merry 
346ee9c90c7SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
347ee9c90c7SKenneth D. Merry 
3485f3fed85SEdward Tomasz Napierala 	devstat_remove_entry(softc->device_stats);
3495f3fed85SEdward Tomasz Napierala 	cam_periph_unlock(periph);
3505f3fed85SEdward Tomasz Napierala 	destroy_dev(softc->dev);
3515f3fed85SEdward Tomasz Napierala 	cam_periph_lock(periph);
352ee9c90c7SKenneth D. Merry 	free(softc, M_DEVBUF);
35376babe50SJustin T. Gibbs }
35476babe50SJustin T. Gibbs 
35576babe50SJustin T. Gibbs static void
ptasync(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)356*7c5d20a6SWarner Losh ptasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
35776babe50SJustin T. Gibbs {
35876babe50SJustin T. Gibbs 	struct cam_periph *periph;
35976babe50SJustin T. Gibbs 
36076babe50SJustin T. Gibbs 	periph = (struct cam_periph *)callback_arg;
36176babe50SJustin T. Gibbs 	switch (code) {
36276babe50SJustin T. Gibbs 	case AC_FOUND_DEVICE:
36376babe50SJustin T. Gibbs 	{
36476babe50SJustin T. Gibbs 		struct ccb_getdev *cgd;
36576babe50SJustin T. Gibbs 		cam_status status;
36676babe50SJustin T. Gibbs 
36776babe50SJustin T. Gibbs 		cgd = (struct ccb_getdev *)arg;
368c5ff3b2fSMatt Jacob 		if (cgd == NULL)
369c5ff3b2fSMatt Jacob 			break;
37076babe50SJustin T. Gibbs 
37152c9ce25SScott Long 		if (cgd->protocol != PROTO_SCSI)
37252c9ce25SScott Long 			break;
37392024858SAlexander Motin 		if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
37492024858SAlexander Motin 			break;
37510b6172aSMatt Jacob 		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
37676babe50SJustin T. Gibbs 			break;
37776babe50SJustin T. Gibbs 
37876babe50SJustin T. Gibbs 		/*
37976babe50SJustin T. Gibbs 		 * Allocate a peripheral instance for
38076babe50SJustin T. Gibbs 		 * this device and start the probe
38176babe50SJustin T. Gibbs 		 * process.
38276babe50SJustin T. Gibbs 		 */
383ee9c90c7SKenneth D. Merry 		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
384ee9c90c7SKenneth D. Merry 					  ptstart, "pt", CAM_PERIPH_BIO,
385227d67aaSAlexander Motin 					  path, ptasync,
386ee9c90c7SKenneth D. Merry 					  AC_FOUND_DEVICE, cgd);
38776babe50SJustin T. Gibbs 
38876babe50SJustin T. Gibbs 		if (status != CAM_REQ_CMP
38976babe50SJustin T. Gibbs 		 && status != CAM_REQ_INPROG)
39076babe50SJustin T. Gibbs 			printf("ptasync: Unable to attach to new device "
39176babe50SJustin T. Gibbs 				"due to status 0x%x\n", status);
39276babe50SJustin T. Gibbs 		break;
39376babe50SJustin T. Gibbs 	}
39476babe50SJustin T. Gibbs 	case AC_SENT_BDR:
39576babe50SJustin T. Gibbs 	case AC_BUS_RESET:
39676babe50SJustin T. Gibbs 	{
39776babe50SJustin T. Gibbs 		struct pt_softc *softc;
39876babe50SJustin T. Gibbs 		struct ccb_hdr *ccbh;
39976babe50SJustin T. Gibbs 
40076babe50SJustin T. Gibbs 		softc = (struct pt_softc *)periph->softc;
40176babe50SJustin T. Gibbs 		/*
40276babe50SJustin T. Gibbs 		 * Don't fail on the expected unit attention
40376babe50SJustin T. Gibbs 		 * that will occur.
40476babe50SJustin T. Gibbs 		 */
40576babe50SJustin T. Gibbs 		softc->flags |= PT_FLAG_RETRY_UA;
406fc2ffbe6SPoul-Henning Kamp 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
40776babe50SJustin T. Gibbs 			ccbh->ccb_state |= PT_CCB_RETRY_UA;
40876babe50SJustin T. Gibbs 	}
40907c6eac9SPoul-Henning Kamp 	/* FALLTHROUGH */
41076babe50SJustin T. Gibbs 	default:
411516871c6SJustin T. Gibbs 		cam_periph_async(periph, code, path, arg);
41276babe50SJustin T. Gibbs 		break;
41376babe50SJustin T. Gibbs 	}
41476babe50SJustin T. Gibbs }
41576babe50SJustin T. Gibbs 
41676babe50SJustin T. Gibbs static void
ptstart(struct cam_periph * periph,union ccb * start_ccb)41776babe50SJustin T. Gibbs ptstart(struct cam_periph *periph, union ccb *start_ccb)
41876babe50SJustin T. Gibbs {
41976babe50SJustin T. Gibbs 	struct pt_softc *softc;
4208177437dSPoul-Henning Kamp 	struct bio *bp;
42176babe50SJustin T. Gibbs 
42276babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
42376babe50SJustin T. Gibbs 
424fddde2b8SAlexander Motin 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
425fddde2b8SAlexander Motin 
42676babe50SJustin T. Gibbs 	/*
42776babe50SJustin T. Gibbs 	 * See if there is a buf with work for us to do..
42876babe50SJustin T. Gibbs 	 */
4298177437dSPoul-Henning Kamp 	bp = bioq_first(&softc->bio_queue);
430227d67aaSAlexander Motin 	if (bp == NULL) {
43176babe50SJustin T. Gibbs 		xpt_release_ccb(start_ccb);
43276babe50SJustin T. Gibbs 	} else {
4338177437dSPoul-Henning Kamp 		bioq_remove(&softc->bio_queue, bp);
43476babe50SJustin T. Gibbs 
4351ecc485cSPoul-Henning Kamp 		devstat_start_transaction_bio(softc->device_stats, bp);
43676babe50SJustin T. Gibbs 
43776babe50SJustin T. Gibbs 		scsi_send_receive(&start_ccb->csio,
43876babe50SJustin T. Gibbs 				  /*retries*/4,
43976babe50SJustin T. Gibbs 				  ptdone,
44076babe50SJustin T. Gibbs 				  MSG_SIMPLE_Q_TAG,
4418177437dSPoul-Henning Kamp 				  bp->bio_cmd == BIO_READ,
44276babe50SJustin T. Gibbs 				  /*byte2*/0,
4438177437dSPoul-Henning Kamp 				  bp->bio_bcount,
4448177437dSPoul-Henning Kamp 				  bp->bio_data,
44576babe50SJustin T. Gibbs 				  /*sense_len*/SSD_FULL_SIZE,
4463ece1bd2SKenneth D. Merry 				  /*timeout*/softc->io_timeout);
44776babe50SJustin T. Gibbs 
4489c6a0920SKenneth D. Merry 		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
44976babe50SJustin T. Gibbs 
45076babe50SJustin T. Gibbs 		/*
4517a2b450fSEitan Adler 		 * Block out any asynchronous callbacks
45276babe50SJustin T. Gibbs 		 * while we touch the pending ccb list.
45376babe50SJustin T. Gibbs 		 */
45476babe50SJustin T. Gibbs 		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
45576babe50SJustin T. Gibbs 				 periph_links.le);
45676babe50SJustin T. Gibbs 
45776babe50SJustin T. Gibbs 		start_ccb->ccb_h.ccb_bp = bp;
4588177437dSPoul-Henning Kamp 		bp = bioq_first(&softc->bio_queue);
45976babe50SJustin T. Gibbs 
46076babe50SJustin T. Gibbs 		xpt_action(start_ccb);
46176babe50SJustin T. Gibbs 
46276babe50SJustin T. Gibbs 		if (bp != NULL) {
46376babe50SJustin T. Gibbs 			/* Have more work to do, so ensure we stay scheduled */
464bbfa4aa1SAlexander Motin 			xpt_schedule(periph, CAM_PRIORITY_NORMAL);
46576babe50SJustin T. Gibbs 		}
46676babe50SJustin T. Gibbs 	}
46776babe50SJustin T. Gibbs }
46876babe50SJustin T. Gibbs 
46976babe50SJustin T. Gibbs static void
ptdone(struct cam_periph * periph,union ccb * done_ccb)47076babe50SJustin T. Gibbs ptdone(struct cam_periph *periph, union ccb *done_ccb)
47176babe50SJustin T. Gibbs {
47276babe50SJustin T. Gibbs 	struct pt_softc *softc;
47376babe50SJustin T. Gibbs 	struct ccb_scsiio *csio;
47476babe50SJustin T. Gibbs 
47576babe50SJustin T. Gibbs 	softc = (struct pt_softc *)periph->softc;
476fddde2b8SAlexander Motin 
477fddde2b8SAlexander Motin 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
478fddde2b8SAlexander Motin 
47976babe50SJustin T. Gibbs 	csio = &done_ccb->csio;
48076babe50SJustin T. Gibbs 	switch (csio->ccb_h.ccb_state) {
48176babe50SJustin T. Gibbs 	case PT_CCB_BUFFER_IO:
48276babe50SJustin T. Gibbs 	case PT_CCB_BUFFER_IO_UA:
48376babe50SJustin T. Gibbs 	{
4848177437dSPoul-Henning Kamp 		struct bio *bp;
48576babe50SJustin T. Gibbs 
4868177437dSPoul-Henning Kamp 		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
48776babe50SJustin T. Gibbs 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48876babe50SJustin T. Gibbs 			int error;
48976babe50SJustin T. Gibbs 			int sf;
49076babe50SJustin T. Gibbs 
49176babe50SJustin T. Gibbs 			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
49276babe50SJustin T. Gibbs 				sf = SF_RETRY_UA;
49376babe50SJustin T. Gibbs 			else
49476babe50SJustin T. Gibbs 				sf = 0;
49576babe50SJustin T. Gibbs 
4963393f8daSKenneth D. Merry 			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
4973393f8daSKenneth D. Merry 			if (error == ERESTART) {
49876babe50SJustin T. Gibbs 				/*
49976babe50SJustin T. Gibbs 				 * A retry was scheuled, so
50076babe50SJustin T. Gibbs 				 * just return.
50176babe50SJustin T. Gibbs 				 */
50276babe50SJustin T. Gibbs 				return;
50376babe50SJustin T. Gibbs 			}
50476babe50SJustin T. Gibbs 			if (error != 0) {
50576babe50SJustin T. Gibbs 				if (error == ENXIO) {
50676babe50SJustin T. Gibbs 					/*
50776babe50SJustin T. Gibbs 					 * Catastrophic error.  Mark our device
50876babe50SJustin T. Gibbs 					 * as invalid.
50976babe50SJustin T. Gibbs 					 */
510f0d9af51SMatt Jacob 					xpt_print(periph->path,
511f0d9af51SMatt Jacob 					    "Invalidating device\n");
51276babe50SJustin T. Gibbs 					softc->flags |= PT_FLAG_DEVICE_INVALID;
51376babe50SJustin T. Gibbs 				}
51476babe50SJustin T. Gibbs 
51576babe50SJustin T. Gibbs 				/*
51676babe50SJustin T. Gibbs 				 * return all queued I/O with EIO, so that
51776babe50SJustin T. Gibbs 				 * the client can retry these I/Os in the
51876babe50SJustin T. Gibbs 				 * proper order should it attempt to recover.
51976babe50SJustin T. Gibbs 				 */
520891619a6SPoul-Henning Kamp 				bioq_flush(&softc->bio_queue, NULL, EIO);
5218177437dSPoul-Henning Kamp 				bp->bio_error = error;
5228177437dSPoul-Henning Kamp 				bp->bio_resid = bp->bio_bcount;
5238177437dSPoul-Henning Kamp 				bp->bio_flags |= BIO_ERROR;
52476babe50SJustin T. Gibbs 			} else {
5258177437dSPoul-Henning Kamp 				bp->bio_resid = csio->resid;
5268177437dSPoul-Henning Kamp 				bp->bio_error = 0;
5278177437dSPoul-Henning Kamp 				if (bp->bio_resid != 0) {
52876babe50SJustin T. Gibbs 					/* Short transfer ??? */
5298177437dSPoul-Henning Kamp 					bp->bio_flags |= BIO_ERROR;
53076babe50SJustin T. Gibbs 				}
53176babe50SJustin T. Gibbs 			}
53276babe50SJustin T. Gibbs 			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
53376babe50SJustin T. Gibbs 				cam_release_devq(done_ccb->ccb_h.path,
53476babe50SJustin T. Gibbs 						 /*relsim_flags*/0,
53576babe50SJustin T. Gibbs 						 /*reduction*/0,
53676babe50SJustin T. Gibbs 						 /*timeout*/0,
53776babe50SJustin T. Gibbs 						 /*getcount_only*/0);
53876babe50SJustin T. Gibbs 		} else {
5398177437dSPoul-Henning Kamp 			bp->bio_resid = csio->resid;
5408177437dSPoul-Henning Kamp 			if (bp->bio_resid != 0)
5418177437dSPoul-Henning Kamp 				bp->bio_flags |= BIO_ERROR;
54276babe50SJustin T. Gibbs 		}
54376babe50SJustin T. Gibbs 
54476babe50SJustin T. Gibbs 		/*
5457a2b450fSEitan Adler 		 * Block out any asynchronous callbacks
54676babe50SJustin T. Gibbs 		 * while we touch the pending ccb list.
54776babe50SJustin T. Gibbs 		 */
54876babe50SJustin T. Gibbs 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
54976babe50SJustin T. Gibbs 
550a9d2245eSPoul-Henning Kamp 		biofinish(bp, softc->device_stats, 0);
55176babe50SJustin T. Gibbs 		break;
55276babe50SJustin T. Gibbs 	}
55376babe50SJustin T. Gibbs 	}
55476babe50SJustin T. Gibbs 	xpt_release_ccb(done_ccb);
55576babe50SJustin T. Gibbs }
55676babe50SJustin T. Gibbs 
55776babe50SJustin T. Gibbs static int
pterror(union ccb * ccb,uint32_t cam_flags,uint32_t sense_flags)558*7c5d20a6SWarner Losh pterror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
55976babe50SJustin T. Gibbs {
56076babe50SJustin T. Gibbs 
561553484aeSWarner Losh 	return(cam_periph_error(ccb, cam_flags, sense_flags));
56276babe50SJustin T. Gibbs }
56376babe50SJustin T. Gibbs 
5643ece1bd2SKenneth D. Merry static int
ptioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flag,struct thread * td)56589c9c53dSPoul-Henning Kamp ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
5663ece1bd2SKenneth D. Merry {
5673ece1bd2SKenneth D. Merry 	struct cam_periph *periph;
5683ece1bd2SKenneth D. Merry 	struct pt_softc *softc;
5692b83592fSScott Long 	int error = 0;
5703ece1bd2SKenneth D. Merry 
571e2a5fdf9SNate Lawson 	periph = (struct cam_periph *)dev->si_drv1;
5723ece1bd2SKenneth D. Merry 	softc = (struct pt_softc *)periph->softc;
5733ece1bd2SKenneth D. Merry 
5742b83592fSScott Long 	cam_periph_lock(periph);
5753ece1bd2SKenneth D. Merry 
5763ece1bd2SKenneth D. Merry 	switch(cmd) {
5773ece1bd2SKenneth D. Merry 	case PTIOCGETTIMEOUT:
5783ece1bd2SKenneth D. Merry 		if (softc->io_timeout >= 1000)
5793ece1bd2SKenneth D. Merry 			*(int *)addr = softc->io_timeout / 1000;
5803ece1bd2SKenneth D. Merry 		else
5813ece1bd2SKenneth D. Merry 			*(int *)addr = 0;
5823ece1bd2SKenneth D. Merry 		break;
5833ece1bd2SKenneth D. Merry 	case PTIOCSETTIMEOUT:
5843ece1bd2SKenneth D. Merry 		if (*(int *)addr < 1) {
5853ece1bd2SKenneth D. Merry 			error = EINVAL;
5863ece1bd2SKenneth D. Merry 			break;
5873ece1bd2SKenneth D. Merry 		}
5883ece1bd2SKenneth D. Merry 
5893ece1bd2SKenneth D. Merry 		softc->io_timeout = *(int *)addr * 1000;
5903ece1bd2SKenneth D. Merry 
5913ece1bd2SKenneth D. Merry 		break;
5923ece1bd2SKenneth D. Merry 	default:
5933ece1bd2SKenneth D. Merry 		error = cam_periph_ioctl(periph, cmd, addr, pterror);
5943ece1bd2SKenneth D. Merry 		break;
5953ece1bd2SKenneth D. Merry 	}
5963ece1bd2SKenneth D. Merry 
5973ece1bd2SKenneth D. Merry 	cam_periph_unlock(periph);
5983ece1bd2SKenneth D. Merry 
5993ece1bd2SKenneth D. Merry 	return(error);
6003ece1bd2SKenneth D. Merry }
6013ece1bd2SKenneth D. Merry 
60276babe50SJustin T. Gibbs void
scsi_send_receive(struct ccb_scsiio * csio,uint32_t retries,void (* cbfcnp)(struct cam_periph *,union ccb *),u_int tag_action,int readop,u_int byte2,uint32_t xfer_len,uint8_t * data_ptr,uint8_t sense_len,uint32_t timeout)603*7c5d20a6SWarner Losh scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
60476babe50SJustin T. Gibbs 		  void (*cbfcnp)(struct cam_periph *, union ccb *),
60576babe50SJustin T. Gibbs 		  u_int tag_action, int readop, u_int byte2,
606*7c5d20a6SWarner Losh 		  uint32_t xfer_len, uint8_t *data_ptr, uint8_t sense_len,
607*7c5d20a6SWarner Losh 		  uint32_t timeout)
60876babe50SJustin T. Gibbs {
60976babe50SJustin T. Gibbs 	struct scsi_send_receive *scsi_cmd;
61076babe50SJustin T. Gibbs 
61176babe50SJustin T. Gibbs 	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
61276babe50SJustin T. Gibbs 	scsi_cmd->opcode = readop ? RECEIVE : SEND;
61376babe50SJustin T. Gibbs 	scsi_cmd->byte2 = byte2;
61476babe50SJustin T. Gibbs 	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
61576babe50SJustin T. Gibbs 	scsi_cmd->control = 0;
61676babe50SJustin T. Gibbs 
61776babe50SJustin T. Gibbs 	cam_fill_csio(csio,
61876babe50SJustin T. Gibbs 		      retries,
61976babe50SJustin T. Gibbs 		      cbfcnp,
62076babe50SJustin T. Gibbs 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
62176babe50SJustin T. Gibbs 		      tag_action,
62276babe50SJustin T. Gibbs 		      data_ptr,
62376babe50SJustin T. Gibbs 		      xfer_len,
62476babe50SJustin T. Gibbs 		      sense_len,
62576babe50SJustin T. Gibbs 		      sizeof(*scsi_cmd),
62676babe50SJustin T. Gibbs 		      timeout);
62776babe50SJustin T. Gibbs }
628