xref: /freebsd/sys/cam/ctl/scsi_ctl.c (revision ac7a514e20f394ffed0126c0c356aa9107821880)
1130f4520SKenneth D. Merry /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3bec9534dSPedro F. Giffuni  *
4130f4520SKenneth D. Merry  * Copyright (c) 2008, 2009 Silicon Graphics International Corp.
559f063d5SAlexander Motin  * Copyright (c) 2014-2015 Alexander Motin <mav@FreeBSD.org>
6130f4520SKenneth D. Merry  * All rights reserved.
7130f4520SKenneth D. Merry  *
8130f4520SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
9130f4520SKenneth D. Merry  * modification, are permitted provided that the following conditions
10130f4520SKenneth D. Merry  * are met:
11130f4520SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
12130f4520SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
13130f4520SKenneth D. Merry  *    without modification.
14130f4520SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15130f4520SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
16130f4520SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
17130f4520SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
18130f4520SKenneth D. Merry  *    binary redistribution.
19130f4520SKenneth D. Merry  *
20130f4520SKenneth D. Merry  * NO WARRANTY
21130f4520SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22130f4520SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23130f4520SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
24130f4520SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25130f4520SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26130f4520SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27130f4520SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28130f4520SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29130f4520SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30130f4520SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31130f4520SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
32130f4520SKenneth D. Merry  *
33130f4520SKenneth D. Merry  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/scsi_ctl.c#4 $
34130f4520SKenneth D. Merry  */
35130f4520SKenneth D. Merry /*
36130f4520SKenneth D. Merry  * Peripheral driver interface between CAM and CTL (CAM Target Layer).
37130f4520SKenneth D. Merry  *
38130f4520SKenneth D. Merry  * Author: Ken Merry <ken@FreeBSD.org>
39130f4520SKenneth D. Merry  */
40130f4520SKenneth D. Merry 
41130f4520SKenneth D. Merry #include <sys/param.h>
42130f4520SKenneth D. Merry #include <sys/queue.h>
43130f4520SKenneth D. Merry #include <sys/systm.h>
44130f4520SKenneth D. Merry #include <sys/kernel.h>
45130f4520SKenneth D. Merry #include <sys/lock.h>
46130f4520SKenneth D. Merry #include <sys/mutex.h>
47130f4520SKenneth D. Merry #include <sys/condvar.h>
48130f4520SKenneth D. Merry #include <sys/malloc.h>
49130f4520SKenneth D. Merry #include <sys/bus.h>
50130f4520SKenneth D. Merry #include <sys/endian.h>
51130f4520SKenneth D. Merry #include <sys/sbuf.h>
52130f4520SKenneth D. Merry #include <sys/sysctl.h>
53130f4520SKenneth D. Merry #include <sys/types.h>
54130f4520SKenneth D. Merry #include <sys/systm.h>
553afd4806SAlexander Motin #include <sys/taskqueue.h>
56130f4520SKenneth D. Merry #include <machine/bus.h>
57130f4520SKenneth D. Merry 
58130f4520SKenneth D. Merry #include <cam/cam.h>
59130f4520SKenneth D. Merry #include <cam/cam_ccb.h>
60130f4520SKenneth D. Merry #include <cam/cam_periph.h>
61130f4520SKenneth D. Merry #include <cam/cam_queue.h>
62130f4520SKenneth D. Merry #include <cam/cam_xpt_periph.h>
63130f4520SKenneth D. Merry #include <cam/cam_debug.h>
64130f4520SKenneth D. Merry #include <cam/cam_sim.h>
65130f4520SKenneth D. Merry #include <cam/cam_xpt.h>
66130f4520SKenneth D. Merry 
67130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h>
68130f4520SKenneth D. Merry #include <cam/scsi/scsi_message.h>
69130f4520SKenneth D. Merry 
70130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h>
71130f4520SKenneth D. Merry #include <cam/ctl/ctl.h>
72130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend.h>
73130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h>
74130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h>
75130f4520SKenneth D. Merry 
76130f4520SKenneth D. Merry struct ctlfe_softc {
7792168f4cSAlexander Motin 	struct ctl_port	port;
78130f4520SKenneth D. Merry 	path_id_t	path_id;
79d1f40587SAlexander Motin 	target_id_t	target_id;
8059f063d5SAlexander Motin 	uint32_t	hba_misc;
81acf5bea4SAlexander Motin 	u_int		maxio;
82130f4520SKenneth D. Merry 	struct cam_sim *sim;
83130f4520SKenneth D. Merry 	char		port_name[DEV_IDLEN];
84227d67aaSAlexander Motin 	struct mtx	lun_softc_mtx;
85130f4520SKenneth D. Merry 	STAILQ_HEAD(, ctlfe_lun_softc) lun_softc_list;
86130f4520SKenneth D. Merry 	STAILQ_ENTRY(ctlfe_softc) links;
87130f4520SKenneth D. Merry };
88130f4520SKenneth D. Merry 
89130f4520SKenneth D. Merry STAILQ_HEAD(, ctlfe_softc) ctlfe_softc_list;
90130f4520SKenneth D. Merry struct mtx ctlfe_list_mtx;
91130f4520SKenneth D. Merry static char ctlfe_mtx_desc[] = "ctlfelist";
92130f4520SKenneth D. Merry 
93130f4520SKenneth D. Merry typedef enum {
94130f4520SKenneth D. Merry 	CTLFE_LUN_NONE		= 0x00,
95130f4520SKenneth D. Merry 	CTLFE_LUN_WILDCARD	= 0x01
96130f4520SKenneth D. Merry } ctlfe_lun_flags;
97130f4520SKenneth D. Merry 
98130f4520SKenneth D. Merry struct ctlfe_lun_softc {
99130f4520SKenneth D. Merry 	struct ctlfe_softc *parent_softc;
100130f4520SKenneth D. Merry 	struct cam_periph *periph;
101130f4520SKenneth D. Merry 	ctlfe_lun_flags flags;
1023afd4806SAlexander Motin 	int	 ctios_sent;		/* Number of active CTIOs */
1033afd4806SAlexander Motin 	int	 refcount;		/* Number of active xpt_action() */
1043afd4806SAlexander Motin 	int	 atios_alloced;		/* Number of ATIOs not freed */
1053afd4806SAlexander Motin 	int	 inots_alloced;		/* Number of INOTs not freed */
1063afd4806SAlexander Motin 	struct task	refdrain_task;
107832529c5SAlexander Motin 	STAILQ_HEAD(, ccb_hdr) work_queue;
108ad0f05e6SAlexander Motin 	LIST_HEAD(, ccb_hdr) atio_list;	/* List of ATIOs queued to SIM. */
109ad0f05e6SAlexander Motin 	LIST_HEAD(, ccb_hdr) inot_list;	/* List of INOTs queued to SIM. */
110130f4520SKenneth D. Merry 	STAILQ_ENTRY(ctlfe_lun_softc) links;
111130f4520SKenneth D. Merry };
112130f4520SKenneth D. Merry 
113130f4520SKenneth D. Merry typedef enum {
114130f4520SKenneth D. Merry 	CTLFE_CMD_NONE		= 0x00,
115130f4520SKenneth D. Merry 	CTLFE_CMD_PIECEWISE	= 0x01
116130f4520SKenneth D. Merry } ctlfe_cmd_flags;
117130f4520SKenneth D. Merry 
1187278725bSAlexander Motin struct ctlfe_cmd_info {
119130f4520SKenneth D. Merry 	int cur_transfer_index;
120acf5bea4SAlexander Motin 	size_t cur_transfer_off;
121130f4520SKenneth D. Merry 	ctlfe_cmd_flags flags;
122130f4520SKenneth D. Merry 	/*
123130f4520SKenneth D. Merry 	 * XXX KDM struct bus_dma_segment is 8 bytes on i386, and 16
124130f4520SKenneth D. Merry 	 * bytes on amd64.  So with 32 elements, this is 256 bytes on
125130f4520SKenneth D. Merry 	 * i386 and 512 bytes on amd64.
126130f4520SKenneth D. Merry 	 */
127acf5bea4SAlexander Motin #define CTLFE_MAX_SEGS	32
128acf5bea4SAlexander Motin 	bus_dma_segment_t cam_sglist[CTLFE_MAX_SEGS];
129130f4520SKenneth D. Merry };
130130f4520SKenneth D. Merry 
131130f4520SKenneth D. Merry /*
132130f4520SKenneth D. Merry  * When we register the adapter/bus, request that this many ctl_ios be
133130f4520SKenneth D. Merry  * allocated.  This should be the maximum supported by the adapter, but we
134130f4520SKenneth D. Merry  * currently don't have a way to get that back from the path inquiry.
135130f4520SKenneth D. Merry  * XXX KDM add that to the path inquiry.
136130f4520SKenneth D. Merry  */
137130f4520SKenneth D. Merry #define	CTLFE_REQ_CTL_IO	4096
138130f4520SKenneth D. Merry /*
139130f4520SKenneth D. Merry  * Number of Accept Target I/O CCBs to allocate and queue down to the
140130f4520SKenneth D. Merry  * adapter per LUN.
141130f4520SKenneth D. Merry  * XXX KDM should this be controlled by CTL?
142130f4520SKenneth D. Merry  */
143130f4520SKenneth D. Merry #define	CTLFE_ATIO_PER_LUN	1024
144130f4520SKenneth D. Merry /*
145130f4520SKenneth D. Merry  * Number of Immediate Notify CCBs (used for aborts, resets, etc.) to
146130f4520SKenneth D. Merry  * allocate and queue down to the adapter per LUN.
147130f4520SKenneth D. Merry  * XXX KDM should this be controlled by CTL?
148130f4520SKenneth D. Merry  */
149130f4520SKenneth D. Merry #define	CTLFE_IN_PER_LUN	1024
150130f4520SKenneth D. Merry 
151130f4520SKenneth D. Merry /*
15203ea6ef2SAlexander Motin  * Timeout (in seconds) on CTIO CCB doing DMA or sending status
153130f4520SKenneth D. Merry  */
15403ea6ef2SAlexander Motin #define	CTLFE_TIMEOUT	5
155130f4520SKenneth D. Merry 
156130f4520SKenneth D. Merry /*
157130f4520SKenneth D. Merry  * Turn this on to enable extra debugging prints.
158130f4520SKenneth D. Merry  */
159130f4520SKenneth D. Merry #if 0
160130f4520SKenneth D. Merry #define	CTLFE_DEBUG
161130f4520SKenneth D. Merry #endif
162130f4520SKenneth D. Merry 
163130f4520SKenneth D. Merry MALLOC_DEFINE(M_CTLFE, "CAM CTL FE", "CAM CTL FE interface");
164130f4520SKenneth D. Merry 
1651251a76bSAlexander Motin #define	io_ptr		ppriv_ptr0
166130f4520SKenneth D. Merry 
167130f4520SKenneth D. Merry /* This is only used in the CTIO */
168130f4520SKenneth D. Merry #define	ccb_atio	ppriv_ptr1
169130f4520SKenneth D. Merry 
170e67ac203SAlexander Motin #define PRIV_CCB(io)	((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[0])
171e67ac203SAlexander Motin #define PRIV_INFO(io)	((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[1])
172e67ac203SAlexander Motin 
1730c629e28SAlexander Motin static int		ctlfeinitialize(void);
1740c629e28SAlexander Motin static int		ctlfeshutdown(void);
17592168f4cSAlexander Motin static periph_init_t	ctlfeperiphinit;
17694173c3cSAlexander Motin static periph_deinit_t	ctlfeperiphdeinit;
177130f4520SKenneth D. Merry static void		ctlfeasync(void *callback_arg, uint32_t code,
178130f4520SKenneth D. Merry 				   struct cam_path *path, void *arg);
179130f4520SKenneth D. Merry static periph_ctor_t	ctlferegister;
180130f4520SKenneth D. Merry static periph_oninv_t	ctlfeoninvalidate;
181130f4520SKenneth D. Merry static periph_dtor_t	ctlfecleanup;
182130f4520SKenneth D. Merry static periph_start_t	ctlfestart;
183130f4520SKenneth D. Merry static void		ctlfedone(struct cam_periph *periph,
184130f4520SKenneth D. Merry 				  union ccb *done_ccb);
185130f4520SKenneth D. Merry 
186130f4520SKenneth D. Merry static void 		ctlfe_onoffline(void *arg, int online);
187130f4520SKenneth D. Merry static void 		ctlfe_online(void *arg);
188130f4520SKenneth D. Merry static void 		ctlfe_offline(void *arg);
1897834ea88SAlexander Motin static int 		ctlfe_lun_enable(void *arg, int lun_id);
1907834ea88SAlexander Motin static int 		ctlfe_lun_disable(void *arg, int lun_id);
191130f4520SKenneth D. Merry static void		ctlfe_dump_sim(struct cam_sim *sim);
192130f4520SKenneth D. Merry static void		ctlfe_dump_queue(struct ctlfe_lun_softc *softc);
193993a751eSAlexander Motin static void 		ctlfe_datamove(union ctl_io *io);
194993a751eSAlexander Motin static void 		ctlfe_done(union ctl_io *io);
195130f4520SKenneth D. Merry static void 		ctlfe_dump(void);
196a504738fSAlexander Motin static void		ctlfe_free_ccb(struct cam_periph *periph,
197a504738fSAlexander Motin 			    union ccb *ccb);
198a504738fSAlexander Motin static void		ctlfe_requeue_ccb(struct cam_periph *periph,
199a504738fSAlexander Motin 			    union ccb *ccb, int unlock);
200130f4520SKenneth D. Merry 
201130f4520SKenneth D. Merry static struct periph_driver ctlfe_driver =
202130f4520SKenneth D. Merry {
20392168f4cSAlexander Motin 	ctlfeperiphinit, "ctl",
204dc5362fdSAlexander Motin 	TAILQ_HEAD_INITIALIZER(ctlfe_driver.units), /*generation*/ 0,
20594173c3cSAlexander Motin 	CAM_PERIPH_DRV_EARLY,
20694173c3cSAlexander Motin 	ctlfeperiphdeinit
207130f4520SKenneth D. Merry };
20832562145SEdward Tomasz Napierala 
20992168f4cSAlexander Motin static struct ctl_frontend ctlfe_frontend =
21092168f4cSAlexander Motin {
2115c8dcc11SAlexander Motin 	.name = "camtgt",
21292168f4cSAlexander Motin 	.init = ctlfeinitialize,
21392168f4cSAlexander Motin 	.fe_dump = ctlfe_dump,
21492168f4cSAlexander Motin 	.shutdown = ctlfeshutdown,
21532562145SEdward Tomasz Napierala };
21692168f4cSAlexander Motin CTL_FRONTEND_DECLARE(ctlfe, ctlfe_frontend);
217130f4520SKenneth D. Merry 
2180c629e28SAlexander Motin static int
21992168f4cSAlexander Motin ctlfeinitialize(void)
22092168f4cSAlexander Motin {
22192168f4cSAlexander Motin 
22292168f4cSAlexander Motin 	STAILQ_INIT(&ctlfe_softc_list);
22392168f4cSAlexander Motin 	mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
22492168f4cSAlexander Motin 	periphdriver_register(&ctlfe_driver);
22592168f4cSAlexander Motin 	return (0);
22692168f4cSAlexander Motin }
22792168f4cSAlexander Motin 
22894173c3cSAlexander Motin static int
22994173c3cSAlexander Motin ctlfeshutdown(void)
23094173c3cSAlexander Motin {
23194173c3cSAlexander Motin 	int error;
23294173c3cSAlexander Motin 
23394173c3cSAlexander Motin 	error = periphdriver_unregister(&ctlfe_driver);
23494173c3cSAlexander Motin 	if (error != 0)
23594173c3cSAlexander Motin 		return (error);
23694173c3cSAlexander Motin 	mtx_destroy(&ctlfe_list_mtx);
23794173c3cSAlexander Motin 	return (0);
23894173c3cSAlexander Motin }
23994173c3cSAlexander Motin 
2400c629e28SAlexander Motin static void
24192168f4cSAlexander Motin ctlfeperiphinit(void)
242130f4520SKenneth D. Merry {
243130f4520SKenneth D. Merry 	cam_status status;
244130f4520SKenneth D. Merry 
245130f4520SKenneth D. Merry 	status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED |
246130f4520SKenneth D. Merry 				    AC_CONTRACT, ctlfeasync, NULL, NULL);
247130f4520SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
248130f4520SKenneth D. Merry 		printf("ctl: Failed to attach async callback due to CAM "
249130f4520SKenneth D. Merry 		       "status 0x%x!\n", status);
250130f4520SKenneth D. Merry 	}
251130f4520SKenneth D. Merry }
252130f4520SKenneth D. Merry 
25394173c3cSAlexander Motin static int
25494173c3cSAlexander Motin ctlfeperiphdeinit(void)
25594173c3cSAlexander Motin {
25694173c3cSAlexander Motin 
25794173c3cSAlexander Motin 	/* XXX: It would be good to tear down active ports here. */
25894173c3cSAlexander Motin 	if (!TAILQ_EMPTY(&ctlfe_driver.units))
25994173c3cSAlexander Motin 		return (EBUSY);
26094173c3cSAlexander Motin 	xpt_register_async(0, ctlfeasync, NULL, NULL);
26194173c3cSAlexander Motin 	return (0);
26294173c3cSAlexander Motin }
26394173c3cSAlexander Motin 
264130f4520SKenneth D. Merry static void
265130f4520SKenneth D. Merry ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
266130f4520SKenneth D. Merry {
2677d9cb4d9SAlexander Motin 	struct ctlfe_softc *softc;
268130f4520SKenneth D. Merry 
269130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
270130f4520SKenneth D. Merry 	printf("%s: entered\n", __func__);
271130f4520SKenneth D. Merry #endif
272130f4520SKenneth D. Merry 
2737d9cb4d9SAlexander Motin 	mtx_lock(&ctlfe_list_mtx);
2747d9cb4d9SAlexander Motin 	STAILQ_FOREACH(softc, &ctlfe_softc_list, links) {
2757d9cb4d9SAlexander Motin 		if (softc->path_id == xpt_path_path_id(path))
2767d9cb4d9SAlexander Motin 			break;
2777d9cb4d9SAlexander Motin 	}
2787d9cb4d9SAlexander Motin 	mtx_unlock(&ctlfe_list_mtx);
2797d9cb4d9SAlexander Motin 
280130f4520SKenneth D. Merry 	/*
281130f4520SKenneth D. Merry 	 * When a new path gets registered, and it is capable of target
282130f4520SKenneth D. Merry 	 * mode, go ahead and attach.  Later on, we may need to be more
283130f4520SKenneth D. Merry 	 * selective, but for now this will be sufficient.
284130f4520SKenneth D. Merry  	 */
285130f4520SKenneth D. Merry 	switch (code) {
286130f4520SKenneth D. Merry 	case AC_PATH_REGISTERED: {
28792168f4cSAlexander Motin 		struct ctl_port *port;
288130f4520SKenneth D. Merry 		struct ccb_pathinq *cpi;
289130f4520SKenneth D. Merry 		int retval;
290130f4520SKenneth D. Merry 
291130f4520SKenneth D. Merry 		cpi = (struct ccb_pathinq *)arg;
292130f4520SKenneth D. Merry 
293130f4520SKenneth D. Merry 		/* Don't attach if it doesn't support target mode */
294130f4520SKenneth D. Merry 		if ((cpi->target_sprt & PIT_PROCESSOR) == 0) {
295b87c6ae0SKenneth D. Merry #ifdef CTLFEDEBUG
296130f4520SKenneth D. Merry 			printf("%s: SIM %s%d doesn't support target mode\n",
297130f4520SKenneth D. Merry 			       __func__, cpi->dev_name, cpi->unit_number);
298b87c6ae0SKenneth D. Merry #endif
299130f4520SKenneth D. Merry 			break;
300130f4520SKenneth D. Merry 		}
301130f4520SKenneth D. Merry 
3027d9cb4d9SAlexander Motin 		if (softc != NULL) {
3037d9cb4d9SAlexander Motin #ifdef CTLFEDEBUG
3047d9cb4d9SAlexander Motin 			printf("%s: CTL port for CAM path %u already exists\n",
3057d9cb4d9SAlexander Motin 			       __func__, xpt_path_path_id(path));
3067d9cb4d9SAlexander Motin #endif
3077d9cb4d9SAlexander Motin 			break;
3087d9cb4d9SAlexander Motin 		}
3097d9cb4d9SAlexander Motin 
310130f4520SKenneth D. Merry 		/*
311130f4520SKenneth D. Merry 		 * We're in an interrupt context here, so we have to
312130f4520SKenneth D. Merry 		 * use M_NOWAIT.  Of course this means trouble if we
313130f4520SKenneth D. Merry 		 * can't allocate memory.
314130f4520SKenneth D. Merry 		 */
3157d9cb4d9SAlexander Motin 		softc = malloc(sizeof(*softc), M_CTLFE, M_NOWAIT | M_ZERO);
3167d9cb4d9SAlexander Motin 		if (softc == NULL) {
317130f4520SKenneth D. Merry 			printf("%s: unable to malloc %zd bytes for softc\n",
3187d9cb4d9SAlexander Motin 			       __func__, sizeof(*softc));
319130f4520SKenneth D. Merry 			return;
320130f4520SKenneth D. Merry 		}
321130f4520SKenneth D. Merry 
3227d9cb4d9SAlexander Motin 		softc->path_id = cpi->ccb_h.path_id;
323d1f40587SAlexander Motin 		softc->target_id = cpi->initiator_id;
3247d9cb4d9SAlexander Motin 		softc->sim = xpt_path_sim(path);
32559f063d5SAlexander Motin 		softc->hba_misc = cpi->hba_misc;
326acf5bea4SAlexander Motin 		if (cpi->maxio != 0)
3277d9cb4d9SAlexander Motin 			softc->maxio = cpi->maxio;
328acf5bea4SAlexander Motin 		else
3297d9cb4d9SAlexander Motin 			softc->maxio = DFLTPHYS;
3307d9cb4d9SAlexander Motin 		mtx_init(&softc->lun_softc_mtx, "LUN softc mtx", NULL, MTX_DEF);
3317d9cb4d9SAlexander Motin 		STAILQ_INIT(&softc->lun_softc_list);
332130f4520SKenneth D. Merry 
3337d9cb4d9SAlexander Motin 		port = &softc->port;
33492168f4cSAlexander Motin 		port->frontend = &ctlfe_frontend;
335130f4520SKenneth D. Merry 
336130f4520SKenneth D. Merry 		/*
337130f4520SKenneth D. Merry 		 * XXX KDM should we be more accurate here ?
338130f4520SKenneth D. Merry 		 */
339130f4520SKenneth D. Merry 		if (cpi->transport == XPORT_FC)
34092168f4cSAlexander Motin 			port->port_type = CTL_PORT_FC;
3411e5a8b8fSAlexander Motin 		else if (cpi->transport == XPORT_SAS)
3421e5a8b8fSAlexander Motin 			port->port_type = CTL_PORT_SAS;
343130f4520SKenneth D. Merry 		else
34492168f4cSAlexander Motin 			port->port_type = CTL_PORT_SCSI;
345130f4520SKenneth D. Merry 
346130f4520SKenneth D. Merry 		/* XXX KDM what should the real number be here? */
34703ea6ef2SAlexander Motin 		port->num_requested_ctl_io = CTLFE_REQ_CTL_IO;
3487d9cb4d9SAlexander Motin 		snprintf(softc->port_name, sizeof(softc->port_name),
349130f4520SKenneth D. Merry 			 "%s%d", cpi->dev_name, cpi->unit_number);
350130f4520SKenneth D. Merry 		/*
351130f4520SKenneth D. Merry 		 * XXX KDM it would be nice to allocate storage in the
352130f4520SKenneth D. Merry 		 * frontend structure itself.
353130f4520SKenneth D. Merry 	 	 */
3547d9cb4d9SAlexander Motin 		port->port_name = softc->port_name;
3559045dbb2SAlexander Motin 		port->physical_port = cpi->bus_id;
3569045dbb2SAlexander Motin 		port->virtual_port = 0;
35792168f4cSAlexander Motin 		port->port_online = ctlfe_online;
35892168f4cSAlexander Motin 		port->port_offline = ctlfe_offline;
3597d9cb4d9SAlexander Motin 		port->onoff_arg = softc;
36092168f4cSAlexander Motin 		port->lun_enable = ctlfe_lun_enable;
36192168f4cSAlexander Motin 		port->lun_disable = ctlfe_lun_disable;
3627d9cb4d9SAlexander Motin 		port->targ_lun_arg = softc;
363993a751eSAlexander Motin 		port->fe_datamove = ctlfe_datamove;
364993a751eSAlexander Motin 		port->fe_done = ctlfe_done;
3657ac58230SAlexander Motin 		port->targ_port = -1;
366130f4520SKenneth D. Merry 
36723b30f56SAlexander Motin 		retval = ctl_port_register(port);
368130f4520SKenneth D. Merry 		if (retval != 0) {
36992168f4cSAlexander Motin 			printf("%s: ctl_port_register() failed with "
370130f4520SKenneth D. Merry 			       "error %d!\n", __func__, retval);
3717d9cb4d9SAlexander Motin 			mtx_destroy(&softc->lun_softc_mtx);
3727d9cb4d9SAlexander Motin 			free(softc, M_CTLFE);
373130f4520SKenneth D. Merry 			break;
374130f4520SKenneth D. Merry 		} else {
375130f4520SKenneth D. Merry 			mtx_lock(&ctlfe_list_mtx);
3767d9cb4d9SAlexander Motin 			STAILQ_INSERT_TAIL(&ctlfe_softc_list, softc, links);
377130f4520SKenneth D. Merry 			mtx_unlock(&ctlfe_list_mtx);
378130f4520SKenneth D. Merry 		}
379130f4520SKenneth D. Merry 
380130f4520SKenneth D. Merry 		break;
381130f4520SKenneth D. Merry 	}
382744c26b2SKenneth D. Merry 	case AC_PATH_DEREGISTERED: {
383744c26b2SKenneth D. Merry 		if (softc != NULL) {
384744c26b2SKenneth D. Merry 			/*
385744c26b2SKenneth D. Merry 			 * XXX KDM are we certain at this point that there
386744c26b2SKenneth D. Merry 			 * are no outstanding commands for this frontend?
387744c26b2SKenneth D. Merry 			 */
3887d9cb4d9SAlexander Motin 			mtx_lock(&ctlfe_list_mtx);
3897d9cb4d9SAlexander Motin 			STAILQ_REMOVE(&ctlfe_softc_list, softc, ctlfe_softc,
3907d9cb4d9SAlexander Motin 			    links);
3917d9cb4d9SAlexander Motin 			mtx_unlock(&ctlfe_list_mtx);
39292168f4cSAlexander Motin 			ctl_port_deregister(&softc->port);
393227d67aaSAlexander Motin 			mtx_destroy(&softc->lun_softc_mtx);
394744c26b2SKenneth D. Merry 			free(softc, M_CTLFE);
395744c26b2SKenneth D. Merry 		}
396130f4520SKenneth D. Merry 		break;
397130f4520SKenneth D. Merry 	}
398130f4520SKenneth D. Merry 	case AC_CONTRACT: {
399130f4520SKenneth D. Merry 		struct ac_contract *ac;
400130f4520SKenneth D. Merry 
401130f4520SKenneth D. Merry 		ac = (struct ac_contract *)arg;
402130f4520SKenneth D. Merry 
403130f4520SKenneth D. Merry 		switch (ac->contract_number) {
404130f4520SKenneth D. Merry 		case AC_CONTRACT_DEV_CHG: {
405130f4520SKenneth D. Merry 			struct ac_device_changed *dev_chg;
4067d9cb4d9SAlexander Motin 			int retval;
407130f4520SKenneth D. Merry 
408130f4520SKenneth D. Merry 			dev_chg = (struct ac_device_changed *)ac->contract_data;
409130f4520SKenneth D. Merry 
4105a1ae35dSMatt Jacob 			printf("%s: WWPN %#jx port 0x%06x path %u target %u %s\n",
411130f4520SKenneth D. Merry 			       __func__, dev_chg->wwpn, dev_chg->port,
412130f4520SKenneth D. Merry 			       xpt_path_path_id(path), dev_chg->target,
413130f4520SKenneth D. Merry 			       (dev_chg->arrived == 0) ?  "left" : "arrived");
414130f4520SKenneth D. Merry 
4157d9cb4d9SAlexander Motin 			if (softc == NULL) {
416130f4520SKenneth D. Merry 				printf("%s: CTL port for CAM path %u not "
417130f4520SKenneth D. Merry 				       "found!\n", __func__,
418130f4520SKenneth D. Merry 				       xpt_path_path_id(path));
419130f4520SKenneth D. Merry 				break;
420130f4520SKenneth D. Merry 			}
421130f4520SKenneth D. Merry 			if (dev_chg->arrived != 0) {
422604e2579SAlexander Motin 				retval = ctl_add_initiator(&softc->port,
423604e2579SAlexander Motin 				    dev_chg->target, dev_chg->wwpn, NULL);
424130f4520SKenneth D. Merry 			} else {
425604e2579SAlexander Motin 				retval = ctl_remove_initiator(&softc->port,
426604e2579SAlexander Motin 				    dev_chg->target);
427130f4520SKenneth D. Merry 			}
428130f4520SKenneth D. Merry 
429604e2579SAlexander Motin 			if (retval < 0) {
430130f4520SKenneth D. Merry 				printf("%s: could not %s port %d iid %u "
431130f4520SKenneth D. Merry 				       "WWPN %#jx!\n", __func__,
432130f4520SKenneth D. Merry 				       (dev_chg->arrived != 0) ? "add" :
43392168f4cSAlexander Motin 				       "remove", softc->port.targ_port,
434130f4520SKenneth D. Merry 				       dev_chg->target,
435130f4520SKenneth D. Merry 				       (uintmax_t)dev_chg->wwpn);
436130f4520SKenneth D. Merry 			}
437130f4520SKenneth D. Merry 			break;
438130f4520SKenneth D. Merry 		}
439130f4520SKenneth D. Merry 		default:
440130f4520SKenneth D. Merry 			printf("%s: unsupported contract number %ju\n",
441130f4520SKenneth D. Merry 			       __func__, (uintmax_t)ac->contract_number);
442130f4520SKenneth D. Merry 			break;
443130f4520SKenneth D. Merry 		}
444130f4520SKenneth D. Merry 		break;
445130f4520SKenneth D. Merry 	}
446130f4520SKenneth D. Merry 	default:
447130f4520SKenneth D. Merry 		break;
448130f4520SKenneth D. Merry 	}
449130f4520SKenneth D. Merry }
450130f4520SKenneth D. Merry 
451130f4520SKenneth D. Merry static cam_status
452130f4520SKenneth D. Merry ctlferegister(struct cam_periph *periph, void *arg)
453130f4520SKenneth D. Merry {
454130f4520SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
455130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
456ad0f05e6SAlexander Motin 	union ccb ccb;
457130f4520SKenneth D. Merry 	cam_status status;
45899e7a4adSScott Long 	int i, acstatus;
459130f4520SKenneth D. Merry 
460130f4520SKenneth D. Merry 	softc = (struct ctlfe_lun_softc *)arg;
461130f4520SKenneth D. Merry 	bus_softc = softc->parent_softc;
462130f4520SKenneth D. Merry 
463832529c5SAlexander Motin 	STAILQ_INIT(&softc->work_queue);
464ad0f05e6SAlexander Motin 	LIST_INIT(&softc->atio_list);
465ad0f05e6SAlexander Motin 	LIST_INIT(&softc->inot_list);
466130f4520SKenneth D. Merry 	softc->periph = periph;
467130f4520SKenneth D. Merry 	periph->softc = softc;
468130f4520SKenneth D. Merry 
469b1303ffeSAlexander Motin 	/* Increase device openings to maximum for the SIM. */
470b1303ffeSAlexander Motin 	if (bus_softc->sim->max_tagged_dev_openings >
471b1303ffeSAlexander Motin 	    bus_softc->sim->max_dev_openings) {
472b1303ffeSAlexander Motin 		cam_release_devq(periph->path,
473b1303ffeSAlexander Motin 		    /*relsim_flags*/RELSIM_ADJUST_OPENINGS,
474b1303ffeSAlexander Motin 		    /*openings*/bus_softc->sim->max_tagged_dev_openings,
475b1303ffeSAlexander Motin 		    /*timeout*/0,
476b1303ffeSAlexander Motin 		    /*getcount_only*/1);
477b1303ffeSAlexander Motin 	}
478b1303ffeSAlexander Motin 
479616a676aSEdward Tomasz Napierala 	memset(&ccb, 0, sizeof(ccb));
480ad0f05e6SAlexander Motin 	xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NONE);
481ad0f05e6SAlexander Motin 	ccb.ccb_h.func_code = XPT_EN_LUN;
482ad0f05e6SAlexander Motin 	ccb.cel.grp6_len = 0;
483ad0f05e6SAlexander Motin 	ccb.cel.grp7_len = 0;
484ad0f05e6SAlexander Motin 	ccb.cel.enable = 1;
485ad0f05e6SAlexander Motin 	xpt_action(&ccb);
486ad0f05e6SAlexander Motin 	status = (ccb.ccb_h.status & CAM_STATUS_MASK);
487130f4520SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
488130f4520SKenneth D. Merry 		xpt_print(periph->path, "%s: Enable LUN failed, status 0x%x\n",
489ad0f05e6SAlexander Motin 			  __func__, ccb.ccb_h.status);
490130f4520SKenneth D. Merry 		return (status);
491130f4520SKenneth D. Merry 	}
492130f4520SKenneth D. Merry 
493130f4520SKenneth D. Merry 	status = CAM_REQ_CMP;
494130f4520SKenneth D. Merry 
495130f4520SKenneth D. Merry 	for (i = 0; i < CTLFE_ATIO_PER_LUN; i++) {
496130f4520SKenneth D. Merry 		union ccb *new_ccb;
4971251a76bSAlexander Motin 		union ctl_io *new_io;
4987278725bSAlexander Motin 		struct ctlfe_cmd_info *cmd_info;
499130f4520SKenneth D. Merry 
500130f4520SKenneth D. Merry 		new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE,
5015a1ae35dSMatt Jacob 					      M_ZERO|M_NOWAIT);
502130f4520SKenneth D. Merry 		if (new_ccb == NULL) {
503130f4520SKenneth D. Merry 			status = CAM_RESRC_UNAVAIL;
504130f4520SKenneth D. Merry 			break;
505130f4520SKenneth D. Merry 		}
5061251a76bSAlexander Motin 		new_io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref);
5071251a76bSAlexander Motin 		if (new_io == NULL) {
5081251a76bSAlexander Motin 			free(new_ccb, M_CTLFE);
5091251a76bSAlexander Motin 			status = CAM_RESRC_UNAVAIL;
5101251a76bSAlexander Motin 			break;
5111251a76bSAlexander Motin 		}
5127278725bSAlexander Motin 		cmd_info = malloc(sizeof(*cmd_info), M_CTLFE,
5137278725bSAlexander Motin 		    M_ZERO | M_NOWAIT);
5147278725bSAlexander Motin 		if (cmd_info == NULL) {
5157278725bSAlexander Motin 			ctl_free_io(new_io);
5167278725bSAlexander Motin 			free(new_ccb, M_CTLFE);
5177278725bSAlexander Motin 			status = CAM_RESRC_UNAVAIL;
5187278725bSAlexander Motin 			break;
5197278725bSAlexander Motin 		}
520e67ac203SAlexander Motin 		PRIV_INFO(new_io) = cmd_info;
521521db0acSAlexander Motin 		softc->atios_alloced++;
5221251a76bSAlexander Motin 		new_ccb->ccb_h.io_ptr = new_io;
523ad0f05e6SAlexander Motin 		LIST_INSERT_HEAD(&softc->atio_list, &new_ccb->ccb_h, periph_links.le);
5241251a76bSAlexander Motin 
52586ce2be6SAlexander Motin 		xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE);
526130f4520SKenneth D. Merry 		new_ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
527130f4520SKenneth D. Merry 		new_ccb->ccb_h.cbfcnp = ctlfedone;
528227d67aaSAlexander Motin 		new_ccb->ccb_h.flags |= CAM_UNLOCKED;
529130f4520SKenneth D. Merry 		xpt_action(new_ccb);
530130f4520SKenneth D. Merry 		status = new_ccb->ccb_h.status;
531130f4520SKenneth D. Merry 		if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
5327278725bSAlexander Motin 			free(cmd_info, M_CTLFE);
5331251a76bSAlexander Motin 			ctl_free_io(new_io);
534130f4520SKenneth D. Merry 			free(new_ccb, M_CTLFE);
535130f4520SKenneth D. Merry 			break;
536130f4520SKenneth D. Merry 		}
537130f4520SKenneth D. Merry 	}
538130f4520SKenneth D. Merry 
53999e7a4adSScott Long 	acstatus = cam_periph_acquire(periph);
54099e7a4adSScott Long 	if (acstatus != 0) {
541130f4520SKenneth D. Merry 		xpt_print(periph->path, "%s: could not acquire reference "
54299e7a4adSScott Long 			  "count, status = %#x\n", __func__, acstatus);
54399e7a4adSScott Long 		return (CAM_REQ_CMP_ERR);
544130f4520SKenneth D. Merry 	}
545130f4520SKenneth D. Merry 
546130f4520SKenneth D. Merry 	if (i == 0) {
547130f4520SKenneth D. Merry 		xpt_print(periph->path, "%s: could not allocate ATIO CCBs, "
548130f4520SKenneth D. Merry 			  "status 0x%x\n", __func__, status);
549130f4520SKenneth D. Merry 		return (CAM_REQ_CMP_ERR);
550130f4520SKenneth D. Merry 	}
551130f4520SKenneth D. Merry 
552130f4520SKenneth D. Merry 	for (i = 0; i < CTLFE_IN_PER_LUN; i++) {
553130f4520SKenneth D. Merry 		union ccb *new_ccb;
5541251a76bSAlexander Motin 		union ctl_io *new_io;
555130f4520SKenneth D. Merry 
556130f4520SKenneth D. Merry 		new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE,
5575a1ae35dSMatt Jacob 					      M_ZERO|M_NOWAIT);
558130f4520SKenneth D. Merry 		if (new_ccb == NULL) {
559130f4520SKenneth D. Merry 			status = CAM_RESRC_UNAVAIL;
560130f4520SKenneth D. Merry 			break;
561130f4520SKenneth D. Merry 		}
5621251a76bSAlexander Motin 		new_io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref);
5631251a76bSAlexander Motin 		if (new_io == NULL) {
5641251a76bSAlexander Motin 			free(new_ccb, M_CTLFE);
5651251a76bSAlexander Motin 			status = CAM_RESRC_UNAVAIL;
5661251a76bSAlexander Motin 			break;
5671251a76bSAlexander Motin 		}
568521db0acSAlexander Motin 		softc->inots_alloced++;
5691251a76bSAlexander Motin 		new_ccb->ccb_h.io_ptr = new_io;
570ad0f05e6SAlexander Motin 		LIST_INSERT_HEAD(&softc->inot_list, &new_ccb->ccb_h, periph_links.le);
571130f4520SKenneth D. Merry 
57286ce2be6SAlexander Motin 		xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE);
573130f4520SKenneth D. Merry 		new_ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
574130f4520SKenneth D. Merry 		new_ccb->ccb_h.cbfcnp = ctlfedone;
575227d67aaSAlexander Motin 		new_ccb->ccb_h.flags |= CAM_UNLOCKED;
576130f4520SKenneth D. Merry 		xpt_action(new_ccb);
577130f4520SKenneth D. Merry 		status = new_ccb->ccb_h.status;
578b79dc8a8SKenneth D. Merry 		if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
579b79dc8a8SKenneth D. Merry 			/*
580b79dc8a8SKenneth D. Merry 			 * Note that we don't free the CCB here.  If the
581b79dc8a8SKenneth D. Merry 			 * status is not CAM_REQ_INPROG, then we're
582b79dc8a8SKenneth D. Merry 			 * probably talking to a SIM that says it is
583b79dc8a8SKenneth D. Merry 			 * target-capable but doesn't support the
584b79dc8a8SKenneth D. Merry 			 * XPT_IMMEDIATE_NOTIFY CCB.  i.e. it supports the
585b79dc8a8SKenneth D. Merry 			 * older API.  In that case, it'll call xpt_done()
586b79dc8a8SKenneth D. Merry 			 * on the CCB, and we need to free it in our done
587b79dc8a8SKenneth D. Merry 			 * routine as a result.
588b79dc8a8SKenneth D. Merry 			 */
589130f4520SKenneth D. Merry 			break;
590130f4520SKenneth D. Merry 		}
591130f4520SKenneth D. Merry 	}
592b79dc8a8SKenneth D. Merry 	if ((i == 0)
593b79dc8a8SKenneth D. Merry 	 || (status != CAM_REQ_INPROG)) {
594130f4520SKenneth D. Merry 		xpt_print(periph->path, "%s: could not allocate immediate "
595130f4520SKenneth D. Merry 			  "notify CCBs, status 0x%x\n", __func__, status);
596130f4520SKenneth D. Merry 		return (CAM_REQ_CMP_ERR);
597130f4520SKenneth D. Merry 	}
5987511bd04SAlexander Motin 	mtx_lock(&bus_softc->lun_softc_mtx);
5997511bd04SAlexander Motin 	STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, softc, links);
6007511bd04SAlexander Motin 	mtx_unlock(&bus_softc->lun_softc_mtx);
601130f4520SKenneth D. Merry 	return (CAM_REQ_CMP);
602130f4520SKenneth D. Merry }
603130f4520SKenneth D. Merry 
604130f4520SKenneth D. Merry static void
605130f4520SKenneth D. Merry ctlfeoninvalidate(struct cam_periph *periph)
606130f4520SKenneth D. Merry {
607ad0f05e6SAlexander Motin 	struct ctlfe_lun_softc *softc = (struct ctlfe_lun_softc *)periph->softc;
608227d67aaSAlexander Motin 	struct ctlfe_softc *bus_softc;
609ad0f05e6SAlexander Motin 	union ccb ccb;
610ad0f05e6SAlexander Motin 	struct ccb_hdr *hdr;
611ad0f05e6SAlexander Motin 	cam_status status;
612130f4520SKenneth D. Merry 
613ad0f05e6SAlexander Motin 	/* Abort all ATIOs and INOTs queued to SIM. */
614616a676aSEdward Tomasz Napierala 	memset(&ccb, 0, sizeof(ccb));
615ad0f05e6SAlexander Motin 	xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NONE);
616ad0f05e6SAlexander Motin 	ccb.ccb_h.func_code = XPT_ABORT;
617ad0f05e6SAlexander Motin 	LIST_FOREACH(hdr, &softc->atio_list, periph_links.le) {
618ad0f05e6SAlexander Motin 		ccb.cab.abort_ccb = (union ccb *)hdr;
619ad0f05e6SAlexander Motin 		xpt_action(&ccb);
620ad0f05e6SAlexander Motin 	}
621ad0f05e6SAlexander Motin 	LIST_FOREACH(hdr, &softc->inot_list, periph_links.le) {
622ad0f05e6SAlexander Motin 		ccb.cab.abort_ccb = (union ccb *)hdr;
623ad0f05e6SAlexander Motin 		xpt_action(&ccb);
624ad0f05e6SAlexander Motin 	}
625130f4520SKenneth D. Merry 
626ad0f05e6SAlexander Motin 	/* Disable the LUN in SIM. */
627ad0f05e6SAlexander Motin 	ccb.ccb_h.func_code = XPT_EN_LUN;
628ad0f05e6SAlexander Motin 	ccb.cel.grp6_len = 0;
629ad0f05e6SAlexander Motin 	ccb.cel.grp7_len = 0;
630ad0f05e6SAlexander Motin 	ccb.cel.enable = 0;
631ad0f05e6SAlexander Motin 	xpt_action(&ccb);
632ad0f05e6SAlexander Motin 	status = (ccb.ccb_h.status & CAM_STATUS_MASK);
633130f4520SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
634130f4520SKenneth D. Merry 		xpt_print(periph->path, "%s: Disable LUN failed, status 0x%x\n",
635ad0f05e6SAlexander Motin 			  __func__, ccb.ccb_h.status);
636130f4520SKenneth D. Merry 		/*
637130f4520SKenneth D. Merry 		 * XXX KDM what do we do now?
638130f4520SKenneth D. Merry 		 */
639130f4520SKenneth D. Merry 	}
640227d67aaSAlexander Motin 
641227d67aaSAlexander Motin 	bus_softc = softc->parent_softc;
642227d67aaSAlexander Motin 	mtx_lock(&bus_softc->lun_softc_mtx);
643227d67aaSAlexander Motin 	STAILQ_REMOVE(&bus_softc->lun_softc_list, softc, ctlfe_lun_softc, links);
644227d67aaSAlexander Motin 	mtx_unlock(&bus_softc->lun_softc_mtx);
645130f4520SKenneth D. Merry }
646130f4520SKenneth D. Merry 
647130f4520SKenneth D. Merry static void
648130f4520SKenneth D. Merry ctlfecleanup(struct cam_periph *periph)
649130f4520SKenneth D. Merry {
650130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
651130f4520SKenneth D. Merry 
652130f4520SKenneth D. Merry 	softc = (struct ctlfe_lun_softc *)periph->softc;
653130f4520SKenneth D. Merry 
6543afd4806SAlexander Motin 	KASSERT(softc->ctios_sent == 0, ("%s: ctios_sent %d != 0",
6553afd4806SAlexander Motin 	    __func__, softc->ctios_sent));
6563afd4806SAlexander Motin 	KASSERT(softc->refcount == 0, ("%s: refcount %d != 0",
6573afd4806SAlexander Motin 	    __func__, softc->refcount));
6583afd4806SAlexander Motin 	KASSERT(softc->atios_alloced == 0, ("%s: atios_alloced %d != 0",
6593afd4806SAlexander Motin 	    __func__, softc->atios_alloced));
6603afd4806SAlexander Motin 	KASSERT(softc->inots_alloced == 0, ("%s: inots_alloced %d != 0",
6613afd4806SAlexander Motin 	    __func__, softc->inots_alloced));
662744c26b2SKenneth D. Merry 
663130f4520SKenneth D. Merry 	free(softc, M_CTLFE);
664130f4520SKenneth D. Merry }
665130f4520SKenneth D. Merry 
666130f4520SKenneth D. Merry static void
667acf5bea4SAlexander Motin ctlfedata(struct ctlfe_lun_softc *softc, union ctl_io *io,
668acf5bea4SAlexander Motin     ccb_flags *flags, uint8_t **data_ptr, uint32_t *dxfer_len,
669a74530d9SWarner Losh     uint16_t *sglist_cnt)
670acf5bea4SAlexander Motin {
671acf5bea4SAlexander Motin 	struct ctlfe_softc *bus_softc;
6727278725bSAlexander Motin 	struct ctlfe_cmd_info *cmd_info;
673acf5bea4SAlexander Motin 	struct ctl_sg_entry *ctl_sglist;
674acf5bea4SAlexander Motin 	bus_dma_segment_t *cam_sglist;
675acf5bea4SAlexander Motin 	size_t off;
676acf5bea4SAlexander Motin 	int i, idx;
677acf5bea4SAlexander Motin 
678e67ac203SAlexander Motin 	cmd_info = PRIV_INFO(io);
679acf5bea4SAlexander Motin 	bus_softc = softc->parent_softc;
680acf5bea4SAlexander Motin 
681acf5bea4SAlexander Motin 	/*
682acf5bea4SAlexander Motin 	 * Set the direction, relative to the initiator.
683acf5bea4SAlexander Motin 	 */
684acf5bea4SAlexander Motin 	*flags &= ~CAM_DIR_MASK;
685acf5bea4SAlexander Motin 	if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN)
686acf5bea4SAlexander Motin 		*flags |= CAM_DIR_IN;
687acf5bea4SAlexander Motin 	else
688acf5bea4SAlexander Motin 		*flags |= CAM_DIR_OUT;
689acf5bea4SAlexander Motin 
690acf5bea4SAlexander Motin 	*flags &= ~CAM_DATA_MASK;
691acf5bea4SAlexander Motin 	idx = cmd_info->cur_transfer_index;
692acf5bea4SAlexander Motin 	off = cmd_info->cur_transfer_off;
693acf5bea4SAlexander Motin 	cmd_info->flags &= ~CTLFE_CMD_PIECEWISE;
694eb6ac6f9SAlexander Motin 	if (io->scsiio.kern_sg_entries == 0) {	/* No S/G list. */
695eb6ac6f9SAlexander Motin 
696eb6ac6f9SAlexander Motin 		/* One time shift for SRR offset. */
697eb6ac6f9SAlexander Motin 		off += io->scsiio.ext_data_filled;
698eb6ac6f9SAlexander Motin 		io->scsiio.ext_data_filled = 0;
699eb6ac6f9SAlexander Motin 
700acf5bea4SAlexander Motin 		*data_ptr = io->scsiio.kern_data_ptr + off;
701acf5bea4SAlexander Motin 		if (io->scsiio.kern_data_len - off <= bus_softc->maxio) {
702acf5bea4SAlexander Motin 			*dxfer_len = io->scsiio.kern_data_len - off;
703acf5bea4SAlexander Motin 		} else {
704acf5bea4SAlexander Motin 			*dxfer_len = bus_softc->maxio;
705eb6ac6f9SAlexander Motin 			cmd_info->cur_transfer_off += bus_softc->maxio;
706acf5bea4SAlexander Motin 			cmd_info->flags |= CTLFE_CMD_PIECEWISE;
707acf5bea4SAlexander Motin 		}
708acf5bea4SAlexander Motin 		*sglist_cnt = 0;
709acf5bea4SAlexander Motin 
710acf5bea4SAlexander Motin 		if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR)
711acf5bea4SAlexander Motin 			*flags |= CAM_DATA_PADDR;
712acf5bea4SAlexander Motin 		else
713acf5bea4SAlexander Motin 			*flags |= CAM_DATA_VADDR;
714eb6ac6f9SAlexander Motin 	} else {	/* S/G list with physical or virtual pointers. */
715acf5bea4SAlexander Motin 		ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
716eb6ac6f9SAlexander Motin 
717eb6ac6f9SAlexander Motin 		/* One time shift for SRR offset. */
718eb6ac6f9SAlexander Motin 		while (io->scsiio.ext_data_filled >= ctl_sglist[idx].len - off) {
719eb6ac6f9SAlexander Motin 			io->scsiio.ext_data_filled -= ctl_sglist[idx].len - off;
720eb6ac6f9SAlexander Motin 			idx++;
721eb6ac6f9SAlexander Motin 			off = 0;
722eb6ac6f9SAlexander Motin 		}
723eb6ac6f9SAlexander Motin 		off += io->scsiio.ext_data_filled;
724eb6ac6f9SAlexander Motin 		io->scsiio.ext_data_filled = 0;
725eb6ac6f9SAlexander Motin 
726acf5bea4SAlexander Motin 		cam_sglist = cmd_info->cam_sglist;
727acf5bea4SAlexander Motin 		*dxfer_len = 0;
728acf5bea4SAlexander Motin 		for (i = 0; i < io->scsiio.kern_sg_entries - idx; i++) {
729a99028fcSJustin Hibbits 			cam_sglist[i].ds_addr = (bus_addr_t)(uintptr_t)ctl_sglist[i + idx].addr + off;
730acf5bea4SAlexander Motin 			if (ctl_sglist[i + idx].len - off <= bus_softc->maxio - *dxfer_len) {
731acf5bea4SAlexander Motin 				cam_sglist[i].ds_len = ctl_sglist[idx + i].len - off;
732acf5bea4SAlexander Motin 				*dxfer_len += cam_sglist[i].ds_len;
733acf5bea4SAlexander Motin 			} else {
734acf5bea4SAlexander Motin 				cam_sglist[i].ds_len = bus_softc->maxio - *dxfer_len;
735acf5bea4SAlexander Motin 				cmd_info->cur_transfer_index = idx + i;
736acf5bea4SAlexander Motin 				cmd_info->cur_transfer_off = cam_sglist[i].ds_len + off;
737acf5bea4SAlexander Motin 				cmd_info->flags |= CTLFE_CMD_PIECEWISE;
738acf5bea4SAlexander Motin 				*dxfer_len += cam_sglist[i].ds_len;
739acf5bea4SAlexander Motin 				if (ctl_sglist[i].len != 0)
740acf5bea4SAlexander Motin 					i++;
741acf5bea4SAlexander Motin 				break;
742acf5bea4SAlexander Motin 			}
743acf5bea4SAlexander Motin 			if (i == (CTLFE_MAX_SEGS - 1) &&
744acf5bea4SAlexander Motin 			    idx + i < (io->scsiio.kern_sg_entries - 1)) {
745acf5bea4SAlexander Motin 				cmd_info->cur_transfer_index = idx + i + 1;
746acf5bea4SAlexander Motin 				cmd_info->cur_transfer_off = 0;
747acf5bea4SAlexander Motin 				cmd_info->flags |= CTLFE_CMD_PIECEWISE;
748acf5bea4SAlexander Motin 				i++;
749acf5bea4SAlexander Motin 				break;
750acf5bea4SAlexander Motin 			}
751acf5bea4SAlexander Motin 			off = 0;
752acf5bea4SAlexander Motin 		}
753acf5bea4SAlexander Motin 		*sglist_cnt = i;
754acf5bea4SAlexander Motin 		if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR)
755acf5bea4SAlexander Motin 			*flags |= CAM_DATA_SG_PADDR;
756acf5bea4SAlexander Motin 		else
757acf5bea4SAlexander Motin 			*flags |= CAM_DATA_SG;
758acf5bea4SAlexander Motin 		*data_ptr = (uint8_t *)cam_sglist;
759acf5bea4SAlexander Motin 	}
760acf5bea4SAlexander Motin }
761acf5bea4SAlexander Motin 
762acf5bea4SAlexander Motin static void
763130f4520SKenneth D. Merry ctlfestart(struct cam_periph *periph, union ccb *start_ccb)
764130f4520SKenneth D. Merry {
765130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
7667278725bSAlexander Motin 	struct ctlfe_cmd_info *cmd_info;
767130f4520SKenneth D. Merry 	struct ccb_hdr *ccb_h;
768130f4520SKenneth D. Merry 	struct ccb_accept_tio *atio;
769130f4520SKenneth D. Merry 	struct ccb_scsiio *csio;
770130f4520SKenneth D. Merry 	uint8_t *data_ptr;
771130f4520SKenneth D. Merry 	uint32_t dxfer_len;
772130f4520SKenneth D. Merry 	ccb_flags flags;
773130f4520SKenneth D. Merry 	union ctl_io *io;
774130f4520SKenneth D. Merry 	uint8_t scsi_status;
775130f4520SKenneth D. Merry 
776993a751eSAlexander Motin 	softc = (struct ctlfe_lun_softc *)periph->softc;
777993a751eSAlexander Motin 
778a504738fSAlexander Motin next:
779832529c5SAlexander Motin 	/* Take the ATIO off the work queue */
780832529c5SAlexander Motin 	ccb_h = STAILQ_FIRST(&softc->work_queue);
781993a751eSAlexander Motin 	if (ccb_h == NULL) {
782993a751eSAlexander Motin 		xpt_release_ccb(start_ccb);
783993a751eSAlexander Motin 		return;
784993a751eSAlexander Motin 	}
785832529c5SAlexander Motin 	STAILQ_REMOVE_HEAD(&softc->work_queue, periph_links.stqe);
786130f4520SKenneth D. Merry 	atio = (struct ccb_accept_tio *)ccb_h;
787130f4520SKenneth D. Merry 	io = (union ctl_io *)ccb_h->io_ptr;
788130f4520SKenneth D. Merry 	csio = &start_ccb->csio;
789130f4520SKenneth D. Merry 
790130f4520SKenneth D. Merry 	flags = atio->ccb_h.flags &
791130f4520SKenneth D. Merry 		(CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
792e67ac203SAlexander Motin 	cmd_info = PRIV_INFO(io);
793f7241cceSAlexander Motin 	cmd_info->cur_transfer_index = 0;
794f7241cceSAlexander Motin 	cmd_info->cur_transfer_off = 0;
795f7241cceSAlexander Motin 	cmd_info->flags = 0;
796130f4520SKenneth D. Merry 
797993a751eSAlexander Motin 	if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) {
798993a751eSAlexander Motin 		/*
799993a751eSAlexander Motin 		 * Datamove call, we need to setup the S/G list.
800993a751eSAlexander Motin 		 */
801993a751eSAlexander Motin 		ctlfedata(softc, io, &flags, &data_ptr, &dxfer_len,
802993a751eSAlexander Motin 		    &csio->sglist_cnt);
803993a751eSAlexander Motin 	} else {
804130f4520SKenneth D. Merry 		/*
805130f4520SKenneth D. Merry 		 * We're done, send status back.
806130f4520SKenneth D. Merry 		 */
807993a751eSAlexander Motin 		if ((io->io_hdr.flags & CTL_FLAG_ABORT) &&
808b33b96e3SAlexander Motin 		    (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) {
809130f4520SKenneth D. Merry 			io->io_hdr.flags &= ~CTL_FLAG_STATUS_QUEUED;
810130f4520SKenneth D. Merry 
8116b087850SAlexander Motin 			/* Tell the SIM that we've aborted this ATIO */
8126b087850SAlexander Motin #ifdef CTLFEDEBUG
8136b087850SAlexander Motin 			printf("%s: tag %04x abort\n", __func__, atio->tag_id);
8146b087850SAlexander Motin #endif
8156b087850SAlexander Motin 			KASSERT(atio->ccb_h.func_code == XPT_ACCEPT_TARGET_IO,
8166b087850SAlexander Motin 			    ("func_code %#x is not ATIO", atio->ccb_h.func_code));
817130f4520SKenneth D. Merry 			start_ccb->ccb_h.func_code = XPT_ABORT;
818130f4520SKenneth D. Merry 			start_ccb->cab.abort_ccb = (union ccb *)atio;
819130f4520SKenneth D. Merry 			xpt_action(start_ccb);
820130f4520SKenneth D. Merry 
821a504738fSAlexander Motin 			ctlfe_requeue_ccb(periph, (union ccb *)atio,
822a504738fSAlexander Motin 			    /* unlock */0);
823130f4520SKenneth D. Merry 
824a504738fSAlexander Motin 			/* XPT_ABORT is not queued, so we can take next I/O. */
825a504738fSAlexander Motin 			goto next;
826993a751eSAlexander Motin 		}
827f7241cceSAlexander Motin 		data_ptr = NULL;
828f7241cceSAlexander Motin 		dxfer_len = 0;
829f7241cceSAlexander Motin 		csio->sglist_cnt = 0;
830f7241cceSAlexander Motin 	}
831eb6ac6f9SAlexander Motin 	scsi_status = 0;
832f7241cceSAlexander Motin 	if ((io->io_hdr.flags & CTL_FLAG_STATUS_QUEUED) &&
833f7241cceSAlexander Motin 	    (cmd_info->flags & CTLFE_CMD_PIECEWISE) == 0 &&
834f7241cceSAlexander Motin 	    ((io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) == 0 ||
835f7241cceSAlexander Motin 	     io->io_hdr.status == CTL_SUCCESS)) {
836993a751eSAlexander Motin 		flags |= CAM_SEND_STATUS;
837130f4520SKenneth D. Merry 		scsi_status = io->scsiio.scsi_status;
838130f4520SKenneth D. Merry 		csio->sense_len = io->scsiio.sense_len;
839130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
840130f4520SKenneth D. Merry 		printf("%s: tag %04x status %x\n", __func__,
841130f4520SKenneth D. Merry 		       atio->tag_id, io->io_hdr.status);
842130f4520SKenneth D. Merry #endif
843130f4520SKenneth D. Merry 		if (csio->sense_len != 0) {
844130f4520SKenneth D. Merry 			csio->sense_data = io->scsiio.sense_data;
845130f4520SKenneth D. Merry 			flags |= CAM_SEND_SENSE;
846130f4520SKenneth D. Merry 		}
847130f4520SKenneth D. Merry 	}
848130f4520SKenneth D. Merry 
849130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
850130f4520SKenneth D. Merry 	printf("%s: %s: tag %04x flags %x ptr %p len %u\n", __func__,
851130f4520SKenneth D. Merry 	       (flags & CAM_SEND_STATUS) ? "done" : "datamove",
852130f4520SKenneth D. Merry 	       atio->tag_id, flags, data_ptr, dxfer_len);
853130f4520SKenneth D. Merry #endif
854130f4520SKenneth D. Merry 
855130f4520SKenneth D. Merry 	/*
856130f4520SKenneth D. Merry 	 * Valid combinations:
85727492beaSAlexander Motin 	 *  - CAM_SEND_STATUS, CAM_DATA_SG = 0, dxfer_len = 0,
858130f4520SKenneth D. Merry 	 *    sglist_cnt = 0
85927492beaSAlexander Motin 	 *  - CAM_SEND_STATUS = 0, CAM_DATA_SG = 0, dxfer_len != 0,
860130f4520SKenneth D. Merry 	 *    sglist_cnt = 0
86127492beaSAlexander Motin 	 *  - CAM_SEND_STATUS = 0, CAM_DATA_SG, dxfer_len != 0,
862130f4520SKenneth D. Merry 	 *    sglist_cnt != 0
863130f4520SKenneth D. Merry 	 */
864130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
865130f4520SKenneth D. Merry 	if (((flags & CAM_SEND_STATUS)
86627492beaSAlexander Motin 	  && (((flags & CAM_DATA_SG) != 0)
867130f4520SKenneth D. Merry 	   || (dxfer_len != 0)
868130f4520SKenneth D. Merry 	   || (csio->sglist_cnt != 0)))
869130f4520SKenneth D. Merry 	 || (((flags & CAM_SEND_STATUS) == 0)
870130f4520SKenneth D. Merry 	  && (dxfer_len == 0))
87127492beaSAlexander Motin 	 || ((flags & CAM_DATA_SG)
872130f4520SKenneth D. Merry 	  && (csio->sglist_cnt == 0))
87327492beaSAlexander Motin 	 || (((flags & CAM_DATA_SG) == 0)
874130f4520SKenneth D. Merry 	  && (csio->sglist_cnt != 0))) {
875130f4520SKenneth D. Merry 		printf("%s: tag %04x cdb %02x flags %#x dxfer_len "
876130f4520SKenneth D. Merry 		       "%d sg %u\n", __func__, atio->tag_id,
8774902e14dSAlexander Motin 		       atio_cdb_ptr(atio)[0], flags, dxfer_len,
878130f4520SKenneth D. Merry 		       csio->sglist_cnt);
879130f4520SKenneth D. Merry 		printf("%s: tag %04x io status %#x\n", __func__,
880130f4520SKenneth D. Merry 		       atio->tag_id, io->io_hdr.status);
881130f4520SKenneth D. Merry 	}
882130f4520SKenneth D. Merry #endif
883130f4520SKenneth D. Merry 	cam_fill_ctio(csio,
884130f4520SKenneth D. Merry 		      /*retries*/ 2,
885130f4520SKenneth D. Merry 		      ctlfedone,
886130f4520SKenneth D. Merry 		      flags,
887993a751eSAlexander Motin 		      (flags & CAM_TAG_ACTION_VALID) ? MSG_SIMPLE_Q_TAG : 0,
888130f4520SKenneth D. Merry 		      atio->tag_id,
889130f4520SKenneth D. Merry 		      atio->init_id,
890130f4520SKenneth D. Merry 		      scsi_status,
891130f4520SKenneth D. Merry 		      /*data_ptr*/ data_ptr,
892130f4520SKenneth D. Merry 		      /*dxfer_len*/ dxfer_len,
89303ea6ef2SAlexander Motin 		      /*timeout*/ CTLFE_TIMEOUT * 1000);
894227d67aaSAlexander Motin 	start_ccb->ccb_h.flags |= CAM_UNLOCKED;
895130f4520SKenneth D. Merry 	start_ccb->ccb_h.ccb_atio = atio;
896993a751eSAlexander Motin 	if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED)
897130f4520SKenneth D. Merry 		io->io_hdr.flags |= CTL_FLAG_DMA_INPROG;
898993a751eSAlexander Motin 	io->io_hdr.flags &= ~(CTL_FLAG_DMA_QUEUED | CTL_FLAG_STATUS_QUEUED);
899130f4520SKenneth D. Merry 
900130f4520SKenneth D. Merry 	softc->ctios_sent++;
9013afd4806SAlexander Motin 	softc->refcount++;
902227d67aaSAlexander Motin 	cam_periph_unlock(periph);
903130f4520SKenneth D. Merry 	xpt_action(start_ccb);
904227d67aaSAlexander Motin 	cam_periph_lock(periph);
9053afd4806SAlexander Motin 	softc->refcount--;
906130f4520SKenneth D. Merry 
907130f4520SKenneth D. Merry 	/*
908993a751eSAlexander Motin 	 * If we still have work to do, ask for another CCB.
909130f4520SKenneth D. Merry 	 */
910832529c5SAlexander Motin 	if (!STAILQ_EMPTY(&softc->work_queue))
9113afd4806SAlexander Motin 		xpt_schedule(periph, CAM_PRIORITY_NORMAL);
9123afd4806SAlexander Motin }
9133afd4806SAlexander Motin 
9143afd4806SAlexander Motin static void
9153afd4806SAlexander Motin ctlfe_drain(void *context, int pending)
9163afd4806SAlexander Motin {
9173afd4806SAlexander Motin 	struct cam_periph *periph = context;
9183afd4806SAlexander Motin 	struct ctlfe_lun_softc *softc = periph->softc;
9193afd4806SAlexander Motin 
9203afd4806SAlexander Motin 	cam_periph_lock(periph);
9213afd4806SAlexander Motin 	while (softc->refcount != 0) {
9223afd4806SAlexander Motin 		cam_periph_sleep(periph, &softc->refcount, PRIBIO,
9233afd4806SAlexander Motin 		    "ctlfe_drain", 1);
9243afd4806SAlexander Motin 	}
9253afd4806SAlexander Motin 	cam_periph_unlock(periph);
9263afd4806SAlexander Motin 	cam_periph_release(periph);
927130f4520SKenneth D. Merry }
928130f4520SKenneth D. Merry 
929130f4520SKenneth D. Merry static void
930130f4520SKenneth D. Merry ctlfe_free_ccb(struct cam_periph *periph, union ccb *ccb)
931130f4520SKenneth D. Merry {
932130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
9337278725bSAlexander Motin 	union ctl_io *io;
9347278725bSAlexander Motin 	struct ctlfe_cmd_info *cmd_info;
935130f4520SKenneth D. Merry 
936130f4520SKenneth D. Merry 	softc = (struct ctlfe_lun_softc *)periph->softc;
9377278725bSAlexander Motin 	io = ccb->ccb_h.io_ptr;
938130f4520SKenneth D. Merry 
939130f4520SKenneth D. Merry 	switch (ccb->ccb_h.func_code) {
940130f4520SKenneth D. Merry 	case XPT_ACCEPT_TARGET_IO:
9413afd4806SAlexander Motin 		softc->atios_alloced--;
942e67ac203SAlexander Motin 		cmd_info = PRIV_INFO(io);
9437278725bSAlexander Motin 		free(cmd_info, M_CTLFE);
944130f4520SKenneth D. Merry 		break;
945130f4520SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY:
946130f4520SKenneth D. Merry 	case XPT_NOTIFY_ACKNOWLEDGE:
9473afd4806SAlexander Motin 		softc->inots_alloced--;
948130f4520SKenneth D. Merry 		break;
949130f4520SKenneth D. Merry 	default:
950130f4520SKenneth D. Merry 		break;
951130f4520SKenneth D. Merry 	}
952130f4520SKenneth D. Merry 
9537278725bSAlexander Motin 	ctl_free_io(io);
954130f4520SKenneth D. Merry 	free(ccb, M_CTLFE);
955130f4520SKenneth D. Merry 
9563afd4806SAlexander Motin 	KASSERT(softc->atios_alloced >= 0, ("%s: atios_alloced %d < 0",
9573afd4806SAlexander Motin 	    __func__, softc->atios_alloced));
9583afd4806SAlexander Motin 	KASSERT(softc->inots_alloced >= 0, ("%s: inots_alloced %d < 0",
9593afd4806SAlexander Motin 	    __func__, softc->inots_alloced));
960130f4520SKenneth D. Merry 
961130f4520SKenneth D. Merry 	/*
962130f4520SKenneth D. Merry 	 * If we have received all of our CCBs, we can release our
963130f4520SKenneth D. Merry 	 * reference on the peripheral driver.  It will probably go away
964130f4520SKenneth D. Merry 	 * now.
965130f4520SKenneth D. Merry 	 */
9663afd4806SAlexander Motin 	if (softc->atios_alloced == 0 && softc->inots_alloced == 0) {
9673afd4806SAlexander Motin 		if (softc->refcount == 0) {
968130f4520SKenneth D. Merry 			cam_periph_release_locked(periph);
9693afd4806SAlexander Motin 		} else {
9703afd4806SAlexander Motin 			TASK_INIT(&softc->refdrain_task, 0, ctlfe_drain, periph);
9713afd4806SAlexander Motin 			taskqueue_enqueue(taskqueue_thread,
9723afd4806SAlexander Motin 			    &softc->refdrain_task);
9733afd4806SAlexander Motin 		}
974130f4520SKenneth D. Merry 	}
975130f4520SKenneth D. Merry }
976130f4520SKenneth D. Merry 
977a504738fSAlexander Motin /*
978a504738fSAlexander Motin  * Send the ATIO/INOT back to the SIM, or free it if periph was invalidated.
979a504738fSAlexander Motin  */
980a504738fSAlexander Motin static void
981a504738fSAlexander Motin ctlfe_requeue_ccb(struct cam_periph *periph, union ccb *ccb, int unlock)
982a504738fSAlexander Motin {
983a504738fSAlexander Motin 	struct ctlfe_lun_softc *softc;
9848d1316f9SAlexander Motin 	struct mtx *mtx;
985a504738fSAlexander Motin 
986a504738fSAlexander Motin 	if (periph->flags & CAM_PERIPH_INVALID) {
9878d1316f9SAlexander Motin 		mtx = cam_periph_mtx(periph);
988a504738fSAlexander Motin 		ctlfe_free_ccb(periph, ccb);
989a504738fSAlexander Motin 		if (unlock)
9908d1316f9SAlexander Motin 			mtx_unlock(mtx);
991a504738fSAlexander Motin 		return;
992a504738fSAlexander Motin 	}
993ad0f05e6SAlexander Motin 	softc = (struct ctlfe_lun_softc *)periph->softc;
994ad0f05e6SAlexander Motin 	if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
995ad0f05e6SAlexander Motin 		LIST_INSERT_HEAD(&softc->atio_list, &ccb->ccb_h, periph_links.le);
996ad0f05e6SAlexander Motin 	else
997ad0f05e6SAlexander Motin 		LIST_INSERT_HEAD(&softc->inot_list, &ccb->ccb_h, periph_links.le);
998a504738fSAlexander Motin 	if (unlock)
999a504738fSAlexander Motin 		cam_periph_unlock(periph);
1000a504738fSAlexander Motin 
1001a504738fSAlexander Motin 	/*
1002a504738fSAlexander Motin 	 * For a wildcard attachment, commands can come in with a specific
1003a504738fSAlexander Motin 	 * target/lun.  Reset the target and LUN fields back to the wildcard
1004a504738fSAlexander Motin 	 * values before we send them back down to the SIM.
1005a504738fSAlexander Motin 	 */
1006c901a9b1SAlexander Motin 	xpt_setup_ccb_flags(&ccb->ccb_h, periph->path, CAM_PRIORITY_NONE,
1007c901a9b1SAlexander Motin 	    ccb->ccb_h.flags);
1008a504738fSAlexander Motin 
1009a504738fSAlexander Motin 	xpt_action(ccb);
1010a504738fSAlexander Motin }
1011a504738fSAlexander Motin 
10123388f7a9SMatt Jacob static int
10133388f7a9SMatt Jacob ctlfe_adjust_cdb(struct ccb_accept_tio *atio, uint32_t offset)
10143388f7a9SMatt Jacob {
10153388f7a9SMatt Jacob 	uint64_t lba;
10163388f7a9SMatt Jacob 	uint32_t num_blocks, nbc;
10174902e14dSAlexander Motin 	uint8_t *cmdbyt = atio_cdb_ptr(atio);
10183388f7a9SMatt Jacob 
10193388f7a9SMatt Jacob 	nbc = offset >> 9;	/* ASSUMING 512 BYTE BLOCKS */
10203388f7a9SMatt Jacob 
10213388f7a9SMatt Jacob 	switch (cmdbyt[0]) {
10223388f7a9SMatt Jacob 	case READ_6:
10233388f7a9SMatt Jacob 	case WRITE_6:
10243388f7a9SMatt Jacob 	{
10253388f7a9SMatt Jacob 		struct scsi_rw_6 *cdb = (struct scsi_rw_6 *)cmdbyt;
10263388f7a9SMatt Jacob 		lba = scsi_3btoul(cdb->addr);
10273388f7a9SMatt Jacob 		lba &= 0x1fffff;
10283388f7a9SMatt Jacob 		num_blocks = cdb->length;
10293388f7a9SMatt Jacob 		if (num_blocks == 0)
10303388f7a9SMatt Jacob 			num_blocks = 256;
10313388f7a9SMatt Jacob 		lba += nbc;
10323388f7a9SMatt Jacob 		num_blocks -= nbc;
10333388f7a9SMatt Jacob 		scsi_ulto3b(lba, cdb->addr);
10343388f7a9SMatt Jacob 		cdb->length = num_blocks;
10353388f7a9SMatt Jacob 		break;
10363388f7a9SMatt Jacob 	}
10373388f7a9SMatt Jacob 	case READ_10:
10383388f7a9SMatt Jacob 	case WRITE_10:
10393388f7a9SMatt Jacob 	{
10403388f7a9SMatt Jacob 		struct scsi_rw_10 *cdb = (struct scsi_rw_10 *)cmdbyt;
10413388f7a9SMatt Jacob 		lba = scsi_4btoul(cdb->addr);
10423388f7a9SMatt Jacob 		num_blocks = scsi_2btoul(cdb->length);
10433388f7a9SMatt Jacob 		lba += nbc;
10443388f7a9SMatt Jacob 		num_blocks -= nbc;
10453388f7a9SMatt Jacob 		scsi_ulto4b(lba, cdb->addr);
10463388f7a9SMatt Jacob 		scsi_ulto2b(num_blocks, cdb->length);
10473388f7a9SMatt Jacob 		break;
10483388f7a9SMatt Jacob 	}
10493388f7a9SMatt Jacob 	case READ_12:
10503388f7a9SMatt Jacob 	case WRITE_12:
10513388f7a9SMatt Jacob 	{
10523388f7a9SMatt Jacob 		struct scsi_rw_12 *cdb = (struct scsi_rw_12 *)cmdbyt;
10533388f7a9SMatt Jacob 		lba = scsi_4btoul(cdb->addr);
10543388f7a9SMatt Jacob 		num_blocks = scsi_4btoul(cdb->length);
10553388f7a9SMatt Jacob 		lba += nbc;
10563388f7a9SMatt Jacob 		num_blocks -= nbc;
10573388f7a9SMatt Jacob 		scsi_ulto4b(lba, cdb->addr);
10583388f7a9SMatt Jacob 		scsi_ulto4b(num_blocks, cdb->length);
10593388f7a9SMatt Jacob 		break;
10603388f7a9SMatt Jacob 	}
10613388f7a9SMatt Jacob 	case READ_16:
10623388f7a9SMatt Jacob 	case WRITE_16:
10633388f7a9SMatt Jacob 	{
10643388f7a9SMatt Jacob 		struct scsi_rw_16 *cdb = (struct scsi_rw_16 *)cmdbyt;
10653388f7a9SMatt Jacob 		lba = scsi_8btou64(cdb->addr);
10663388f7a9SMatt Jacob 		num_blocks = scsi_4btoul(cdb->length);
10673388f7a9SMatt Jacob 		lba += nbc;
10683388f7a9SMatt Jacob 		num_blocks -= nbc;
10693388f7a9SMatt Jacob 		scsi_u64to8b(lba, cdb->addr);
10703388f7a9SMatt Jacob 		scsi_ulto4b(num_blocks, cdb->length);
10713388f7a9SMatt Jacob 		break;
10723388f7a9SMatt Jacob 	}
10733388f7a9SMatt Jacob 	default:
10743388f7a9SMatt Jacob 		return -1;
10753388f7a9SMatt Jacob 	}
10763388f7a9SMatt Jacob 	return (0);
10773388f7a9SMatt Jacob }
10783388f7a9SMatt Jacob 
1079130f4520SKenneth D. Merry static void
1080130f4520SKenneth D. Merry ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
1081130f4520SKenneth D. Merry {
1082130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
1083130f4520SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
10847278725bSAlexander Motin 	struct ctlfe_cmd_info *cmd_info;
10853388f7a9SMatt Jacob 	struct ccb_accept_tio *atio = NULL;
10863388f7a9SMatt Jacob 	union ctl_io *io = NULL;
1087227d67aaSAlexander Motin 	struct mtx *mtx;
10883b63a91dSAlexander Motin 	cam_status status;
1089130f4520SKenneth D. Merry 
1090227d67aaSAlexander Motin 	KASSERT((done_ccb->ccb_h.flags & CAM_UNLOCKED) != 0,
1091227d67aaSAlexander Motin 	    ("CCB in ctlfedone() without CAM_UNLOCKED flag"));
1092130f4520SKenneth D. Merry #ifdef CTLFE_DEBUG
10931251a76bSAlexander Motin 	printf("%s: entered, func_code = %#x\n", __func__,
10941251a76bSAlexander Motin 	       done_ccb->ccb_h.func_code);
1095130f4520SKenneth D. Merry #endif
1096130f4520SKenneth D. Merry 
1097b9807a43SAlexander Motin 	/*
1098b9807a43SAlexander Motin 	 * At this point CTL has no known use case for device queue freezes.
1099b9807a43SAlexander Motin 	 * In case some SIM think different -- drop its freeze right here.
1100b9807a43SAlexander Motin 	 */
1101b9807a43SAlexander Motin 	if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1102b9807a43SAlexander Motin 		cam_release_devq(periph->path,
1103b9807a43SAlexander Motin 				 /*relsim_flags*/0,
1104b9807a43SAlexander Motin 				 /*reduction*/0,
1105b9807a43SAlexander Motin 				 /*timeout*/0,
1106b9807a43SAlexander Motin 				 /*getcount_only*/0);
1107b9807a43SAlexander Motin 		done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
1108b9807a43SAlexander Motin 	}
1109b9807a43SAlexander Motin 
1110130f4520SKenneth D. Merry 	softc = (struct ctlfe_lun_softc *)periph->softc;
1111130f4520SKenneth D. Merry 	bus_softc = softc->parent_softc;
1112227d67aaSAlexander Motin 	mtx = cam_periph_mtx(periph);
1113227d67aaSAlexander Motin 	mtx_lock(mtx);
1114130f4520SKenneth D. Merry 
1115130f4520SKenneth D. Merry 	switch (done_ccb->ccb_h.func_code) {
1116130f4520SKenneth D. Merry 	case XPT_ACCEPT_TARGET_IO: {
1117ad0f05e6SAlexander Motin 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1118130f4520SKenneth D. Merry 		atio = &done_ccb->atio;
11193b63a91dSAlexander Motin 		status = atio->ccb_h.status & CAM_STATUS_MASK;
11203b63a91dSAlexander Motin 		if (status != CAM_CDB_RECVD) {
11213b63a91dSAlexander Motin 			ctlfe_free_ccb(periph, done_ccb);
11223b63a91dSAlexander Motin 			goto out;
11233b63a91dSAlexander Motin 		}
1124130f4520SKenneth D. Merry 
11253388f7a9SMatt Jacob  resubmit:
1126130f4520SKenneth D. Merry 		/*
1127130f4520SKenneth D. Merry 		 * Allocate a ctl_io, pass it to CTL, and wait for the
1128130f4520SKenneth D. Merry 		 * datamove or done.
1129130f4520SKenneth D. Merry 		 */
1130227d67aaSAlexander Motin 		mtx_unlock(mtx);
11311251a76bSAlexander Motin 		io = done_ccb->ccb_h.io_ptr;
1132e67ac203SAlexander Motin 		cmd_info = PRIV_INFO(io);
1133130f4520SKenneth D. Merry 		ctl_zero_io(io);
1134130f4520SKenneth D. Merry 
1135130f4520SKenneth D. Merry 		/* Save pointers on both sides */
1136e67ac203SAlexander Motin 		PRIV_CCB(io) = done_ccb;
1137e67ac203SAlexander Motin 		PRIV_INFO(io) = cmd_info;
1138130f4520SKenneth D. Merry 		done_ccb->ccb_h.io_ptr = io;
1139130f4520SKenneth D. Merry 
1140130f4520SKenneth D. Merry 		/*
1141130f4520SKenneth D. Merry 		 * Only SCSI I/O comes down this path, resets, etc. come
1142130f4520SKenneth D. Merry 		 * down the immediate notify path below.
1143130f4520SKenneth D. Merry 		 */
1144130f4520SKenneth D. Merry 		io->io_hdr.io_type = CTL_IO_SCSI;
1145fb606ebaSAlexander Motin 		io->io_hdr.nexus.initid = atio->init_id;
114692168f4cSAlexander Motin 		io->io_hdr.nexus.targ_port = bus_softc->port.targ_port;
114759f063d5SAlexander Motin 		if (bus_softc->hba_misc & PIM_EXTLUNS) {
114859f063d5SAlexander Motin 			io->io_hdr.nexus.targ_lun = ctl_decode_lun(
114959f063d5SAlexander Motin 			    CAM_EXTLUN_BYTE_SWIZZLE(atio->ccb_h.target_lun));
115059f063d5SAlexander Motin 		} else {
1151130f4520SKenneth D. Merry 			io->io_hdr.nexus.targ_lun = atio->ccb_h.target_lun;
115259f063d5SAlexander Motin 		}
115388364968SAlexander Motin 		io->scsiio.priority = atio->priority;
1154130f4520SKenneth D. Merry 		io->scsiio.tag_num = atio->tag_id;
1155130f4520SKenneth D. Merry 		switch (atio->tag_action) {
1156130f4520SKenneth D. Merry 		case CAM_TAG_ACTION_NONE:
1157130f4520SKenneth D. Merry 			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
1158130f4520SKenneth D. Merry 			break;
1159130f4520SKenneth D. Merry 		case MSG_SIMPLE_TASK:
1160130f4520SKenneth D. Merry 			io->scsiio.tag_type = CTL_TAG_SIMPLE;
1161130f4520SKenneth D. Merry 			break;
1162130f4520SKenneth D. Merry 		case MSG_HEAD_OF_QUEUE_TASK:
1163130f4520SKenneth D. Merry         		io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
1164130f4520SKenneth D. Merry 			break;
1165130f4520SKenneth D. Merry 		case MSG_ORDERED_TASK:
1166130f4520SKenneth D. Merry         		io->scsiio.tag_type = CTL_TAG_ORDERED;
1167130f4520SKenneth D. Merry 			break;
1168130f4520SKenneth D. Merry 		case MSG_ACA_TASK:
1169130f4520SKenneth D. Merry 			io->scsiio.tag_type = CTL_TAG_ACA;
1170130f4520SKenneth D. Merry 			break;
1171130f4520SKenneth D. Merry 		default:
1172130f4520SKenneth D. Merry 			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
1173130f4520SKenneth D. Merry 			printf("%s: unhandled tag type %#x!!\n", __func__,
1174130f4520SKenneth D. Merry 			       atio->tag_action);
1175130f4520SKenneth D. Merry 			break;
1176130f4520SKenneth D. Merry 		}
1177130f4520SKenneth D. Merry 		if (atio->cdb_len > sizeof(io->scsiio.cdb)) {
1178130f4520SKenneth D. Merry 			printf("%s: WARNING: CDB len %d > ctl_io space %zd\n",
1179130f4520SKenneth D. Merry 			       __func__, atio->cdb_len, sizeof(io->scsiio.cdb));
1180130f4520SKenneth D. Merry 		}
1181130f4520SKenneth D. Merry 		io->scsiio.cdb_len = min(atio->cdb_len, sizeof(io->scsiio.cdb));
11824902e14dSAlexander Motin 		bcopy(atio_cdb_ptr(atio), io->scsiio.cdb, io->scsiio.cdb_len);
1183130f4520SKenneth D. Merry 
1184130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
11850acc026dSAlexander Motin 		printf("%s: %u:%u:%u: tag %jx CDB %02x\n", __func__,
1186fb606ebaSAlexander Motin 		        io->io_hdr.nexus.initid,
1187130f4520SKenneth D. Merry 		        io->io_hdr.nexus.targ_port,
1188130f4520SKenneth D. Merry 		        io->io_hdr.nexus.targ_lun,
1189130f4520SKenneth D. Merry 			io->scsiio.tag_num, io->scsiio.cdb[0]);
1190130f4520SKenneth D. Merry #endif
1191130f4520SKenneth D. Merry 
1192130f4520SKenneth D. Merry 		ctl_queue(io);
1193227d67aaSAlexander Motin 		return;
1194130f4520SKenneth D. Merry 	}
1195130f4520SKenneth D. Merry 	case XPT_CONT_TARGET_IO: {
11963388f7a9SMatt Jacob 		int srr = 0;
11973388f7a9SMatt Jacob 		uint32_t srr_off = 0;
1198130f4520SKenneth D. Merry 
1199130f4520SKenneth D. Merry 		atio = (struct ccb_accept_tio *)done_ccb->ccb_h.ccb_atio;
1200130f4520SKenneth D. Merry 		io = (union ctl_io *)atio->ccb_h.io_ptr;
1201130f4520SKenneth D. Merry 
12023afd4806SAlexander Motin 		softc->ctios_sent--;
1203130f4520SKenneth D. Merry #ifdef CTLFEDEBUG
1204130f4520SKenneth D. Merry 		printf("%s: got XPT_CONT_TARGET_IO tag %#x flags %#x\n",
1205130f4520SKenneth D. Merry 		       __func__, atio->tag_id, done_ccb->ccb_h.flags);
1206130f4520SKenneth D. Merry #endif
1207130f4520SKenneth D. Merry 		/*
12083388f7a9SMatt Jacob 		 * Handle SRR case were the data pointer is pushed back hack
12093388f7a9SMatt Jacob 		 */
12103388f7a9SMatt Jacob 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_MESSAGE_RECV
12113388f7a9SMatt Jacob 		    && done_ccb->csio.msg_ptr != NULL
12123388f7a9SMatt Jacob 		    && done_ccb->csio.msg_ptr[0] == MSG_EXTENDED
12133388f7a9SMatt Jacob 		    && done_ccb->csio.msg_ptr[1] == 5
12143388f7a9SMatt Jacob        		    && done_ccb->csio.msg_ptr[2] == 0) {
12153388f7a9SMatt Jacob 			srr = 1;
12163388f7a9SMatt Jacob 			srr_off =
12173388f7a9SMatt Jacob 			    (done_ccb->csio.msg_ptr[3] << 24)
12183388f7a9SMatt Jacob 			    | (done_ccb->csio.msg_ptr[4] << 16)
12193388f7a9SMatt Jacob 			    | (done_ccb->csio.msg_ptr[5] << 8)
12203388f7a9SMatt Jacob 			    | (done_ccb->csio.msg_ptr[6]);
12213388f7a9SMatt Jacob 		}
12223388f7a9SMatt Jacob 
12233388f7a9SMatt Jacob 		/*
1224eb6ac6f9SAlexander Motin 		 * If we have an SRR and we're still sending data, we
1225eb6ac6f9SAlexander Motin 		 * should be able to adjust offsets and cycle again.
1226eb6ac6f9SAlexander Motin 		 * It is possible only if offset is from this datamove.
12273388f7a9SMatt Jacob 		 */
1228eb6ac6f9SAlexander Motin 		if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) &&
1229eb6ac6f9SAlexander Motin 		    srr_off >= io->scsiio.kern_rel_offset &&
1230eb6ac6f9SAlexander Motin 		    srr_off < io->scsiio.kern_rel_offset +
1231eb6ac6f9SAlexander Motin 		     io->scsiio.kern_data_len) {
1232eb6ac6f9SAlexander Motin 			io->scsiio.kern_data_resid =
1233eb6ac6f9SAlexander Motin 			    io->scsiio.kern_rel_offset +
1234eb6ac6f9SAlexander Motin 			    io->scsiio.kern_data_len - srr_off;
1235eb6ac6f9SAlexander Motin 			io->scsiio.ext_data_filled = srr_off;
1236eb6ac6f9SAlexander Motin 			io->scsiio.io_hdr.status = CTL_STATUS_NONE;
1237eb6ac6f9SAlexander Motin 			io->io_hdr.flags |= CTL_FLAG_DMA_QUEUED;
1238eb6ac6f9SAlexander Motin 			xpt_release_ccb(done_ccb);
1239832529c5SAlexander Motin 			STAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
1240832529c5SAlexander Motin 					  periph_links.stqe);
12413afd4806SAlexander Motin 			xpt_schedule(periph, CAM_PRIORITY_NORMAL);
1242eb6ac6f9SAlexander Motin 			break;
1243eb6ac6f9SAlexander Motin 		}
1244eb6ac6f9SAlexander Motin 
1245eb6ac6f9SAlexander Motin 		/*
1246eb6ac6f9SAlexander Motin 		 * If status was being sent, the back end data is now history.
1247eb6ac6f9SAlexander Motin 		 * Hack it up and resubmit a new command with the CDB adjusted.
1248eb6ac6f9SAlexander Motin 		 * If the SIM does the right thing, all of the resid math
1249eb6ac6f9SAlexander Motin 		 * should work.
1250eb6ac6f9SAlexander Motin 		 */
1251eb6ac6f9SAlexander Motin 		if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) == 0) {
12523388f7a9SMatt Jacob 			xpt_release_ccb(done_ccb);
12533388f7a9SMatt Jacob 			if (ctlfe_adjust_cdb(atio, srr_off) == 0) {
12543388f7a9SMatt Jacob 				done_ccb = (union ccb *)atio;
12553388f7a9SMatt Jacob 				goto resubmit;
12563388f7a9SMatt Jacob 			}
12573388f7a9SMatt Jacob 			/*
12583388f7a9SMatt Jacob 			 * Fall through to doom....
12593388f7a9SMatt Jacob 			 */
12603388f7a9SMatt Jacob 		}
12613388f7a9SMatt Jacob 
12621b922b70SAlexander Motin 		if ((done_ccb->ccb_h.flags & CAM_SEND_STATUS) &&
12631b922b70SAlexander Motin 		    (done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
12641b922b70SAlexander Motin 			io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
12651b922b70SAlexander Motin 
12663388f7a9SMatt Jacob 		/*
1267130f4520SKenneth D. Merry 		 * If we were sending status back to the initiator, free up
1268130f4520SKenneth D. Merry 		 * resources.  If we were doing a datamove, call the
1269130f4520SKenneth D. Merry 		 * datamove done routine.
1270130f4520SKenneth D. Merry 		 */
1271993a751eSAlexander Motin 		if ((io->io_hdr.flags & CTL_FLAG_DMA_INPROG) == 0) {
1272b371466eSAlexander Motin 			/*
1273b371466eSAlexander Motin 			 * If we asked to send sense data but it wasn't sent,
1274b371466eSAlexander Motin 			 * queue the I/O back to CTL for later REQUEST SENSE.
1275b371466eSAlexander Motin 			 */
1276b371466eSAlexander Motin 			if ((done_ccb->ccb_h.flags & CAM_SEND_SENSE) != 0 &&
1277b371466eSAlexander Motin 			    (done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
1278b371466eSAlexander Motin 			    (done_ccb->ccb_h.status & CAM_SENT_SENSE) == 0 &&
1279b371466eSAlexander Motin 			    (io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref)) != NULL) {
1280b371466eSAlexander Motin 				PRIV_INFO(io) = PRIV_INFO(
1281b371466eSAlexander Motin 				    (union ctl_io *)atio->ccb_h.io_ptr);
1282b371466eSAlexander Motin 				ctl_queue_sense(atio->ccb_h.io_ptr);
1283b371466eSAlexander Motin 				atio->ccb_h.io_ptr = io;
1284b371466eSAlexander Motin 			}
1285b371466eSAlexander Motin 
1286d7c2cc35SAlexander Motin 			/* Abort ATIO if CTIO sending status has failed. */
1287d7c2cc35SAlexander Motin 			if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) !=
1288d7c2cc35SAlexander Motin 			    CAM_REQ_CMP) {
1289d7c2cc35SAlexander Motin 				done_ccb->ccb_h.func_code = XPT_ABORT;
1290d7c2cc35SAlexander Motin 				done_ccb->cab.abort_ccb = (union ccb *)atio;
1291d7c2cc35SAlexander Motin 				xpt_action(done_ccb);
1292d7c2cc35SAlexander Motin 			}
1293d7c2cc35SAlexander Motin 
1294130f4520SKenneth D. Merry 			xpt_release_ccb(done_ccb);
1295a504738fSAlexander Motin 			ctlfe_requeue_ccb(periph, (union ccb *)atio,
1296a504738fSAlexander Motin 			    /* unlock */1);
1297227d67aaSAlexander Motin 			return;
1298130f4520SKenneth D. Merry 		} else {
12997278725bSAlexander Motin 			struct ctlfe_cmd_info *cmd_info;
1300130f4520SKenneth D. Merry 			struct ccb_scsiio *csio;
1301130f4520SKenneth D. Merry 
1302130f4520SKenneth D. Merry 			csio = &done_ccb->csio;
1303e67ac203SAlexander Motin 			cmd_info = PRIV_INFO(io);
1304130f4520SKenneth D. Merry 
1305130f4520SKenneth D. Merry 			io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
1306130f4520SKenneth D. Merry 
1307130f4520SKenneth D. Merry 			/*
1308130f4520SKenneth D. Merry 			 * Translate CAM status to CTL status.  Success
1309130f4520SKenneth D. Merry 			 * does not change the overall, ctl_io status.  In
1310130f4520SKenneth D. Merry 			 * that case we just set port_status to 0.  If we
1311130f4520SKenneth D. Merry 			 * have a failure, though, set a data phase error
1312130f4520SKenneth D. Merry 			 * for the overall ctl_io.
1313130f4520SKenneth D. Merry 			 */
1314130f4520SKenneth D. Merry 			switch (done_ccb->ccb_h.status & CAM_STATUS_MASK) {
1315130f4520SKenneth D. Merry 			case CAM_REQ_CMP:
131615b2cdedSAlexander Motin 				io->scsiio.kern_data_resid -=
131715b2cdedSAlexander Motin 				    csio->dxfer_len - csio->resid;
1318130f4520SKenneth D. Merry 				io->io_hdr.port_status = 0;
1319130f4520SKenneth D. Merry 				break;
1320130f4520SKenneth D. Merry 			default:
1321130f4520SKenneth D. Merry 				/*
1322744c26b2SKenneth D. Merry 				 * XXX KDM we probably need to figure out a
1323744c26b2SKenneth D. Merry 				 * standard set of errors that the SIM
1324744c26b2SKenneth D. Merry 				 * drivers should return in the event of a
1325744c26b2SKenneth D. Merry 				 * data transfer failure.  A data phase
1326744c26b2SKenneth D. Merry 				 * error will at least point the user to a
1327744c26b2SKenneth D. Merry 				 * data transfer error of some sort.
1328744c26b2SKenneth D. Merry 				 * Hopefully the SIM printed out some
1329744c26b2SKenneth D. Merry 				 * additional information to give the user
1330744c26b2SKenneth D. Merry 				 * a clue what happened.
1331130f4520SKenneth D. Merry 				 */
1332130f4520SKenneth D. Merry 				io->io_hdr.port_status = 0xbad1;
1333130f4520SKenneth D. Merry 				ctl_set_data_phase_error(&io->scsiio);
1334130f4520SKenneth D. Merry 				/*
1335130f4520SKenneth D. Merry 				 * XXX KDM figure out residual.
1336130f4520SKenneth D. Merry 				 */
1337130f4520SKenneth D. Merry 				break;
1338130f4520SKenneth D. Merry 			}
1339130f4520SKenneth D. Merry 			/*
1340130f4520SKenneth D. Merry 			 * If we had to break this S/G list into multiple
1341130f4520SKenneth D. Merry 			 * pieces, figure out where we are in the list, and
1342130f4520SKenneth D. Merry 			 * continue sending pieces if necessary.
1343130f4520SKenneth D. Merry 			 */
134415b2cdedSAlexander Motin 			if ((cmd_info->flags & CTLFE_CMD_PIECEWISE) &&
134515b2cdedSAlexander Motin 			    io->io_hdr.port_status == 0 && csio->resid == 0) {
1346130f4520SKenneth D. Merry 				ccb_flags flags;
1347130f4520SKenneth D. Merry 				uint8_t *data_ptr;
1348130f4520SKenneth D. Merry 				uint32_t dxfer_len;
1349130f4520SKenneth D. Merry 
1350130f4520SKenneth D. Merry 				flags = atio->ccb_h.flags &
1351130f4520SKenneth D. Merry 					(CAM_DIS_DISCONNECT|
1352acf5bea4SAlexander Motin 					 CAM_TAG_ACTION_VALID);
1353130f4520SKenneth D. Merry 
1354acf5bea4SAlexander Motin 				ctlfedata(softc, io, &flags, &data_ptr,
1355acf5bea4SAlexander Motin 				    &dxfer_len, &csio->sglist_cnt);
1356130f4520SKenneth D. Merry 
1357130f4520SKenneth D. Merry 				if (((flags & CAM_SEND_STATUS) == 0)
1358130f4520SKenneth D. Merry 				 && (dxfer_len == 0)) {
1359130f4520SKenneth D. Merry 					printf("%s: tag %04x no status or "
1360130f4520SKenneth D. Merry 					       "len cdb = %02x\n", __func__,
1361130f4520SKenneth D. Merry 					       atio->tag_id,
13624902e14dSAlexander Motin 					       atio_cdb_ptr(atio)[0]);
1363130f4520SKenneth D. Merry 					printf("%s: tag %04x io status %#x\n",
1364130f4520SKenneth D. Merry 					       __func__, atio->tag_id,
1365130f4520SKenneth D. Merry 					       io->io_hdr.status);
1366130f4520SKenneth D. Merry 				}
1367130f4520SKenneth D. Merry 
1368130f4520SKenneth D. Merry 				cam_fill_ctio(csio,
1369130f4520SKenneth D. Merry 					      /*retries*/ 2,
1370130f4520SKenneth D. Merry 					      ctlfedone,
1371130f4520SKenneth D. Merry 					      flags,
1372130f4520SKenneth D. Merry 					      (flags & CAM_TAG_ACTION_VALID) ?
1373130f4520SKenneth D. Merry 					       MSG_SIMPLE_Q_TAG : 0,
1374130f4520SKenneth D. Merry 					      atio->tag_id,
1375130f4520SKenneth D. Merry 					      atio->init_id,
1376eb6ac6f9SAlexander Motin 					      0,
1377130f4520SKenneth D. Merry 					      /*data_ptr*/ data_ptr,
1378130f4520SKenneth D. Merry 					      /*dxfer_len*/ dxfer_len,
137903ea6ef2SAlexander Motin 					      CTLFE_TIMEOUT * 1000);
1380130f4520SKenneth D. Merry 
1381227d67aaSAlexander Motin 				csio->ccb_h.flags |= CAM_UNLOCKED;
1382130f4520SKenneth D. Merry 				csio->resid = 0;
1383130f4520SKenneth D. Merry 				csio->ccb_h.ccb_atio = atio;
1384130f4520SKenneth D. Merry 				io->io_hdr.flags |= CTL_FLAG_DMA_INPROG;
1385130f4520SKenneth D. Merry 				softc->ctios_sent++;
1386227d67aaSAlexander Motin 				mtx_unlock(mtx);
1387130f4520SKenneth D. Merry 				xpt_action((union ccb *)csio);
1388130f4520SKenneth D. Merry 			} else {
1389130f4520SKenneth D. Merry 				/*
1390130f4520SKenneth D. Merry 				 * Release the CTIO.  The ATIO will be sent back
1391130f4520SKenneth D. Merry 				 * down to the SIM once we send status.
1392130f4520SKenneth D. Merry 				 */
1393130f4520SKenneth D. Merry 				xpt_release_ccb(done_ccb);
1394227d67aaSAlexander Motin 				mtx_unlock(mtx);
1395130f4520SKenneth D. Merry 
13962c7dc6baSAlexander Motin 				ctl_datamove_done(io, false);
1397130f4520SKenneth D. Merry 			}
1398227d67aaSAlexander Motin 			return;
1399130f4520SKenneth D. Merry 		}
1400130f4520SKenneth D. Merry 		break;
1401130f4520SKenneth D. Merry 	}
1402130f4520SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY: {
1403130f4520SKenneth D. Merry 		union ctl_io *io;
1404130f4520SKenneth D. Merry 		struct ccb_immediate_notify *inot;
1405b9807a43SAlexander Motin 		int send_ctl_io;
1406130f4520SKenneth D. Merry 
1407ad0f05e6SAlexander Motin 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1408130f4520SKenneth D. Merry 		inot = &done_ccb->cin1;
14091251a76bSAlexander Motin 		io = done_ccb->ccb_h.io_ptr;
14101251a76bSAlexander Motin 		ctl_zero_io(io);
1411130f4520SKenneth D. Merry 
1412130f4520SKenneth D. Merry 		send_ctl_io = 1;
1413130f4520SKenneth D. Merry 
1414130f4520SKenneth D. Merry 		io->io_hdr.io_type = CTL_IO_TASK;
1415e67ac203SAlexander Motin 		PRIV_CCB(io) = done_ccb;
1416130f4520SKenneth D. Merry 		inot->ccb_h.io_ptr = io;
1417fb606ebaSAlexander Motin 		io->io_hdr.nexus.initid = inot->initiator_id;
141892168f4cSAlexander Motin 		io->io_hdr.nexus.targ_port = bus_softc->port.targ_port;
141959f063d5SAlexander Motin 		if (bus_softc->hba_misc & PIM_EXTLUNS) {
142059f063d5SAlexander Motin 			io->io_hdr.nexus.targ_lun = ctl_decode_lun(
142159f063d5SAlexander Motin 			    CAM_EXTLUN_BYTE_SWIZZLE(inot->ccb_h.target_lun));
142259f063d5SAlexander Motin 		} else {
1423130f4520SKenneth D. Merry 			io->io_hdr.nexus.targ_lun = inot->ccb_h.target_lun;
142459f063d5SAlexander Motin 		}
1425130f4520SKenneth D. Merry 		/* XXX KDM should this be the tag_id? */
1426130f4520SKenneth D. Merry 		io->taskio.tag_num = inot->seq_id;
1427130f4520SKenneth D. Merry 
1428130f4520SKenneth D. Merry 		status = inot->ccb_h.status & CAM_STATUS_MASK;
1429130f4520SKenneth D. Merry 		switch (status) {
1430130f4520SKenneth D. Merry 		case CAM_SCSI_BUS_RESET:
1431130f4520SKenneth D. Merry 			io->taskio.task_action = CTL_TASK_BUS_RESET;
1432130f4520SKenneth D. Merry 			break;
1433130f4520SKenneth D. Merry 		case CAM_BDR_SENT:
1434130f4520SKenneth D. Merry 			io->taskio.task_action = CTL_TASK_TARGET_RESET;
1435130f4520SKenneth D. Merry 			break;
1436130f4520SKenneth D. Merry 		case CAM_MESSAGE_RECV:
1437130f4520SKenneth D. Merry 			switch (inot->arg) {
1438130f4520SKenneth D. Merry 			case MSG_ABORT_TASK_SET:
1439130f4520SKenneth D. Merry 				io->taskio.task_action =
1440130f4520SKenneth D. Merry 				    CTL_TASK_ABORT_TASK_SET;
1441130f4520SKenneth D. Merry 				break;
1442130f4520SKenneth D. Merry 			case MSG_TARGET_RESET:
1443c98d2b1fSAlexander Motin 				io->taskio.task_action = CTL_TASK_TARGET_RESET;
1444130f4520SKenneth D. Merry 				break;
1445130f4520SKenneth D. Merry 			case MSG_ABORT_TASK:
1446c98d2b1fSAlexander Motin 				io->taskio.task_action = CTL_TASK_ABORT_TASK;
1447130f4520SKenneth D. Merry 				break;
1448130f4520SKenneth D. Merry 			case MSG_LOGICAL_UNIT_RESET:
1449c98d2b1fSAlexander Motin 				io->taskio.task_action = CTL_TASK_LUN_RESET;
1450130f4520SKenneth D. Merry 				break;
1451130f4520SKenneth D. Merry 			case MSG_CLEAR_TASK_SET:
1452130f4520SKenneth D. Merry 				io->taskio.task_action =
1453130f4520SKenneth D. Merry 				    CTL_TASK_CLEAR_TASK_SET;
1454130f4520SKenneth D. Merry 				break;
1455130f4520SKenneth D. Merry 			case MSG_CLEAR_ACA:
1456c98d2b1fSAlexander Motin 				io->taskio.task_action = CTL_TASK_CLEAR_ACA;
1457c98d2b1fSAlexander Motin 				break;
1458c98d2b1fSAlexander Motin 			case MSG_QUERY_TASK:
1459c98d2b1fSAlexander Motin 				io->taskio.task_action = CTL_TASK_QUERY_TASK;
1460c98d2b1fSAlexander Motin 				break;
1461c98d2b1fSAlexander Motin 			case MSG_QUERY_TASK_SET:
1462130f4520SKenneth D. Merry 				io->taskio.task_action =
1463c98d2b1fSAlexander Motin 				    CTL_TASK_QUERY_TASK_SET;
1464c98d2b1fSAlexander Motin 				break;
1465c98d2b1fSAlexander Motin 			case MSG_QUERY_ASYNC_EVENT:
1466c98d2b1fSAlexander Motin 				io->taskio.task_action =
1467c98d2b1fSAlexander Motin 				    CTL_TASK_QUERY_ASYNC_EVENT;
1468130f4520SKenneth D. Merry 				break;
1469130f4520SKenneth D. Merry 			case MSG_NOOP:
1470130f4520SKenneth D. Merry 				send_ctl_io = 0;
1471130f4520SKenneth D. Merry 				break;
1472130f4520SKenneth D. Merry 			default:
14731251a76bSAlexander Motin 				xpt_print(periph->path,
14743b63a91dSAlexander Motin 				    "%s: unsupported INOT message 0x%x\n",
1475130f4520SKenneth D. Merry 				    __func__, inot->arg);
1476130f4520SKenneth D. Merry 				send_ctl_io = 0;
1477130f4520SKenneth D. Merry 				break;
1478130f4520SKenneth D. Merry 			}
1479130f4520SKenneth D. Merry 			break;
1480130f4520SKenneth D. Merry 		default:
14811251a76bSAlexander Motin 			xpt_print(periph->path,
14823b63a91dSAlexander Motin 			    "%s: unsupported INOT status 0x%x\n",
14831251a76bSAlexander Motin 			    __func__, status);
14843b63a91dSAlexander Motin 			/* FALLTHROUGH */
14853b63a91dSAlexander Motin 		case CAM_REQ_ABORTED:
14863b63a91dSAlexander Motin 		case CAM_REQ_INVALID:
14873b63a91dSAlexander Motin 		case CAM_DEV_NOT_THERE:
14883b63a91dSAlexander Motin 		case CAM_PROVIDE_FAIL:
1489b79dc8a8SKenneth D. Merry 			ctlfe_free_ccb(periph, done_ccb);
1490227d67aaSAlexander Motin 			goto out;
1491130f4520SKenneth D. Merry 		}
1492c67a2909SAlexander Motin 		mtx_unlock(mtx);
1493130f4520SKenneth D. Merry 		if (send_ctl_io != 0) {
1494130f4520SKenneth D. Merry 			ctl_queue(io);
1495130f4520SKenneth D. Merry 		} else {
1496130f4520SKenneth D. Merry 			done_ccb->ccb_h.status = CAM_REQ_INPROG;
1497130f4520SKenneth D. Merry 			done_ccb->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE;
1498130f4520SKenneth D. Merry 			xpt_action(done_ccb);
1499130f4520SKenneth D. Merry 		}
1500c67a2909SAlexander Motin 		return;
1501130f4520SKenneth D. Merry 	}
1502130f4520SKenneth D. Merry 	case XPT_NOTIFY_ACKNOWLEDGE:
1503a504738fSAlexander Motin 		/* Queue this back down to the SIM as an immediate notify. */
150496b5475bSAlexander Motin 		done_ccb->ccb_h.status = CAM_REQ_INPROG;
1505130f4520SKenneth D. Merry 		done_ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
1506a504738fSAlexander Motin 		ctlfe_requeue_ccb(periph, done_ccb, /* unlock */1);
1507a504738fSAlexander Motin 		return;
1508130f4520SKenneth D. Merry 	case XPT_SET_SIM_KNOB:
1509130f4520SKenneth D. Merry 	case XPT_GET_SIM_KNOB:
1510a2531862SWarner Losh 	case XPT_GET_SIM_KNOB_OLD:
1511130f4520SKenneth D. Merry 		break;
1512130f4520SKenneth D. Merry 	default:
1513130f4520SKenneth D. Merry 		panic("%s: unexpected CCB type %#x", __func__,
1514130f4520SKenneth D. Merry 		      done_ccb->ccb_h.func_code);
1515130f4520SKenneth D. Merry 		break;
1516130f4520SKenneth D. Merry 	}
1517227d67aaSAlexander Motin 
1518227d67aaSAlexander Motin out:
1519227d67aaSAlexander Motin 	mtx_unlock(mtx);
1520130f4520SKenneth D. Merry }
1521130f4520SKenneth D. Merry 
1522130f4520SKenneth D. Merry static void
1523130f4520SKenneth D. Merry ctlfe_onoffline(void *arg, int online)
1524130f4520SKenneth D. Merry {
152545400376SAlexander Motin 	struct ctlfe_softc *bus_softc = arg;
1526130f4520SKenneth D. Merry 	union ccb *ccb;
1527130f4520SKenneth D. Merry 	cam_status status;
1528130f4520SKenneth D. Merry 	struct cam_path *path;
152945400376SAlexander Motin 	int set_wwnn = 0;
1530130f4520SKenneth D. Merry 
1531130f4520SKenneth D. Merry 	status = xpt_create_path(&path, /*periph*/ NULL, bus_softc->path_id,
1532130f4520SKenneth D. Merry 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
1533130f4520SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
1534130f4520SKenneth D. Merry 		printf("%s: unable to create path!\n", __func__);
1535130f4520SKenneth D. Merry 		return;
1536130f4520SKenneth D. Merry 	}
15377511bd04SAlexander Motin 	ccb = xpt_alloc_ccb();
153815a2601bSAlexander Motin 	xpt_setup_ccb(&ccb->ccb_h, path, CAM_PRIORITY_NONE);
1539d1f40587SAlexander Motin 	ccb->ccb_h.func_code = XPT_GET_SIM_KNOB;
1540d1f40587SAlexander Motin 	xpt_action(ccb);
1541130f4520SKenneth D. Merry 
154245400376SAlexander Motin 	/* Check whether we should change WWNs. */
1543130f4520SKenneth D. Merry 	if (online != 0) {
1544130f4520SKenneth D. Merry 		if ((ccb->knob.xport_specific.valid & KNOB_VALID_ADDRESS) != 0){
1545130f4520SKenneth D. Merry 			printf("%s: %s current WWNN %#jx\n", __func__,
1546130f4520SKenneth D. Merry 			       bus_softc->port_name,
1547130f4520SKenneth D. Merry 			       ccb->knob.xport_specific.fc.wwnn);
1548130f4520SKenneth D. Merry 			printf("%s: %s current WWPN %#jx\n", __func__,
1549130f4520SKenneth D. Merry 			       bus_softc->port_name,
1550130f4520SKenneth D. Merry 			       ccb->knob.xport_specific.fc.wwpn);
1551130f4520SKenneth D. Merry 
1552130f4520SKenneth D. Merry 			/*
1553130f4520SKenneth D. Merry 			 * If the user has specified a WWNN/WWPN, send them
1554130f4520SKenneth D. Merry 			 * down to the SIM.  Otherwise, record what the SIM
1555130f4520SKenneth D. Merry 			 * has reported.
1556130f4520SKenneth D. Merry 			 */
15577607afb1SAlexander Motin 			if (bus_softc->port.wwnn != 0 && bus_softc->port.wwnn
15587607afb1SAlexander Motin 			    != ccb->knob.xport_specific.fc.wwnn) {
1559130f4520SKenneth D. Merry 				ccb->knob.xport_specific.fc.wwnn =
156092168f4cSAlexander Motin 				    bus_softc->port.wwnn;
15617607afb1SAlexander Motin 				set_wwnn = 1;
15627607afb1SAlexander Motin 			} else {
15637607afb1SAlexander Motin 				ctl_port_set_wwns(&bus_softc->port,
15647607afb1SAlexander Motin 				    true, ccb->knob.xport_specific.fc.wwnn,
15657607afb1SAlexander Motin 				    false, 0);
15667607afb1SAlexander Motin 			}
15677607afb1SAlexander Motin 			if (bus_softc->port.wwpn != 0 && bus_softc->port.wwpn
15687607afb1SAlexander Motin 			     != ccb->knob.xport_specific.fc.wwpn) {
1569130f4520SKenneth D. Merry 				ccb->knob.xport_specific.fc.wwpn =
157092168f4cSAlexander Motin 				    bus_softc->port.wwpn;
1571130f4520SKenneth D. Merry 				set_wwnn = 1;
1572130f4520SKenneth D. Merry 			} else {
1573027e5269SAlexander Motin 				ctl_port_set_wwns(&bus_softc->port,
15747607afb1SAlexander Motin 				    false, 0,
1575027e5269SAlexander Motin 				    true, ccb->knob.xport_specific.fc.wwpn);
1576130f4520SKenneth D. Merry 			}
157745400376SAlexander Motin 		} else {
157845400376SAlexander Motin 			printf("%s: %s has no valid WWNN/WWPN\n", __func__,
157945400376SAlexander Motin 			       bus_softc->port_name);
158045400376SAlexander Motin 			if (bus_softc->port.wwnn != 0) {
158145400376SAlexander Motin 				ccb->knob.xport_specific.fc.wwnn =
158245400376SAlexander Motin 				    bus_softc->port.wwnn;
158345400376SAlexander Motin 				set_wwnn = 1;
158445400376SAlexander Motin 			}
158545400376SAlexander Motin 			if (bus_softc->port.wwpn != 0) {
158645400376SAlexander Motin 				ccb->knob.xport_specific.fc.wwpn =
158745400376SAlexander Motin 				    bus_softc->port.wwpn;
158845400376SAlexander Motin 				set_wwnn = 1;
158945400376SAlexander Motin 			}
159045400376SAlexander Motin 		}
159145400376SAlexander Motin 	}
159245400376SAlexander Motin 	if (set_wwnn) {
159345400376SAlexander Motin 		ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
159445400376SAlexander Motin 		ccb->knob.xport_specific.valid = KNOB_VALID_ADDRESS;
159545400376SAlexander Motin 		xpt_action(ccb);
159645400376SAlexander Motin 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
159745400376SAlexander Motin 			printf("%s: %s (path id %d) failed set WWNs: %#x\n",
159845400376SAlexander Motin 			    __func__, bus_softc->port_name, bus_softc->path_id,
159945400376SAlexander Motin 			    ccb->ccb_h.status);
160045400376SAlexander Motin 		} else {
1601130f4520SKenneth D. Merry 			printf("%s: %s new WWNN %#jx\n", __func__,
1602130f4520SKenneth D. Merry 			       bus_softc->port_name,
1603130f4520SKenneth D. Merry 			       ccb->knob.xport_specific.fc.wwnn);
1604130f4520SKenneth D. Merry 			printf("%s: %s new WWPN %#jx\n", __func__,
1605130f4520SKenneth D. Merry 			       bus_softc->port_name,
1606130f4520SKenneth D. Merry 			       ccb->knob.xport_specific.fc.wwpn);
1607130f4520SKenneth D. Merry 		}
1608130f4520SKenneth D. Merry 	}
160945400376SAlexander Motin 
161045400376SAlexander Motin 	/* Check whether we should change role. */
161145400376SAlexander Motin 	if ((ccb->knob.xport_specific.valid & KNOB_VALID_ROLE) == 0 ||
161245400376SAlexander Motin 	    ((online != 0) ^
161345400376SAlexander Motin 	    ((ccb->knob.xport_specific.fc.role & KNOB_ROLE_TARGET) != 0)) != 0) {
1614130f4520SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
1615130f4520SKenneth D. Merry 		ccb->knob.xport_specific.valid = KNOB_VALID_ROLE;
161645400376SAlexander Motin 		if (online)
1617d1f40587SAlexander Motin 			ccb->knob.xport_specific.fc.role |= KNOB_ROLE_TARGET;
1618130f4520SKenneth D. Merry 		else
1619d1f40587SAlexander Motin 			ccb->knob.xport_specific.fc.role &= ~KNOB_ROLE_TARGET;
1620130f4520SKenneth D. Merry 		xpt_action(ccb);
1621130f4520SKenneth D. Merry 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
162245400376SAlexander Motin 			printf("%s: %s (path id %d) failed %s target role: %#x\n",
1623130f4520SKenneth D. Merry 			    __func__, bus_softc->port_name, bus_softc->path_id,
162445400376SAlexander Motin 			    online ? "enable" : "disable", ccb->ccb_h.status);
1625130f4520SKenneth D. Merry 		} else {
162645400376SAlexander Motin 			printf("%s: %s (path id %d) target role %s succeeded\n",
1627130f4520SKenneth D. Merry 			    __func__, bus_softc->port_name, bus_softc->path_id,
162845400376SAlexander Motin 			    online ? "enable" : "disable");
162945400376SAlexander Motin 		}
1630130f4520SKenneth D. Merry 	}
1631130f4520SKenneth D. Merry 
1632130f4520SKenneth D. Merry 	xpt_free_path(path);
16337511bd04SAlexander Motin 	xpt_free_ccb(ccb);
1634130f4520SKenneth D. Merry }
1635130f4520SKenneth D. Merry 
1636130f4520SKenneth D. Merry static void
1637130f4520SKenneth D. Merry ctlfe_online(void *arg)
1638130f4520SKenneth D. Merry {
1639744c26b2SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
1640744c26b2SKenneth D. Merry 	struct cam_path *path;
1641744c26b2SKenneth D. Merry 	cam_status status;
1642744c26b2SKenneth D. Merry 	struct ctlfe_lun_softc *lun_softc;
16433134cce0SAlexander Motin 	struct cam_periph *periph;
1644744c26b2SKenneth D. Merry 
1645744c26b2SKenneth D. Merry 	bus_softc = (struct ctlfe_softc *)arg;
1646744c26b2SKenneth D. Merry 
1647744c26b2SKenneth D. Merry 	/*
1648744c26b2SKenneth D. Merry 	 * Create the wildcard LUN before bringing the port online.
1649744c26b2SKenneth D. Merry 	 */
1650744c26b2SKenneth D. Merry 	status = xpt_create_path(&path, /*periph*/ NULL,
1651744c26b2SKenneth D. Merry 				 bus_softc->path_id, CAM_TARGET_WILDCARD,
1652744c26b2SKenneth D. Merry 				 CAM_LUN_WILDCARD);
1653744c26b2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
1654744c26b2SKenneth D. Merry 		printf("%s: unable to create path for wildcard periph\n",
1655744c26b2SKenneth D. Merry 				__func__);
1656744c26b2SKenneth D. Merry 		return;
1657744c26b2SKenneth D. Merry 	}
1658744c26b2SKenneth D. Merry 
16597511bd04SAlexander Motin 	lun_softc = malloc(sizeof(*lun_softc), M_CTLFE, M_WAITOK | M_ZERO);
1660744c26b2SKenneth D. Merry 
1661227d67aaSAlexander Motin 	xpt_path_lock(path);
16623134cce0SAlexander Motin 	periph = cam_periph_find(path, "ctl");
16633134cce0SAlexander Motin 	if (periph != NULL) {
16643134cce0SAlexander Motin 		/* We've already got a periph, no need to alloc a new one. */
16653134cce0SAlexander Motin 		xpt_path_unlock(path);
16663134cce0SAlexander Motin 		xpt_free_path(path);
16673134cce0SAlexander Motin 		free(lun_softc, M_CTLFE);
16683134cce0SAlexander Motin 		return;
16693134cce0SAlexander Motin 	}
1670744c26b2SKenneth D. Merry 	lun_softc->parent_softc = bus_softc;
1671744c26b2SKenneth D. Merry 	lun_softc->flags |= CTLFE_LUN_WILDCARD;
1672744c26b2SKenneth D. Merry 
1673744c26b2SKenneth D. Merry 	status = cam_periph_alloc(ctlferegister,
1674744c26b2SKenneth D. Merry 				  ctlfeoninvalidate,
1675744c26b2SKenneth D. Merry 				  ctlfecleanup,
1676744c26b2SKenneth D. Merry 				  ctlfestart,
1677744c26b2SKenneth D. Merry 				  "ctl",
1678744c26b2SKenneth D. Merry 				  CAM_PERIPH_BIO,
1679744c26b2SKenneth D. Merry 				  path,
1680744c26b2SKenneth D. Merry 				  ctlfeasync,
1681744c26b2SKenneth D. Merry 				  0,
1682744c26b2SKenneth D. Merry 				  lun_softc);
1683744c26b2SKenneth D. Merry 
1684744c26b2SKenneth D. Merry 	if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1685744c26b2SKenneth D. Merry 		const struct cam_status_entry *entry;
1686744c26b2SKenneth D. Merry 
1687744c26b2SKenneth D. Merry 		entry = cam_fetch_status_entry(status);
1688744c26b2SKenneth D. Merry 		printf("%s: CAM error %s (%#x) returned from "
1689744c26b2SKenneth D. Merry 		       "cam_periph_alloc()\n", __func__, (entry != NULL) ?
1690744c26b2SKenneth D. Merry 		       entry->status_text : "Unknown", status);
16913134cce0SAlexander Motin 		free(lun_softc, M_CTLFE);
16923134cce0SAlexander Motin 	}
1693744c26b2SKenneth D. Merry 
1694227d67aaSAlexander Motin 	xpt_path_unlock(path);
16957511bd04SAlexander Motin 	ctlfe_onoffline(arg, /*online*/ 1);
1696227d67aaSAlexander Motin 	xpt_free_path(path);
1697130f4520SKenneth D. Merry }
1698130f4520SKenneth D. Merry 
1699130f4520SKenneth D. Merry static void
1700130f4520SKenneth D. Merry ctlfe_offline(void *arg)
1701130f4520SKenneth D. Merry {
1702744c26b2SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
1703744c26b2SKenneth D. Merry 	struct cam_path *path;
1704744c26b2SKenneth D. Merry 	cam_status status;
1705744c26b2SKenneth D. Merry 	struct cam_periph *periph;
1706744c26b2SKenneth D. Merry 
1707744c26b2SKenneth D. Merry 	bus_softc = (struct ctlfe_softc *)arg;
1708744c26b2SKenneth D. Merry 
17097511bd04SAlexander Motin 	ctlfe_onoffline(arg, /*online*/ 0);
17107511bd04SAlexander Motin 
1711744c26b2SKenneth D. Merry 	/*
1712744c26b2SKenneth D. Merry 	 * Disable the wildcard LUN for this port now that we have taken
1713744c26b2SKenneth D. Merry 	 * the port offline.
1714744c26b2SKenneth D. Merry 	 */
1715744c26b2SKenneth D. Merry 	status = xpt_create_path(&path, /*periph*/ NULL,
1716744c26b2SKenneth D. Merry 				 bus_softc->path_id, CAM_TARGET_WILDCARD,
1717744c26b2SKenneth D. Merry 				 CAM_LUN_WILDCARD);
1718744c26b2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
1719744c26b2SKenneth D. Merry 		printf("%s: unable to create path for wildcard periph\n",
1720744c26b2SKenneth D. Merry 		       __func__);
1721744c26b2SKenneth D. Merry 		return;
1722744c26b2SKenneth D. Merry 	}
1723227d67aaSAlexander Motin 	xpt_path_lock(path);
1724744c26b2SKenneth D. Merry 	if ((periph = cam_periph_find(path, "ctl")) != NULL)
1725744c26b2SKenneth D. Merry 		cam_periph_invalidate(periph);
1726227d67aaSAlexander Motin 	xpt_path_unlock(path);
1727744c26b2SKenneth D. Merry 	xpt_free_path(path);
1728130f4520SKenneth D. Merry }
1729130f4520SKenneth D. Merry 
1730130f4520SKenneth D. Merry /*
1731130f4520SKenneth D. Merry  * This will get called to enable a LUN on every bus that is attached to
1732130f4520SKenneth D. Merry  * CTL.  So we only need to create a path/periph for this particular bus.
1733130f4520SKenneth D. Merry  */
1734130f4520SKenneth D. Merry static int
17357834ea88SAlexander Motin ctlfe_lun_enable(void *arg, int lun_id)
1736130f4520SKenneth D. Merry {
1737130f4520SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
1738130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
1739130f4520SKenneth D. Merry 	struct cam_path *path;
1740130f4520SKenneth D. Merry 	struct cam_periph *periph;
1741130f4520SKenneth D. Merry 	cam_status status;
1742130f4520SKenneth D. Merry 
1743130f4520SKenneth D. Merry 	bus_softc = (struct ctlfe_softc *)arg;
174459f063d5SAlexander Motin 	if (bus_softc->hba_misc & PIM_EXTLUNS)
174559f063d5SAlexander Motin 		lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id));
1746130f4520SKenneth D. Merry 
1747227d67aaSAlexander Motin 	status = xpt_create_path(&path, /*periph*/ NULL,
1748d1f40587SAlexander Motin 	    bus_softc->path_id, bus_softc->target_id, lun_id);
1749130f4520SKenneth D. Merry 	/* XXX KDM need some way to return status to CTL here? */
1750130f4520SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
1751130f4520SKenneth D. Merry 		printf("%s: could not create path, status %#x\n", __func__,
1752130f4520SKenneth D. Merry 		       status);
1753130f4520SKenneth D. Merry 		return (1);
1754130f4520SKenneth D. Merry 	}
1755130f4520SKenneth D. Merry 
1756130f4520SKenneth D. Merry 	softc = malloc(sizeof(*softc), M_CTLFE, M_WAITOK | M_ZERO);
1757227d67aaSAlexander Motin 	xpt_path_lock(path);
1758130f4520SKenneth D. Merry 	periph = cam_periph_find(path, "ctl");
1759130f4520SKenneth D. Merry 	if (periph != NULL) {
1760130f4520SKenneth D. Merry 		/* We've already got a periph, no need to alloc a new one. */
1761227d67aaSAlexander Motin 		xpt_path_unlock(path);
1762130f4520SKenneth D. Merry 		xpt_free_path(path);
1763130f4520SKenneth D. Merry 		free(softc, M_CTLFE);
1764130f4520SKenneth D. Merry 		return (0);
1765130f4520SKenneth D. Merry 	}
1766130f4520SKenneth D. Merry 	softc->parent_softc = bus_softc;
1767130f4520SKenneth D. Merry 
1768130f4520SKenneth D. Merry 	status = cam_periph_alloc(ctlferegister,
1769130f4520SKenneth D. Merry 				  ctlfeoninvalidate,
1770130f4520SKenneth D. Merry 				  ctlfecleanup,
1771130f4520SKenneth D. Merry 				  ctlfestart,
1772130f4520SKenneth D. Merry 				  "ctl",
1773130f4520SKenneth D. Merry 				  CAM_PERIPH_BIO,
1774130f4520SKenneth D. Merry 				  path,
1775130f4520SKenneth D. Merry 				  ctlfeasync,
1776130f4520SKenneth D. Merry 				  0,
1777130f4520SKenneth D. Merry 				  softc);
1778130f4520SKenneth D. Merry 
17793134cce0SAlexander Motin 	if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
17803134cce0SAlexander Motin 		const struct cam_status_entry *entry;
17813134cce0SAlexander Motin 
17823134cce0SAlexander Motin 		entry = cam_fetch_status_entry(status);
17833134cce0SAlexander Motin 		printf("%s: CAM error %s (%#x) returned from "
17843134cce0SAlexander Motin 		       "cam_periph_alloc()\n", __func__, (entry != NULL) ?
17853134cce0SAlexander Motin 		       entry->status_text : "Unknown", status);
17863134cce0SAlexander Motin 		free(softc, M_CTLFE);
17873134cce0SAlexander Motin 	}
17883134cce0SAlexander Motin 
1789227d67aaSAlexander Motin 	xpt_path_unlock(path);
1790130f4520SKenneth D. Merry 	xpt_free_path(path);
1791130f4520SKenneth D. Merry 	return (0);
1792130f4520SKenneth D. Merry }
1793130f4520SKenneth D. Merry 
1794130f4520SKenneth D. Merry /*
1795744c26b2SKenneth D. Merry  * This will get called when the user removes a LUN to disable that LUN
1796744c26b2SKenneth D. Merry  * on every bus that is attached to CTL.
1797130f4520SKenneth D. Merry  */
1798130f4520SKenneth D. Merry static int
17997834ea88SAlexander Motin ctlfe_lun_disable(void *arg, int lun_id)
1800130f4520SKenneth D. Merry {
1801130f4520SKenneth D. Merry 	struct ctlfe_softc *softc;
1802130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *lun_softc;
1803130f4520SKenneth D. Merry 
1804130f4520SKenneth D. Merry 	softc = (struct ctlfe_softc *)arg;
180559f063d5SAlexander Motin 	if (softc->hba_misc & PIM_EXTLUNS)
180659f063d5SAlexander Motin 		lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id));
1807130f4520SKenneth D. Merry 
1808227d67aaSAlexander Motin 	mtx_lock(&softc->lun_softc_mtx);
1809130f4520SKenneth D. Merry 	STAILQ_FOREACH(lun_softc, &softc->lun_softc_list, links) {
1810130f4520SKenneth D. Merry 		struct cam_path *path;
1811130f4520SKenneth D. Merry 
1812130f4520SKenneth D. Merry 		path = lun_softc->periph->path;
1813130f4520SKenneth D. Merry 
1814aeb1faa0SAlexander Motin 		if ((xpt_path_target_id(path) == softc->target_id)
1815130f4520SKenneth D. Merry 		 && (xpt_path_lun_id(path) == lun_id)) {
1816130f4520SKenneth D. Merry 			break;
1817130f4520SKenneth D. Merry 		}
1818130f4520SKenneth D. Merry 	}
1819130f4520SKenneth D. Merry 	if (lun_softc == NULL) {
1820227d67aaSAlexander Motin 		mtx_unlock(&softc->lun_softc_mtx);
18217834ea88SAlexander Motin 		printf("%s: can't find lun %d\n", __func__, lun_id);
1822130f4520SKenneth D. Merry 		return (1);
1823130f4520SKenneth D. Merry 	}
1824227d67aaSAlexander Motin 	cam_periph_acquire(lun_softc->periph);
1825227d67aaSAlexander Motin 	mtx_unlock(&softc->lun_softc_mtx);
1826130f4520SKenneth D. Merry 
1827227d67aaSAlexander Motin 	cam_periph_lock(lun_softc->periph);
1828130f4520SKenneth D. Merry 	cam_periph_invalidate(lun_softc->periph);
1829227d67aaSAlexander Motin 	cam_periph_unlock(lun_softc->periph);
1830227d67aaSAlexander Motin 	cam_periph_release(lun_softc->periph);
1831130f4520SKenneth D. Merry 	return (0);
1832130f4520SKenneth D. Merry }
1833130f4520SKenneth D. Merry 
1834130f4520SKenneth D. Merry static void
1835130f4520SKenneth D. Merry ctlfe_dump_sim(struct cam_sim *sim)
1836130f4520SKenneth D. Merry {
1837130f4520SKenneth D. Merry 
1838b1303ffeSAlexander Motin 	printf("%s%d: max dev openings: %d, max tagged dev openings: %d\n",
1839b1303ffeSAlexander Motin 	    sim->sim_name, sim->unit_number, sim->max_dev_openings,
1840b1303ffeSAlexander Motin 	    sim->max_tagged_dev_openings);
1841130f4520SKenneth D. Merry }
1842130f4520SKenneth D. Merry 
1843130f4520SKenneth D. Merry /*
1844130f4520SKenneth D. Merry  * Assumes that the SIM lock is held.
1845130f4520SKenneth D. Merry  */
1846130f4520SKenneth D. Merry static void
1847130f4520SKenneth D. Merry ctlfe_dump_queue(struct ctlfe_lun_softc *softc)
1848130f4520SKenneth D. Merry {
1849b1303ffeSAlexander Motin 	struct cam_periph *periph = softc->periph;
1850130f4520SKenneth D. Merry 	struct ccb_hdr *hdr;
1851b1303ffeSAlexander Motin 	struct ccb_getdevstats cgds;
1852130f4520SKenneth D. Merry 	int num_items;
1853130f4520SKenneth D. Merry 
1854616a676aSEdward Tomasz Napierala 	memset(&cgds, 0, sizeof(cgds));
1855b1303ffeSAlexander Motin 	xpt_setup_ccb(&cgds.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
1856b1303ffeSAlexander Motin 	cgds.ccb_h.func_code = XPT_GDEV_STATS;
1857b1303ffeSAlexander Motin 	xpt_action((union ccb *)&cgds);
1858b1303ffeSAlexander Motin 	if ((cgds.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1859b1303ffeSAlexander Motin 		xpt_print(periph->path, "devq: openings %d, active %d, "
1860b1303ffeSAlexander Motin 		    "allocated %d, queued %d, held %d\n",
1861b1303ffeSAlexander Motin 		    cgds.dev_openings, cgds.dev_active, cgds.allocated,
1862b1303ffeSAlexander Motin 		    cgds.queued, cgds.held);
1863b1303ffeSAlexander Motin 	}
1864b1303ffeSAlexander Motin 
1865130f4520SKenneth D. Merry 	num_items = 0;
1866130f4520SKenneth D. Merry 
1867832529c5SAlexander Motin 	STAILQ_FOREACH(hdr, &softc->work_queue, periph_links.stqe) {
1868993a751eSAlexander Motin 		union ctl_io *io = hdr->io_ptr;
1869130f4520SKenneth D. Merry 
1870130f4520SKenneth D. Merry 		num_items++;
1871130f4520SKenneth D. Merry 
1872130f4520SKenneth D. Merry 		/*
1873130f4520SKenneth D. Merry 		 * Only regular SCSI I/O is put on the work
1874130f4520SKenneth D. Merry 		 * queue, so we can print sense here.  There may be no
1875130f4520SKenneth D. Merry 		 * sense if it's no the queue for a DMA, but this serves to
1876130f4520SKenneth D. Merry 		 * print out the CCB as well.
1877130f4520SKenneth D. Merry 		 *
1878130f4520SKenneth D. Merry 		 * XXX KDM switch this over to scsi_sense_print() when
1879130f4520SKenneth D. Merry 		 * CTL is merged in with CAM.
1880130f4520SKenneth D. Merry 		 */
1881130f4520SKenneth D. Merry 		ctl_io_error_print(io, NULL);
1882130f4520SKenneth D. Merry 
1883130f4520SKenneth D. Merry 		/*
1884993a751eSAlexander Motin 		 * Print DMA status if we are DMA_QUEUED.
1885130f4520SKenneth D. Merry 		 */
1886993a751eSAlexander Motin 		if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) {
1887993a751eSAlexander Motin 			xpt_print(periph->path,
1888993a751eSAlexander Motin 			    "Total %u, Current %u, Resid %u\n",
1889993a751eSAlexander Motin 			    io->scsiio.kern_total_len,
1890993a751eSAlexander Motin 			    io->scsiio.kern_data_len,
1891130f4520SKenneth D. Merry 			    io->scsiio.kern_data_resid);
1892130f4520SKenneth D. Merry 		}
1893993a751eSAlexander Motin 	}
1894130f4520SKenneth D. Merry 
18953afd4806SAlexander Motin 	xpt_print(periph->path, "%d requests waiting for CCBs\n", num_items);
18963afd4806SAlexander Motin 	xpt_print(periph->path, "%d CTIOs outstanding\n", softc->ctios_sent);
1897130f4520SKenneth D. Merry }
1898130f4520SKenneth D. Merry 
1899130f4520SKenneth D. Merry /*
1900130f4520SKenneth D. Merry  * Datamove/done routine called by CTL.  Put ourselves on the queue to
1901130f4520SKenneth D. Merry  * receive a CCB from CAM so we can queue the continue I/O request down
1902130f4520SKenneth D. Merry  * to the adapter.
1903130f4520SKenneth D. Merry  */
1904130f4520SKenneth D. Merry static void
1905993a751eSAlexander Motin ctlfe_datamove(union ctl_io *io)
1906993a751eSAlexander Motin {
1907993a751eSAlexander Motin 	union ccb *ccb;
1908993a751eSAlexander Motin 	struct cam_periph *periph;
1909993a751eSAlexander Motin 	struct ctlfe_lun_softc *softc;
1910993a751eSAlexander Motin 
1911*ac7a514eSJohn Baldwin 	CTL_IO_ASSERT(io, SCSI);
1912993a751eSAlexander Motin 
1913eb6ac6f9SAlexander Motin 	io->scsiio.ext_data_filled = 0;
1914e67ac203SAlexander Motin 	ccb = PRIV_CCB(io);
1915993a751eSAlexander Motin 	periph = xpt_path_periph(ccb->ccb_h.path);
1916993a751eSAlexander Motin 	cam_periph_lock(periph);
1917993a751eSAlexander Motin 	softc = (struct ctlfe_lun_softc *)periph->softc;
1918993a751eSAlexander Motin 	io->io_hdr.flags |= CTL_FLAG_DMA_QUEUED;
1919993a751eSAlexander Motin 	if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)
1920993a751eSAlexander Motin 		io->io_hdr.flags |= CTL_FLAG_STATUS_QUEUED;
1921832529c5SAlexander Motin 	STAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h,
1922832529c5SAlexander Motin 			  periph_links.stqe);
19233afd4806SAlexander Motin 	xpt_schedule(periph, CAM_PRIORITY_NORMAL);
1924993a751eSAlexander Motin 	cam_periph_unlock(periph);
1925993a751eSAlexander Motin }
1926993a751eSAlexander Motin 
1927993a751eSAlexander Motin static void
1928993a751eSAlexander Motin ctlfe_done(union ctl_io *io)
1929130f4520SKenneth D. Merry {
1930130f4520SKenneth D. Merry 	union ccb *ccb;
1931130f4520SKenneth D. Merry 	struct cam_periph *periph;
1932130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *softc;
1933130f4520SKenneth D. Merry 
1934e67ac203SAlexander Motin 	ccb = PRIV_CCB(io);
1935130f4520SKenneth D. Merry 	periph = xpt_path_periph(ccb->ccb_h.path);
1936227d67aaSAlexander Motin 	cam_periph_lock(periph);
1937130f4520SKenneth D. Merry 	softc = (struct ctlfe_lun_softc *)periph->softc;
1938130f4520SKenneth D. Merry 
1939130f4520SKenneth D. Merry 	if (io->io_hdr.io_type == CTL_IO_TASK) {
1940130f4520SKenneth D. Merry 		/*
1941130f4520SKenneth D. Merry 		 * Send the notify acknowledge down to the SIM, to let it
1942130f4520SKenneth D. Merry 		 * know we processed the task management command.
1943130f4520SKenneth D. Merry 		 */
1944130f4520SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INPROG;
1945130f4520SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE;
194696b5475bSAlexander Motin 		switch (io->taskio.task_status) {
194796b5475bSAlexander Motin 		case CTL_TASK_FUNCTION_COMPLETE:
194896b5475bSAlexander Motin 			ccb->cna2.arg = CAM_RSP_TMF_COMPLETE;
194996b5475bSAlexander Motin 			break;
195096b5475bSAlexander Motin 		case CTL_TASK_FUNCTION_SUCCEEDED:
195196b5475bSAlexander Motin 			ccb->cna2.arg = CAM_RSP_TMF_SUCCEEDED;
195296b5475bSAlexander Motin 			ccb->ccb_h.flags |= CAM_SEND_STATUS;
195396b5475bSAlexander Motin 			break;
195496b5475bSAlexander Motin 		case CTL_TASK_FUNCTION_REJECTED:
195596b5475bSAlexander Motin 			ccb->cna2.arg = CAM_RSP_TMF_REJECTED;
195696b5475bSAlexander Motin 			ccb->ccb_h.flags |= CAM_SEND_STATUS;
195796b5475bSAlexander Motin 			break;
195896b5475bSAlexander Motin 		case CTL_TASK_LUN_DOES_NOT_EXIST:
195996b5475bSAlexander Motin 			ccb->cna2.arg = CAM_RSP_TMF_INCORRECT_LUN;
196096b5475bSAlexander Motin 			ccb->ccb_h.flags |= CAM_SEND_STATUS;
196196b5475bSAlexander Motin 			break;
196296b5475bSAlexander Motin 		case CTL_TASK_FUNCTION_NOT_SUPPORTED:
196396b5475bSAlexander Motin 			ccb->cna2.arg = CAM_RSP_TMF_FAILED;
196496b5475bSAlexander Motin 			ccb->ccb_h.flags |= CAM_SEND_STATUS;
196596b5475bSAlexander Motin 			break;
196696b5475bSAlexander Motin 		}
196796b5475bSAlexander Motin 		ccb->cna2.arg |= scsi_3btoul(io->taskio.task_resp) << 8;
1968130f4520SKenneth D. Merry 		xpt_action(ccb);
1969f7241cceSAlexander Motin 	} else if (io->io_hdr.flags & CTL_FLAG_STATUS_SENT) {
1970a504738fSAlexander Motin 		ctlfe_requeue_ccb(periph, ccb, /* unlock */1);
1971f7241cceSAlexander Motin 		return;
1972130f4520SKenneth D. Merry 	} else {
1973130f4520SKenneth D. Merry 		io->io_hdr.flags |= CTL_FLAG_STATUS_QUEUED;
1974832529c5SAlexander Motin 		STAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h,
1975832529c5SAlexander Motin 				  periph_links.stqe);
19763afd4806SAlexander Motin 		xpt_schedule(periph, CAM_PRIORITY_NORMAL);
1977130f4520SKenneth D. Merry 	}
1978130f4520SKenneth D. Merry 
1979227d67aaSAlexander Motin 	cam_periph_unlock(periph);
1980130f4520SKenneth D. Merry }
1981130f4520SKenneth D. Merry 
1982130f4520SKenneth D. Merry static void
1983130f4520SKenneth D. Merry ctlfe_dump(void)
1984130f4520SKenneth D. Merry {
1985130f4520SKenneth D. Merry 	struct ctlfe_softc *bus_softc;
1986130f4520SKenneth D. Merry 	struct ctlfe_lun_softc *lun_softc;
1987130f4520SKenneth D. Merry 
1988993a751eSAlexander Motin 	STAILQ_FOREACH(bus_softc, &ctlfe_softc_list, links) {
1989130f4520SKenneth D. Merry 		ctlfe_dump_sim(bus_softc->sim);
1990993a751eSAlexander Motin 		STAILQ_FOREACH(lun_softc, &bus_softc->lun_softc_list, links)
1991130f4520SKenneth D. Merry 			ctlfe_dump_queue(lun_softc);
1992130f4520SKenneth D. Merry 	}
1993130f4520SKenneth D. Merry }
1994