xref: /freebsd/sys/cam/scsi/scsi_targ_bh.c (revision 2ffd30f7ee15c87ee092cbac6a4438bcb3af923c)
1898b0535SWarner Losh /*-
26fda903fSJustin T. Gibbs  * Implementation of the Target Mode 'Black Hole device' for CAM.
36fda903fSJustin T. Gibbs  *
44d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
5bec9534dSPedro F. Giffuni  *
66fda903fSJustin T. Gibbs  * Copyright (c) 1999 Justin T. Gibbs.
76fda903fSJustin T. Gibbs  * All rights reserved.
86fda903fSJustin T. Gibbs  *
96fda903fSJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
106fda903fSJustin T. Gibbs  * modification, are permitted provided that the following conditions
116fda903fSJustin T. Gibbs  * are met:
126fda903fSJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
136fda903fSJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
146fda903fSJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
156fda903fSJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
166fda903fSJustin T. Gibbs  *    derived from this software without specific prior written permission.
176fda903fSJustin T. Gibbs  *
186fda903fSJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
196fda903fSJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
206fda903fSJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
216fda903fSJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
226fda903fSJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
236fda903fSJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
246fda903fSJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256fda903fSJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
266fda903fSJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
276fda903fSJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
286fda903fSJustin T. Gibbs  * SUCH DAMAGE.
296fda903fSJustin T. Gibbs  */
306fda903fSJustin T. Gibbs 
316fda903fSJustin T. Gibbs #include <sys/param.h>
326fda903fSJustin T. Gibbs #include <sys/queue.h>
336fda903fSJustin T. Gibbs #include <sys/systm.h>
346fda903fSJustin T. Gibbs #include <sys/kernel.h>
356fda903fSJustin T. Gibbs #include <sys/types.h>
369626b608SPoul-Henning Kamp #include <sys/bio.h>
376fda903fSJustin T. Gibbs #include <sys/conf.h>
386fda903fSJustin T. Gibbs #include <sys/devicestat.h>
396fda903fSJustin T. Gibbs #include <sys/malloc.h>
406fda903fSJustin T. Gibbs #include <sys/uio.h>
416fda903fSJustin T. Gibbs 
426fda903fSJustin T. Gibbs #include <cam/cam.h>
436fda903fSJustin T. Gibbs #include <cam/cam_ccb.h>
446fda903fSJustin T. Gibbs #include <cam/cam_periph.h>
456fda903fSJustin T. Gibbs #include <cam/cam_queue.h>
466fda903fSJustin T. Gibbs #include <cam/cam_xpt_periph.h>
476fda903fSJustin T. Gibbs #include <cam/cam_debug.h>
482b83592fSScott Long #include <cam/cam_sim.h>
496fda903fSJustin T. Gibbs 
506fda903fSJustin T. Gibbs #include <cam/scsi/scsi_all.h>
516fda903fSJustin T. Gibbs #include <cam/scsi/scsi_message.h>
526fda903fSJustin T. Gibbs 
53d745c852SEd Schouten static MALLOC_DEFINE(M_SCSIBH, "SCSI bh", "SCSI blackhole buffers");
54362abc44STai-hwa Liang 
556fda903fSJustin T. Gibbs typedef enum {
566fda903fSJustin T. Gibbs 	TARGBH_STATE_NORMAL,
576fda903fSJustin T. Gibbs 	TARGBH_STATE_EXCEPTION,
586fda903fSJustin T. Gibbs 	TARGBH_STATE_TEARDOWN
596fda903fSJustin T. Gibbs } targbh_state;
606fda903fSJustin T. Gibbs 
616fda903fSJustin T. Gibbs typedef enum {
626fda903fSJustin T. Gibbs 	TARGBH_FLAG_NONE	 = 0x00,
636fda903fSJustin T. Gibbs 	TARGBH_FLAG_LUN_ENABLED	 = 0x01
646fda903fSJustin T. Gibbs } targbh_flags;
656fda903fSJustin T. Gibbs 
666fda903fSJustin T. Gibbs typedef enum {
67227d67aaSAlexander Motin 	TARGBH_CCB_WORKQ
686fda903fSJustin T. Gibbs } targbh_ccb_types;
696fda903fSJustin T. Gibbs 
70e7783a9fSJustin T. Gibbs #define MAX_ACCEPT	8
716fda903fSJustin T. Gibbs #define MAX_IMMEDIATE	16
726fda903fSJustin T. Gibbs #define MAX_BUF_SIZE	256	/* Max inquiry/sense/mode page transfer */
736fda903fSJustin T. Gibbs 
746fda903fSJustin T. Gibbs /* Offsets into our private CCB area for storing accept information */
756fda903fSJustin T. Gibbs #define ccb_type	ppriv_field0
766fda903fSJustin T. Gibbs #define ccb_descr	ppriv_ptr1
776fda903fSJustin T. Gibbs 
786fda903fSJustin T. Gibbs /* We stick a pointer to the originating accept TIO in each continue I/O CCB */
796fda903fSJustin T. Gibbs #define ccb_atio	ppriv_ptr1
806fda903fSJustin T. Gibbs 
81e3975643SJake Burkholder TAILQ_HEAD(ccb_queue, ccb_hdr);
826fda903fSJustin T. Gibbs 
836fda903fSJustin T. Gibbs struct targbh_softc {
846fda903fSJustin T. Gibbs 	struct		ccb_queue pending_queue;
856fda903fSJustin T. Gibbs 	struct		ccb_queue work_queue;
866fda903fSJustin T. Gibbs 	struct		ccb_queue unknown_atio_queue;
876fda903fSJustin T. Gibbs 	struct		devstat device_stats;
886fda903fSJustin T. Gibbs 	targbh_state	state;
896fda903fSJustin T. Gibbs 	targbh_flags	flags;
906fda903fSJustin T. Gibbs 	u_int		init_level;
916fda903fSJustin T. Gibbs 	u_int		inq_data_len;
926fda903fSJustin T. Gibbs 	struct		ccb_accept_tio *accept_tio_list;
936fda903fSJustin T. Gibbs 	struct		ccb_hdr_slist immed_notify_slist;
946fda903fSJustin T. Gibbs };
956fda903fSJustin T. Gibbs 
966fda903fSJustin T. Gibbs struct targbh_cmd_desc {
976fda903fSJustin T. Gibbs 	struct	  ccb_accept_tio* atio_link;
986fda903fSJustin T. Gibbs 	u_int	  data_resid;	/* How much left to transfer */
996fda903fSJustin T. Gibbs 	u_int	  data_increment;/* Amount to send before next disconnect */
1006fda903fSJustin T. Gibbs 	void*	  data;		/* The data. Can be from backing_store or not */
1016fda903fSJustin T. Gibbs 	void*	  backing_store;/* Backing store allocated for this descriptor*/
1026fda903fSJustin T. Gibbs 	u_int	  max_size;	/* Size of backing_store */
103*7c5d20a6SWarner Losh 	uint32_t timeout;
104*7c5d20a6SWarner Losh 	uint8_t  status;	/* Status to return to initiator */
1056fda903fSJustin T. Gibbs };
1066fda903fSJustin T. Gibbs 
1076fda903fSJustin T. Gibbs static struct scsi_inquiry_data no_lun_inq_data =
1086fda903fSJustin T. Gibbs {
1096fda903fSJustin T. Gibbs 	T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
1106fda903fSJustin T. Gibbs 	/* version */2, /* format version */2
1116fda903fSJustin T. Gibbs };
1126fda903fSJustin T. Gibbs 
1131cc052e8SKenneth D. Merry static struct scsi_sense_data_fixed no_lun_sense_data =
1146fda903fSJustin T. Gibbs {
1156fda903fSJustin T. Gibbs 	SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
1166fda903fSJustin T. Gibbs 	0,
1176fda903fSJustin T. Gibbs 	SSD_KEY_NOT_READY,
118e7783a9fSJustin T. Gibbs 	{ 0, 0, 0, 0 },
1191cc052e8SKenneth D. Merry 	/*extra_len*/offsetof(struct scsi_sense_data_fixed, fru)
1201cc052e8SKenneth D. Merry                    - offsetof(struct scsi_sense_data_fixed, extra_len),
121e7783a9fSJustin T. Gibbs 	{ 0, 0, 0, 0 },
1226fda903fSJustin T. Gibbs 	/* Logical Unit Not Supported */
1236fda903fSJustin T. Gibbs 	/*ASC*/0x25, /*ASCQ*/0
1246fda903fSJustin T. Gibbs };
1256fda903fSJustin T. Gibbs 
1261cc052e8SKenneth D. Merry static const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru);
1276fda903fSJustin T. Gibbs 
1286fda903fSJustin T. Gibbs static periph_init_t	targbhinit;
129*7c5d20a6SWarner Losh static void		targbhasync(void *callback_arg, uint32_t code,
1306fda903fSJustin T. Gibbs 				    struct cam_path *path, void *arg);
1316fda903fSJustin T. Gibbs static cam_status	targbhenlun(struct cam_periph *periph);
1326fda903fSJustin T. Gibbs static cam_status	targbhdislun(struct cam_periph *periph);
1336fda903fSJustin T. Gibbs static periph_ctor_t	targbhctor;
1346fda903fSJustin T. Gibbs static periph_dtor_t	targbhdtor;
1356fda903fSJustin T. Gibbs static periph_start_t	targbhstart;
1366fda903fSJustin T. Gibbs static void		targbhdone(struct cam_periph *periph,
1376fda903fSJustin T. Gibbs 				   union ccb *done_ccb);
138e7783a9fSJustin T. Gibbs #ifdef NOTYET
139*7c5d20a6SWarner Losh static  int		targbherror(union ccb *ccb, uint32_t cam_flags,
140*7c5d20a6SWarner Losh 				    uint32_t sense_flags);
141e7783a9fSJustin T. Gibbs #endif
1426fda903fSJustin T. Gibbs static struct targbh_cmd_desc*	targbhallocdescr(void);
1436fda903fSJustin T. Gibbs static void		targbhfreedescr(struct targbh_cmd_desc *buf);
1446fda903fSJustin T. Gibbs 
1456fda903fSJustin T. Gibbs static struct periph_driver targbhdriver =
1466fda903fSJustin T. Gibbs {
1476fda903fSJustin T. Gibbs 	targbhinit, "targbh",
1486fda903fSJustin T. Gibbs 	TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
1496fda903fSJustin T. Gibbs };
1506fda903fSJustin T. Gibbs 
1510b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(targbh, targbhdriver);
1526fda903fSJustin T. Gibbs 
1536fda903fSJustin T. Gibbs static void
targbhinit(void)1546fda903fSJustin T. Gibbs targbhinit(void)
1556fda903fSJustin T. Gibbs {
1566fda903fSJustin T. Gibbs 	cam_status status;
1576fda903fSJustin T. Gibbs 
1586fda903fSJustin T. Gibbs 	/*
1596fda903fSJustin T. Gibbs 	 * Install a global async callback.  This callback will
1606fda903fSJustin T. Gibbs 	 * receive async callbacks like "new path registered".
1616fda903fSJustin T. Gibbs 	 */
16285d92640SScott Long 	status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED,
16385d92640SScott Long 				    targbhasync, NULL, NULL);
1646fda903fSJustin T. Gibbs 
1656fda903fSJustin T. Gibbs 	if (status != CAM_REQ_CMP) {
1666fda903fSJustin T. Gibbs 		printf("targbh: Failed to attach master async callback "
1676fda903fSJustin T. Gibbs 		       "due to status 0x%x!\n", status);
1686fda903fSJustin T. Gibbs 	}
1696fda903fSJustin T. Gibbs }
1706fda903fSJustin T. Gibbs 
1716fda903fSJustin T. Gibbs static void
targbhasync(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)172*7c5d20a6SWarner Losh targbhasync(void *callback_arg, uint32_t code,
1736fda903fSJustin T. Gibbs 	    struct cam_path *path, void *arg)
1746fda903fSJustin T. Gibbs {
1756fda903fSJustin T. Gibbs 	struct cam_path *new_path;
17660ddd2e4SHidetoshi Shimokawa 	struct ccb_pathinq *cpi;
17760ddd2e4SHidetoshi Shimokawa 	path_id_t bus_path_id;
1786fda903fSJustin T. Gibbs 	cam_status status;
1796fda903fSJustin T. Gibbs 
18060ddd2e4SHidetoshi Shimokawa 	cpi = (struct ccb_pathinq *)arg;
18160ddd2e4SHidetoshi Shimokawa 	if (code == AC_PATH_REGISTERED)
18260ddd2e4SHidetoshi Shimokawa 		bus_path_id = cpi->ccb_h.path_id;
18360ddd2e4SHidetoshi Shimokawa 	else
18460ddd2e4SHidetoshi Shimokawa 		bus_path_id = xpt_path_path_id(path);
1856fda903fSJustin T. Gibbs 	/*
1866fda903fSJustin T. Gibbs 	 * Allocate a peripheral instance for
1876fda903fSJustin T. Gibbs 	 * this target instance.
1886fda903fSJustin T. Gibbs 	 */
1896fda903fSJustin T. Gibbs 	status = xpt_create_path(&new_path, NULL,
19060ddd2e4SHidetoshi Shimokawa 				 bus_path_id,
1916fda903fSJustin T. Gibbs 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
1926fda903fSJustin T. Gibbs 	if (status != CAM_REQ_CMP) {
1936fda903fSJustin T. Gibbs 		printf("targbhasync: Unable to create path "
1946fda903fSJustin T. Gibbs 			"due to status 0x%x\n", status);
195388f522dSHidetoshi Shimokawa 		return;
1966fda903fSJustin T. Gibbs 	}
197388f522dSHidetoshi Shimokawa 
198388f522dSHidetoshi Shimokawa 	switch (code) {
199388f522dSHidetoshi Shimokawa 	case AC_PATH_REGISTERED:
200388f522dSHidetoshi Shimokawa 	{
201388f522dSHidetoshi Shimokawa 		/* Only attach to controllers that support target mode */
202388f522dSHidetoshi Shimokawa 		if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
203388f522dSHidetoshi Shimokawa 			break;
204388f522dSHidetoshi Shimokawa 
2056fda903fSJustin T. Gibbs 		status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
2066fda903fSJustin T. Gibbs 					  targbhstart,
2076fda903fSJustin T. Gibbs 					  "targbh", CAM_PERIPH_BIO,
2086fda903fSJustin T. Gibbs 					  new_path, targbhasync,
2096fda903fSJustin T. Gibbs 					  AC_PATH_REGISTERED,
2106fda903fSJustin T. Gibbs 					  cpi);
2116fda903fSJustin T. Gibbs 		break;
2126fda903fSJustin T. Gibbs 	}
2136fda903fSJustin T. Gibbs 	case AC_PATH_DEREGISTERED:
2146fda903fSJustin T. Gibbs 	{
21560ddd2e4SHidetoshi Shimokawa 		struct cam_periph *periph;
21660ddd2e4SHidetoshi Shimokawa 
21760ddd2e4SHidetoshi Shimokawa 		if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
21860ddd2e4SHidetoshi Shimokawa 			cam_periph_invalidate(periph);
2196fda903fSJustin T. Gibbs 		break;
2206fda903fSJustin T. Gibbs 	}
2216fda903fSJustin T. Gibbs 	default:
2226fda903fSJustin T. Gibbs 		break;
2236fda903fSJustin T. Gibbs 	}
224388f522dSHidetoshi Shimokawa 	xpt_free_path(new_path);
2256fda903fSJustin T. Gibbs }
2266fda903fSJustin T. Gibbs 
2276fda903fSJustin T. Gibbs /* Attempt to enable our lun */
2286fda903fSJustin T. Gibbs static cam_status
targbhenlun(struct cam_periph * periph)2296fda903fSJustin T. Gibbs targbhenlun(struct cam_periph *periph)
2306fda903fSJustin T. Gibbs {
2316fda903fSJustin T. Gibbs 	union ccb immed_ccb;
2326fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
2336fda903fSJustin T. Gibbs 	cam_status status;
2346fda903fSJustin T. Gibbs 	int i;
2356fda903fSJustin T. Gibbs 
2366fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)periph->softc;
2376fda903fSJustin T. Gibbs 
2386fda903fSJustin T. Gibbs 	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
2396fda903fSJustin T. Gibbs 		return (CAM_REQ_CMP);
2406fda903fSJustin T. Gibbs 
241616a676aSEdward Tomasz Napierala 	memset(&immed_ccb, 0, sizeof(immed_ccb));
242bbfa4aa1SAlexander Motin 	xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
2436fda903fSJustin T. Gibbs 	immed_ccb.ccb_h.func_code = XPT_EN_LUN;
2446fda903fSJustin T. Gibbs 
2456fda903fSJustin T. Gibbs 	/* Don't need support for any vendor specific commands */
2466fda903fSJustin T. Gibbs 	immed_ccb.cel.grp6_len = 0;
2476fda903fSJustin T. Gibbs 	immed_ccb.cel.grp7_len = 0;
2486fda903fSJustin T. Gibbs 	immed_ccb.cel.enable = 1;
2496fda903fSJustin T. Gibbs 	xpt_action(&immed_ccb);
2506fda903fSJustin T. Gibbs 	status = immed_ccb.ccb_h.status;
2516fda903fSJustin T. Gibbs 	if (status != CAM_REQ_CMP) {
252f0d9af51SMatt Jacob 		xpt_print(periph->path,
253f0d9af51SMatt Jacob 		    "targbhenlun - Enable Lun Rejected with status 0x%x\n",
2546fda903fSJustin T. Gibbs 		    status);
2556fda903fSJustin T. Gibbs 		return (status);
2566fda903fSJustin T. Gibbs 	}
2576fda903fSJustin T. Gibbs 
2586fda903fSJustin T. Gibbs 	softc->flags |= TARGBH_FLAG_LUN_ENABLED;
2596fda903fSJustin T. Gibbs 
2606fda903fSJustin T. Gibbs 	/*
2616fda903fSJustin T. Gibbs 	 * Build up a buffer of accept target I/O
2626fda903fSJustin T. Gibbs 	 * operations for incoming selections.
2636fda903fSJustin T. Gibbs 	 */
2646fda903fSJustin T. Gibbs 	for (i = 0; i < MAX_ACCEPT; i++) {
2656fda903fSJustin T. Gibbs 		struct ccb_accept_tio *atio;
2666fda903fSJustin T. Gibbs 
267362abc44STai-hwa Liang 		atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH,
268616a676aSEdward Tomasz Napierala 						      M_ZERO | M_NOWAIT);
2696fda903fSJustin T. Gibbs 		if (atio == NULL) {
2706fda903fSJustin T. Gibbs 			status = CAM_RESRC_UNAVAIL;
2716fda903fSJustin T. Gibbs 			break;
2726fda903fSJustin T. Gibbs 		}
2736fda903fSJustin T. Gibbs 
2746fda903fSJustin T. Gibbs 		atio->ccb_h.ccb_descr = targbhallocdescr();
2756fda903fSJustin T. Gibbs 
2766fda903fSJustin T. Gibbs 		if (atio->ccb_h.ccb_descr == NULL) {
277362abc44STai-hwa Liang 			free(atio, M_SCSIBH);
2786fda903fSJustin T. Gibbs 			status = CAM_RESRC_UNAVAIL;
2796fda903fSJustin T. Gibbs 			break;
2806fda903fSJustin T. Gibbs 		}
2816fda903fSJustin T. Gibbs 
282bbfa4aa1SAlexander Motin 		xpt_setup_ccb(&atio->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
2836fda903fSJustin T. Gibbs 		atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
2846fda903fSJustin T. Gibbs 		atio->ccb_h.cbfcnp = targbhdone;
2856fda903fSJustin T. Gibbs 		((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
2866fda903fSJustin T. Gibbs 		    softc->accept_tio_list;
2876fda903fSJustin T. Gibbs 		softc->accept_tio_list = atio;
288d1d536f0SAlexander Motin 		xpt_action((union ccb *)atio);
289d1d536f0SAlexander Motin 		status = atio->ccb_h.status;
290d1d536f0SAlexander Motin 		if (status != CAM_REQ_INPROG)
291d1d536f0SAlexander Motin 			break;
2926fda903fSJustin T. Gibbs 	}
2936fda903fSJustin T. Gibbs 
2946fda903fSJustin T. Gibbs 	if (i == 0) {
295f0d9af51SMatt Jacob 		xpt_print(periph->path,
296f0d9af51SMatt Jacob 		    "targbhenlun - Could not allocate accept tio CCBs: status "
297f0d9af51SMatt Jacob 		    "= 0x%x\n", status);
2986fda903fSJustin T. Gibbs 		targbhdislun(periph);
2996fda903fSJustin T. Gibbs 		return (CAM_REQ_CMP_ERR);
3006fda903fSJustin T. Gibbs 	}
3016fda903fSJustin T. Gibbs 
3026fda903fSJustin T. Gibbs 	/*
3036fda903fSJustin T. Gibbs 	 * Build up a buffer of immediate notify CCBs
3046fda903fSJustin T. Gibbs 	 * so the SIM can tell us of asynchronous target mode events.
3056fda903fSJustin T. Gibbs 	 */
3066fda903fSJustin T. Gibbs 	for (i = 0; i < MAX_ACCEPT; i++) {
3071d64933fSAlexander Motin 		struct ccb_immediate_notify *inot;
3086fda903fSJustin T. Gibbs 
3091d64933fSAlexander Motin 		inot = (struct ccb_immediate_notify*)malloc(sizeof(*inot),
310616a676aSEdward Tomasz Napierala 			    M_SCSIBH, M_ZERO | M_NOWAIT);
3116fda903fSJustin T. Gibbs 
3126fda903fSJustin T. Gibbs 		if (inot == NULL) {
3136fda903fSJustin T. Gibbs 			status = CAM_RESRC_UNAVAIL;
3146fda903fSJustin T. Gibbs 			break;
3156fda903fSJustin T. Gibbs 		}
3166fda903fSJustin T. Gibbs 
317bbfa4aa1SAlexander Motin 		xpt_setup_ccb(&inot->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3181d64933fSAlexander Motin 		inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
3196fda903fSJustin T. Gibbs 		inot->ccb_h.cbfcnp = targbhdone;
3206fda903fSJustin T. Gibbs 		SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
3216fda903fSJustin T. Gibbs 				  periph_links.sle);
322d1d536f0SAlexander Motin 		xpt_action((union ccb *)inot);
323d1d536f0SAlexander Motin 		status = inot->ccb_h.status;
324d1d536f0SAlexander Motin 		if (status != CAM_REQ_INPROG)
325d1d536f0SAlexander Motin 			break;
3266fda903fSJustin T. Gibbs 	}
3276fda903fSJustin T. Gibbs 
3286fda903fSJustin T. Gibbs 	if (i == 0) {
329f0d9af51SMatt Jacob 		xpt_print(periph->path,
330f0d9af51SMatt Jacob 		    "targbhenlun - Could not allocate immediate notify "
3316fda903fSJustin T. Gibbs 		    "CCBs: status = 0x%x\n", status);
3326fda903fSJustin T. Gibbs 		targbhdislun(periph);
3336fda903fSJustin T. Gibbs 		return (CAM_REQ_CMP_ERR);
3346fda903fSJustin T. Gibbs 	}
3356fda903fSJustin T. Gibbs 
3366fda903fSJustin T. Gibbs 	return (CAM_REQ_CMP);
3376fda903fSJustin T. Gibbs }
3386fda903fSJustin T. Gibbs 
3396fda903fSJustin T. Gibbs static cam_status
targbhdislun(struct cam_periph * periph)3406fda903fSJustin T. Gibbs targbhdislun(struct cam_periph *periph)
3416fda903fSJustin T. Gibbs {
3426fda903fSJustin T. Gibbs 	union ccb ccb;
3436fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
3446fda903fSJustin T. Gibbs 	struct ccb_accept_tio* atio;
3456fda903fSJustin T. Gibbs 	struct ccb_hdr *ccb_h;
3466fda903fSJustin T. Gibbs 
3476fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)periph->softc;
3486fda903fSJustin T. Gibbs 	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
3496fda903fSJustin T. Gibbs 		return CAM_REQ_CMP;
3506fda903fSJustin T. Gibbs 
351616a676aSEdward Tomasz Napierala 	memset(&ccb, 0, sizeof(ccb));
352616a676aSEdward Tomasz Napierala 
3536fda903fSJustin T. Gibbs 	/* XXX Block for Continue I/O completion */
3546fda903fSJustin T. Gibbs 
3556fda903fSJustin T. Gibbs 	/* Kill off all ACCECPT and IMMEDIATE CCBs */
3566fda903fSJustin T. Gibbs 	while ((atio = softc->accept_tio_list) != NULL) {
3576fda903fSJustin T. Gibbs 
3586fda903fSJustin T. Gibbs 		softc->accept_tio_list =
3596fda903fSJustin T. Gibbs 		    ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
360bbfa4aa1SAlexander Motin 		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3616fda903fSJustin T. Gibbs 		ccb.cab.ccb_h.func_code = XPT_ABORT;
3626fda903fSJustin T. Gibbs 		ccb.cab.abort_ccb = (union ccb *)atio;
3636fda903fSJustin T. Gibbs 		xpt_action(&ccb);
3646fda903fSJustin T. Gibbs 	}
3656fda903fSJustin T. Gibbs 
3666fda903fSJustin T. Gibbs 	while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
3676fda903fSJustin T. Gibbs 		SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
368bbfa4aa1SAlexander Motin 		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3696fda903fSJustin T. Gibbs 		ccb.cab.ccb_h.func_code = XPT_ABORT;
3706fda903fSJustin T. Gibbs 		ccb.cab.abort_ccb = (union ccb *)ccb_h;
3716fda903fSJustin T. Gibbs 		xpt_action(&ccb);
3726fda903fSJustin T. Gibbs 	}
3736fda903fSJustin T. Gibbs 
3746fda903fSJustin T. Gibbs 	/*
3756fda903fSJustin T. Gibbs 	 * Dissable this lun.
3766fda903fSJustin T. Gibbs 	 */
377bbfa4aa1SAlexander Motin 	xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3786fda903fSJustin T. Gibbs 	ccb.cel.ccb_h.func_code = XPT_EN_LUN;
3796fda903fSJustin T. Gibbs 	ccb.cel.enable = 0;
3806fda903fSJustin T. Gibbs 	xpt_action(&ccb);
3816fda903fSJustin T. Gibbs 
3826fda903fSJustin T. Gibbs 	if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
3836fda903fSJustin T. Gibbs 		printf("targbhdislun - Disabling lun on controller failed "
3846fda903fSJustin T. Gibbs 		       "with status 0x%x\n", ccb.cel.ccb_h.status);
3856fda903fSJustin T. Gibbs 	else
3866fda903fSJustin T. Gibbs 		softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
3876fda903fSJustin T. Gibbs 	return (ccb.cel.ccb_h.status);
3886fda903fSJustin T. Gibbs }
3896fda903fSJustin T. Gibbs 
3906fda903fSJustin T. Gibbs static cam_status
targbhctor(struct cam_periph * periph,void * arg)3916fda903fSJustin T. Gibbs targbhctor(struct cam_periph *periph, void *arg)
3926fda903fSJustin T. Gibbs {
3936fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
3946fda903fSJustin T. Gibbs 
3956fda903fSJustin T. Gibbs 	/* Allocate our per-instance private storage */
3966fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)malloc(sizeof(*softc),
397362abc44STai-hwa Liang 					      M_SCSIBH, M_NOWAIT);
3986fda903fSJustin T. Gibbs 	if (softc == NULL) {
3996fda903fSJustin T. Gibbs 		printf("targctor: unable to malloc softc\n");
4006fda903fSJustin T. Gibbs 		return (CAM_REQ_CMP_ERR);
4016fda903fSJustin T. Gibbs 	}
4026fda903fSJustin T. Gibbs 
403966a2adfSMatt Jacob 	bzero(softc, sizeof(*softc));
4046fda903fSJustin T. Gibbs 	TAILQ_INIT(&softc->pending_queue);
4056fda903fSJustin T. Gibbs 	TAILQ_INIT(&softc->work_queue);
4066fda903fSJustin T. Gibbs 	softc->accept_tio_list = NULL;
4076fda903fSJustin T. Gibbs 	SLIST_INIT(&softc->immed_notify_slist);
4086fda903fSJustin T. Gibbs 	softc->state = TARGBH_STATE_NORMAL;
4096fda903fSJustin T. Gibbs 	periph->softc = softc;
4106fda903fSJustin T. Gibbs 	softc->init_level++;
4116fda903fSJustin T. Gibbs 
412d1d536f0SAlexander Motin 	if (targbhenlun(periph) != CAM_REQ_CMP)
413d1d536f0SAlexander Motin 		cam_periph_invalidate(periph);
414d1d536f0SAlexander Motin 	return (CAM_REQ_CMP);
4156fda903fSJustin T. Gibbs }
4166fda903fSJustin T. Gibbs 
4176fda903fSJustin T. Gibbs static void
targbhdtor(struct cam_periph * periph)4186fda903fSJustin T. Gibbs targbhdtor(struct cam_periph *periph)
4196fda903fSJustin T. Gibbs {
4206fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
4216fda903fSJustin T. Gibbs 
4226fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)periph->softc;
4236fda903fSJustin T. Gibbs 
4246fda903fSJustin T. Gibbs 	softc->state = TARGBH_STATE_TEARDOWN;
4256fda903fSJustin T. Gibbs 
4266fda903fSJustin T. Gibbs 	targbhdislun(periph);
4276fda903fSJustin T. Gibbs 
4286fda903fSJustin T. Gibbs 	switch (softc->init_level) {
4296fda903fSJustin T. Gibbs 	case 0:
430c2ede4b3SMartin Blapp 		panic("targdtor - impossible init level");
43182dcf708SPoul-Henning Kamp 	case 1:
43282dcf708SPoul-Henning Kamp 		/* FALLTHROUGH */
43382dcf708SPoul-Henning Kamp 	default:
434388f522dSHidetoshi Shimokawa 		/* XXX Wait for callback of targbhdislun() */
435227d67aaSAlexander Motin 		cam_periph_sleep(periph, softc, PRIBIO, "targbh", hz/2);
436362abc44STai-hwa Liang 		free(softc, M_SCSIBH);
43782dcf708SPoul-Henning Kamp 		break;
4386fda903fSJustin T. Gibbs 	}
4396fda903fSJustin T. Gibbs }
4406fda903fSJustin T. Gibbs 
4416fda903fSJustin T. Gibbs static void
targbhstart(struct cam_periph * periph,union ccb * start_ccb)4426fda903fSJustin T. Gibbs targbhstart(struct cam_periph *periph, union ccb *start_ccb)
4436fda903fSJustin T. Gibbs {
4446fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
4456fda903fSJustin T. Gibbs 	struct ccb_hdr *ccbh;
4466fda903fSJustin T. Gibbs 	struct ccb_accept_tio *atio;
4476fda903fSJustin T. Gibbs 	struct targbh_cmd_desc *desc;
4486fda903fSJustin T. Gibbs 	struct ccb_scsiio *csio;
4496fda903fSJustin T. Gibbs 	ccb_flags flags;
4506fda903fSJustin T. Gibbs 
4516fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)periph->softc;
4526fda903fSJustin T. Gibbs 
4536fda903fSJustin T. Gibbs 	ccbh = TAILQ_FIRST(&softc->work_queue);
454227d67aaSAlexander Motin 	if (ccbh == NULL) {
4556fda903fSJustin T. Gibbs 		xpt_release_ccb(start_ccb);
4566fda903fSJustin T. Gibbs 	} else {
4576fda903fSJustin T. Gibbs 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
4586fda903fSJustin T. Gibbs 		TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
4596fda903fSJustin T. Gibbs 				  periph_links.tqe);
4606fda903fSJustin T. Gibbs 		atio = (struct ccb_accept_tio*)ccbh;
4616fda903fSJustin T. Gibbs 		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
4626fda903fSJustin T. Gibbs 
4636fda903fSJustin T. Gibbs 		/* Is this a tagged request? */
464c2accd34SMatt Jacob 		flags = atio->ccb_h.flags &
465c2accd34SMatt Jacob 		    (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
4666fda903fSJustin T. Gibbs 
467471da226SMatt Jacob 		csio = &start_ccb->csio;
4686fda903fSJustin T. Gibbs 		/*
4696fda903fSJustin T. Gibbs 		 * If we are done with the transaction, tell the
4706fda903fSJustin T. Gibbs 		 * controller to send status and perform a CMD_CMPLT.
471471da226SMatt Jacob 		 * If we have associated sense data, see if we can
472471da226SMatt Jacob 		 * send that too.
4736fda903fSJustin T. Gibbs 		 */
474471da226SMatt Jacob 		if (desc->data_resid == desc->data_increment) {
4756fda903fSJustin T. Gibbs 			flags |= CAM_SEND_STATUS;
476471da226SMatt Jacob 			if (atio->sense_len) {
477471da226SMatt Jacob 				csio->sense_len = atio->sense_len;
478471da226SMatt Jacob 				csio->sense_data = atio->sense_data;
479471da226SMatt Jacob 				flags |= CAM_SEND_SENSE;
480471da226SMatt Jacob 			}
481471da226SMatt Jacob 		}
482471da226SMatt Jacob 
4836fda903fSJustin T. Gibbs 		cam_fill_ctio(csio,
4846fda903fSJustin T. Gibbs 			      /*retries*/2,
4856fda903fSJustin T. Gibbs 			      targbhdone,
4866fda903fSJustin T. Gibbs 			      flags,
4876bd19f42SMatt Jacob 			      (flags & CAM_TAG_ACTION_VALID)?
4886bd19f42SMatt Jacob 				MSG_SIMPLE_Q_TAG : 0,
4896fda903fSJustin T. Gibbs 			      atio->tag_id,
4906fda903fSJustin T. Gibbs 			      atio->init_id,
4916fda903fSJustin T. Gibbs 			      desc->status,
4926fda903fSJustin T. Gibbs 			      /*data_ptr*/desc->data_increment == 0
4936fda903fSJustin T. Gibbs 					  ? NULL : desc->data,
4946fda903fSJustin T. Gibbs 			      /*dxfer_len*/desc->data_increment,
4956fda903fSJustin T. Gibbs 			      /*timeout*/desc->timeout);
4966fda903fSJustin T. Gibbs 
4976fda903fSJustin T. Gibbs 		/* Override our wildcard attachment */
4986fda903fSJustin T. Gibbs 		start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
4996fda903fSJustin T. Gibbs 		start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
5006fda903fSJustin T. Gibbs 
5016fda903fSJustin T. Gibbs 		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
5026fda903fSJustin T. Gibbs 		start_ccb->ccb_h.ccb_atio = atio;
5036fda903fSJustin T. Gibbs 		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
5046fda903fSJustin T. Gibbs 			  ("Sending a CTIO\n"));
5056fda903fSJustin T. Gibbs 		xpt_action(start_ccb);
506c2accd34SMatt Jacob 		/*
507c2accd34SMatt Jacob 		 * If the queue was frozen waiting for the response
508c2accd34SMatt Jacob 		 * to this ATIO (for instance disconnection was disallowed),
509c2accd34SMatt Jacob 		 * then release it now that our response has been queued.
510c2accd34SMatt Jacob 		 */
511c2accd34SMatt Jacob 		if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
512c2accd34SMatt Jacob 			cam_release_devq(periph->path,
513c2accd34SMatt Jacob 					 /*relsim_flags*/0,
514c2accd34SMatt Jacob 					 /*reduction*/0,
515c2accd34SMatt Jacob 					 /*timeout*/0,
516c2accd34SMatt Jacob 					 /*getcount_only*/0);
517c2accd34SMatt Jacob 			atio->ccb_h.status &= ~CAM_DEV_QFRZN;
518c2accd34SMatt Jacob 		}
5196fda903fSJustin T. Gibbs 		ccbh = TAILQ_FIRST(&softc->work_queue);
5206fda903fSJustin T. Gibbs 	}
5216fda903fSJustin T. Gibbs 	if (ccbh != NULL)
522bbfa4aa1SAlexander Motin 		xpt_schedule(periph, CAM_PRIORITY_NORMAL);
5236fda903fSJustin T. Gibbs }
5246fda903fSJustin T. Gibbs 
5256fda903fSJustin T. Gibbs static void
targbhdone(struct cam_periph * periph,union ccb * done_ccb)5266fda903fSJustin T. Gibbs targbhdone(struct cam_periph *periph, union ccb *done_ccb)
5276fda903fSJustin T. Gibbs {
5286fda903fSJustin T. Gibbs 	struct targbh_softc *softc;
5296fda903fSJustin T. Gibbs 
5306fda903fSJustin T. Gibbs 	softc = (struct targbh_softc *)periph->softc;
5316fda903fSJustin T. Gibbs 
5326fda903fSJustin T. Gibbs 	switch (done_ccb->ccb_h.func_code) {
5336fda903fSJustin T. Gibbs 	case XPT_ACCEPT_TARGET_IO:
5346fda903fSJustin T. Gibbs 	{
5356fda903fSJustin T. Gibbs 		struct ccb_accept_tio *atio;
5366fda903fSJustin T. Gibbs 		struct targbh_cmd_desc *descr;
537*7c5d20a6SWarner Losh 		uint8_t *cdb;
538c2accd34SMatt Jacob 		int priority;
5396fda903fSJustin T. Gibbs 
5406fda903fSJustin T. Gibbs 		atio = &done_ccb->atio;
5416fda903fSJustin T. Gibbs 		descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
5426fda903fSJustin T. Gibbs 		cdb = atio->cdb_io.cdb_bytes;
5436fda903fSJustin T. Gibbs 		if (softc->state == TARGBH_STATE_TEARDOWN
5446fda903fSJustin T. Gibbs 		 || atio->ccb_h.status == CAM_REQ_ABORTED) {
5456fda903fSJustin T. Gibbs 			targbhfreedescr(descr);
546362abc44STai-hwa Liang 			xpt_free_ccb(done_ccb);
5476fda903fSJustin T. Gibbs 			return;
5486fda903fSJustin T. Gibbs 		}
5496fda903fSJustin T. Gibbs 
5506fda903fSJustin T. Gibbs 		/*
5516fda903fSJustin T. Gibbs 		 * Determine the type of incoming command and
5526fda903fSJustin T. Gibbs 		 * setup our buffer for a response.
5536fda903fSJustin T. Gibbs 		 */
5546fda903fSJustin T. Gibbs 		switch (cdb[0]) {
5556fda903fSJustin T. Gibbs 		case INQUIRY:
5566fda903fSJustin T. Gibbs 		{
5576fda903fSJustin T. Gibbs 			struct scsi_inquiry *inq;
5586fda903fSJustin T. Gibbs 
5596fda903fSJustin T. Gibbs 			inq = (struct scsi_inquiry *)cdb;
5606fda903fSJustin T. Gibbs 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
5616fda903fSJustin T. Gibbs 				  ("Saw an inquiry!\n"));
5626fda903fSJustin T. Gibbs 			/*
5636fda903fSJustin T. Gibbs 			 * Validate the command.  We don't
5646fda903fSJustin T. Gibbs 			 * support any VPD pages, so complain
5656fda903fSJustin T. Gibbs 			 * if EVPD is set.
5666fda903fSJustin T. Gibbs 			 */
5676fda903fSJustin T. Gibbs 			if ((inq->byte2 & SI_EVPD) != 0
5686fda903fSJustin T. Gibbs 			 || inq->page_code != 0) {
5696fda903fSJustin T. Gibbs 				atio->ccb_h.flags &= ~CAM_DIR_MASK;
5706fda903fSJustin T. Gibbs 				atio->ccb_h.flags |= CAM_DIR_NONE;
571471da226SMatt Jacob 				/*
572471da226SMatt Jacob 				 * This needs to have other than a
573471da226SMatt Jacob 				 * no_lun_sense_data response.
574471da226SMatt Jacob 				 */
5751cc052e8SKenneth D. Merry 				bcopy(&no_lun_sense_data, &atio->sense_data,
5761cc052e8SKenneth D. Merry 				      min(sizeof(no_lun_sense_data),
5771cc052e8SKenneth D. Merry 					  sizeof(atio->sense_data)));
578471da226SMatt Jacob 				atio->sense_len = sizeof(no_lun_sense_data);
5796fda903fSJustin T. Gibbs 				descr->data_resid = 0;
5806fda903fSJustin T. Gibbs 				descr->data_increment = 0;
5816fda903fSJustin T. Gibbs 				descr->status = SCSI_STATUS_CHECK_COND;
5826fda903fSJustin T. Gibbs 				break;
5836fda903fSJustin T. Gibbs 			}
5846fda903fSJustin T. Gibbs 			/*
5856fda903fSJustin T. Gibbs 			 * Direction is always relative
5866fda903fSJustin T. Gibbs 			 * to the initator.
5876fda903fSJustin T. Gibbs 			 */
5886fda903fSJustin T. Gibbs 			atio->ccb_h.flags &= ~CAM_DIR_MASK;
5896fda903fSJustin T. Gibbs 			atio->ccb_h.flags |= CAM_DIR_IN;
5906fda903fSJustin T. Gibbs 			descr->data = &no_lun_inq_data;
5916fda903fSJustin T. Gibbs 			descr->data_resid = MIN(sizeof(no_lun_inq_data),
592130f4520SKenneth D. Merry 						scsi_2btoul(inq->length));
5936fda903fSJustin T. Gibbs 			descr->data_increment = descr->data_resid;
5946fda903fSJustin T. Gibbs 			descr->timeout = 5 * 1000;
5956fda903fSJustin T. Gibbs 			descr->status = SCSI_STATUS_OK;
5966fda903fSJustin T. Gibbs 			break;
5976fda903fSJustin T. Gibbs 		}
5986fda903fSJustin T. Gibbs 		case REQUEST_SENSE:
5996fda903fSJustin T. Gibbs 		{
6006fda903fSJustin T. Gibbs 			struct scsi_request_sense *rsense;
6016fda903fSJustin T. Gibbs 
6026fda903fSJustin T. Gibbs 			rsense = (struct scsi_request_sense *)cdb;
6036fda903fSJustin T. Gibbs 			/* Refer to static sense data */
6046fda903fSJustin T. Gibbs 			atio->ccb_h.flags &= ~CAM_DIR_MASK;
6056fda903fSJustin T. Gibbs 			atio->ccb_h.flags |= CAM_DIR_IN;
6066fda903fSJustin T. Gibbs 			descr->data = &no_lun_sense_data;
6076fda903fSJustin T. Gibbs 			descr->data_resid = request_sense_size;
6086fda903fSJustin T. Gibbs 			descr->data_resid = MIN(descr->data_resid,
609966a2adfSMatt Jacob 						SCSI_CDB6_LEN(rsense->length));
6106fda903fSJustin T. Gibbs 			descr->data_increment = descr->data_resid;
6116fda903fSJustin T. Gibbs 			descr->timeout = 5 * 1000;
6126fda903fSJustin T. Gibbs 			descr->status = SCSI_STATUS_OK;
6136fda903fSJustin T. Gibbs 			break;
6146fda903fSJustin T. Gibbs 		}
6156fda903fSJustin T. Gibbs 		default:
6166fda903fSJustin T. Gibbs 			/* Constant CA, tell initiator */
6176fda903fSJustin T. Gibbs 			/* Direction is always relative to the initator */
6186fda903fSJustin T. Gibbs 			atio->ccb_h.flags &= ~CAM_DIR_MASK;
6196fda903fSJustin T. Gibbs 			atio->ccb_h.flags |= CAM_DIR_NONE;
6201cc052e8SKenneth D. Merry 			bcopy(&no_lun_sense_data, &atio->sense_data,
6211cc052e8SKenneth D. Merry 			      min(sizeof(no_lun_sense_data),
6221cc052e8SKenneth D. Merry 				  sizeof(atio->sense_data)));
623471da226SMatt Jacob 			atio->sense_len = sizeof (no_lun_sense_data);
6246fda903fSJustin T. Gibbs 			descr->data_resid = 0;
6256fda903fSJustin T. Gibbs 			descr->data_increment = 0;
6266fda903fSJustin T. Gibbs 			descr->timeout = 5 * 1000;
6276fda903fSJustin T. Gibbs 			descr->status = SCSI_STATUS_CHECK_COND;
6286fda903fSJustin T. Gibbs 			break;
6296fda903fSJustin T. Gibbs 		}
6306fda903fSJustin T. Gibbs 
6316fda903fSJustin T. Gibbs 		/* Queue us up to receive a Continue Target I/O ccb. */
632c2accd34SMatt Jacob 		if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
633c2accd34SMatt Jacob 			TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
634c2accd34SMatt Jacob 					  periph_links.tqe);
635c2accd34SMatt Jacob 			priority = 0;
636c2accd34SMatt Jacob 		} else {
6376fda903fSJustin T. Gibbs 			TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
6386fda903fSJustin T. Gibbs 					  periph_links.tqe);
639bbfa4aa1SAlexander Motin 			priority = CAM_PRIORITY_NORMAL;
640c2accd34SMatt Jacob 		}
641c2accd34SMatt Jacob 		xpt_schedule(periph, priority);
6426fda903fSJustin T. Gibbs 		break;
6436fda903fSJustin T. Gibbs 	}
6446fda903fSJustin T. Gibbs 	case XPT_CONT_TARGET_IO:
6456fda903fSJustin T. Gibbs 	{
6466fda903fSJustin T. Gibbs 		struct ccb_accept_tio *atio;
6476fda903fSJustin T. Gibbs 		struct targbh_cmd_desc *desc;
6486fda903fSJustin T. Gibbs 
6496fda903fSJustin T. Gibbs 		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
6506fda903fSJustin T. Gibbs 			  ("Received completed CTIO\n"));
6516fda903fSJustin T. Gibbs 		atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
6526fda903fSJustin T. Gibbs 		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
6536fda903fSJustin T. Gibbs 
6546fda903fSJustin T. Gibbs 		TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
6556fda903fSJustin T. Gibbs 			     periph_links.tqe);
6566fda903fSJustin T. Gibbs 
657471da226SMatt Jacob 		/*
658471da226SMatt Jacob 		 * We could check for CAM_SENT_SENSE bein set here,
659471da226SMatt Jacob 		 * but since we're not maintaining any CA/UA state,
660471da226SMatt Jacob 		 * there's no point.
661471da226SMatt Jacob 		 */
662471da226SMatt Jacob 		atio->sense_len = 0;
663471da226SMatt Jacob 		done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
664471da226SMatt Jacob 		done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
665471da226SMatt Jacob 
666c2accd34SMatt Jacob 		/*
667c2accd34SMatt Jacob 		 * Any errors will not change the data we return,
668c2accd34SMatt Jacob 		 * so make sure the queue is not left frozen.
669c2accd34SMatt Jacob 		 * XXX - At some point there may be errors that
670c2accd34SMatt Jacob 		 *       leave us in a connected state with the
671c2accd34SMatt Jacob 		 *       initiator...
672c2accd34SMatt Jacob 		 */
673c2accd34SMatt Jacob 		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
674c2accd34SMatt Jacob 			printf("Releasing Queue\n");
675c2accd34SMatt Jacob 			cam_release_devq(done_ccb->ccb_h.path,
676c2accd34SMatt Jacob 					 /*relsim_flags*/0,
677c2accd34SMatt Jacob 					 /*reduction*/0,
678c2accd34SMatt Jacob 					 /*timeout*/0,
679c2accd34SMatt Jacob 					 /*getcount_only*/0);
680c2accd34SMatt Jacob 			done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
681c2accd34SMatt Jacob 		}
6826fda903fSJustin T. Gibbs 		desc->data_resid -= desc->data_increment;
6836fda903fSJustin T. Gibbs 		xpt_release_ccb(done_ccb);
6846fda903fSJustin T. Gibbs 		if (softc->state != TARGBH_STATE_TEARDOWN) {
6856fda903fSJustin T. Gibbs 			/*
6866fda903fSJustin T. Gibbs 			 * Send the original accept TIO back to the
6876fda903fSJustin T. Gibbs 			 * controller to handle more work.
6886fda903fSJustin T. Gibbs 			 */
6896fda903fSJustin T. Gibbs 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
6906fda903fSJustin T. Gibbs 				  ("Returning ATIO to target\n"));
6916fda903fSJustin T. Gibbs 			/* Restore wildcards */
6926fda903fSJustin T. Gibbs 			atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
6936fda903fSJustin T. Gibbs 			atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
6946fda903fSJustin T. Gibbs 			xpt_action((union ccb *)atio);
6956fda903fSJustin T. Gibbs 			break;
6966fda903fSJustin T. Gibbs 		} else {
6976fda903fSJustin T. Gibbs 			targbhfreedescr(desc);
698362abc44STai-hwa Liang 			free(atio, M_SCSIBH);
6996fda903fSJustin T. Gibbs 		}
7006fda903fSJustin T. Gibbs 		break;
7016fda903fSJustin T. Gibbs 	}
7021d64933fSAlexander Motin 	case XPT_IMMEDIATE_NOTIFY:
7036fda903fSJustin T. Gibbs 	{
704c2accd34SMatt Jacob 		int frozen;
705c2accd34SMatt Jacob 
706c2accd34SMatt Jacob 		frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
7076fda903fSJustin T. Gibbs 		if (softc->state == TARGBH_STATE_TEARDOWN
7086fda903fSJustin T. Gibbs 		 || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
7096fda903fSJustin T. Gibbs 			printf("Freed an immediate notify\n");
710362abc44STai-hwa Liang 			xpt_free_ccb(done_ccb);
711c2accd34SMatt Jacob 		} else {
712c2accd34SMatt Jacob 			/* Requeue for another immediate event */
713c2accd34SMatt Jacob 			xpt_action(done_ccb);
7146fda903fSJustin T. Gibbs 		}
715c2accd34SMatt Jacob 		if (frozen != 0)
716c2accd34SMatt Jacob 			cam_release_devq(periph->path,
717c2accd34SMatt Jacob 					 /*relsim_flags*/0,
718c2accd34SMatt Jacob 					 /*opening reduction*/0,
719c2accd34SMatt Jacob 					 /*timeout*/0,
720c2accd34SMatt Jacob 					 /*getcount_only*/0);
7216fda903fSJustin T. Gibbs 		break;
7226fda903fSJustin T. Gibbs 	}
723e7783a9fSJustin T. Gibbs 	default:
724e7783a9fSJustin T. Gibbs 		panic("targbhdone: Unexpected ccb opcode");
725e7783a9fSJustin T. Gibbs 		break;
7266fda903fSJustin T. Gibbs 	}
7276fda903fSJustin T. Gibbs }
7286fda903fSJustin T. Gibbs 
729e7783a9fSJustin T. Gibbs #ifdef NOTYET
7306fda903fSJustin T. Gibbs static int
targbherror(union ccb * ccb,uint32_t cam_flags,uint32_t sense_flags)731*7c5d20a6SWarner Losh targbherror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
7326fda903fSJustin T. Gibbs {
7336fda903fSJustin T. Gibbs 	return 0;
7346fda903fSJustin T. Gibbs }
735e7783a9fSJustin T. Gibbs #endif
7366fda903fSJustin T. Gibbs 
7376fda903fSJustin T. Gibbs static struct targbh_cmd_desc*
targbhallocdescr(void)7389982b3eeSConrad Meyer targbhallocdescr(void)
7396fda903fSJustin T. Gibbs {
7406fda903fSJustin T. Gibbs 	struct targbh_cmd_desc* descr;
7416fda903fSJustin T. Gibbs 
7426fda903fSJustin T. Gibbs 	/* Allocate the targbh_descr structure */
7436fda903fSJustin T. Gibbs 	descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
744362abc44STai-hwa Liang 					       M_SCSIBH, M_NOWAIT);
7456fda903fSJustin T. Gibbs 	if (descr == NULL)
7466fda903fSJustin T. Gibbs 		return (NULL);
7476fda903fSJustin T. Gibbs 
7486fda903fSJustin T. Gibbs 	bzero(descr, sizeof(*descr));
7496fda903fSJustin T. Gibbs 
7506fda903fSJustin T. Gibbs 	/* Allocate buffer backing store */
751362abc44STai-hwa Liang 	descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT);
7526fda903fSJustin T. Gibbs 	if (descr->backing_store == NULL) {
753362abc44STai-hwa Liang 		free(descr, M_SCSIBH);
7546fda903fSJustin T. Gibbs 		return (NULL);
7556fda903fSJustin T. Gibbs 	}
7566fda903fSJustin T. Gibbs 	descr->max_size = MAX_BUF_SIZE;
7576fda903fSJustin T. Gibbs 	return (descr);
7586fda903fSJustin T. Gibbs }
7596fda903fSJustin T. Gibbs 
7606fda903fSJustin T. Gibbs static void
targbhfreedescr(struct targbh_cmd_desc * descr)7616fda903fSJustin T. Gibbs targbhfreedescr(struct targbh_cmd_desc *descr)
7626fda903fSJustin T. Gibbs {
763362abc44STai-hwa Liang 	free(descr->backing_store, M_SCSIBH);
764362abc44STai-hwa Liang 	free(descr, M_SCSIBH);
7656fda903fSJustin T. Gibbs }
766