xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 9e7d423d23c6e3ed8d9b55ff602843eb79fc1825)
1098ca2bdSWarner Losh /*-
22df76c16SMatt Jacob  * Copyright (c) 1997-2009 by Matthew Jacob
3e5265237SMatt Jacob  * All rights reserved.
46054c3f6SMatt Jacob  *
56054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
66054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
76054c3f6SMatt Jacob  * are met:
86054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
96054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
106054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
11aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
12aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
136054c3f6SMatt Jacob  *
146054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
156054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
166054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
176054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
186054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
196054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
206054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
216054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
226054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
236054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
246054c3f6SMatt Jacob  * SUCH DAMAGE.
256054c3f6SMatt Jacob  */
26aad970f1SDavid E. O'Brien 
27799881e0SMatt Jacob /*
28799881e0SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
29799881e0SMatt Jacob  */
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
326054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
335d571944SMatt Jacob #include <sys/unistd.h>
345d571944SMatt Jacob #include <sys/kthread.h>
355d571944SMatt Jacob #include <sys/conf.h>
364eb49427SMatt Jacob #include <sys/module.h>
375d571944SMatt Jacob #include <sys/ioccom.h>
385d571944SMatt Jacob #include <dev/isp/isp_ioctl.h>
3970273f90SMatt Jacob #include <sys/devicestat.h>
40f7c631bcSMatt Jacob #include <cam/cam_periph.h>
416c81a0aeSMatt Jacob #include <cam/cam_xpt_periph.h>
426054c3f6SMatt Jacob 
432df76c16SMatt Jacob #if	__FreeBSD_version < 800002
442df76c16SMatt Jacob #define	THREAD_CREATE	kthread_create
452df76c16SMatt Jacob #else
462df76c16SMatt Jacob #define	THREAD_CREATE	kproc_create
47805e1f82SMatt Jacob #endif
48805e1f82SMatt Jacob 
494eb49427SMatt Jacob MODULE_VERSION(isp, 1);
5056c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1);
5173030e03SMatt Jacob int isp_announced = 0;
52427fa8f9SMatt Jacob int isp_fabric_hysteresis = 5;
532df76c16SMatt Jacob int isp_loop_down_limit = 60;	/* default loop down limit */
54f7c631bcSMatt Jacob int isp_change_is_bad = 0;	/* "changed" devices are bad */
552df76c16SMatt Jacob int isp_quickboot_time = 7;	/* don't wait more than N secs for loop up */
56f7c631bcSMatt Jacob int isp_gone_device_time = 30;	/* grace time before reporting device lost */
572df76c16SMatt Jacob int isp_autoconfig = 1;		/* automatically attach/detach devices */
58f7c631bcSMatt Jacob static const char *roles[4] = {
59f7c631bcSMatt Jacob     "(none)", "Target", "Initiator", "Target/Initiator"
60f7c631bcSMatt Jacob };
612df76c16SMatt Jacob static const char prom3[] = "Chan %d PortID 0x%06x Departed from Target %u because of %s";
622df76c16SMatt Jacob static const char rqo[] = "%s: Request Queue Overflow\n";
6373030e03SMatt Jacob 
642df76c16SMatt Jacob static void isp_freeze_loopdown(ispsoftc_t *, int, char *);
655d571944SMatt Jacob static d_ioctl_t ispioctl;
66f6e75de2SMatt Jacob static void isp_intr_enable(void *);
671dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
680470d791SMatt Jacob static void isp_poll(struct cam_sim *);
69b85389e1SMatt Jacob static timeout_t isp_watchdog;
70de461933SMatt Jacob static timeout_t isp_gdt;
71de461933SMatt Jacob static task_fn_t isp_gdt_task;
72f7c631bcSMatt Jacob static timeout_t isp_ldt;
73de461933SMatt Jacob static task_fn_t isp_ldt_task;
745d571944SMatt Jacob static void isp_kthread(void *);
75d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
762df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
772df76c16SMatt Jacob static void isp_target_thread_pi(void *);
782df76c16SMatt Jacob static void isp_target_thread_fc(void *);
79784ed707SMatt Jacob #endif
802df76c16SMatt Jacob static void isp_timer(void *);
81cc8df88bSMatt Jacob 
825d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
83dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
847ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
857ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
865d571944SMatt Jacob };
875d571944SMatt Jacob 
882df76c16SMatt Jacob static int
892df76c16SMatt Jacob isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan)
90478f8a96SJustin T. Gibbs {
91478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
92ea6f23cdSMatt Jacob 	struct cam_sim *sim;
93ea6f23cdSMatt Jacob 	struct cam_path *path;
94478f8a96SJustin T. Gibbs 
95478f8a96SJustin T. Gibbs 	/*
962df76c16SMatt Jacob 	 * Construct our SIM entry.
97ea6f23cdSMatt Jacob 	 */
982df76c16SMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, device_get_unit(isp->isp_dev), &isp->isp_osinfo.lock, isp->isp_maxcmds, isp->isp_maxcmds, devq);
99ea6f23cdSMatt Jacob 
1002df76c16SMatt Jacob 	if (sim == NULL) {
1012df76c16SMatt Jacob 		return (ENOMEM);
1022df76c16SMatt Jacob 	}
1032df76c16SMatt Jacob 
1042df76c16SMatt Jacob 	ISP_LOCK(isp);
1052df76c16SMatt Jacob 	if (xpt_bus_register(sim, isp->isp_dev, chan) != CAM_SUCCESS) {
1062df76c16SMatt Jacob 		ISP_UNLOCK(isp);
1072df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
1082df76c16SMatt Jacob 		return (EIO);
1092df76c16SMatt Jacob 	}
1102df76c16SMatt Jacob 	ISP_UNLOCK(isp);
111e95725cbSMatt Jacob 	if (xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1122df76c16SMatt Jacob 		ISP_LOCK(isp);
1132df76c16SMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
1142df76c16SMatt Jacob 		ISP_UNLOCK(isp);
1152df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
1162df76c16SMatt Jacob 		return (ENXIO);
1172df76c16SMatt Jacob 	}
1182df76c16SMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
1192df76c16SMatt Jacob 	csa.ccb_h.func_code = XPT_SASYNC_CB;
1202df76c16SMatt Jacob 	csa.event_enable = AC_LOST_DEVICE;
1212df76c16SMatt Jacob 	csa.callback = isp_cam_async;
1222df76c16SMatt Jacob 	csa.callback_arg = sim;
1232df76c16SMatt Jacob 	xpt_action((union ccb *)&csa);
1242df76c16SMatt Jacob 
1252df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
1262df76c16SMatt Jacob 		struct isp_spi *spi = ISP_SPI_PC(isp, chan);
1272df76c16SMatt Jacob 		spi->sim = sim;
1282df76c16SMatt Jacob 		spi->path = path;
1292df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
1302df76c16SMatt Jacob 		ISP_SET_PC(isp, chan, proc_active, 1);
1312df76c16SMatt Jacob 		if (THREAD_CREATE(isp_target_thread_pi, spi, &spi->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
1322df76c16SMatt Jacob 			ISP_SET_PC(isp, chan, proc_active, 0);
1332df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot create test target thread");
1342df76c16SMatt Jacob 		}
1352df76c16SMatt Jacob #endif
1362df76c16SMatt Jacob 	} else {
137a01f5aebSMatt Jacob 		fcparam *fcp = FCPARAM(isp, chan);
1382df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
1392df76c16SMatt Jacob 
140a01f5aebSMatt Jacob 		ISP_LOCK(isp);
1412df76c16SMatt Jacob 		fc->sim = sim;
1422df76c16SMatt Jacob 		fc->path = path;
1432df76c16SMatt Jacob 		fc->isp = isp;
144a01f5aebSMatt Jacob 		fc->ready = 1;
145de461933SMatt Jacob 
1462df76c16SMatt Jacob 		callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
1472df76c16SMatt Jacob 		callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
148de461933SMatt Jacob 		TASK_INIT(&fc->ltask, 1, isp_ldt_task, fc);
149de461933SMatt Jacob 		TASK_INIT(&fc->gtask, 1, isp_gdt_task, fc);
150427fa8f9SMatt Jacob 
1512df76c16SMatt Jacob 		/*
1522df76c16SMatt Jacob 		 * We start by being "loop down" if we have an initiator role
1532df76c16SMatt Jacob 		 */
154a01f5aebSMatt Jacob 		if (fcp->role & ISP_ROLE_INITIATOR) {
1552df76c16SMatt Jacob 			isp_freeze_loopdown(isp, chan, "isp_attach");
1562df76c16SMatt Jacob 			callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc);
1572df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime);
1582df76c16SMatt Jacob 		}
1592df76c16SMatt Jacob 		ISP_UNLOCK(isp);
160a01f5aebSMatt Jacob 		if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
161a01f5aebSMatt Jacob 			xpt_free_path(fc->path);
162a01f5aebSMatt Jacob 			ISP_LOCK(isp);
163a01f5aebSMatt Jacob 			if (callout_active(&fc->ldt)) {
164a01f5aebSMatt Jacob 				callout_stop(&fc->ldt);
165a01f5aebSMatt Jacob 			}
166a01f5aebSMatt Jacob 			xpt_bus_deregister(cam_sim_path(fc->sim));
167a01f5aebSMatt Jacob 			ISP_UNLOCK(isp);
168a01f5aebSMatt Jacob 			cam_sim_free(fc->sim, FALSE);
169a01f5aebSMatt Jacob 			return (ENOMEM);
170a01f5aebSMatt Jacob 		}
1712df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
1722df76c16SMatt Jacob 		ISP_SET_PC(isp, chan, proc_active, 1);
1732df76c16SMatt Jacob 		if (THREAD_CREATE(isp_target_thread_fc, fc, &fc->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
1742df76c16SMatt Jacob 			ISP_SET_PC(isp, chan, proc_active, 0);
1752df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot create test target thread");
1762df76c16SMatt Jacob 		}
1772df76c16SMatt Jacob #endif
178a0ec8e99SMatt Jacob 		if (chan == 0) {
179a0ec8e99SMatt Jacob 			struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(isp->isp_osinfo.dev);
180a0ec8e99SMatt Jacob 			struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev);
181a0ec8e99SMatt Jacob 			SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "wwnn", CTLFLAG_RD, &FCPARAM(isp, 0)->isp_wwnn, "World Wide Node Name");
182a0ec8e99SMatt Jacob 			SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "wwpn", CTLFLAG_RD, &FCPARAM(isp, 0)->isp_wwpn, "World Wide Port Name");
183a0ec8e99SMatt Jacob 			SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "loop_down_limit", CTLFLAG_RW, &ISP_FC_PC(isp, 0)->loop_down_limit, 0, "Loop Down Limit");
184a0ec8e99SMatt Jacob 			SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "gone_device_time", CTLFLAG_RW, &ISP_FC_PC(isp, 0)->gone_device_time, 0, "Gone Device Time");
185a0ec8e99SMatt Jacob 		}
1862df76c16SMatt Jacob 	}
1872df76c16SMatt Jacob 	return (0);
1882df76c16SMatt Jacob }
1892df76c16SMatt Jacob 
1902df76c16SMatt Jacob int
1912df76c16SMatt Jacob isp_attach(ispsoftc_t *isp)
1922df76c16SMatt Jacob {
1932df76c16SMatt Jacob 	const char *nu = device_get_nameunit(isp->isp_osinfo.dev);
1942df76c16SMatt Jacob 	int du = device_get_unit(isp->isp_dev);
1952df76c16SMatt Jacob 	int chan;
1962df76c16SMatt Jacob 
1972df76c16SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
1982df76c16SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
199e95725cbSMatt Jacob 	/*
200e95725cbSMatt Jacob 	 * Haha. Set this first, because if we're loaded as a module isp_intr_enable
201e95725cbSMatt Jacob 	 * will be called right awawy, which will clear isp_osinfo.ehook_active,
202e95725cbSMatt Jacob 	 * which would be unwise to then set again later.
203e95725cbSMatt Jacob 	 */
204e95725cbSMatt Jacob 	isp->isp_osinfo.ehook_active = 1;
2052df76c16SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
2062df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "could not establish interrupt enable hook");
2072df76c16SMatt Jacob 		return (-EIO);
2082df76c16SMatt Jacob 	}
209ea6f23cdSMatt Jacob 
210ea6f23cdSMatt Jacob 	/*
211ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
212478f8a96SJustin T. Gibbs 	 */
2132df76c16SMatt Jacob 	isp->isp_osinfo.devq = cam_simq_alloc(isp->isp_maxcmds);
2142df76c16SMatt Jacob 	if (isp->isp_osinfo.devq == NULL) {
2155d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2162df76c16SMatt Jacob 		return (EIO);
217478f8a96SJustin T. Gibbs 	}
218478f8a96SJustin T. Gibbs 
2192df76c16SMatt Jacob 	for (chan = 0; chan < isp->isp_nchan; chan++) {
2202df76c16SMatt Jacob 		if (isp_attach_chan(isp, isp->isp_osinfo.devq, chan)) {
2212df76c16SMatt Jacob 			goto unwind;
222ea6f23cdSMatt Jacob 		}
223ea6f23cdSMatt Jacob 	}
224ea6f23cdSMatt Jacob 
2252df76c16SMatt Jacob 	callout_init_mtx(&isp->isp_osinfo.tmo, &isp->isp_osinfo.lock, 0);
2262df76c16SMatt Jacob 	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
2272df76c16SMatt Jacob 	isp->isp_osinfo.timer_active = 1;
228ea6f23cdSMatt Jacob 
2292df76c16SMatt Jacob 	isp->isp_osinfo.cdev = make_dev(&isp_cdevsw, du, UID_ROOT, GID_OPERATOR, 0600, "%s", nu);
2302df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
2312df76c16SMatt Jacob 		isp->isp_osinfo.cdev->si_drv1 = isp;
232ea6f23cdSMatt Jacob 	}
2332df76c16SMatt Jacob 	return (0);
2345d571944SMatt Jacob 
2352df76c16SMatt Jacob unwind:
2362df76c16SMatt Jacob 	while (--chan >= 0) {
2372df76c16SMatt Jacob 		struct cam_sim *sim;
2382df76c16SMatt Jacob 		struct cam_path *path;
2390a70657fSMatt Jacob 		if (IS_FC(isp)) {
2402df76c16SMatt Jacob 			sim = ISP_FC_PC(isp, chan)->sim;
2412df76c16SMatt Jacob 			path = ISP_FC_PC(isp, chan)->path;
2422df76c16SMatt Jacob 		} else {
2432df76c16SMatt Jacob 			sim = ISP_SPI_PC(isp, chan)->sim;
2442df76c16SMatt Jacob 			path = ISP_SPI_PC(isp, chan)->path;
2452df76c16SMatt Jacob 		}
2462df76c16SMatt Jacob 		xpt_free_path(path);
2470a70657fSMatt Jacob 		ISP_LOCK(isp);
2480a70657fSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
2492df76c16SMatt Jacob 		ISP_UNLOCK(isp);
2502df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
2512df76c16SMatt Jacob 	}
2522df76c16SMatt Jacob 	if (isp->isp_osinfo.ehook_active) {
2530a70657fSMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2542df76c16SMatt Jacob 		isp->isp_osinfo.ehook_active = 0;
2550a70657fSMatt Jacob 	}
2562df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
2572df76c16SMatt Jacob 		destroy_dev(isp->isp_osinfo.cdev);
2582df76c16SMatt Jacob 		isp->isp_osinfo.cdev = NULL;
2592df76c16SMatt Jacob 	}
2602df76c16SMatt Jacob 	cam_simq_free(isp->isp_osinfo.devq);
2612df76c16SMatt Jacob 	isp->isp_osinfo.devq = NULL;
2622df76c16SMatt Jacob 	return (-1);
2632df76c16SMatt Jacob }
2642df76c16SMatt Jacob 
265e95725cbSMatt Jacob int
2662df76c16SMatt Jacob isp_detach(ispsoftc_t *isp)
2672df76c16SMatt Jacob {
268e95725cbSMatt Jacob 	struct cam_sim *sim;
269e95725cbSMatt Jacob 	struct cam_path *path;
270e95725cbSMatt Jacob 	struct ccb_setasync csa;
2712df76c16SMatt Jacob 	int chan;
2722df76c16SMatt Jacob 
2730a70657fSMatt Jacob 	ISP_LOCK(isp);
2742df76c16SMatt Jacob 	for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) {
2752df76c16SMatt Jacob 		if (IS_FC(isp)) {
2762df76c16SMatt Jacob 			sim = ISP_FC_PC(isp, chan)->sim;
2772df76c16SMatt Jacob 			path = ISP_FC_PC(isp, chan)->path;
2782df76c16SMatt Jacob 		} else {
2792df76c16SMatt Jacob 			sim = ISP_SPI_PC(isp, chan)->sim;
2802df76c16SMatt Jacob 			path = ISP_SPI_PC(isp, chan)->path;
2812df76c16SMatt Jacob 		}
282e95725cbSMatt Jacob 		if (sim->refcount > 2) {
2832df76c16SMatt Jacob 			ISP_UNLOCK(isp);
284e95725cbSMatt Jacob 			return (EBUSY);
285e95725cbSMatt Jacob 		}
286e95725cbSMatt Jacob 	}
287e95725cbSMatt Jacob 	if (isp->isp_osinfo.timer_active) {
288e95725cbSMatt Jacob 		callout_stop(&isp->isp_osinfo.tmo);
289e95725cbSMatt Jacob 		isp->isp_osinfo.timer_active = 0;
290e95725cbSMatt Jacob 	}
291e95725cbSMatt Jacob 	for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) {
292e95725cbSMatt Jacob 		if (IS_FC(isp)) {
293e95725cbSMatt Jacob 			sim = ISP_FC_PC(isp, chan)->sim;
294e95725cbSMatt Jacob 			path = ISP_FC_PC(isp, chan)->path;
295e95725cbSMatt Jacob 		} else {
296e95725cbSMatt Jacob 			sim = ISP_SPI_PC(isp, chan)->sim;
297e95725cbSMatt Jacob 			path = ISP_SPI_PC(isp, chan)->path;
298e95725cbSMatt Jacob 		}
299e95725cbSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
300e95725cbSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
301e95725cbSMatt Jacob 		csa.event_enable = 0;
302e95725cbSMatt Jacob 		csa.callback = isp_cam_async;
303e95725cbSMatt Jacob 		csa.callback_arg = sim;
304e95725cbSMatt Jacob 		xpt_action((union ccb *)&csa);
305e95725cbSMatt Jacob 		xpt_free_path(path);
306e95725cbSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
3072df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
3082df76c16SMatt Jacob 	}
309e95725cbSMatt Jacob 	ISP_UNLOCK(isp);
3102df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
3112df76c16SMatt Jacob 		destroy_dev(isp->isp_osinfo.cdev);
3122df76c16SMatt Jacob 		isp->isp_osinfo.cdev = NULL;
3132df76c16SMatt Jacob 	}
3142df76c16SMatt Jacob 	if (isp->isp_osinfo.ehook_active) {
3152df76c16SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
3162df76c16SMatt Jacob 		isp->isp_osinfo.ehook_active = 0;
3172df76c16SMatt Jacob 	}
318a035b0afSMatt Jacob 	if (isp->isp_osinfo.devq != NULL) {
3192df76c16SMatt Jacob 		cam_simq_free(isp->isp_osinfo.devq);
3202df76c16SMatt Jacob 		isp->isp_osinfo.devq = NULL;
3210a70657fSMatt Jacob 	}
322e95725cbSMatt Jacob 	return (0);
3235d571944SMatt Jacob }
3245d571944SMatt Jacob 
325f7c631bcSMatt Jacob static void
3262df76c16SMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg)
327fdeb9f2fSMatt Jacob {
3282df76c16SMatt Jacob 	if (IS_FC(isp)) {
3292df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
3302df76c16SMatt Jacob 		if (fc->simqfrozen == 0) {
3312df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown) chan %d", msg, chan);
3322df76c16SMatt Jacob 			fc->simqfrozen = SIMQFRZ_LOOPDOWN;
3332df76c16SMatt Jacob 			xpt_freeze_simq(fc->sim, 1);
334fdeb9f2fSMatt Jacob 		} else {
3352df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown) chan %d", msg, chan);
3362df76c16SMatt Jacob 			fc->simqfrozen |= SIMQFRZ_LOOPDOWN;
3372df76c16SMatt Jacob 		}
338fdeb9f2fSMatt Jacob 	}
339fdeb9f2fSMatt Jacob }
340fdeb9f2fSMatt Jacob 
341e95725cbSMatt Jacob static void
342e95725cbSMatt Jacob isp_unfreeze_loopdown(ispsoftc_t *isp, int chan)
343e95725cbSMatt Jacob {
344e95725cbSMatt Jacob 	if (IS_FC(isp)) {
345e95725cbSMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
346e95725cbSMatt Jacob 		int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
347e95725cbSMatt Jacob 		fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
348e95725cbSMatt Jacob 		if (wasfrozen && fc->simqfrozen == 0) {
349e95725cbSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
350e95725cbSMatt Jacob 			xpt_release_simq(fc->sim, 1);
351e95725cbSMatt Jacob 		}
352e95725cbSMatt Jacob 	}
353e95725cbSMatt Jacob }
354e95725cbSMatt Jacob 
3559cd7268eSMatt Jacob 
3565d571944SMatt Jacob static int
3572df76c16SMatt Jacob ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
3585d571944SMatt Jacob {
3599cd7268eSMatt Jacob 	ispsoftc_t *isp;
3602df76c16SMatt Jacob 	int nr, chan, retval = ENOTTY;
3615d571944SMatt Jacob 
3622df76c16SMatt Jacob 	isp = dev->si_drv1;
3635d571944SMatt Jacob 
364c1504bc0SMatt Jacob 	switch (c) {
3655d571944SMatt Jacob 	case ISP_SDBLEV:
3665d571944SMatt Jacob 	{
3675d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3685d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3695d571944SMatt Jacob 		*(int *)addr = olddblev;
3705d571944SMatt Jacob 		retval = 0;
3715d571944SMatt Jacob 		break;
3725d571944SMatt Jacob 	}
373746e9c85SMatt Jacob 	case ISP_GETROLE:
3742df76c16SMatt Jacob 		chan = *(int *)addr;
3752df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
3762df76c16SMatt Jacob 			retval = -ENXIO;
3772df76c16SMatt Jacob 			break;
3782df76c16SMatt Jacob 		}
3792df76c16SMatt Jacob 		if (IS_FC(isp)) {
3802df76c16SMatt Jacob 			*(int *)addr = FCPARAM(isp, chan)->role;
3812df76c16SMatt Jacob 		} else {
3822df76c16SMatt Jacob 			*(int *)addr = SDPARAM(isp, chan)->role;
3832df76c16SMatt Jacob 		}
384746e9c85SMatt Jacob 		retval = 0;
385746e9c85SMatt Jacob 		break;
386746e9c85SMatt Jacob 	case ISP_SETROLE:
387746e9c85SMatt Jacob 		nr = *(int *)addr;
3882df76c16SMatt Jacob 		chan = nr >> 8;
3892df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
3902df76c16SMatt Jacob 			retval = -ENXIO;
3912df76c16SMatt Jacob 			break;
3922df76c16SMatt Jacob 		}
3932df76c16SMatt Jacob 		nr &= 0xff;
394746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
395746e9c85SMatt Jacob 			retval = EINVAL;
396746e9c85SMatt Jacob 			break;
397746e9c85SMatt Jacob 		}
3982df76c16SMatt Jacob 		if (IS_FC(isp)) {
399ae5db118SMatt Jacob 			/*
400ae5db118SMatt Jacob 			 * We don't really support dual role at present on FC cards.
401ae5db118SMatt Jacob 			 *
402ae5db118SMatt Jacob 			 * We should, but a bunch of things are currently broken,
403ae5db118SMatt Jacob 			 * so don't allow it.
404ae5db118SMatt Jacob 			 */
405ae5db118SMatt Jacob 			if (nr == ISP_ROLE_BOTH) {
406ae5db118SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "cannot support dual role at present");
407ae5db118SMatt Jacob 				retval = EINVAL;
408ae5db118SMatt Jacob 				break;
409ae5db118SMatt Jacob 			}
4102df76c16SMatt Jacob 			*(int *)addr = FCPARAM(isp, chan)->role;
4112df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
4122df76c16SMatt Jacob 			ISP_LOCK(isp);
4132df76c16SMatt Jacob 			retval = isp_fc_change_role(isp, chan, nr);
4142df76c16SMatt Jacob 			ISP_UNLOCK(isp);
4152df76c16SMatt Jacob #else
4162df76c16SMatt Jacob 			FCPARAM(isp, chan)->role = nr;
4172df76c16SMatt Jacob #endif
4182df76c16SMatt Jacob 		} else {
4192df76c16SMatt Jacob 			*(int *)addr = SDPARAM(isp, chan)->role;
4202df76c16SMatt Jacob 			SDPARAM(isp, chan)->role = nr;
4212df76c16SMatt Jacob 		}
4222df76c16SMatt Jacob 		retval = 0;
4232df76c16SMatt Jacob 		break;
4242df76c16SMatt Jacob 
4255d571944SMatt Jacob 	case ISP_RESETHBA:
426511ced9bSMatt Jacob 		ISP_LOCK(isp);
4272df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
4282df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, ISP_NOCHAN);
4292df76c16SMatt Jacob #endif
4302df76c16SMatt Jacob 		isp_reinit(isp, 0);
431511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
4325d571944SMatt Jacob 		retval = 0;
4335d571944SMatt Jacob 		break;
4342df76c16SMatt Jacob 
435f553351eSMatt Jacob 	case ISP_RESCAN:
4365d571944SMatt Jacob 		if (IS_FC(isp)) {
4372df76c16SMatt Jacob 			chan = *(int *)addr;
4382df76c16SMatt Jacob 			if (chan < 0 || chan >= isp->isp_nchan) {
4392df76c16SMatt Jacob 				retval = -ENXIO;
4402df76c16SMatt Jacob 				break;
4412df76c16SMatt Jacob 			}
442511ced9bSMatt Jacob 			ISP_LOCK(isp);
4432df76c16SMatt Jacob 			if (isp_fc_runstate(isp, chan, 5 * 1000000)) {
4445d571944SMatt Jacob 				retval = EIO;
4455d571944SMatt Jacob 			} else {
4465d571944SMatt Jacob 				retval = 0;
4475d571944SMatt Jacob 			}
448511ced9bSMatt Jacob 			ISP_UNLOCK(isp);
4495d571944SMatt Jacob 		}
4505d571944SMatt Jacob 		break;
4512df76c16SMatt Jacob 
4525d571944SMatt Jacob 	case ISP_FC_LIP:
4535d571944SMatt Jacob 		if (IS_FC(isp)) {
4542df76c16SMatt Jacob 			chan = *(int *)addr;
4552df76c16SMatt Jacob 			if (chan < 0 || chan >= isp->isp_nchan) {
4562df76c16SMatt Jacob 				retval = -ENXIO;
4572df76c16SMatt Jacob 				break;
4582df76c16SMatt Jacob 			}
459511ced9bSMatt Jacob 			ISP_LOCK(isp);
4602df76c16SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, chan)) {
4615d571944SMatt Jacob 				retval = EIO;
4625d571944SMatt Jacob 			} else {
4635d571944SMatt Jacob 				retval = 0;
4645d571944SMatt Jacob 			}
465511ced9bSMatt Jacob 			ISP_UNLOCK(isp);
4665d571944SMatt Jacob 		}
4675d571944SMatt Jacob 		break;
4685d571944SMatt Jacob 	case ISP_FC_GETDINFO:
4695d571944SMatt Jacob 	{
4705d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
47110365e5aSMatt Jacob 		fcportdb_t *lp;
4725d571944SMatt Jacob 
47302e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
47402e2b2d9SMatt Jacob 			break;
47502e2b2d9SMatt Jacob 		}
4762e4637cdSMatt Jacob 		if (ifc->loopid >= MAX_FC_TARG) {
4775d571944SMatt Jacob 			retval = EINVAL;
4785d571944SMatt Jacob 			break;
4795d571944SMatt Jacob 		}
4802df76c16SMatt Jacob 		lp = &FCPARAM(isp, ifc->chan)->portdb[ifc->loopid];
4812df76c16SMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID || lp->target_mode) {
482c6435ff3SMatt Jacob 			ifc->role = lp->roles;
48310365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4845d571944SMatt Jacob 			ifc->portid = lp->portid;
4855d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4865d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4875d571944SMatt Jacob 			retval = 0;
4885d571944SMatt Jacob 		} else {
4895d571944SMatt Jacob 			retval = ENODEV;
4905d571944SMatt Jacob 		}
4915d571944SMatt Jacob 		break;
4925d571944SMatt Jacob 	}
4932903b272SMatt Jacob 	case ISP_GET_STATS:
4942903b272SMatt Jacob 	{
4952903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4962903b272SMatt Jacob 
4972df76c16SMatt Jacob 		ISP_MEMZERO(sp, sizeof (*sp));
4982903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4992903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
5002903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
501511ced9bSMatt Jacob 		ISP_LOCK(isp);
5022903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
5032903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
5042903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
5052903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
5062903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
5072903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
5082903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
5092903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
510511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
5112903b272SMatt Jacob 		retval = 0;
5122903b272SMatt Jacob 		break;
5132903b272SMatt Jacob 	}
5142903b272SMatt Jacob 	case ISP_CLR_STATS:
515511ced9bSMatt Jacob 		ISP_LOCK(isp);
5162903b272SMatt Jacob 		isp->isp_intcnt = 0;
5172903b272SMatt Jacob 		isp->isp_intbogus = 0;
5182903b272SMatt Jacob 		isp->isp_intmboxc = 0;
5192903b272SMatt Jacob 		isp->isp_intoasync = 0;
5202903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
5212903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
5222903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
5232903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
524511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
5252903b272SMatt Jacob 		retval = 0;
5262903b272SMatt Jacob 		break;
527570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
528570c7a3fSMatt Jacob 	{
529570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
5302df76c16SMatt Jacob 		int chan = hba->fc_channel;
53102e2b2d9SMatt Jacob 
5322df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
5332df76c16SMatt Jacob 			retval = ENXIO;
5342df76c16SMatt Jacob 			break;
5352df76c16SMatt Jacob 		}
536a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
537a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
538a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
5392df76c16SMatt Jacob 		hba->fc_nchannels = isp->isp_nchan;
54002e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
5412df76c16SMatt Jacob 			hba->fc_nports = MAX_FC_TARG;
5422df76c16SMatt Jacob 			hba->fc_speed = FCPARAM(isp, hba->fc_channel)->isp_gbspeed;
5432df76c16SMatt Jacob 			hba->fc_topology = FCPARAM(isp, chan)->isp_topo + 1;
5442df76c16SMatt Jacob 			hba->fc_loopid = FCPARAM(isp, chan)->isp_loopid;
5452df76c16SMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp, chan)->isp_wwnn_nvram;
5462df76c16SMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp, chan)->isp_wwpn_nvram;
5472df76c16SMatt Jacob 			hba->active_node_wwn = FCPARAM(isp, chan)->isp_wwnn;
5482df76c16SMatt Jacob 			hba->active_port_wwn = FCPARAM(isp, chan)->isp_wwpn;
5492df76c16SMatt Jacob 		} else {
5502df76c16SMatt Jacob 			hba->fc_nports = MAX_TARGETS;
5512df76c16SMatt Jacob 			hba->fc_speed = 0;
5522df76c16SMatt Jacob 			hba->fc_topology = 0;
5532df76c16SMatt Jacob 			hba->nvram_node_wwn = 0ull;
5542df76c16SMatt Jacob 			hba->nvram_port_wwn = 0ull;
5552df76c16SMatt Jacob 			hba->active_node_wwn = 0ull;
5562df76c16SMatt Jacob 			hba->active_port_wwn = 0ull;
55702e2b2d9SMatt Jacob 		}
558570c7a3fSMatt Jacob 		retval = 0;
559570c7a3fSMatt Jacob 		break;
560570c7a3fSMatt Jacob 	}
5618e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5628e62a8acSMatt Jacob 	{
5638e62a8acSMatt Jacob 		int needmarker;
5648e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5651dae40ebSMatt Jacob 		uint16_t loopid;
5668e62a8acSMatt Jacob 		mbreg_t mbs;
5678e62a8acSMatt Jacob 
5688e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5698e62a8acSMatt Jacob 			break;
5708e62a8acSMatt Jacob 		}
5718e62a8acSMatt Jacob 
5722df76c16SMatt Jacob 		chan = fct->chan;
5732df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
5742df76c16SMatt Jacob 			retval = -ENXIO;
5752df76c16SMatt Jacob 			break;
5762df76c16SMatt Jacob 		}
5772df76c16SMatt Jacob 
5788e62a8acSMatt Jacob 		needmarker = retval = 0;
579e5265237SMatt Jacob 		loopid = fct->loopid;
5802df76c16SMatt Jacob 		ISP_LOCK(isp);
5812df76c16SMatt Jacob 		if (IS_24XX(isp)) {
5822df76c16SMatt Jacob 			uint8_t local[QENTRY_LEN];
5832df76c16SMatt Jacob 			isp24xx_tmf_t *tmf;
5842df76c16SMatt Jacob 			isp24xx_statusreq_t *sp;
5852df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, chan);
5862df76c16SMatt Jacob 			fcportdb_t *lp;
5872df76c16SMatt Jacob 			int i;
5882df76c16SMatt Jacob 
5892df76c16SMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
5902df76c16SMatt Jacob 				lp = &fcp->portdb[i];
5912df76c16SMatt Jacob 				if (lp->handle == loopid) {
5922df76c16SMatt Jacob 					break;
5932df76c16SMatt Jacob 				}
5942df76c16SMatt Jacob 			}
5952df76c16SMatt Jacob 			if (i == MAX_FC_TARG) {
5962df76c16SMatt Jacob 				retval = ENXIO;
5972df76c16SMatt Jacob 				ISP_UNLOCK(isp);
5982df76c16SMatt Jacob 				break;
5992df76c16SMatt Jacob 			}
6002df76c16SMatt Jacob 			/* XXX VALIDATE LP XXX */
6012df76c16SMatt Jacob 			tmf = (isp24xx_tmf_t *) local;
6022df76c16SMatt Jacob 			ISP_MEMZERO(tmf, QENTRY_LEN);
6032df76c16SMatt Jacob 			tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT;
6042df76c16SMatt Jacob 			tmf->tmf_header.rqs_entry_count = 1;
6052df76c16SMatt Jacob 			tmf->tmf_nphdl = lp->handle;
6062df76c16SMatt Jacob 			tmf->tmf_delay = 2;
6072df76c16SMatt Jacob 			tmf->tmf_timeout = 2;
6082df76c16SMatt Jacob 			tmf->tmf_tidlo = lp->portid;
6092df76c16SMatt Jacob 			tmf->tmf_tidhi = lp->portid >> 16;
6102df76c16SMatt Jacob 			tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan);
6112df76c16SMatt Jacob 			tmf->tmf_lun[1] = fct->lun & 0xff;
6122df76c16SMatt Jacob 			if (fct->lun >= 256) {
6132df76c16SMatt Jacob 				tmf->tmf_lun[0] = 0x40 | (fct->lun >> 8);
6142df76c16SMatt Jacob 			}
6152df76c16SMatt Jacob 			switch (fct->action) {
6162df76c16SMatt Jacob 			case IPT_CLEAR_ACA:
6172df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_CLEAR_ACA;
6182df76c16SMatt Jacob 				break;
6192df76c16SMatt Jacob 			case IPT_TARGET_RESET:
6202df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET;
6212df76c16SMatt Jacob 				needmarker = 1;
6222df76c16SMatt Jacob 				break;
6232df76c16SMatt Jacob 			case IPT_LUN_RESET:
6242df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_LUN_RESET;
6252df76c16SMatt Jacob 				needmarker = 1;
6262df76c16SMatt Jacob 				break;
6272df76c16SMatt Jacob 			case IPT_CLEAR_TASK_SET:
6282df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_CLEAR_TASK_SET;
6292df76c16SMatt Jacob 				needmarker = 1;
6302df76c16SMatt Jacob 				break;
6312df76c16SMatt Jacob 			case IPT_ABORT_TASK_SET:
6322df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_ABORT_TASK_SET;
6332df76c16SMatt Jacob 				needmarker = 1;
6342df76c16SMatt Jacob 				break;
6352df76c16SMatt Jacob 			default:
6362df76c16SMatt Jacob 				retval = EINVAL;
6372df76c16SMatt Jacob 				break;
6382df76c16SMatt Jacob 			}
6392df76c16SMatt Jacob 			if (retval) {
6402df76c16SMatt Jacob 				ISP_UNLOCK(isp);
6412df76c16SMatt Jacob 				break;
6422df76c16SMatt Jacob 			}
6432df76c16SMatt Jacob 			MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000);
6442df76c16SMatt Jacob 			mbs.param[1] = QENTRY_LEN;
6452df76c16SMatt Jacob 			mbs.param[2] = DMA_WD1(fcp->isp_scdma);
6462df76c16SMatt Jacob 			mbs.param[3] = DMA_WD0(fcp->isp_scdma);
6472df76c16SMatt Jacob 			mbs.param[6] = DMA_WD3(fcp->isp_scdma);
6482df76c16SMatt Jacob 			mbs.param[7] = DMA_WD2(fcp->isp_scdma);
6492df76c16SMatt Jacob 
6502df76c16SMatt Jacob 			if (FC_SCRATCH_ACQUIRE(isp, chan)) {
6512df76c16SMatt Jacob 				ISP_UNLOCK(isp);
6522df76c16SMatt Jacob 				retval = ENOMEM;
6532df76c16SMatt Jacob 				break;
6542df76c16SMatt Jacob 			}
6552df76c16SMatt Jacob 			isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch);
65637bb79f1SMarius Strobl 			MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan);
6572df76c16SMatt Jacob 			sp = (isp24xx_statusreq_t *) local;
6582df76c16SMatt Jacob 			sp->req_completion_status = 1;
6592df76c16SMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
66037bb79f1SMarius Strobl 			MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
6612df76c16SMatt Jacob 			isp_get_24xx_response(isp, &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp);
6622df76c16SMatt Jacob 			FC_SCRATCH_RELEASE(isp, chan);
6632df76c16SMatt Jacob 			if (retval || sp->req_completion_status != 0) {
6642df76c16SMatt Jacob 				FC_SCRATCH_RELEASE(isp, chan);
6652df76c16SMatt Jacob 				retval = EIO;
6662df76c16SMatt Jacob 			}
6672df76c16SMatt Jacob 			if (retval == 0) {
6682df76c16SMatt Jacob 				if (needmarker) {
6692df76c16SMatt Jacob 					fcp->sendmarker = 1;
6702df76c16SMatt Jacob 				}
6712df76c16SMatt Jacob 			}
6722df76c16SMatt Jacob 		} else {
6732df76c16SMatt Jacob 			MBSINIT(&mbs, 0, MBLOGALL, 0);
6742df76c16SMatt Jacob 			if (ISP_CAP_2KLOGIN(isp) == 0) {
675e5265237SMatt Jacob 				loopid <<= 8;
676e5265237SMatt Jacob 			}
6778e62a8acSMatt Jacob 			switch (fct->action) {
678f0f536d1SMatt Jacob 			case IPT_CLEAR_ACA:
6798e62a8acSMatt Jacob 				mbs.param[0] = MBOX_CLEAR_ACA;
680e5265237SMatt Jacob 				mbs.param[1] = loopid;
6818e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6828e62a8acSMatt Jacob 				break;
683f0f536d1SMatt Jacob 			case IPT_TARGET_RESET:
6848e62a8acSMatt Jacob 				mbs.param[0] = MBOX_TARGET_RESET;
685e5265237SMatt Jacob 				mbs.param[1] = loopid;
6868e62a8acSMatt Jacob 				needmarker = 1;
6878e62a8acSMatt Jacob 				break;
688f0f536d1SMatt Jacob 			case IPT_LUN_RESET:
6898e62a8acSMatt Jacob 				mbs.param[0] = MBOX_LUN_RESET;
690e5265237SMatt Jacob 				mbs.param[1] = loopid;
6918e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6928e62a8acSMatt Jacob 				needmarker = 1;
6938e62a8acSMatt Jacob 				break;
694f0f536d1SMatt Jacob 			case IPT_CLEAR_TASK_SET:
6958e62a8acSMatt Jacob 				mbs.param[0] = MBOX_CLEAR_TASK_SET;
696e5265237SMatt Jacob 				mbs.param[1] = loopid;
6978e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6988e62a8acSMatt Jacob 				needmarker = 1;
6998e62a8acSMatt Jacob 				break;
700f0f536d1SMatt Jacob 			case IPT_ABORT_TASK_SET:
7018e62a8acSMatt Jacob 				mbs.param[0] = MBOX_ABORT_TASK_SET;
702e5265237SMatt Jacob 				mbs.param[1] = loopid;
7038e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
7048e62a8acSMatt Jacob 				needmarker = 1;
7058e62a8acSMatt Jacob 				break;
7068e62a8acSMatt Jacob 			default:
7078e62a8acSMatt Jacob 				retval = EINVAL;
7088e62a8acSMatt Jacob 				break;
7098e62a8acSMatt Jacob 			}
7108e62a8acSMatt Jacob 			if (retval == 0) {
7118e62a8acSMatt Jacob 				if (needmarker) {
7122df76c16SMatt Jacob 					FCPARAM(isp, chan)->sendmarker = 1;
7138e62a8acSMatt Jacob 				}
7148e62a8acSMatt Jacob 				retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
7152df76c16SMatt Jacob 				if (retval) {
7168e62a8acSMatt Jacob 					retval = EIO;
7178e62a8acSMatt Jacob 				}
7182df76c16SMatt Jacob 			}
7192df76c16SMatt Jacob 		}
7202df76c16SMatt Jacob 		ISP_UNLOCK(isp);
7218e62a8acSMatt Jacob 		break;
7228e62a8acSMatt Jacob 	}
7235d571944SMatt Jacob 	default:
7245d571944SMatt Jacob 		break;
7255d571944SMatt Jacob 	}
7265d571944SMatt Jacob 	return (retval);
7270470d791SMatt Jacob }
728478f8a96SJustin T. Gibbs 
729f6e75de2SMatt Jacob static void
730f6e75de2SMatt Jacob isp_intr_enable(void *arg)
731f6e75de2SMatt Jacob {
7322df76c16SMatt Jacob 	int chan;
7339cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
7340a70657fSMatt Jacob 	ISP_LOCK(isp);
7352df76c16SMatt Jacob 	for (chan = 0; chan < isp->isp_nchan; chan++) {
7362df76c16SMatt Jacob 		if (IS_FC(isp)) {
7372df76c16SMatt Jacob 			if (FCPARAM(isp, chan)->role != ISP_ROLE_NONE) {
73810365e5aSMatt Jacob 				ISP_ENABLE_INTS(isp);
7392df76c16SMatt Jacob 				break;
7402df76c16SMatt Jacob 			}
7412df76c16SMatt Jacob 		} else {
7422df76c16SMatt Jacob 			if (SDPARAM(isp, chan)->role != ISP_ROLE_NONE) {
7432df76c16SMatt Jacob 				ISP_ENABLE_INTS(isp);
7442df76c16SMatt Jacob 				break;
7452df76c16SMatt Jacob 			}
7462df76c16SMatt Jacob 		}
747d6e5500fSMatt Jacob 	}
748e95725cbSMatt Jacob 	isp->isp_osinfo.ehook_active = 0;
7490a70657fSMatt Jacob 	ISP_UNLOCK(isp);
750f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
751f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
752f6e75de2SMatt Jacob }
753d81ba9d5SMatt Jacob 
754d81ba9d5SMatt Jacob /*
7552df76c16SMatt Jacob  * Local Inlines
7562df76c16SMatt Jacob  */
7572df76c16SMatt Jacob 
7582df76c16SMatt Jacob static ISP_INLINE int isp_get_pcmd(ispsoftc_t *, union ccb *);
7592df76c16SMatt Jacob static ISP_INLINE void isp_free_pcmd(ispsoftc_t *, union ccb *);
7602df76c16SMatt Jacob 
7612df76c16SMatt Jacob static ISP_INLINE int
7622df76c16SMatt Jacob isp_get_pcmd(ispsoftc_t *isp, union ccb *ccb)
7632df76c16SMatt Jacob {
7642df76c16SMatt Jacob 	ISP_PCMD(ccb) = isp->isp_osinfo.pcmd_free;
7652df76c16SMatt Jacob 	if (ISP_PCMD(ccb) == NULL) {
7662df76c16SMatt Jacob 		return (-1);
7672df76c16SMatt Jacob 	}
7682df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_free = ((struct isp_pcmd *)ISP_PCMD(ccb))->next;
7692df76c16SMatt Jacob 	return (0);
7702df76c16SMatt Jacob }
7712df76c16SMatt Jacob 
7722df76c16SMatt Jacob static ISP_INLINE void
7732df76c16SMatt Jacob isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb)
7742df76c16SMatt Jacob {
7752df76c16SMatt Jacob 	((struct isp_pcmd *)ISP_PCMD(ccb))->next = isp->isp_osinfo.pcmd_free;
7762df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb);
7772df76c16SMatt Jacob 	ISP_PCMD(ccb) = NULL;
7782df76c16SMatt Jacob }
7792df76c16SMatt Jacob /*
780d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
781d81ba9d5SMatt Jacob  */
782d81ba9d5SMatt Jacob 
783d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
784e2873b76SMatt Jacob static ISP_INLINE void isp_tmlock(ispsoftc_t *, const char *);
785e2873b76SMatt Jacob static ISP_INLINE void isp_tmunlk(ispsoftc_t *);
786e2873b76SMatt Jacob static ISP_INLINE int is_any_lun_enabled(ispsoftc_t *, int);
7872df76c16SMatt Jacob static ISP_INLINE int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7882df76c16SMatt Jacob static ISP_INLINE tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7892df76c16SMatt Jacob static ISP_INLINE tstate_t *get_lun_statep_from_tag(ispsoftc_t *, int, uint32_t);
7902df76c16SMatt Jacob static ISP_INLINE void rls_lun_statep(ispsoftc_t *, tstate_t *);
7912df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *get_ntp_from_tagdata(ispsoftc_t *, uint32_t, uint32_t, tstate_t **);
7922df76c16SMatt Jacob static ISP_INLINE atio_private_data_t *isp_get_atpd(ispsoftc_t *, tstate_t *, uint32_t);
7932df76c16SMatt Jacob static ISP_INLINE void isp_put_atpd(ispsoftc_t *, tstate_t *, atio_private_data_t *);
7942df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *isp_get_ntpd(ispsoftc_t *, tstate_t *);
7952df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *isp_find_ntpd(ispsoftc_t *, tstate_t *, uint32_t, uint32_t);
7962df76c16SMatt Jacob static ISP_INLINE void isp_put_ntpd(ispsoftc_t *, tstate_t *, inot_private_data_t *);
7972df76c16SMatt Jacob static cam_status create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7989cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7992df76c16SMatt Jacob static void isp_enable_lun(ispsoftc_t *, union ccb *);
800e2873b76SMatt Jacob static cam_status isp_enable_deferred_luns(ispsoftc_t *, int);
8012df76c16SMatt Jacob static cam_status isp_enable_deferred(ispsoftc_t *, int, lun_id_t);
8022df76c16SMatt Jacob static void isp_disable_lun(ispsoftc_t *, union ccb *);
8032df76c16SMatt Jacob static int isp_enable_target_mode(ispsoftc_t *, int);
804e2873b76SMatt Jacob static int isp_disable_target_mode(ispsoftc_t *, int);
8059cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
806f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
807a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
808a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
8099cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
8102df76c16SMatt Jacob static void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
8112df76c16SMatt Jacob static void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
8122df76c16SMatt Jacob static void isp_handle_platform_atio7(ispsoftc_t *, at7_entry_t *);
8132df76c16SMatt Jacob static void isp_handle_platform_ctio(ispsoftc_t *, void *);
8142df76c16SMatt Jacob static void isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
8152df76c16SMatt Jacob static void isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
8162df76c16SMatt Jacob static void isp_handle_platform_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *);
8172df76c16SMatt Jacob static int isp_handle_platform_target_notify_ack(ispsoftc_t *, isp_notify_t *);
8182df76c16SMatt Jacob static void isp_handle_platform_target_tmf(ispsoftc_t *, isp_notify_t *);
8192df76c16SMatt Jacob static void isp_target_mark_aborted(ispsoftc_t *, union ccb *);
8202df76c16SMatt Jacob static void isp_target_mark_aborted_early(ispsoftc_t *, tstate_t *, uint32_t);
821d81ba9d5SMatt Jacob 
822e2873b76SMatt Jacob static ISP_INLINE void
823e2873b76SMatt Jacob isp_tmlock(ispsoftc_t *isp, const char *msg)
824e2873b76SMatt Jacob {
825e2873b76SMatt Jacob 	while (isp->isp_osinfo.tmbusy) {
826e2873b76SMatt Jacob 		isp->isp_osinfo.tmwanted = 1;
827e2873b76SMatt Jacob 		mtx_sleep(isp, &isp->isp_lock, PRIBIO, msg, 0);
828e2873b76SMatt Jacob 	}
829e2873b76SMatt Jacob 	isp->isp_osinfo.tmbusy = 1;
830e2873b76SMatt Jacob }
831e2873b76SMatt Jacob 
832e2873b76SMatt Jacob static ISP_INLINE void
833e2873b76SMatt Jacob isp_tmunlk(ispsoftc_t *isp)
834e2873b76SMatt Jacob {
835e2873b76SMatt Jacob 	isp->isp_osinfo.tmbusy = 0;
836e2873b76SMatt Jacob 	if (isp->isp_osinfo.tmwanted) {
837e2873b76SMatt Jacob 		isp->isp_osinfo.tmwanted = 0;
838e2873b76SMatt Jacob 		wakeup(isp);
839e2873b76SMatt Jacob 	}
840e2873b76SMatt Jacob }
841e2873b76SMatt Jacob 
842e2873b76SMatt Jacob static ISP_INLINE int
843e2873b76SMatt Jacob is_any_lun_enabled(ispsoftc_t *isp, int bus)
844e2873b76SMatt Jacob {
845e2873b76SMatt Jacob 	struct tslist *lhp;
846e2873b76SMatt Jacob 	int i;
847e2873b76SMatt Jacob 
848e2873b76SMatt Jacob 	for (i = 0; i < LUN_HASH_SIZE; i++) {
849e2873b76SMatt Jacob 		ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
850e2873b76SMatt Jacob 		if (SLIST_FIRST(lhp))
851e2873b76SMatt Jacob 			return (1);
852e2873b76SMatt Jacob 	}
853e2873b76SMatt Jacob 	return (0);
854e2873b76SMatt Jacob }
855e2873b76SMatt Jacob 
8562df76c16SMatt Jacob static ISP_INLINE int
8579cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
858d81ba9d5SMatt Jacob {
859d81ba9d5SMatt Jacob 	tstate_t *tptr;
8602df76c16SMatt Jacob 	struct tslist *lhp;
8612df76c16SMatt Jacob 
8622df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(lun)], lhp);
8632df76c16SMatt Jacob 	SLIST_FOREACH(tptr, lhp, next) {
8642df76c16SMatt Jacob 		if (xpt_path_lun_id(tptr->owner) == lun) {
865d81ba9d5SMatt Jacob 			return (1);
866d81ba9d5SMatt Jacob 		}
8672df76c16SMatt Jacob 	}
868d81ba9d5SMatt Jacob 	return (0);
869d81ba9d5SMatt Jacob }
870d81ba9d5SMatt Jacob 
8712df76c16SMatt Jacob static void
8722df76c16SMatt Jacob dump_tstates(ispsoftc_t *isp, int bus)
873d81ba9d5SMatt Jacob {
8742df76c16SMatt Jacob 	int i, j;
8752df76c16SMatt Jacob 	struct tslist *lhp;
8762df76c16SMatt Jacob 	tstate_t *tptr = NULL;
8772df76c16SMatt Jacob 
8782df76c16SMatt Jacob 	if (bus >= isp->isp_nchan) {
8792df76c16SMatt Jacob 		return;
880a1bc34c6SMatt Jacob 	}
8812df76c16SMatt Jacob 	for (i = 0; i < LUN_HASH_SIZE; i++) {
8822df76c16SMatt Jacob 		ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
8832df76c16SMatt Jacob 		j = 0;
8842df76c16SMatt Jacob 		SLIST_FOREACH(tptr, lhp, next) {
8852df76c16SMatt Jacob 			xpt_print(tptr->owner, "[%d, %d] atio_cnt=%d inot_cnt=%d\n", i, j, tptr->atio_count, tptr->inot_count);
8862df76c16SMatt Jacob 			j++;
887d81ba9d5SMatt Jacob 		}
888d81ba9d5SMatt Jacob 	}
889d81ba9d5SMatt Jacob }
890d81ba9d5SMatt Jacob 
8912df76c16SMatt Jacob static ISP_INLINE tstate_t *
8929cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
893d81ba9d5SMatt Jacob {
89464edff94SMatt Jacob 	tstate_t *tptr = NULL;
8952df76c16SMatt Jacob 	struct tslist *lhp;
8962df76c16SMatt Jacob 	int i;
897d81ba9d5SMatt Jacob 
8982df76c16SMatt Jacob 	if (bus < isp->isp_nchan) {
8992df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
9002df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
9012df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
9022df76c16SMatt Jacob 				if (xpt_path_lun_id(tptr->owner) == lun) {
903d81ba9d5SMatt Jacob 					tptr->hold++;
904d81ba9d5SMatt Jacob 					return (tptr);
905d81ba9d5SMatt Jacob 				}
90664edff94SMatt Jacob 			}
907126ec864SMatt Jacob 		}
9082df76c16SMatt Jacob 	}
9092df76c16SMatt Jacob 	return (NULL);
9102df76c16SMatt Jacob }
911d81ba9d5SMatt Jacob 
9122df76c16SMatt Jacob static ISP_INLINE tstate_t *
9132df76c16SMatt Jacob get_lun_statep_from_tag(ispsoftc_t *isp, int bus, uint32_t tagval)
9142df76c16SMatt Jacob {
9152df76c16SMatt Jacob 	tstate_t *tptr = NULL;
9162df76c16SMatt Jacob 	atio_private_data_t *atp;
9172df76c16SMatt Jacob 	struct tslist *lhp;
9182df76c16SMatt Jacob 	int i;
9192df76c16SMatt Jacob 
9202df76c16SMatt Jacob 	if (bus < isp->isp_nchan && tagval != 0) {
9212df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
9222df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
9232df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
9242df76c16SMatt Jacob 				atp = isp_get_atpd(isp, tptr, tagval);
9252df76c16SMatt Jacob 				if (atp && atp->tag == tagval) {
926d81ba9d5SMatt Jacob 					tptr->hold++;
927d81ba9d5SMatt Jacob 					return (tptr);
928d81ba9d5SMatt Jacob 				}
9292df76c16SMatt Jacob 			}
9302df76c16SMatt Jacob 		}
9312df76c16SMatt Jacob 	}
9322df76c16SMatt Jacob 	return (NULL);
933d81ba9d5SMatt Jacob }
934d81ba9d5SMatt Jacob 
9352df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
9362df76c16SMatt Jacob get_ntp_from_tagdata(ispsoftc_t *isp, uint32_t tag_id, uint32_t seq_id, tstate_t **rslt)
9372df76c16SMatt Jacob {
9382df76c16SMatt Jacob 	inot_private_data_t *ntp;
9392df76c16SMatt Jacob 	tstate_t *tptr;
9402df76c16SMatt Jacob 	struct tslist *lhp;
9412df76c16SMatt Jacob 	int bus, i;
9422df76c16SMatt Jacob 
9432df76c16SMatt Jacob 	for (bus = 0; bus < isp->isp_nchan; bus++) {
9442df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
9452df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
9462df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
9472df76c16SMatt Jacob 				ntp = isp_find_ntpd(isp, tptr, tag_id, seq_id);
9482df76c16SMatt Jacob 				if (ntp) {
9492df76c16SMatt Jacob 					*rslt = tptr;
9502df76c16SMatt Jacob 					tptr->hold++;
9512df76c16SMatt Jacob 					return (ntp);
9522df76c16SMatt Jacob 				}
9532df76c16SMatt Jacob 			}
9542df76c16SMatt Jacob 		}
9552df76c16SMatt Jacob 	}
9562df76c16SMatt Jacob 	return (NULL);
9572df76c16SMatt Jacob }
958e2873b76SMatt Jacob 
9592df76c16SMatt Jacob static ISP_INLINE void
9609cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
961d81ba9d5SMatt Jacob {
9622df76c16SMatt Jacob 	KASSERT((tptr->hold), ("tptr not held"));
963d81ba9d5SMatt Jacob 	tptr->hold--;
964d81ba9d5SMatt Jacob }
965d81ba9d5SMatt Jacob 
9662df76c16SMatt Jacob static void
9672df76c16SMatt Jacob isp_tmcmd_restart(ispsoftc_t *isp)
9682df76c16SMatt Jacob {
9692df76c16SMatt Jacob 	inot_private_data_t *ntp;
9702df76c16SMatt Jacob 	tstate_t *tptr;
9712df76c16SMatt Jacob 	struct tslist *lhp;
9722df76c16SMatt Jacob 	int bus, i;
9732df76c16SMatt Jacob 
9742df76c16SMatt Jacob 	for (bus = 0; bus < isp->isp_nchan; bus++) {
9752df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
9762df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
9772df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
9782df76c16SMatt Jacob 				inot_private_data_t *restart_queue = tptr->restart_queue;
9792df76c16SMatt Jacob 				tptr->restart_queue = NULL;
9802df76c16SMatt Jacob 				while (restart_queue) {
9812df76c16SMatt Jacob 					ntp = restart_queue;
9822df76c16SMatt Jacob 					restart_queue = ntp->rd.nt.nt_hba;
9832df76c16SMatt Jacob 					if (IS_24XX(isp)) {
9842df76c16SMatt Jacob 						isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid);
9852df76c16SMatt Jacob 						isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data);
9862df76c16SMatt Jacob 					} else {
9872df76c16SMatt Jacob 						isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid);
9882df76c16SMatt Jacob 						isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data);
9892df76c16SMatt Jacob 					}
9902df76c16SMatt Jacob 					isp_put_ntpd(isp, tptr, ntp);
9912df76c16SMatt Jacob 					if (tptr->restart_queue && restart_queue != NULL) {
9922df76c16SMatt Jacob 						ntp = tptr->restart_queue;
9932df76c16SMatt Jacob 						tptr->restart_queue = restart_queue;
9942df76c16SMatt Jacob 						while (restart_queue->rd.nt.nt_hba) {
9952df76c16SMatt Jacob 							restart_queue = restart_queue->rd.nt.nt_hba;
9962df76c16SMatt Jacob 						}
9972df76c16SMatt Jacob 						restart_queue->rd.nt.nt_hba = ntp;
9982df76c16SMatt Jacob 						break;
9992df76c16SMatt Jacob 					}
10002df76c16SMatt Jacob 				}
10012df76c16SMatt Jacob 			}
10022df76c16SMatt Jacob 		}
10032df76c16SMatt Jacob 	}
10042df76c16SMatt Jacob }
10052df76c16SMatt Jacob 
10062df76c16SMatt Jacob static ISP_INLINE atio_private_data_t *
10072df76c16SMatt Jacob isp_get_atpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag)
100853036e92SMatt Jacob {
100953036e92SMatt Jacob 	atio_private_data_t *atp;
10102df76c16SMatt Jacob 
10112df76c16SMatt Jacob 	if (tag == 0) {
10122df76c16SMatt Jacob 		atp = tptr->atfree;
10132df76c16SMatt Jacob 		if (atp) {
10142df76c16SMatt Jacob 			tptr->atfree = atp->next;
10152df76c16SMatt Jacob 		}
101653036e92SMatt Jacob 		return (atp);
101753036e92SMatt Jacob 	}
10182df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
10192df76c16SMatt Jacob 		if (atp->tag == tag) {
10202df76c16SMatt Jacob 			return (atp);
10212df76c16SMatt Jacob 		}
10222df76c16SMatt Jacob 	}
102353036e92SMatt Jacob 	return (NULL);
102453036e92SMatt Jacob }
102553036e92SMatt Jacob 
10262df76c16SMatt Jacob static ISP_INLINE void
10272df76c16SMatt Jacob isp_put_atpd(ispsoftc_t *isp, tstate_t *tptr, atio_private_data_t *atp)
10282df76c16SMatt Jacob {
10292df76c16SMatt Jacob 	atp->tag = 0;
10302df76c16SMatt Jacob 	atp->dead = 0;
10312df76c16SMatt Jacob 	atp->next = tptr->atfree;
10322df76c16SMatt Jacob 	tptr->atfree = atp;
10332df76c16SMatt Jacob }
10342df76c16SMatt Jacob 
10352df76c16SMatt Jacob static void
10362df76c16SMatt Jacob isp_dump_atpd(ispsoftc_t *isp, tstate_t *tptr)
10372df76c16SMatt Jacob {
10382df76c16SMatt Jacob 	atio_private_data_t *atp;
10392df76c16SMatt Jacob 	const char *states[8] = { "Free", "ATIO", "CAM", "CTIO", "LAST_CTIO", "PDON", "?6", "7" };
10402df76c16SMatt Jacob 
10412df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
10422df76c16SMatt Jacob 		if (atp->tag == 0) {
10432df76c16SMatt Jacob 			continue;
10442df76c16SMatt Jacob 		}
10452df76c16SMatt Jacob 		xpt_print(tptr->owner, "ATP: [0x%x] origdlen %u bytes_xfrd %u last_xfr %u lun %u nphdl 0x%04x s_id 0x%06x d_id 0x%06x oxid 0x%04x state %s\n",
10462df76c16SMatt Jacob                     atp->tag, atp->orig_datalen, atp->bytes_xfered, atp->last_xframt, atp->lun, atp->nphdl, atp->sid, atp->portid, atp->oxid, states[atp->state & 0x7]);
10472df76c16SMatt Jacob 	}
10482df76c16SMatt Jacob }
10492df76c16SMatt Jacob 
10502df76c16SMatt Jacob 
10512df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
10522df76c16SMatt Jacob isp_get_ntpd(ispsoftc_t *isp, tstate_t *tptr)
10532df76c16SMatt Jacob {
10542df76c16SMatt Jacob 	inot_private_data_t *ntp;
10552df76c16SMatt Jacob 	ntp = tptr->ntfree;
10562df76c16SMatt Jacob 	if (ntp) {
10572df76c16SMatt Jacob 		tptr->ntfree = ntp->next;
10582df76c16SMatt Jacob 	}
10592df76c16SMatt Jacob 	return (ntp);
10602df76c16SMatt Jacob }
10612df76c16SMatt Jacob 
10622df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
10632df76c16SMatt Jacob isp_find_ntpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id, uint32_t seq_id)
10642df76c16SMatt Jacob {
10652df76c16SMatt Jacob 	inot_private_data_t *ntp;
10662df76c16SMatt Jacob 	for (ntp = tptr->ntpool; ntp < &tptr->ntpool[ATPDPSIZE]; ntp++) {
10672df76c16SMatt Jacob 		if (ntp->rd.tag_id == tag_id && ntp->rd.seq_id == seq_id) {
10682df76c16SMatt Jacob 			return (ntp);
10692df76c16SMatt Jacob 		}
10702df76c16SMatt Jacob 	}
10712df76c16SMatt Jacob 	return (NULL);
10722df76c16SMatt Jacob }
10732df76c16SMatt Jacob 
10742df76c16SMatt Jacob static ISP_INLINE void
10752df76c16SMatt Jacob isp_put_ntpd(ispsoftc_t *isp, tstate_t *tptr, inot_private_data_t *ntp)
10762df76c16SMatt Jacob {
10772df76c16SMatt Jacob 	ntp->rd.tag_id = ntp->rd.seq_id = 0;
10782df76c16SMatt Jacob 	ntp->next = tptr->ntfree;
10792df76c16SMatt Jacob 	tptr->ntfree = ntp;
10802df76c16SMatt Jacob }
10812df76c16SMatt Jacob 
1082d81ba9d5SMatt Jacob static cam_status
10832df76c16SMatt Jacob create_lun_state(ispsoftc_t *isp, int bus, struct cam_path *path, tstate_t **rslt)
1084d81ba9d5SMatt Jacob {
1085d81ba9d5SMatt Jacob 	cam_status status;
1086d81ba9d5SMatt Jacob 	lun_id_t lun;
10872df76c16SMatt Jacob 	struct tslist *lhp;
10882df76c16SMatt Jacob 	tstate_t *tptr;
10892df76c16SMatt Jacob 	int i;
1090d81ba9d5SMatt Jacob 
1091d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
10922df76c16SMatt Jacob 	if (lun != CAM_LUN_WILDCARD) {
10932e4637cdSMatt Jacob 		if (lun >= ISP_MAX_LUNS(isp)) {
1094d81ba9d5SMatt Jacob 			return (CAM_LUN_INVALID);
1095d81ba9d5SMatt Jacob 		}
10962df76c16SMatt Jacob 	}
1097a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
1098d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
1099d81ba9d5SMatt Jacob 	}
1100e2873b76SMatt Jacob 	tptr = malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
11012df76c16SMatt Jacob 	if (tptr == NULL) {
1102d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1103d81ba9d5SMatt Jacob 	}
11042df76c16SMatt Jacob 	status = xpt_create_path(&tptr->owner, NULL, xpt_path_path_id(path), xpt_path_target_id(path), lun);
1105d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
11062df76c16SMatt Jacob 		free(tptr, M_DEVBUF);
1107d81ba9d5SMatt Jacob 		return (status);
1108d81ba9d5SMatt Jacob 	}
11092df76c16SMatt Jacob 	SLIST_INIT(&tptr->atios);
11102df76c16SMatt Jacob 	SLIST_INIT(&tptr->inots);
11112df76c16SMatt Jacob 	for (i = 0; i < ATPDPSIZE-1; i++) {
11122df76c16SMatt Jacob 		tptr->atpool[i].next = &tptr->atpool[i+1];
11132df76c16SMatt Jacob 		tptr->ntpool[i].next = &tptr->ntpool[i+1];
1114d81ba9d5SMatt Jacob 	}
11152df76c16SMatt Jacob 	tptr->atfree = tptr->atpool;
11162df76c16SMatt Jacob 	tptr->ntfree = tptr->ntpool;
11172df76c16SMatt Jacob 	tptr->hold = 1;
11182df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp);
11192df76c16SMatt Jacob 	SLIST_INSERT_HEAD(lhp, tptr, next);
11202df76c16SMatt Jacob 	*rslt = tptr;
11212df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, path, "created tstate\n");
1122d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
1123d81ba9d5SMatt Jacob }
1124d81ba9d5SMatt Jacob 
11252df76c16SMatt Jacob static ISP_INLINE void
11269cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
1127d81ba9d5SMatt Jacob {
11282df76c16SMatt Jacob 	struct tslist *lhp;
1129e2873b76SMatt Jacob 
113045210a25SAlexander Motin 	KASSERT((tptr->hold != 0), ("tptr is not held"));
113145210a25SAlexander Motin 	KASSERT((tptr->hold == 1), ("tptr still held (%d)", tptr->hold));
113245210a25SAlexander Motin 	ISP_GET_PC_ADDR(isp, cam_sim_bus(xpt_path_sim(tptr->owner)), lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp);
11332df76c16SMatt Jacob 	SLIST_REMOVE(lhp, tptr, tstate, next);
1134e2873b76SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "destroyed tstate\n");
11352df76c16SMatt Jacob 	xpt_free_path(tptr->owner);
1136d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
1137d81ba9d5SMatt Jacob }
1138d81ba9d5SMatt Jacob 
11395d571944SMatt Jacob /*
11402df76c16SMatt Jacob  * Enable a lun.
11415d571944SMatt Jacob  */
11422df76c16SMatt Jacob static void
11432df76c16SMatt Jacob isp_enable_lun(ispsoftc_t *isp, union ccb *ccb)
1144d81ba9d5SMatt Jacob {
11451fd47020SMatt Jacob 	tstate_t *tptr = NULL;
11462df76c16SMatt Jacob 	int bus, tm_enabled, target_role;
11472df76c16SMatt Jacob 	target_id_t target;
1148d81ba9d5SMatt Jacob 	lun_id_t lun;
1149d81ba9d5SMatt Jacob 
1150e2873b76SMatt Jacob 
1151746e9c85SMatt Jacob 	/*
11522df76c16SMatt Jacob 	 * We only support either a wildcard target/lun or a target ID of zero and a non-wildcard lun
1153746e9c85SMatt Jacob 	 */
11542df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
11552df76c16SMatt Jacob 	target = ccb->ccb_h.target_id;
11562df76c16SMatt Jacob 	lun = ccb->ccb_h.target_lun;
1157e2873b76SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0|ISP_LOGCONFIG, ccb->ccb_h.path, "enabling lun %u\n", lun);
11582df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && target != 0) {
1159d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_TID_INVALID;
11602df76c16SMatt Jacob 		xpt_done(ccb);
11612df76c16SMatt Jacob 		return;
1162d81ba9d5SMatt Jacob 	}
11632df76c16SMatt Jacob 	if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) {
11642df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
11652df76c16SMatt Jacob 		xpt_done(ccb);
11662df76c16SMatt Jacob 		return;
11672df76c16SMatt Jacob 	}
11682df76c16SMatt Jacob 
11692df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) {
11702df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
11712df76c16SMatt Jacob 		xpt_done(ccb);
11722df76c16SMatt Jacob 		return;
11732df76c16SMatt Jacob 	}
11742df76c16SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
11752df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus);
11762df76c16SMatt Jacob 	}
11772df76c16SMatt Jacob 
11782df76c16SMatt Jacob 	/*
11792df76c16SMatt Jacob 	 * Wait until we're not busy with the lun enables subsystem
11802df76c16SMatt Jacob 	 */
1181e2873b76SMatt Jacob 	isp_tmlock(isp, "isp_enable_lun");
11822df76c16SMatt Jacob 
118364edff94SMatt Jacob 	/*
118464edff94SMatt Jacob 	 * This is as a good a place as any to check f/w capabilities.
118564edff94SMatt Jacob 	 */
11862df76c16SMatt Jacob 
11872df76c16SMatt Jacob 	if (IS_FC(isp)) {
11882df76c16SMatt Jacob 		if (ISP_CAP_TMODE(isp) == 0) {
11892df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "firmware does not support target mode\n");
119064edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
11912df76c16SMatt Jacob 			goto done;
119264edff94SMatt Jacob 		}
119364edff94SMatt Jacob 		/*
11942df76c16SMatt Jacob 		 * We *could* handle non-SCCLUN f/w, but we'd have to
11952df76c16SMatt Jacob 		 * dork with our already fragile enable/disable code.
119664edff94SMatt Jacob 		 */
11972df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp) == 0) {
11982df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "firmware not SCCLUN capable\n");
1199746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
12002df76c16SMatt Jacob 			goto done;
1201d81ba9d5SMatt Jacob 		}
1202d81ba9d5SMatt Jacob 
12032df76c16SMatt Jacob 		target_role = (FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0;
12042df76c16SMatt Jacob 
120564edff94SMatt Jacob 	} else {
12062df76c16SMatt Jacob 		target_role = (SDPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0;
1207126ec864SMatt Jacob 	}
1208126ec864SMatt Jacob 
1209126ec864SMatt Jacob 	/*
12102df76c16SMatt Jacob 	 * Create the state pointer.
12112df76c16SMatt Jacob 	 * It should not already exist.
1212126ec864SMatt Jacob 	 */
1213a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, lun);
12142df76c16SMatt Jacob 	if (tptr) {
12152df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
12162df76c16SMatt Jacob 		goto done;
1217d81ba9d5SMatt Jacob 	}
12182df76c16SMatt Jacob 	ccb->ccb_h.status = create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
12192df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
12202df76c16SMatt Jacob 		goto done;
1221d81ba9d5SMatt Jacob 	}
1222d81ba9d5SMatt Jacob 
12235d571944SMatt Jacob 	/*
12242df76c16SMatt Jacob 	 * We have a tricky maneuver to perform here.
12252df76c16SMatt Jacob 	 *
12262df76c16SMatt Jacob 	 * If target mode isn't already enabled here,
12272df76c16SMatt Jacob 	 * *and* our current role includes target mode,
12282df76c16SMatt Jacob 	 * we enable target mode here.
12292df76c16SMatt Jacob 	 *
12305d571944SMatt Jacob 	 */
12312df76c16SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, tm_enabled);
12322df76c16SMatt Jacob 	if (tm_enabled == 0 && target_role != 0) {
12332df76c16SMatt Jacob 		if (isp_enable_target_mode(isp, bus)) {
123467ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
12352df76c16SMatt Jacob 			destroy_lun_state(isp, tptr);
12362df76c16SMatt Jacob 			tptr = NULL;
12372df76c16SMatt Jacob 			goto done;
12385d571944SMatt Jacob 		}
12392df76c16SMatt Jacob 		tm_enabled = 1;
12402df76c16SMatt Jacob 	}
12412df76c16SMatt Jacob 
12422df76c16SMatt Jacob 	/*
12432df76c16SMatt Jacob 	 * Now check to see whether this bus is in target mode already.
12442df76c16SMatt Jacob 	 *
12452df76c16SMatt Jacob 	 * If not, a later role change into target mode will finish the job.
12462df76c16SMatt Jacob 	 */
12472df76c16SMatt Jacob 	if (tm_enabled == 0) {
12482df76c16SMatt Jacob 		ISP_SET_PC(isp, bus, tm_enable_defer, 1);
12492df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1250e2873b76SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode not enabled yet- lun enable deferred\n");
12512df76c16SMatt Jacob 		goto done;
12522df76c16SMatt Jacob 	}
12532df76c16SMatt Jacob 
12542df76c16SMatt Jacob 	/*
12552df76c16SMatt Jacob 	 * Enable the lun.
12562df76c16SMatt Jacob 	 */
12572df76c16SMatt Jacob 	ccb->ccb_h.status = isp_enable_deferred(isp, bus, lun);
12582df76c16SMatt Jacob 
12592df76c16SMatt Jacob done:
1260e2873b76SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP)  {
1261e2873b76SMatt Jacob 		if (tptr) {
12622df76c16SMatt Jacob 			destroy_lun_state(isp, tptr);
12632df76c16SMatt Jacob 			tptr = NULL;
12642df76c16SMatt Jacob 		}
1265e2873b76SMatt Jacob 	} else {
1266e2873b76SMatt Jacob 		tptr->enabled = 1;
1267e2873b76SMatt Jacob 	}
12682df76c16SMatt Jacob 	if (tptr) {
12692df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
12702df76c16SMatt Jacob 	}
1271e2873b76SMatt Jacob 
1272e2873b76SMatt Jacob 	/*
1273e2873b76SMatt Jacob 	 * And we're outta here....
1274e2873b76SMatt Jacob 	 */
1275e2873b76SMatt Jacob 	isp_tmunlk(isp);
12762df76c16SMatt Jacob 	xpt_done(ccb);
12772df76c16SMatt Jacob }
12782df76c16SMatt Jacob 
1279e2873b76SMatt Jacob static cam_status
12802df76c16SMatt Jacob isp_enable_deferred_luns(ispsoftc_t *isp, int bus)
12812df76c16SMatt Jacob {
1282e2873b76SMatt Jacob 	tstate_t *tptr = NULL;
1283e2873b76SMatt Jacob 	struct tslist *lhp;
1284e2873b76SMatt Jacob 	int i, n;
1285e2873b76SMatt Jacob 
1286e2873b76SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, i);
1287e2873b76SMatt Jacob 	if (i == 1) {
1288e2873b76SMatt Jacob 		return (CAM_REQ_CMP);
1289e2873b76SMatt Jacob 	}
1290e2873b76SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enable_defer, i);
1291e2873b76SMatt Jacob 	if (i == 0) {
1292e2873b76SMatt Jacob 		return (CAM_REQ_CMP);
1293e2873b76SMatt Jacob 	}
12942df76c16SMatt Jacob 	/*
1295e2873b76SMatt Jacob 	 * If this succeeds, it will set tm_enable
12962df76c16SMatt Jacob 	 */
1297e2873b76SMatt Jacob 	if (isp_enable_target_mode(isp, bus)) {
1298e2873b76SMatt Jacob 		return (CAM_REQ_CMP_ERR);
1299e2873b76SMatt Jacob 	}
1300e2873b76SMatt Jacob 	isp_tmlock(isp, "isp_enable_deferred_luns");
1301e2873b76SMatt Jacob 	for (n = i = 0; i < LUN_HASH_SIZE; i++) {
1302e2873b76SMatt Jacob 		ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
1303e2873b76SMatt Jacob 		SLIST_FOREACH(tptr, lhp, next) {
1304e2873b76SMatt Jacob 			tptr->hold++;
1305e2873b76SMatt Jacob 			if (tptr->enabled == 0) {
1306e2873b76SMatt Jacob 				if (isp_enable_deferred(isp, bus, xpt_path_lun_id(tptr->owner)) == 0) {
1307e2873b76SMatt Jacob 					tptr->enabled = 1;
1308e2873b76SMatt Jacob 					n++;
1309e2873b76SMatt Jacob 				}
1310e2873b76SMatt Jacob 			} else {
1311e2873b76SMatt Jacob 				n++;
1312e2873b76SMatt Jacob 			}
1313e2873b76SMatt Jacob 			tptr->hold--;
1314e2873b76SMatt Jacob 		}
1315e2873b76SMatt Jacob 	}
1316e2873b76SMatt Jacob 	isp_tmunlk(isp);
1317e2873b76SMatt Jacob 	if (n == 0) {
1318e2873b76SMatt Jacob 		return (CAM_REQ_CMP_ERR);
1319e2873b76SMatt Jacob 	}
1320e2873b76SMatt Jacob 	ISP_SET_PC(isp, bus, tm_enable_defer, 0);
1321e2873b76SMatt Jacob 	return (CAM_REQ_CMP);
13222df76c16SMatt Jacob }
13232df76c16SMatt Jacob 
1324e2873b76SMatt Jacob static cam_status
13252df76c16SMatt Jacob isp_enable_deferred(ispsoftc_t *isp, int bus, lun_id_t lun)
13262df76c16SMatt Jacob {
13272df76c16SMatt Jacob 	cam_status status;
1328e2873b76SMatt Jacob 	int luns_already_enabled = ISP_FC_PC(isp, bus)->tm_luns_enabled;
13292df76c16SMatt Jacob 
13302df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTINFO, "%s: bus %d lun %u", __func__, bus, lun);
1331e2873b76SMatt Jacob 	if (IS_24XX(isp) || (IS_FC(isp) && luns_already_enabled)) {
13322df76c16SMatt Jacob 		status = CAM_REQ_CMP;
13332df76c16SMatt Jacob 	} else {
13342df76c16SMatt Jacob 		int cmd_cnt, not_cnt;
13352df76c16SMatt Jacob 
13362df76c16SMatt Jacob 		if (IS_23XX(isp)) {
13372df76c16SMatt Jacob 			cmd_cnt = DFLT_CMND_CNT;
13382df76c16SMatt Jacob 			not_cnt = DFLT_INOT_CNT;
13392df76c16SMatt Jacob 		} else {
13402df76c16SMatt Jacob 			cmd_cnt = 64;
13412df76c16SMatt Jacob 			not_cnt = 8;
13422df76c16SMatt Jacob 		}
13432df76c16SMatt Jacob 		status = CAM_REQ_INPROG;
13442df76c16SMatt Jacob 		isp->isp_osinfo.rptr = &status;
13452df76c16SMatt Jacob 		if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, DFLT_CMND_CNT, DFLT_INOT_CNT)) {
13462df76c16SMatt Jacob 			status = CAM_RESRC_UNAVAIL;
13472df76c16SMatt Jacob 		} else {
13482df76c16SMatt Jacob 			mtx_sleep(&status, &isp->isp_lock, PRIBIO, "isp_enable_deferred", 0);
13492df76c16SMatt Jacob 		}
13502df76c16SMatt Jacob 		isp->isp_osinfo.rptr = NULL;
13512df76c16SMatt Jacob 	}
13522df76c16SMatt Jacob 	if (status == CAM_REQ_CMP) {
13532df76c16SMatt Jacob 		ISP_SET_PC(isp, bus, tm_luns_enabled, 1);
1354e2873b76SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG|ISP_LOGTINFO, "bus %d lun %u now enabled for target mode", bus, lun);
13552df76c16SMatt Jacob 	}
13562df76c16SMatt Jacob 	return (status);
13572df76c16SMatt Jacob }
13582df76c16SMatt Jacob 
13592df76c16SMatt Jacob static void
13602df76c16SMatt Jacob isp_disable_lun(ispsoftc_t *isp, union ccb *ccb)
13612df76c16SMatt Jacob {
13622df76c16SMatt Jacob 	tstate_t *tptr = NULL;
13632df76c16SMatt Jacob 	int bus;
13642df76c16SMatt Jacob 	cam_status status;
13652df76c16SMatt Jacob 	target_id_t target;
13662df76c16SMatt Jacob 	lun_id_t lun;
13672df76c16SMatt Jacob 
13682df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
13692df76c16SMatt Jacob 	target = ccb->ccb_h.target_id;
13702df76c16SMatt Jacob 	lun = ccb->ccb_h.target_lun;
1371e2873b76SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0|ISP_LOGCONFIG, ccb->ccb_h.path, "disabling lun %u\n", lun);
13722df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && target != 0) {
13732df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_TID_INVALID;
13742df76c16SMatt Jacob 		xpt_done(ccb);
13752df76c16SMatt Jacob 		return;
13762df76c16SMatt Jacob 	}
1377e2873b76SMatt Jacob 
13782df76c16SMatt Jacob 	if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) {
13792df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
13802df76c16SMatt Jacob 		xpt_done(ccb);
13812df76c16SMatt Jacob 		return;
13822df76c16SMatt Jacob 	}
13832df76c16SMatt Jacob 
13842df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) {
13852df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
13862df76c16SMatt Jacob 		xpt_done(ccb);
13872df76c16SMatt Jacob 		return;
13882df76c16SMatt Jacob 	}
13892df76c16SMatt Jacob 
13902df76c16SMatt Jacob 	/*
13912df76c16SMatt Jacob 	 * See if we're busy disabling a lun now.
13922df76c16SMatt Jacob 	 */
1393e2873b76SMatt Jacob 	isp_tmlock(isp, "isp_disable_lun");
139445210a25SAlexander Motin 	status = CAM_REQ_INPROG;
13952df76c16SMatt Jacob 
13962df76c16SMatt Jacob 	/*
13972df76c16SMatt Jacob 	 * Find the state pointer.
13982df76c16SMatt Jacob 	 */
13992df76c16SMatt Jacob 	if ((tptr = get_lun_statep(isp, bus, lun)) == NULL) {
140045210a25SAlexander Motin 		status = CAM_PATH_INVALID;
14012df76c16SMatt Jacob 		goto done;
14022df76c16SMatt Jacob 	}
14032df76c16SMatt Jacob 
14042df76c16SMatt Jacob 	/*
14052df76c16SMatt Jacob 	 * If we're a 24XX card, we're done.
14062df76c16SMatt Jacob 	 */
14072df76c16SMatt Jacob 	if (IS_24XX(isp)) {
14082df76c16SMatt Jacob 		status = CAM_REQ_CMP;
14092df76c16SMatt Jacob 		goto done;
14102df76c16SMatt Jacob 	}
14112df76c16SMatt Jacob 
14122df76c16SMatt Jacob 	/*
14132df76c16SMatt Jacob 	 * For SCC FW, we only deal with lun zero.
14142df76c16SMatt Jacob 	 */
14152df76c16SMatt Jacob 	if (IS_FC(isp)) {
14162df76c16SMatt Jacob 		lun = 0;
14172df76c16SMatt Jacob 	}
14182df76c16SMatt Jacob 	isp->isp_osinfo.rptr = &status;
14192df76c16SMatt Jacob 	if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, 0, 0)) {
14202df76c16SMatt Jacob 		status = CAM_RESRC_UNAVAIL;
14212df76c16SMatt Jacob 	} else {
14222df76c16SMatt Jacob 		mtx_sleep(ccb, &isp->isp_lock, PRIBIO, "isp_disable_lun", 0);
14232df76c16SMatt Jacob 	}
1424e2873b76SMatt Jacob 	isp->isp_osinfo.rptr = NULL;
14252df76c16SMatt Jacob done:
1426e2873b76SMatt Jacob 	if (status == CAM_REQ_CMP) {
1427e2873b76SMatt Jacob 		tptr->enabled = 0;
1428e2873b76SMatt Jacob 		/*
1429e2873b76SMatt Jacob 		 * If we have no more luns enabled for this bus, delete all tracked wwns for it (if we are FC)
1430e2873b76SMatt Jacob 		 * and disable target mode.
1431e2873b76SMatt Jacob 		 */
1432e2873b76SMatt Jacob 		if (is_any_lun_enabled(isp, bus) == 0) {
1433e2873b76SMatt Jacob 			isp_del_all_wwn_entries(isp, bus);
1434e2873b76SMatt Jacob 			if (isp_disable_target_mode(isp, bus)) {
1435e2873b76SMatt Jacob 				status = CAM_REQ_CMP_ERR;
1436e2873b76SMatt Jacob 			}
1437e2873b76SMatt Jacob 		}
1438e2873b76SMatt Jacob 	}
143945210a25SAlexander Motin 	ccb->ccb_h.status = status;
14402df76c16SMatt Jacob 	if (status == CAM_REQ_CMP) {
1441e2873b76SMatt Jacob 		xpt_print(ccb->ccb_h.path, "lun now disabled for target mode\n");
1442e95725cbSMatt Jacob 		destroy_lun_state(isp, tptr);
1443e2873b76SMatt Jacob 	} else {
1444e2873b76SMatt Jacob 		if (tptr)
1445e2873b76SMatt Jacob 			rls_lun_statep(isp, tptr);
14462df76c16SMatt Jacob 	}
1447e2873b76SMatt Jacob 	isp_tmunlk(isp);
14482df76c16SMatt Jacob 	xpt_done(ccb);
14492df76c16SMatt Jacob }
14502df76c16SMatt Jacob 
14512df76c16SMatt Jacob static int
14522df76c16SMatt Jacob isp_enable_target_mode(ispsoftc_t *isp, int bus)
14532df76c16SMatt Jacob {
1454e2873b76SMatt Jacob 	int tm_enabled;
14552df76c16SMatt Jacob 
1456e2873b76SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, tm_enabled);
1457e2873b76SMatt Jacob 	if (tm_enabled != 0) {
14582df76c16SMatt Jacob 		return (0);
14592df76c16SMatt Jacob 	}
14602df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
14612df76c16SMatt Jacob 		mbreg_t mbs;
14622df76c16SMatt Jacob 		MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0);
14632df76c16SMatt Jacob 		mbs.param[0] = MBOX_ENABLE_TARGET_MODE;
14642df76c16SMatt Jacob 		mbs.param[1] = ENABLE_TARGET_FLAG|ENABLE_TQING_FLAG;
14652df76c16SMatt Jacob 		mbs.param[2] = bus << 7;
14662df76c16SMatt Jacob 		if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) {
1467e2873b76SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Unable to enable Target Role on Bus %d", bus);
14682df76c16SMatt Jacob 			return (EIO);
14692df76c16SMatt Jacob 		}
14702df76c16SMatt Jacob 	}
14712df76c16SMatt Jacob 	ISP_SET_PC(isp, bus, tm_enabled, 1);
1472e2873b76SMatt Jacob 	isp_prt(isp, ISP_LOGINFO, "Target Role enabled on Bus %d", bus);
14732df76c16SMatt Jacob 	return (0);
14742df76c16SMatt Jacob }
14752df76c16SMatt Jacob 
14762df76c16SMatt Jacob static int
14772df76c16SMatt Jacob isp_disable_target_mode(ispsoftc_t *isp, int bus)
14782df76c16SMatt Jacob {
1479e2873b76SMatt Jacob 	int tm_enabled;
14802df76c16SMatt Jacob 
1481e2873b76SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, tm_enabled);
1482e2873b76SMatt Jacob 	if (tm_enabled == 0) {
14832df76c16SMatt Jacob 		return (0);
14842df76c16SMatt Jacob 	}
14852df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
14862df76c16SMatt Jacob 		mbreg_t mbs;
14872df76c16SMatt Jacob 		MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0);
14882df76c16SMatt Jacob 		mbs.param[2] = bus << 7;
14892df76c16SMatt Jacob 		if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) {
1490e2873b76SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Unable to disable Target Role on Bus %d", bus);
14912df76c16SMatt Jacob 			return (EIO);
14922df76c16SMatt Jacob 		}
14932df76c16SMatt Jacob 	}
14942df76c16SMatt Jacob 	ISP_SET_PC(isp, bus, tm_enabled, 0);
1495e2873b76SMatt Jacob 	isp_prt(isp, ISP_LOGINFO, "Target Role disabled onon  Bus %d", bus);
14962df76c16SMatt Jacob 	return (0);
14972df76c16SMatt Jacob }
14985d571944SMatt Jacob 
149967ff51f1SMatt Jacob static void
15009cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
150167ff51f1SMatt Jacob {
15022df76c16SMatt Jacob 	uint32_t *rptr;
1503d81ba9d5SMatt Jacob 
15042df76c16SMatt Jacob 	rptr = isp->isp_osinfo.rptr;
150567ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
15062df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "ENABLE/MODIFY LUN returned 0x%x", lep->le_status);
15072df76c16SMatt Jacob 		if (rptr) {
15082df76c16SMatt Jacob 			*rptr = CAM_REQ_CMP_ERR;
15092df76c16SMatt Jacob 			wakeup_one(rptr);
15102df76c16SMatt Jacob 		}
151167ff51f1SMatt Jacob 	} else {
15122df76c16SMatt Jacob 		if (rptr) {
15132df76c16SMatt Jacob 			*rptr = CAM_REQ_CMP;
15142df76c16SMatt Jacob 			wakeup_one(rptr);
151567ff51f1SMatt Jacob 		}
1516126ec864SMatt Jacob 	}
1517d81ba9d5SMatt Jacob }
1518d81ba9d5SMatt Jacob 
15199cd7268eSMatt Jacob static void
15209cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1521d81ba9d5SMatt Jacob {
1522d81ba9d5SMatt Jacob 	void *qe;
15232df76c16SMatt Jacob 	tstate_t *tptr;
15242df76c16SMatt Jacob 	atio_private_data_t *atp;
152500a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
15262df76c16SMatt Jacob 	uint32_t dmaresult, handle;
15271dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1528d81ba9d5SMatt Jacob 
15292df76c16SMatt Jacob 	/*
15302df76c16SMatt Jacob 	 * Do some sanity checks.
15312df76c16SMatt Jacob 	 */
15322df76c16SMatt Jacob 	if (cso->dxfer_len == 0) {
15332df76c16SMatt Jacob 		if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
15342df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n");
15352df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
15362df76c16SMatt Jacob 			xpt_done(ccb);
15372df76c16SMatt Jacob 			return;
15382df76c16SMatt Jacob 		}
15392df76c16SMatt Jacob 	}
1540f48ce188SMatt Jacob 
15412df76c16SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
15422df76c16SMatt Jacob 	if (tptr == NULL) {
15432df76c16SMatt Jacob 		tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
15442df76c16SMatt Jacob 		if (tptr == NULL) {
15452df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find tstate pointer in %s\n", __func__, cso->tag_id);
15462df76c16SMatt Jacob 			dump_tstates(isp, XS_CHANNEL(ccb));
15472df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
15482df76c16SMatt Jacob 			xpt_done(ccb);
15492df76c16SMatt Jacob 			return;
15502df76c16SMatt Jacob 		}
15512df76c16SMatt Jacob 	}
15522df76c16SMatt Jacob 
15532df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, cso->tag_id);
15542df76c16SMatt Jacob 	if (atp == NULL) {
15552df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find private data adjunct\n", __func__, cso->tag_id);
15562df76c16SMatt Jacob 		isp_dump_atpd(isp, tptr);
15572df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
15582df76c16SMatt Jacob 		xpt_done(ccb);
15592df76c16SMatt Jacob 		return;
15602df76c16SMatt Jacob 	}
15612df76c16SMatt Jacob 	if (atp->dead) {
15622df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO for a dead command\n", __func__, cso->tag_id);
15632df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_ABORTED;
15642df76c16SMatt Jacob 		xpt_done(ccb);
15652df76c16SMatt Jacob 		return;
15662df76c16SMatt Jacob 	}
15672df76c16SMatt Jacob 
15682df76c16SMatt Jacob 	/*
15692df76c16SMatt Jacob 	 * Check to make sure we're still in target mode.
15702df76c16SMatt Jacob 	 */
15712df76c16SMatt Jacob 	if ((FCPARAM(isp, XS_CHANNEL(ccb))->role & ISP_ROLE_TARGET) == 0) {
15722df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO because we're no longer in target mode\n", __func__, cso->tag_id);
15732df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
15742df76c16SMatt Jacob 		xpt_done(ccb);
15752df76c16SMatt Jacob 		return;
15762df76c16SMatt Jacob 	}
15772df76c16SMatt Jacob 
15782df76c16SMatt Jacob 	/*
15792df76c16SMatt Jacob 	 * Get some resources
15802df76c16SMatt Jacob 	 */
15812df76c16SMatt Jacob 	if (isp_get_pcmd(isp, ccb)) {
15822df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
15832df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "out of PCMDs\n");
15842df76c16SMatt Jacob 		cam_freeze_devq(ccb->ccb_h.path);
15852df76c16SMatt Jacob 		cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
15862df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
15872df76c16SMatt Jacob 		xpt_done(ccb);
15882df76c16SMatt Jacob 		return;
15892df76c16SMatt Jacob 	}
15902df76c16SMatt Jacob 	qe = isp_getrqentry(isp);
15912df76c16SMatt Jacob 	if (qe == NULL) {
15922df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, rqo, __func__);
15932df76c16SMatt Jacob 		cam_freeze_devq(ccb->ccb_h.path);
15942df76c16SMatt Jacob 		cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
15952df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
15969cd7268eSMatt Jacob 		goto out;
1597d81ba9d5SMatt Jacob 	}
159829f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1599d81ba9d5SMatt Jacob 
1600d81ba9d5SMatt Jacob 	/*
1601d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1602d81ba9d5SMatt Jacob 	 */
16032df76c16SMatt Jacob 	if (IS_24XX(isp)) {
16042df76c16SMatt Jacob 		ct7_entry_t *cto = (ct7_entry_t *) local;
1605d81ba9d5SMatt Jacob 
16062df76c16SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
16072df76c16SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
16082df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
16092df76c16SMatt Jacob 		cto->ct_nphdl = atp->nphdl;
16102df76c16SMatt Jacob 		cto->ct_rxid = atp->tag;
16112df76c16SMatt Jacob 		cto->ct_iid_lo = atp->portid;
16122df76c16SMatt Jacob 		cto->ct_iid_hi = atp->portid >> 16;
16132df76c16SMatt Jacob 		cto->ct_oxid = atp->oxid;
16142df76c16SMatt Jacob 		cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb));
16152df76c16SMatt Jacob 		cto->ct_scsi_status = cso->scsi_status;
16162df76c16SMatt Jacob 		cto->ct_timeout = 120;
16172df76c16SMatt Jacob 		cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT;
16182df76c16SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
16192df76c16SMatt Jacob 			cto->ct_flags |= CT7_SENDSTATUS;
16202df76c16SMatt Jacob 		}
16212df76c16SMatt Jacob 		if (cso->dxfer_len == 0) {
16222df76c16SMatt Jacob 			cto->ct_flags |= CT7_FLAG_MODE1 | CT7_NO_DATA;
16232df76c16SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
16242df76c16SMatt Jacob 				int m = min(cso->sense_len, sizeof (struct scsi_sense_data));
16252df76c16SMatt Jacob 				cto->rsp.m1.ct_resplen = cto->ct_senselen = min(m, MAXRESPLEN_24XX);
16262df76c16SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, cto->ct_senselen);
16272df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8);
16282df76c16SMatt Jacob 			}
16292df76c16SMatt Jacob 		} else {
16302df76c16SMatt Jacob 			cto->ct_flags |= CT7_FLAG_MODE0;
16312df76c16SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
16322df76c16SMatt Jacob 				cto->ct_flags |= CT7_DATA_IN;
16332df76c16SMatt Jacob 			} else {
16342df76c16SMatt Jacob 				cto->ct_flags |= CT7_DATA_OUT;
16352df76c16SMatt Jacob 			}
16362df76c16SMatt Jacob 			cto->rsp.m0.reloff = atp->bytes_xfered;
16372df76c16SMatt Jacob 			/*
16382df76c16SMatt Jacob 			 * Don't overrun the limits placed on us
16392df76c16SMatt Jacob 			 */
16402df76c16SMatt Jacob 			if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) {
16412df76c16SMatt Jacob 				cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered;
16422df76c16SMatt Jacob 			}
16432df76c16SMatt Jacob 			atp->last_xframt = cso->dxfer_len;
16442df76c16SMatt Jacob 			cto->rsp.m0.ct_xfrlen = cso->dxfer_len;
16452df76c16SMatt Jacob 		}
16462df76c16SMatt Jacob 		if (cto->ct_flags & CT7_SENDSTATUS) {
16472df76c16SMatt Jacob 			int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0;
16482df76c16SMatt Jacob 			cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len);
16492df76c16SMatt Jacob 			if (cto->ct_resid < 0) {
16502df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
16512df76c16SMatt Jacob 			} else if (cto->ct_resid > 0) {
16522df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
16532df76c16SMatt Jacob 			}
16542df76c16SMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
16552df76c16SMatt Jacob 			ISP_PATH_PRT(isp, lvl, cso->ccb_h.path, "%s: CTIO7[%x] CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u\n", __func__, cto->ct_rxid,
16562df76c16SMatt Jacob 			    atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
16572df76c16SMatt Jacob 		} else {
16582df76c16SMatt Jacob 			cto->ct_resid = 0;
16592df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, cso->ccb_h.path, "%s: CTIO7[%x] flags %x xfrlen %u offset %u\n", __func__, cto->ct_rxid, cto->ct_flags,
16602df76c16SMatt Jacob 			    cso->dxfer_len, atp->bytes_xfered);
16612df76c16SMatt Jacob 			atp->state = ATPD_STATE_CTIO;
16622df76c16SMatt Jacob 		}
16632df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
16644fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
166500a8e174SMatt Jacob 
1666d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1667d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
16682df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
16692df76c16SMatt Jacob 		if (ISP_CAP_2KLOGIN(isp) == 0) {
167029f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
167129f76675SMatt Jacob 		} else {
167200a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
16732df76c16SMatt Jacob 			if (ISP_CAP_SCCFW(isp) == 0) {
1674d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
16752ad50ca5SMatt Jacob 			}
167629f76675SMatt Jacob 		}
167753036e92SMatt Jacob 
1678f48ce188SMatt Jacob 
167900a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
168000a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
16812df76c16SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA | CT2_SENDSTATUS;
1682f48ce188SMatt Jacob 			cto->rsp.m1.ct_scsi_status = cso->scsi_status;
16832df76c16SMatt Jacob 			cto->ct_resid = atp->orig_datalen - atp->bytes_xfered;
1684570c7a3fSMatt Jacob 			if (cto->ct_resid < 0) {
16852df76c16SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER;
1686570c7a3fSMatt Jacob 			} else if (cto->ct_resid > 0) {
16872df76c16SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
1688f48ce188SMatt Jacob 			}
168900a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
169000a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
16912df76c16SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, m);
169200a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
169300a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
16942df76c16SMatt Jacob 			} else if (cso->scsi_status == SCSI_STATUS_CHECK_COND) {
16952df76c16SMatt Jacob 				/*
16962df76c16SMatt Jacob 				 * XXX: DEBUG
16972df76c16SMatt Jacob 				 */
16982df76c16SMatt Jacob 				xpt_print(ccb->ccb_h.path, "CHECK CONDITION being sent without associated SENSE DATA for CDB=0x%x\n", atp->cdb0);
169900a8e174SMatt Jacob 			}
170000a8e174SMatt Jacob 		} else {
170100a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
170200a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
170300a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
170400a8e174SMatt Jacob 			} else {
170500a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1706d81ba9d5SMatt Jacob 			}
1707570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
17082df76c16SMatt Jacob 			cto->rsp.m0.ct_xfrlen = cso->dxfer_len;
17092df76c16SMatt Jacob 			/*
17102df76c16SMatt Jacob 			 * Don't overrun the limits placed on us
17112df76c16SMatt Jacob 			 */
17122df76c16SMatt Jacob 			if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) {
17132df76c16SMatt Jacob 				cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered;
17142df76c16SMatt Jacob 			}
1715d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1716d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
171700a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
17182df76c16SMatt Jacob 				cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len);
1719570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
17202df76c16SMatt Jacob 					cto->rsp.m0.ct_scsi_status |= CT2_DATA_OVER;
1721570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
17222df76c16SMatt Jacob 					cto->rsp.m0.ct_scsi_status |= CT2_DATA_UNDER;
1723570c7a3fSMatt Jacob 				}
172453036e92SMatt Jacob 			} else {
172553036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1726d81ba9d5SMatt Jacob 			}
1727f48ce188SMatt Jacob 			/*
1728f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1729f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1730f48ce188SMatt Jacob 			 */
173100a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
173200a8e174SMatt Jacob 		}
173353036e92SMatt Jacob 
1734290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
17352df76c16SMatt Jacob 			int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0;
1736a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1737570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
17382df76c16SMatt Jacob 			ISP_PATH_PRT(isp, lvl, cso->ccb_h.path, "%s: CTIO2[%x] CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u\n", __func__, cto->ct_rxid,
17392df76c16SMatt Jacob 			    atp->cdb0, cto->rsp.m0.ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
17409cd7268eSMatt Jacob 		} else {
17412df76c16SMatt Jacob 			cto->ct_resid = 0;
1742570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
17432df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: CTIO2[%x] flags %x xfrlen %u offset %u\n", __func__, cto->ct_rxid, cto->ct_flags,
17442df76c16SMatt Jacob 			    cso->dxfer_len, atp->bytes_xfered);
17459cd7268eSMatt Jacob 		}
1746a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1747d81ba9d5SMatt Jacob 	} else {
17484fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
174900a8e174SMatt Jacob 
1750d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1751d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
17522df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
175300a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1754a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1755d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1756d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
17572df76c16SMatt Jacob 		cto->ct_fwhandle = cso->tag_id >> 16;
1758a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
17592df76c16SMatt Jacob 			cto->ct_tag_val = cso->tag_id;
1760f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1761f48ce188SMatt Jacob 		}
1762f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1763f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1764f48ce188SMatt Jacob 		}
1765f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1766d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
176700a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
176800a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
176900a8e174SMatt Jacob 		} else {
177000a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1771d81ba9d5SMatt Jacob 		}
1772f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
177353036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
177400a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
177500a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
17762df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: CTIO[%x] scsi status %x resid %d tag_id %x\n", __func__,
17772df76c16SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid, cso->tag_id);
177892a1e549SMatt Jacob 		}
177964edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1780a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1781d81ba9d5SMatt Jacob 	}
1782d81ba9d5SMatt Jacob 
1783c8b8a2c4SMatt Jacob 	if (isp_allocate_xs_tgt(isp, ccb, &handle)) {
17842df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__);
17852df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
17869cd7268eSMatt Jacob 		goto out;
1787d81ba9d5SMatt Jacob 	}
1788d81ba9d5SMatt Jacob 
1789d81ba9d5SMatt Jacob 
1790d81ba9d5SMatt Jacob 	/*
1791d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1792d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1793b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1794d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1795d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1796d81ba9d5SMatt Jacob 	 * format.
1797d81ba9d5SMatt Jacob 	 */
1798d81ba9d5SMatt Jacob 
17992df76c16SMatt Jacob 	if (IS_24XX(isp)) {
18002df76c16SMatt Jacob 		ct7_entry_t *cto = (ct7_entry_t *) local;
18012df76c16SMatt Jacob 		cto->ct_syshandle = handle;
18022df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
180310365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
180410365e5aSMatt Jacob 		cto->ct_syshandle = handle;
180510365e5aSMatt Jacob 	} else {
180610365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
180710365e5aSMatt Jacob 		cto->ct_syshandle = handle;
180810365e5aSMatt Jacob 	}
1809a1bc34c6SMatt Jacob 
18102df76c16SMatt Jacob 	dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local);
18112df76c16SMatt Jacob 	if (dmaresult == CMD_QUEUED) {
18122df76c16SMatt Jacob 		isp->isp_nactive++;
18139cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
18142df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
18159cd7268eSMatt Jacob 		return;
18162df76c16SMatt Jacob 	}
18172df76c16SMatt Jacob 	if (dmaresult == CMD_EAGAIN) {
18182df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
18192df76c16SMatt Jacob 	} else {
18202df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1821d81ba9d5SMatt Jacob 	}
182210365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
18239cd7268eSMatt Jacob out:
18242df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
18252df76c16SMatt Jacob 	isp_free_pcmd(isp, ccb);
18269cd7268eSMatt Jacob 	xpt_done(ccb);
1827d81ba9d5SMatt Jacob }
1828d81ba9d5SMatt Jacob 
1829a1bc34c6SMatt Jacob static void
1830a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1831f48ce188SMatt Jacob {
18322df76c16SMatt Jacob 	union ccb *ccb = arg;
18332df76c16SMatt Jacob 	ispsoftc_t *isp = XS_ISP(ccb);
18342df76c16SMatt Jacob 	ISP_LOCK(isp);
18352df76c16SMatt Jacob 	isp_target_putback_atio(ccb);
18362df76c16SMatt Jacob 	ISP_UNLOCK(isp);
1837a1bc34c6SMatt Jacob }
1838a1bc34c6SMatt Jacob 
1839a1bc34c6SMatt Jacob static void
1840a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1841a1bc34c6SMatt Jacob {
18429cd7268eSMatt Jacob 	ispsoftc_t *isp;
1843a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
1844a1bc34c6SMatt Jacob 	void *qe;
1845a1bc34c6SMatt Jacob 
1846a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1847f48ce188SMatt Jacob 
18482df76c16SMatt Jacob 	qe = isp_getrqentry(isp);
18492df76c16SMatt Jacob 	if (qe == NULL) {
18502df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, rqo, __func__);
1851a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1852a1bc34c6SMatt Jacob 		return;
1853f48ce188SMatt Jacob 	}
185429f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1855a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1856f48ce188SMatt Jacob 	if (IS_FC(isp)) {
18574fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
18582df76c16SMatt Jacob 		ISP_MEMZERO(at, sizeof (at2_entry_t));
1859f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1860f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
18612df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp)) {
1862a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1863f48ce188SMatt Jacob 		} else {
1864a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1865f48ce188SMatt Jacob 		}
1866f48ce188SMatt Jacob 		at->at_status = CT_OK;
1867a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1868570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
18694fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1870f48ce188SMatt Jacob 	} else {
18714fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
18722df76c16SMatt Jacob 		ISP_MEMZERO(at, sizeof (at_entry_t));
1873f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1874f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1875a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1876a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1877a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1878a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1879f48ce188SMatt Jacob 		at->at_status = CT_OK;
1880a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1881a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
18824fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1883f48ce188SMatt Jacob 	}
18842df76c16SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe);
18852df76c16SMatt Jacob 	ISP_SYNC_REQUEST(isp);
1886a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1887f48ce188SMatt Jacob }
1888f48ce188SMatt Jacob 
1889f48ce188SMatt Jacob static void
1890a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1891f48ce188SMatt Jacob {
1892a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1893a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1894f48ce188SMatt Jacob 	}
1895a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
18962df76c16SMatt Jacob 	isp_free_pcmd(XS_ISP(ccb), ccb);
1897a1bc34c6SMatt Jacob 	xpt_done(ccb);
1898f48ce188SMatt Jacob }
1899f48ce188SMatt Jacob 
1900d81ba9d5SMatt Jacob /*
1901d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1902d81ba9d5SMatt Jacob  * This means handling CDBs.
1903d81ba9d5SMatt Jacob  */
1904d81ba9d5SMatt Jacob 
19052df76c16SMatt Jacob static void
19069cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1907d81ba9d5SMatt Jacob {
1908d81ba9d5SMatt Jacob 	tstate_t *tptr;
19092df76c16SMatt Jacob 	int status, bus;
1910d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
19112df76c16SMatt Jacob 	atio_private_data_t *atp;
1912d81ba9d5SMatt Jacob 
1913d81ba9d5SMatt Jacob 	/*
1914d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1915d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1916d81ba9d5SMatt Jacob 	 *
1917b1ce21c6SRebecca Cran 	 * If QLTM_SVALID is set, the firmware has recommended Sense Data.
1918d81ba9d5SMatt Jacob 	 *
1919d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
19205d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1921d81ba9d5SMatt Jacob 	 */
1922d81ba9d5SMatt Jacob 	status = aep->at_status;
1923d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1924d81ba9d5SMatt Jacob 		/*
1925d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1926d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1927d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1928d81ba9d5SMatt Jacob 		 */
19293c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1930d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
19312df76c16SMatt Jacob 		return;
1932d81ba9d5SMatt Jacob 	}
1933d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
19342df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", status);
1935d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
19362df76c16SMatt Jacob 		return;
1937d81ba9d5SMatt Jacob 	}
1938d81ba9d5SMatt Jacob 
19395d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1940a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1941d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1942a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1943746e9c85SMatt Jacob 		if (tptr == NULL) {
1944d81ba9d5SMatt Jacob 			/*
1945d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1946d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1947d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1948d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1949d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1950d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1951d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1952d81ba9d5SMatt Jacob 			 */
1953d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
19542df76c16SMatt Jacob 			return;
1955d81ba9d5SMatt Jacob 		}
19568c4e89e2SMatt Jacob 	}
1957d81ba9d5SMatt Jacob 
19582df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
1959d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
19602df76c16SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1961d81ba9d5SMatt Jacob 		/*
1962d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1963d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1964d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1965d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1966d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1967d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1968d81ba9d5SMatt Jacob 		 */
19692df76c16SMatt Jacob 		xpt_print(tptr->owner, "no %s for lun %d from initiator %d\n", (atp == NULL && atiop == NULL)? "ATIOs *or* ATPS" :
19702df76c16SMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIOs"), aep->at_lun, aep->at_iid);
1971d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
19722df76c16SMatt Jacob 		if (atp) {
19732df76c16SMatt Jacob 			isp_put_atpd(isp, tptr, atp);
1974d81ba9d5SMatt Jacob 		}
19752df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
19762df76c16SMatt Jacob 		return;
19772df76c16SMatt Jacob 	}
19782df76c16SMatt Jacob 	atp->tag = aep->at_tag_val;
19792df76c16SMatt Jacob 	if (atp->tag == 0) {
19802df76c16SMatt Jacob 		atp->tag = ~0;
19812df76c16SMatt Jacob 	}
19822df76c16SMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1983d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1984746e9c85SMatt Jacob 	tptr->atio_count--;
19852df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
1986d81ba9d5SMatt Jacob 	atiop->ccb_h.target_id = aep->at_tgt;
1987d81ba9d5SMatt Jacob 	atiop->ccb_h.target_lun = aep->at_lun;
1988d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1989f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1990f48ce188SMatt Jacob 	} else {
1991f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1992d81ba9d5SMatt Jacob 	}
1993d81ba9d5SMatt Jacob 
1994f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1995898899d9SMatt Jacob 		size_t amt = ISP_MIN(QLTM_SENSELEN, sizeof (atiop->sense_data));
1996f48ce188SMatt Jacob 		atiop->sense_len = amt;
19972df76c16SMatt Jacob 		ISP_MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1998f48ce188SMatt Jacob 	} else {
1999f48ce188SMatt Jacob 		atiop->sense_len = 0;
2000f48ce188SMatt Jacob 	}
2001d81ba9d5SMatt Jacob 
20025d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
2003d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
20042df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
2005d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
2006a1bc34c6SMatt Jacob 	/*
2007a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
2008a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
2009a1bc34c6SMatt Jacob 	 */
20102df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
2011a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
2012a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
2013d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
2014d81ba9d5SMatt Jacob 	}
20152df76c16SMatt Jacob 	atp->orig_datalen = 0;
20162df76c16SMatt Jacob 	atp->bytes_xfered = 0;
20172df76c16SMatt Jacob 	atp->last_xframt = 0;
20182df76c16SMatt Jacob 	atp->lun = aep->at_lun;
20192df76c16SMatt Jacob 	atp->nphdl = aep->at_iid;
20202df76c16SMatt Jacob 	atp->portid = PORT_NONE;
20212df76c16SMatt Jacob 	atp->oxid = 0;
20222df76c16SMatt Jacob 	atp->cdb0 = atiop->cdb_io.cdb_bytes[0];
20232df76c16SMatt Jacob 	atp->tattr = aep->at_tag_type;
20242df76c16SMatt Jacob 	atp->state = ATPD_STATE_CAM;
20252df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO[%x] CDB=0x%x lun %d\n", aep->at_tag_val, atp->cdb0, atp->lun);
2026d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
2027d81ba9d5SMatt Jacob }
2028d81ba9d5SMatt Jacob 
20292df76c16SMatt Jacob static void
20309cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
2031d81ba9d5SMatt Jacob {
203292a1e549SMatt Jacob 	lun_id_t lun;
20332df76c16SMatt Jacob 	fcportdb_t *lp;
2034d81ba9d5SMatt Jacob 	tstate_t *tptr;
2035d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
20362df76c16SMatt Jacob 	uint16_t nphdl;
2037a035b0afSMatt Jacob 	atio_private_data_t *atp;
20382df76c16SMatt Jacob 	inot_private_data_t *ntp;
2039d81ba9d5SMatt Jacob 
2040d81ba9d5SMatt Jacob 	/*
2041d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
2042d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
2043d81ba9d5SMatt Jacob 	 *
2044b1ce21c6SRebecca Cran 	 * If QLTM_SVALID is set, the firmware has recommended Sense Data.
2045d81ba9d5SMatt Jacob 	 */
2046d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
20472df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bogus atio (0x%x) leaked to platform", aep->at_status);
2048d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
20492df76c16SMatt Jacob 		return;
2050d81ba9d5SMatt Jacob 	}
2051d81ba9d5SMatt Jacob 
20522df76c16SMatt Jacob 	if (ISP_CAP_SCCFW(isp)) {
205392a1e549SMatt Jacob 		lun = aep->at_scclun;
20542ad50ca5SMatt Jacob 	} else {
205592a1e549SMatt Jacob 		lun = aep->at_lun;
20562ad50ca5SMatt Jacob 	}
20572df76c16SMatt Jacob 	if (ISP_CAP_2KLOGIN(isp)) {
20582df76c16SMatt Jacob 		nphdl = ((at2e_entry_t *)aep)->at_iid;
20592df76c16SMatt Jacob 	} else {
20602df76c16SMatt Jacob 		nphdl = aep->at_iid;
20612df76c16SMatt Jacob 	}
2062a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
2063d81ba9d5SMatt Jacob 	if (tptr == NULL) {
2064a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
2065746e9c85SMatt Jacob 		if (tptr == NULL) {
20662df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
20672df76c16SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0);
20682df76c16SMatt Jacob 			return;
2069746e9c85SMatt Jacob 		}
2070d81ba9d5SMatt Jacob 	}
2071d81ba9d5SMatt Jacob 
2072d81ba9d5SMatt Jacob 	/*
20732df76c16SMatt Jacob 	 * Start any commands pending resources first.
2074d81ba9d5SMatt Jacob 	 */
20752df76c16SMatt Jacob 	if (tptr->restart_queue) {
20762df76c16SMatt Jacob 		inot_private_data_t *restart_queue = tptr->restart_queue;
20772df76c16SMatt Jacob 		tptr->restart_queue = NULL;
20782df76c16SMatt Jacob 		while (restart_queue) {
20792df76c16SMatt Jacob 			ntp = restart_queue;
20802df76c16SMatt Jacob 			restart_queue = ntp->rd.nt.nt_hba;
20812df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid);
20822df76c16SMatt Jacob 			isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data);
20832df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
20842df76c16SMatt Jacob 			/*
20852df76c16SMatt Jacob 			 * If a recursion caused the restart queue to start to fill again,
20862df76c16SMatt Jacob 			 * stop and splice the new list on top of the old list and restore
20872df76c16SMatt Jacob 			 * it and go to noresrc.
20882df76c16SMatt Jacob 			 */
20892df76c16SMatt Jacob 			if (tptr->restart_queue) {
20902df76c16SMatt Jacob 				ntp = tptr->restart_queue;
20912df76c16SMatt Jacob 				tptr->restart_queue = restart_queue;
20922df76c16SMatt Jacob 				while (restart_queue->rd.nt.nt_hba) {
20932df76c16SMatt Jacob 					restart_queue = restart_queue->rd.nt.nt_hba;
2094d81ba9d5SMatt Jacob 				}
20952df76c16SMatt Jacob 				restart_queue->rd.nt.nt_hba = ntp;
20962df76c16SMatt Jacob 				goto noresrc;
20972df76c16SMatt Jacob 			}
20982df76c16SMatt Jacob 		}
20992df76c16SMatt Jacob 	}
21002df76c16SMatt Jacob 
21012df76c16SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
21022df76c16SMatt Jacob 	if (atiop == NULL) {
21032df76c16SMatt Jacob 		goto noresrc;
21042df76c16SMatt Jacob 	}
21052df76c16SMatt Jacob 
21062df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
21072df76c16SMatt Jacob 	if (atp == NULL) {
21082df76c16SMatt Jacob 		goto noresrc;
21092df76c16SMatt Jacob 	}
21102df76c16SMatt Jacob 
21112df76c16SMatt Jacob 	atp->tag = aep->at_rxid;
2112570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
2113d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
2114570c7a3fSMatt Jacob 	tptr->atio_count--;
21152df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
21162df76c16SMatt Jacob 	atiop->ccb_h.target_id = FCPARAM(isp, 0)->isp_loopid;
211792a1e549SMatt Jacob 	atiop->ccb_h.target_lun = lun;
21182df76c16SMatt Jacob 
2119b0a3ba7eSMatt Jacob 	/*
2120b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
2121b0a3ba7eSMatt Jacob 	 */
2122f48ce188SMatt Jacob 	atiop->sense_len = 0;
21232df76c16SMatt Jacob 	if (ISP_CAP_2KLOGIN(isp)) {
21242df76c16SMatt Jacob 		/*
21252df76c16SMatt Jacob 		 * NB: We could not possibly have 2K logins if we
21262df76c16SMatt Jacob 		 * NB: also did not have SCC FW.
21272df76c16SMatt Jacob 		 */
21282df76c16SMatt Jacob 		atiop->init_id = ((at2e_entry_t *)aep)->at_iid;
21292df76c16SMatt Jacob 	} else {
2130d81ba9d5SMatt Jacob 		atiop->init_id = aep->at_iid;
21312df76c16SMatt Jacob 	}
21322df76c16SMatt Jacob 
21332df76c16SMatt Jacob 	/*
21342df76c16SMatt Jacob 	 * If we're not in the port database, add ourselves.
21352df76c16SMatt Jacob 	 */
21362df76c16SMatt Jacob 	if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) {
21372df76c16SMatt Jacob     		uint64_t iid =
21382df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[0]) << 48) |
21392df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[1]) << 32) |
21402df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[2]) << 16) |
21412df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[3]) <<  0);
21422df76c16SMatt Jacob 		/*
21432df76c16SMatt Jacob 		 * However, make sure we delete ourselves if otherwise
21442df76c16SMatt Jacob 		 * we were there but at a different loop id.
21452df76c16SMatt Jacob 		 */
21462df76c16SMatt Jacob 		if (isp_find_pdb_by_wwn(isp, 0, iid, &lp)) {
21472df76c16SMatt Jacob 			isp_del_wwn_entry(isp, 0, iid, lp->handle, lp->portid);
21482df76c16SMatt Jacob 		}
21492df76c16SMatt Jacob 		isp_add_wwn_entry(isp, 0, iid, atiop->init_id, PORT_ANY);
21502df76c16SMatt Jacob 	}
2151d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
21522df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
2153d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
21542df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
2155d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
2156d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
21572df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2158d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
2159d81ba9d5SMatt Jacob 		break;
2160d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_HEADOFQ:
21612df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2162d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
2163d81ba9d5SMatt Jacob 		break;
2164d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_ORDERED:
21652df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2166d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
2167d81ba9d5SMatt Jacob 		break;
2168d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_ACAQ:		/* ?? */
2169d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
2170d81ba9d5SMatt Jacob 	default:
2171d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
2172d81ba9d5SMatt Jacob 		break;
2173d81ba9d5SMatt Jacob 	}
2174f48ce188SMatt Jacob 
217553036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
217653036e92SMatt Jacob 	atp->bytes_xfered = 0;
21772df76c16SMatt Jacob 	atp->last_xframt = 0;
21782df76c16SMatt Jacob 	atp->lun = lun;
21792df76c16SMatt Jacob 	atp->nphdl = atiop->init_id;
21802df76c16SMatt Jacob 	atp->sid = PORT_ANY;
21812df76c16SMatt Jacob 	atp->oxid = aep->at_oxid;
21822df76c16SMatt Jacob 	atp->cdb0 = aep->at_cdb[0];
21832df76c16SMatt Jacob 	atp->tattr = aep->at_taskflags & ATIO2_TC_ATTR_MASK;
2184570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
2185d81ba9d5SMatt Jacob 	xpt_done((union ccb *)atiop);
21862df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO2[%x] CDB=0x%x lun %d datalen %u\n", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen);
2187d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
21882df76c16SMatt Jacob 	return;
21892df76c16SMatt Jacob noresrc:
21902df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
21912df76c16SMatt Jacob 	if (ntp == NULL) {
21922df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
21932df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, 0, SCSI_STATUS_BUSY, 0);
21942df76c16SMatt Jacob 		return;
21952df76c16SMatt Jacob 	}
21962df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
21972df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
21982df76c16SMatt Jacob 	tptr->restart_queue = ntp;
21992df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
2200d81ba9d5SMatt Jacob }
2201d81ba9d5SMatt Jacob 
22022df76c16SMatt Jacob static void
22032df76c16SMatt Jacob isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep)
22042df76c16SMatt Jacob {
22052df76c16SMatt Jacob 	int cdbxlen;
22062df76c16SMatt Jacob 	uint16_t lun, chan, nphdl = NIL_HANDLE;
22072df76c16SMatt Jacob 	uint32_t did, sid;
22082df76c16SMatt Jacob 	uint64_t wwn = INI_NONE;
22092df76c16SMatt Jacob 	fcportdb_t *lp;
22102df76c16SMatt Jacob 	tstate_t *tptr;
22112df76c16SMatt Jacob 	struct ccb_accept_tio *atiop;
22122df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
2213*9e7d423dSMatt Jacob 	atio_private_data_t *oatp;
22142df76c16SMatt Jacob 	inot_private_data_t *ntp;
22152df76c16SMatt Jacob 
22162df76c16SMatt Jacob 	did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2];
22172df76c16SMatt Jacob 	sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
22182df76c16SMatt Jacob 	lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | aep->at_cmnd.fcp_cmnd_lun[1];
22192df76c16SMatt Jacob 
22202df76c16SMatt Jacob 	/*
22212df76c16SMatt Jacob 	 * Find the N-port handle, and Virtual Port Index for this command.
22222df76c16SMatt Jacob 	 *
22232df76c16SMatt Jacob 	 * If we can't, we're somewhat in trouble because we can't actually respond w/o that information.
22242df76c16SMatt Jacob 	 * We also, as a matter of course, need to know the WWN of the initiator too.
22252df76c16SMatt Jacob 	 */
22262df76c16SMatt Jacob 	if (ISP_CAP_MULTI_ID(isp)) {
22272df76c16SMatt Jacob 		/*
22282df76c16SMatt Jacob 		 * Find the right channel based upon D_ID
22292df76c16SMatt Jacob 		 */
22302df76c16SMatt Jacob 		isp_find_chan_by_did(isp, did, &chan);
22312df76c16SMatt Jacob 
22322df76c16SMatt Jacob 		if (chan == ISP_NOCHAN) {
22332df76c16SMatt Jacob 			NANOTIME_T now;
22342df76c16SMatt Jacob 
22352df76c16SMatt Jacob 			/*
22362df76c16SMatt Jacob 			 * If we don't recognizer our own D_DID, terminate the exchange, unless we're within 2 seconds of startup
22372df76c16SMatt Jacob 			 * It's a bit tricky here as we need to stash this command *somewhere*.
22382df76c16SMatt Jacob 			 */
22392df76c16SMatt Jacob 			GET_NANOTIME(&now);
22402df76c16SMatt Jacob 			if (NANOTIME_SUB(&isp->isp_init_time, &now) > 2000000000ULL) {
22412df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- dropping", __func__, aep->at_rxid, did);
22422df76c16SMatt Jacob 				isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
22432df76c16SMatt Jacob 				return;
22442df76c16SMatt Jacob 			}
22452df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, 0);
22462df76c16SMatt Jacob 			if (tptr == NULL) {
22472df76c16SMatt Jacob 				tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
22482df76c16SMatt Jacob 				if (tptr == NULL) {
22492df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel and no tptr- dropping", __func__, aep->at_rxid, did);
22502df76c16SMatt Jacob 					isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
22512df76c16SMatt Jacob 					return;
22522df76c16SMatt Jacob 				}
22532df76c16SMatt Jacob 			}
22542df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] D_ID %x not found on any channel- deferring", __func__, aep->at_rxid, did);
22552df76c16SMatt Jacob 			goto noresrc;
22562df76c16SMatt Jacob 		}
22572df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x", __func__, aep->at_rxid, did, chan, sid);
22582df76c16SMatt Jacob 	} else {
22592df76c16SMatt Jacob 		chan = 0;
22602df76c16SMatt Jacob 	}
22612df76c16SMatt Jacob 
22622df76c16SMatt Jacob 	/*
22632df76c16SMatt Jacob 	 * Find the PDB entry for this initiator
22642df76c16SMatt Jacob 	 */
22652df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, chan, sid, &lp) == 0) {
22662df76c16SMatt Jacob 		/*
22672df76c16SMatt Jacob 		 * If we're not in the port database terminate the exchange.
22682df76c16SMatt Jacob 		 */
22692df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "%s: [RX_ID 0x%x] D_ID 0x%06x found on Chan %d for S_ID 0x%06x wasn't in PDB already",
22702df76c16SMatt Jacob 		    __func__, aep->at_rxid, did, chan, sid);
22712df76c16SMatt Jacob 		isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0);
22722df76c16SMatt Jacob 		return;
22732df76c16SMatt Jacob 	}
22742df76c16SMatt Jacob 	nphdl = lp->handle;
22752df76c16SMatt Jacob 	wwn = lp->port_wwn;
22762df76c16SMatt Jacob 
22772df76c16SMatt Jacob 	/*
22782df76c16SMatt Jacob 	 * Get the tstate pointer
22792df76c16SMatt Jacob 	 */
22802df76c16SMatt Jacob 	tptr = get_lun_statep(isp, chan, lun);
22812df76c16SMatt Jacob 	if (tptr == NULL) {
22822df76c16SMatt Jacob 		tptr = get_lun_statep(isp, chan, CAM_LUN_WILDCARD);
22832df76c16SMatt Jacob 		if (tptr == NULL) {
22842df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d or wildcard", aep->at_rxid, lun);
22852df76c16SMatt Jacob 			isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0);
22862df76c16SMatt Jacob 			return;
22872df76c16SMatt Jacob 		}
22882df76c16SMatt Jacob 	}
22892df76c16SMatt Jacob 
22902df76c16SMatt Jacob 	/*
22912df76c16SMatt Jacob 	 * Start any commands pending resources first.
22922df76c16SMatt Jacob 	 */
22932df76c16SMatt Jacob 	if (tptr->restart_queue) {
22942df76c16SMatt Jacob 		inot_private_data_t *restart_queue = tptr->restart_queue;
22952df76c16SMatt Jacob 		tptr->restart_queue = NULL;
22962df76c16SMatt Jacob 		while (restart_queue) {
22972df76c16SMatt Jacob 			ntp = restart_queue;
22982df76c16SMatt Jacob 			restart_queue = ntp->rd.nt.nt_hba;
22992df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid);
23002df76c16SMatt Jacob 			isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data);
23012df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
23022df76c16SMatt Jacob 			/*
23032df76c16SMatt Jacob 			 * If a recursion caused the restart queue to start to fill again,
23042df76c16SMatt Jacob 			 * stop and splice the new list on top of the old list and restore
23052df76c16SMatt Jacob 			 * it and go to noresrc.
23062df76c16SMatt Jacob 			 */
23072df76c16SMatt Jacob 			if (tptr->restart_queue) {
2308*9e7d423dSMatt Jacob 				isp_prt(isp, ISP_LOGTDEBUG0, "%s: restart queue refilling", __func__);
23092df76c16SMatt Jacob 				if (restart_queue) {
23102df76c16SMatt Jacob 					ntp = tptr->restart_queue;
23112df76c16SMatt Jacob 					tptr->restart_queue = restart_queue;
23122df76c16SMatt Jacob 					while (restart_queue->rd.nt.nt_hba) {
23132df76c16SMatt Jacob 						restart_queue = restart_queue->rd.nt.nt_hba;
23142df76c16SMatt Jacob 					}
23152df76c16SMatt Jacob 					restart_queue->rd.nt.nt_hba = ntp;
23162df76c16SMatt Jacob 				}
23172df76c16SMatt Jacob 				goto noresrc;
23182df76c16SMatt Jacob 			}
23192df76c16SMatt Jacob 		}
23202df76c16SMatt Jacob 	}
23212df76c16SMatt Jacob 
23222df76c16SMatt Jacob 	/*
23232df76c16SMatt Jacob 	 * If the f/w is out of resources, just send a BUSY status back.
23242df76c16SMatt Jacob 	 */
23252df76c16SMatt Jacob 	if (aep->at_rxid == AT7_NORESRC_RXID) {
23262df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
23272df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0);
23282df76c16SMatt Jacob 		return;
23292df76c16SMatt Jacob 	}
23302df76c16SMatt Jacob 
23312df76c16SMatt Jacob 	/*
23322df76c16SMatt Jacob 	 * If we're out of resources, just send a BUSY status back.
23332df76c16SMatt Jacob 	 */
23342df76c16SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
23352df76c16SMatt Jacob 	if (atiop == NULL) {
23362df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atios", aep->at_rxid);
23372df76c16SMatt Jacob 		goto noresrc;
23382df76c16SMatt Jacob 	}
23392df76c16SMatt Jacob 
23402df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
23412df76c16SMatt Jacob 	if (atp == NULL) {
23422df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid);
23432df76c16SMatt Jacob 		goto noresrc;
23442df76c16SMatt Jacob 	}
2345*9e7d423dSMatt Jacob 	oatp = isp_get_atpd(isp, tptr, aep->at_rxid);
2346*9e7d423dSMatt Jacob 	if (oatp) {
2347*9e7d423dSMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] tag wraparound in isp_handle_platforms_atio7 (N-Port Handle 0x%04x S_ID 0x%04x OX_ID 0x%04x) oatp state %d\n",
2348*9e7d423dSMatt Jacob 		    aep->at_rxid, nphdl, sid, aep->at_hdr.ox_id, oatp->state);
23492df76c16SMatt Jacob 		/*
23502df76c16SMatt Jacob 		 * It's not a "no resource" condition- but we can treat it like one
23512df76c16SMatt Jacob 		 */
23522df76c16SMatt Jacob 		goto noresrc;
23532df76c16SMatt Jacob 	}
23542df76c16SMatt Jacob 	atp->tag = aep->at_rxid;
23552df76c16SMatt Jacob 	atp->state = ATPD_STATE_ATIO;
23562df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
23572df76c16SMatt Jacob 	tptr->atio_count--;
23582df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
23592df76c16SMatt Jacob 	atiop->init_id = nphdl;
23602df76c16SMatt Jacob 	atiop->ccb_h.target_id = FCPARAM(isp, chan)->isp_loopid;
23612df76c16SMatt Jacob 	atiop->ccb_h.target_lun = lun;
23622df76c16SMatt Jacob 	atiop->sense_len = 0;
23632df76c16SMatt Jacob 	cdbxlen = aep->at_cmnd.fcp_cmnd_alen_datadir >> FCP_CMND_ADDTL_CDBLEN_SHIFT;
23642df76c16SMatt Jacob 	if (cdbxlen) {
23652df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "additional CDBLEN ignored");
23662df76c16SMatt Jacob 	}
23672df76c16SMatt Jacob 	cdbxlen = sizeof (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb);
23682df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb, cdbxlen);
23692df76c16SMatt Jacob 	atiop->cdb_len = cdbxlen;
23702df76c16SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
23712df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
23722df76c16SMatt Jacob 	switch (aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK) {
23732df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_SIMPLE:
23742df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
23752df76c16SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
23762df76c16SMatt Jacob 		break;
23772df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_HEAD:
23782df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
23792df76c16SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
23802df76c16SMatt Jacob 		break;
23812df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ORDERED:
23822df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
23832df76c16SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
23842df76c16SMatt Jacob 		break;
23852df76c16SMatt Jacob 	default:
23862df76c16SMatt Jacob 		/* FALLTHROUGH */
23872df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ACA:
23882df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_UNTAGGED:
23892df76c16SMatt Jacob 		atiop->tag_action = 0;
23902df76c16SMatt Jacob 		break;
23912df76c16SMatt Jacob 	}
23922df76c16SMatt Jacob 	atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl;
23932df76c16SMatt Jacob 	atp->bytes_xfered = 0;
23942df76c16SMatt Jacob 	atp->last_xframt = 0;
23952df76c16SMatt Jacob 	atp->lun = lun;
23962df76c16SMatt Jacob 	atp->nphdl = nphdl;
23972df76c16SMatt Jacob 	atp->portid = sid;
23982df76c16SMatt Jacob 	atp->oxid = aep->at_hdr.ox_id;
2399*9e7d423dSMatt Jacob 	atp->rxid = aep->at_hdr.rx_id;
24002df76c16SMatt Jacob 	atp->cdb0 = atiop->cdb_io.cdb_bytes[0];
24012df76c16SMatt Jacob 	atp->tattr = aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK;
24022df76c16SMatt Jacob 	atp->state = ATPD_STATE_CAM;
24032df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "ATIO7[%x] CDB=0x%x lun %d datalen %u\n", aep->at_rxid, atp->cdb0, lun, atp->orig_datalen);
24042df76c16SMatt Jacob 	xpt_done((union ccb *)atiop);
24052df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
24062df76c16SMatt Jacob 	return;
24072df76c16SMatt Jacob noresrc:
24082df76c16SMatt Jacob 	if (atp) {
24092df76c16SMatt Jacob 		isp_put_atpd(isp, tptr, atp);
24102df76c16SMatt Jacob 	}
24112df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
24122df76c16SMatt Jacob 	if (ntp == NULL) {
24132df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
24142df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_BUSY, 0);
24152df76c16SMatt Jacob 		return;
24162df76c16SMatt Jacob 	}
24172df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
24182df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
24192df76c16SMatt Jacob 	tptr->restart_queue = ntp;
24202df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
24212df76c16SMatt Jacob }
24222df76c16SMatt Jacob 
24232df76c16SMatt Jacob static void
24249cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
2425d81ba9d5SMatt Jacob {
2426d81ba9d5SMatt Jacob 	union ccb *ccb;
2427a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
24282df76c16SMatt Jacob 	tstate_t *tptr = NULL;
24292df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
24302df76c16SMatt Jacob 	int bus;
24312df76c16SMatt Jacob 	uint32_t tval, handle;
2432d81ba9d5SMatt Jacob 
2433d81ba9d5SMatt Jacob 	/*
2434443e752dSMatt Jacob 	 * CTIO handles are 16 bits.
2435443e752dSMatt Jacob 	 * CTIO2 and CTIO7 are 32 bits.
2436d81ba9d5SMatt Jacob 	 */
2437d81ba9d5SMatt Jacob 
24382df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
24392df76c16SMatt Jacob 		handle = ((ct_entry_t *)arg)->ct_syshandle;
24402df76c16SMatt Jacob 	} else {
24412df76c16SMatt Jacob 		handle = ((ct2_entry_t *)arg)->ct_syshandle;
24422df76c16SMatt Jacob 	}
24432df76c16SMatt Jacob 	ccb = isp_find_xs_tgt(isp, handle);
24442df76c16SMatt Jacob 	if (ccb == NULL) {
24452df76c16SMatt Jacob 		isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg);
24462df76c16SMatt Jacob 		return;
24472df76c16SMatt Jacob 	}
24482df76c16SMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
24492df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
24502df76c16SMatt Jacob 	tptr = get_lun_statep(isp, bus, XS_LUN(ccb));
24512df76c16SMatt Jacob 	if (tptr == NULL) {
24522df76c16SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
24532df76c16SMatt Jacob 	}
24542df76c16SMatt Jacob 	KASSERT((tptr != NULL), ("cannot get state pointer"));
24552df76c16SMatt Jacob 	if (isp->isp_nactive) {
24562df76c16SMatt Jacob 		isp->isp_nactive++;
24572df76c16SMatt Jacob 	}
24582df76c16SMatt Jacob 	if (IS_24XX(isp)) {
24592df76c16SMatt Jacob 		ct7_entry_t *ct = arg;
2460d81ba9d5SMatt Jacob 
24612df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
2462570c7a3fSMatt Jacob 		if (atp == NULL) {
24632df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
24642df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
24652df76c16SMatt Jacob 			return;
24662df76c16SMatt Jacob 		}
24672df76c16SMatt Jacob 
24682df76c16SMatt Jacob 		sentstatus = ct->ct_flags & CT7_SENDSTATUS;
24692df76c16SMatt Jacob 		ok = (ct->ct_nphdl == CT7_OK);
24702df76c16SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
24712df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
24722df76c16SMatt Jacob 		}
24732df76c16SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
24742df76c16SMatt Jacob 		if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) {
24752df76c16SMatt Jacob 			resid = ct->ct_resid;
24762df76c16SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
24772df76c16SMatt Jacob 			atp->last_xframt = 0;
24782df76c16SMatt Jacob 		}
24792df76c16SMatt Jacob 		if (ct->ct_nphdl == CT_HBA_RESET) {
24802df76c16SMatt Jacob 			ok = 0;
24812df76c16SMatt Jacob 			notify_cam = 1;
24822df76c16SMatt Jacob 			sentstatus = 1;
24832df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
24842df76c16SMatt Jacob 		} else if (!ok) {
24852df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
24862df76c16SMatt Jacob 		}
24872df76c16SMatt Jacob 		tval = atp->tag;
24882df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
24892df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
24902df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
24912df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
24922df76c16SMatt Jacob 		ct2_entry_t *ct = arg;
24932df76c16SMatt Jacob 
24942df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
24952df76c16SMatt Jacob 		if (atp == NULL) {
24962df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
24972df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
24982df76c16SMatt Jacob 			return;
2499570c7a3fSMatt Jacob 		}
2500d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
2501d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
2502a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
250300a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
250400a8e174SMatt Jacob 		}
2505a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
25065d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
2507a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
250853036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
250953036e92SMatt Jacob 			atp->last_xframt = 0;
2510570c7a3fSMatt Jacob 		}
25112df76c16SMatt Jacob 		if (ct->ct_status == CT_HBA_RESET) {
25122df76c16SMatt Jacob 			ok = 0;
25132df76c16SMatt Jacob 			notify_cam = 1;
25142df76c16SMatt Jacob 			sentstatus = 1;
25152df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
25162df76c16SMatt Jacob 		} else if (!ok) {
25172df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
251853036e92SMatt Jacob 		}
25192df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
25202df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
25212df76c16SMatt Jacob 		tval = atp->tag;
25222df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
2523d81ba9d5SMatt Jacob 	} else {
2524d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
2525d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
2526d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
2527d81ba9d5SMatt Jacob 		/*
2528a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
2529a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
2530a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
2531a1bc34c6SMatt Jacob 		 * private data.
2532a1bc34c6SMatt Jacob 		 *
2533a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
2534a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
2535a1bc34c6SMatt Jacob 		 */
2536a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
25372df76c16SMatt Jacob 		if (ct->ct_status == (CT_HBA_RESET & 0xff)) {
25382df76c16SMatt Jacob 			ok = 0;
25392df76c16SMatt Jacob 			notify_cam = 1;
25402df76c16SMatt Jacob 			sentstatus = 1;
25412df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
25422df76c16SMatt Jacob 		} else if (!ok) {
25432df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
25442df76c16SMatt Jacob 		} else if (ct->ct_status & QLTM_SVALID) {
2545a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
2546a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
25472df76c16SMatt Jacob 			ccb->csio.sense_len = min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
25482df76c16SMatt Jacob 			ISP_MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
2549a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2550a1bc34c6SMatt Jacob 		}
25515d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
2552a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
2553a1bc34c6SMatt Jacob 		}
25542df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] tag %x S_ID 0x%x lun %d sts %x flg %x resid %d %s", __func__,
25552df76c16SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID");
255664edff94SMatt Jacob 		tval = ct->ct_fwhandle;
25575d571944SMatt Jacob 	}
2558a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
2559a1bc34c6SMatt Jacob 
2560a1bc34c6SMatt Jacob 	/*
2561a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
2562a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
2563a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
2564d81ba9d5SMatt Jacob 	 *
2565d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
2566d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
2567a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
2568a1bc34c6SMatt Jacob 	 * freed.
2569d81ba9d5SMatt Jacob 	 */
2570f48ce188SMatt Jacob 	if (notify_cam == 0) {
257164edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
25722df76c16SMatt Jacob 		return;
2573f48ce188SMatt Jacob 	}
25742df76c16SMatt Jacob 	if (tptr) {
25752df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
25762df76c16SMatt Jacob 	}
25772df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", (sentstatus)? "  FINAL " : "MIDTERM ", tval);
2578d81ba9d5SMatt Jacob 
25792df76c16SMatt Jacob 	if (!ok && !IS_24XX(isp)) {
2580a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
2581d81ba9d5SMatt Jacob 	} else {
2582a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
2583d81ba9d5SMatt Jacob 	}
2584d81ba9d5SMatt Jacob }
2585570c7a3fSMatt Jacob 
25862df76c16SMatt Jacob static void
25872df76c16SMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inot)
2588570c7a3fSMatt Jacob {
25892df76c16SMatt Jacob 	(void) isp_notify_ack(isp, inot);
2590570c7a3fSMatt Jacob }
2591570c7a3fSMatt Jacob 
25922df76c16SMatt Jacob static void
25939cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
2594570c7a3fSMatt Jacob {
25952df76c16SMatt Jacob 	int needack = 1;
2596570c7a3fSMatt Jacob 	switch (inp->in_status) {
2597570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
25982df76c16SMatt Jacob 		/*
25992df76c16SMatt Jacob 		 * XXX: Need to delete this initiator's WWN from the database
26002df76c16SMatt Jacob 		 * XXX: Need to send this LOGOUT upstream
26012df76c16SMatt Jacob 		 */
26022df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of S_ID 0x%x", inp->in_iid);
2603570c7a3fSMatt Jacob 		break;
2604570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
26052df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for S_ID 0x%x", inp->in_iid);
2606570c7a3fSMatt Jacob 		break;
2607570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
26082df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, 0);
2609570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
2610570c7a3fSMatt Jacob 		break;
2611570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
2612570c7a3fSMatt Jacob 	{
26132df76c16SMatt Jacob 		tstate_t *tptr;
26142df76c16SMatt Jacob 		uint16_t lun;
26152df76c16SMatt Jacob 		uint32_t loopid;
26162df76c16SMatt Jacob 		uint64_t wwn;
26172df76c16SMatt Jacob 		atio_private_data_t *atp;
26182df76c16SMatt Jacob 		fcportdb_t *lp;
26192df76c16SMatt Jacob 		struct ccb_immediate_notify *inot = NULL;
26202df76c16SMatt Jacob 
26212df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp)) {
26222df76c16SMatt Jacob 			lun = inp->in_scclun;
26232df76c16SMatt Jacob 		} else {
26242df76c16SMatt Jacob 			lun = inp->in_lun;
26252df76c16SMatt Jacob 		}
26262df76c16SMatt Jacob 		if (ISP_CAP_2KLOGIN(isp)) {
2627a035b0afSMatt Jacob 			loopid = ((in_fcentry_e_t *)inp)->in_iid;
26282df76c16SMatt Jacob 		} else {
26292df76c16SMatt Jacob 			loopid = inp->in_iid;
26302df76c16SMatt Jacob 		}
26312df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) {
26322df76c16SMatt Jacob 			wwn = lp->port_wwn;
26332df76c16SMatt Jacob 		} else {
26342df76c16SMatt Jacob 			wwn = INI_ANY;
26352df76c16SMatt Jacob 		}
26362df76c16SMatt Jacob 		tptr = get_lun_statep(isp, 0, lun);
26372df76c16SMatt Jacob 		if (tptr == NULL) {
26382df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
26392df76c16SMatt Jacob 			if (tptr == NULL) {
26402df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "ABORT TASK for lun %u- but no tstate", lun);
26412df76c16SMatt Jacob 				return;
26422df76c16SMatt Jacob 			}
26432df76c16SMatt Jacob 		}
26442df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, inp->in_seqid);
2645570c7a3fSMatt Jacob 
2646570c7a3fSMatt Jacob 		if (atp) {
26472df76c16SMatt Jacob 			inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
26482df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "ABORT TASK RX_ID %x WWN 0x%016llx state %d", inp->in_seqid, (unsigned long long) wwn, atp->state);
2649570c7a3fSMatt Jacob 			if (inot) {
2650746e9c85SMatt Jacob 				tptr->inot_count--;
26512df76c16SMatt Jacob 				SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
26522df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
2653570c7a3fSMatt Jacob 			} else {
26542df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "out of INOT structures\n");
26552df76c16SMatt Jacob 			}
26562df76c16SMatt Jacob 		} else {
26572df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGWARN, tptr->owner, "abort task RX_ID %x from wwn 0x%016llx, state unknown\n", inp->in_seqid, wwn);
2658570c7a3fSMatt Jacob 		}
2659570c7a3fSMatt Jacob 		if (inot) {
26602df76c16SMatt Jacob 			isp_notify_t tmp, *nt = &tmp;
26612df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
26622df76c16SMatt Jacob     			nt->nt_hba = isp;
26632df76c16SMatt Jacob 			nt->nt_tgt = FCPARAM(isp, 0)->isp_wwpn;
26642df76c16SMatt Jacob 			nt->nt_wwn = wwn;
26652df76c16SMatt Jacob 			nt->nt_nphdl = loopid;
26662df76c16SMatt Jacob 			nt->nt_sid = PORT_ANY;
26672df76c16SMatt Jacob 			nt->nt_did = PORT_ANY;
26682df76c16SMatt Jacob     			nt->nt_lun = lun;
26692df76c16SMatt Jacob             		nt->nt_need_ack = 1;
26702df76c16SMatt Jacob     			nt->nt_channel = 0;
26712df76c16SMatt Jacob     			nt->nt_ncode = NT_ABORT_TASK;
26722df76c16SMatt Jacob     			nt->nt_lreserved = inot;
26732df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
26742df76c16SMatt Jacob 			needack = 0;
2675570c7a3fSMatt Jacob 		}
26762df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
2677570c7a3fSMatt Jacob 		break;
2678570c7a3fSMatt Jacob 	}
2679570c7a3fSMatt Jacob 	default:
2680570c7a3fSMatt Jacob 		break;
2681570c7a3fSMatt Jacob 	}
26822df76c16SMatt Jacob 	if (needack) {
26832df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inp);
26842df76c16SMatt Jacob 	}
26852df76c16SMatt Jacob }
26862df76c16SMatt Jacob 
26872df76c16SMatt Jacob static void
26882df76c16SMatt Jacob isp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot)
26892df76c16SMatt Jacob {
26902df76c16SMatt Jacob 	uint16_t nphdl;
26912df76c16SMatt Jacob 	uint32_t portid;
26922df76c16SMatt Jacob 	fcportdb_t *lp;
26932df76c16SMatt Jacob 	uint8_t *ptr = NULL;
26942df76c16SMatt Jacob 	uint64_t wwn;
26952df76c16SMatt Jacob 
26962df76c16SMatt Jacob 	nphdl = inot->in_nphdl;
26972df76c16SMatt Jacob 	if (nphdl != NIL_HANDLE) {
26982df76c16SMatt Jacob 		portid = inot->in_portid_hi << 16 | inot->in_portid_lo;
26992df76c16SMatt Jacob 	} else {
27002df76c16SMatt Jacob 		portid = PORT_ANY;
27012df76c16SMatt Jacob 	}
27022df76c16SMatt Jacob 
27032df76c16SMatt Jacob 	switch (inot->in_status) {
27042df76c16SMatt Jacob 	case IN24XX_ELS_RCVD:
27052df76c16SMatt Jacob 	{
27062df76c16SMatt Jacob 		char buf[16], *msg;
27072df76c16SMatt Jacob 		int chan = ISP_GET_VPIDX(isp, inot->in_vpidx);
27082df76c16SMatt Jacob 
27092df76c16SMatt Jacob 		/*
27102df76c16SMatt Jacob 		 * Note that we're just getting notification that an ELS was received
2711b1ce21c6SRebecca Cran 		 * (possibly with some associated information sent upstream). This is
27122df76c16SMatt Jacob 		 * *not* the same as being given the ELS frame to accept or reject.
27132df76c16SMatt Jacob 		 */
27142df76c16SMatt Jacob 		switch (inot->in_status_subcode) {
27152df76c16SMatt Jacob 		case LOGO:
27162df76c16SMatt Jacob 			msg = "LOGO";
27172df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
27182df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
27192df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF])   << 56) |
27202df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+1]) << 48) |
27212df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+2]) << 40) |
27222df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+3]) << 32) |
27232df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+4]) << 24) |
27242df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+5]) << 16) |
27252df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+6]) <<  8) |
27262df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+7]));
27272df76c16SMatt Jacob 			} else {
27282df76c16SMatt Jacob 				wwn = INI_ANY;
27292df76c16SMatt Jacob 			}
27302df76c16SMatt Jacob 			isp_del_wwn_entry(isp, chan, wwn, nphdl, portid);
27312df76c16SMatt Jacob 			break;
27322df76c16SMatt Jacob 		case PRLO:
27332df76c16SMatt Jacob 			msg = "PRLO";
27342df76c16SMatt Jacob 			break;
27352df76c16SMatt Jacob 		case PLOGI:
2736dad28623SMatt Jacob 		case PRLI:
2737dad28623SMatt Jacob 			/*
2738dad28623SMatt Jacob 			 * Treat PRLI the same as PLOGI and make a database entry for it.
2739dad28623SMatt Jacob 			 */
2740dad28623SMatt Jacob 			if (inot->in_status_subcode == PLOGI)
27412df76c16SMatt Jacob 				msg = "PLOGI";
2742dad28623SMatt Jacob 			else
2743dad28623SMatt Jacob 				msg = "PRLI";
27442df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
27452df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
27462df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF])   << 56) |
27472df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+1]) << 48) |
27482df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+2]) << 40) |
27492df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+3]) << 32) |
27502df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+4]) << 24) |
27512df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+5]) << 16) |
27522df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+6]) <<  8) |
27532df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+7]));
27542df76c16SMatt Jacob 			} else {
27552df76c16SMatt Jacob 				wwn = INI_NONE;
27562df76c16SMatt Jacob 			}
27572df76c16SMatt Jacob 			isp_add_wwn_entry(isp, chan, wwn, nphdl, portid);
27582df76c16SMatt Jacob 			break;
27592df76c16SMatt Jacob 		case PDISC:
27602df76c16SMatt Jacob 			msg = "PDISC";
27612df76c16SMatt Jacob 			break;
27622df76c16SMatt Jacob 		case ADISC:
27632df76c16SMatt Jacob 			msg = "ADISC";
27642df76c16SMatt Jacob 			break;
27652df76c16SMatt Jacob 		default:
27662df76c16SMatt Jacob 			ISP_SNPRINTF(buf, sizeof (buf), "ELS 0x%x", inot->in_status_subcode);
27672df76c16SMatt Jacob 			msg = buf;
27682df76c16SMatt Jacob 			break;
27692df76c16SMatt Jacob 		}
27702df76c16SMatt Jacob 		if (inot->in_flags & IN24XX_FLAG_PUREX_IOCB) {
27712df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s Chan %d ELS N-port handle %x PortID 0x%06x marked as needing a PUREX response", msg, chan, nphdl, portid);
27722df76c16SMatt Jacob 			break;
27732df76c16SMatt Jacob 		}
27742df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "%s Chan %d ELS N-port handle %x PortID 0x%06x RX_ID 0x%x OX_ID 0x%x", msg, chan, nphdl, portid,
27752df76c16SMatt Jacob 		    inot->in_rxid, inot->in_oxid);
27762df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
27772df76c16SMatt Jacob 		break;
27782df76c16SMatt Jacob 	}
27792df76c16SMatt Jacob 
27802df76c16SMatt Jacob 	case IN24XX_PORT_LOGOUT:
27812df76c16SMatt Jacob 		ptr = "PORT LOGOUT";
27822df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) {
27832df76c16SMatt Jacob 			isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid);
27842df76c16SMatt Jacob 		}
27852df76c16SMatt Jacob 		/* FALLTHROUGH */
27862df76c16SMatt Jacob 	case IN24XX_PORT_CHANGED:
27872df76c16SMatt Jacob 		if (ptr == NULL) {
27882df76c16SMatt Jacob 			ptr = "PORT CHANGED";
27892df76c16SMatt Jacob 		}
27902df76c16SMatt Jacob 		/* FALLTHROUGH */
27912df76c16SMatt Jacob 	case IN24XX_LIP_RESET:
27922df76c16SMatt Jacob 		if (ptr == NULL) {
27932df76c16SMatt Jacob 			ptr = "LIP RESET";
27942df76c16SMatt Jacob 		}
27952df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d %s (sub-status 0x%x) for N-port handle 0x%x", ISP_GET_VPIDX(isp, inot->in_vpidx), ptr, inot->in_status_subcode, nphdl);
27962df76c16SMatt Jacob 
27972df76c16SMatt Jacob 		/*
27982df76c16SMatt Jacob 		 * All subcodes here are irrelevant. What is relevant
27992df76c16SMatt Jacob 		 * is that we need to terminate all active commands from
28002df76c16SMatt Jacob 		 * this initiator (known by N-port handle).
28012df76c16SMatt Jacob 		 */
28022df76c16SMatt Jacob 		/* XXX IMPLEMENT XXX */
28032df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
28042df76c16SMatt Jacob 		break;
28052df76c16SMatt Jacob 
28062df76c16SMatt Jacob 	case IN24XX_LINK_RESET:
28072df76c16SMatt Jacob 	case IN24XX_LINK_FAILED:
28082df76c16SMatt Jacob 	case IN24XX_SRR_RCVD:
28092df76c16SMatt Jacob 	default:
28102df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
28112df76c16SMatt Jacob 		break;
28122df76c16SMatt Jacob 	}
28132df76c16SMatt Jacob }
28142df76c16SMatt Jacob 
28152df76c16SMatt Jacob static int
28162df76c16SMatt Jacob isp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp)
28172df76c16SMatt Jacob {
28182df76c16SMatt Jacob 
28192df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
28202df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) acked- h/w not ready (dropping)", mp->nt_ncode, mp->nt_lreserved != NULL);
2821570c7a3fSMatt Jacob 		return (0);
2822570c7a3fSMatt Jacob 	}
28232df76c16SMatt Jacob 
28242df76c16SMatt Jacob 	/*
28252df76c16SMatt Jacob 	 * This case is for a Task Management Function, which shows up as an ATIO7 entry.
28262df76c16SMatt Jacob 	 */
28272df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ATIO) {
28282df76c16SMatt Jacob 		ct7_entry_t local, *cto = &local;
28292df76c16SMatt Jacob 		at7_entry_t *aep = (at7_entry_t *)mp->nt_lreserved;
28302df76c16SMatt Jacob 		fcportdb_t *lp;
28312df76c16SMatt Jacob 		uint32_t sid;
28322df76c16SMatt Jacob 		uint16_t nphdl;
28332df76c16SMatt Jacob 
28342df76c16SMatt Jacob 		sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
28352df76c16SMatt Jacob 		if (isp_find_pdb_by_sid(isp, mp->nt_channel, sid, &lp)) {
28362df76c16SMatt Jacob 			nphdl = lp->handle;
28372df76c16SMatt Jacob 		} else {
28382df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
28392df76c16SMatt Jacob 		}
28402df76c16SMatt Jacob 		ISP_MEMZERO(&local, sizeof (local));
28412df76c16SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
28422df76c16SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
28432df76c16SMatt Jacob 		cto->ct_nphdl = nphdl;
28442df76c16SMatt Jacob 		cto->ct_rxid = aep->at_rxid;
28452df76c16SMatt Jacob 		cto->ct_vpidx = mp->nt_channel;
28462df76c16SMatt Jacob 		cto->ct_iid_lo = sid;
28472df76c16SMatt Jacob 		cto->ct_iid_hi = sid >> 16;
28482df76c16SMatt Jacob 		cto->ct_oxid = aep->at_hdr.ox_id;
28492df76c16SMatt Jacob 		cto->ct_flags = CT7_SENDSTATUS|CT7_NOACK|CT7_NO_DATA|CT7_FLAG_MODE1;
28502df76c16SMatt Jacob 		cto->ct_flags |= (aep->at_ta_len >> 12) << CT7_TASK_ATTR_SHIFT;
28512df76c16SMatt Jacob 		return (isp_target_put_entry(isp, &local));
28522df76c16SMatt Jacob 	}
28532df76c16SMatt Jacob 
28542df76c16SMatt Jacob 	/*
28552df76c16SMatt Jacob 	 * This case is for a responding to an ABTS frame
28562df76c16SMatt Jacob 	 */
28572df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
28582df76c16SMatt Jacob 
28592df76c16SMatt Jacob 		/*
28602df76c16SMatt Jacob 		 * Overload nt_need_ack here to mark whether we've terminated the associated command.
28612df76c16SMatt Jacob 		 */
28622df76c16SMatt Jacob 		if (mp->nt_need_ack) {
28632df76c16SMatt Jacob 			uint8_t storage[QENTRY_LEN];
28642df76c16SMatt Jacob 			ct7_entry_t *cto = (ct7_entry_t *) storage;
28652df76c16SMatt Jacob 			abts_t *abts = (abts_t *)mp->nt_lreserved;
28662df76c16SMatt Jacob 
28672df76c16SMatt Jacob 			ISP_MEMZERO(cto, sizeof (ct7_entry_t));
28682df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task);
28692df76c16SMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
28702df76c16SMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
28712df76c16SMatt Jacob 			cto->ct_nphdl = mp->nt_nphdl;
28722df76c16SMatt Jacob 			cto->ct_rxid = abts->abts_rxid_task;
28732df76c16SMatt Jacob 			cto->ct_iid_lo = mp->nt_sid;
28742df76c16SMatt Jacob 			cto->ct_iid_hi = mp->nt_sid >> 16;
28752df76c16SMatt Jacob 			cto->ct_oxid = abts->abts_ox_id;
28762df76c16SMatt Jacob 			cto->ct_vpidx = mp->nt_channel;
28772df76c16SMatt Jacob 			cto->ct_flags = CT7_NOACK|CT7_TERMINATE;
28782df76c16SMatt Jacob 			if (isp_target_put_entry(isp, cto)) {
28792df76c16SMatt Jacob 				return (ENOMEM);
28802df76c16SMatt Jacob 			}
28812df76c16SMatt Jacob 			mp->nt_need_ack = 0;
28822df76c16SMatt Jacob 		}
28832df76c16SMatt Jacob 		if (isp_acknak_abts(isp, mp->nt_lreserved, 0) == ENOMEM) {
28842df76c16SMatt Jacob 			return (ENOMEM);
28852df76c16SMatt Jacob 		} else {
28862df76c16SMatt Jacob 			return (0);
28872df76c16SMatt Jacob 		}
28882df76c16SMatt Jacob 	}
28892df76c16SMatt Jacob 
28902df76c16SMatt Jacob 	/*
28912df76c16SMatt Jacob 	 * Handle logout cases here
28922df76c16SMatt Jacob 	 */
28932df76c16SMatt Jacob 	if (mp->nt_ncode == NT_GLOBAL_LOGOUT) {
28942df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, mp->nt_channel);
28952df76c16SMatt Jacob 	}
28962df76c16SMatt Jacob 
28972df76c16SMatt Jacob 	if (mp->nt_ncode == NT_LOGOUT) {
28982df76c16SMatt Jacob 		if (!IS_2100(isp) && IS_FC(isp)) {
28992df76c16SMatt Jacob 			isp_del_wwn_entries(isp, mp);
29002df76c16SMatt Jacob 		}
29012df76c16SMatt Jacob 	}
29022df76c16SMatt Jacob 
29032df76c16SMatt Jacob 	/*
29042df76c16SMatt Jacob 	 * General purpose acknowledgement
29052df76c16SMatt Jacob 	 */
29062df76c16SMatt Jacob 	if (mp->nt_need_ack) {
29072df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) being acked", mp->nt_ncode, mp->nt_lreserved != NULL);
29082df76c16SMatt Jacob 		return (isp_notify_ack(isp, mp->nt_lreserved));
29092df76c16SMatt Jacob 	}
29102df76c16SMatt Jacob 	return (0);
29112df76c16SMatt Jacob }
29122df76c16SMatt Jacob 
29132df76c16SMatt Jacob /*
2914b1ce21c6SRebecca Cran  * Handle task management functions.
29152df76c16SMatt Jacob  *
29162df76c16SMatt Jacob  * We show up here with a notify structure filled out.
29172df76c16SMatt Jacob  *
29182df76c16SMatt Jacob  * The nt_lreserved tag points to the original queue entry
29192df76c16SMatt Jacob  */
29202df76c16SMatt Jacob static void
29212df76c16SMatt Jacob isp_handle_platform_target_tmf(ispsoftc_t *isp, isp_notify_t *notify)
29222df76c16SMatt Jacob {
29232df76c16SMatt Jacob 	tstate_t *tptr;
29242df76c16SMatt Jacob 	fcportdb_t *lp;
29252df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
29262df76c16SMatt Jacob 	inot_private_data_t *ntp = NULL;
29272df76c16SMatt Jacob 	lun_id_t lun;
29282df76c16SMatt Jacob 
29292df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s: code 0x%x sid  0x%x tagval 0x%016llx chan %d lun 0x%x", __func__, notify->nt_ncode,
29302df76c16SMatt Jacob 	    notify->nt_sid, (unsigned long long) notify->nt_tagval, notify->nt_channel, notify->nt_lun);
29312df76c16SMatt Jacob 	/*
29322df76c16SMatt Jacob 	 * NB: This assignment is necessary because of tricky type conversion.
29332df76c16SMatt Jacob 	 * XXX: This is tricky and I need to check this. If the lun isn't known
29342df76c16SMatt Jacob 	 * XXX: for the task management function, it does not of necessity follow
29352df76c16SMatt Jacob 	 * XXX: that it should go up stream to the wildcard listener.
29362df76c16SMatt Jacob 	 */
29372df76c16SMatt Jacob 	if (notify->nt_lun == LUN_ANY) {
29382df76c16SMatt Jacob 		lun = CAM_LUN_WILDCARD;
29392df76c16SMatt Jacob 	} else {
29402df76c16SMatt Jacob 		lun = notify->nt_lun;
29412df76c16SMatt Jacob 	}
29422df76c16SMatt Jacob 	tptr = get_lun_statep(isp, notify->nt_channel, lun);
29432df76c16SMatt Jacob 	if (tptr == NULL) {
29442df76c16SMatt Jacob 		tptr = get_lun_statep(isp, notify->nt_channel, CAM_LUN_WILDCARD);
29452df76c16SMatt Jacob 		if (tptr == NULL) {
29462df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: no state pointer found for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
29472df76c16SMatt Jacob 			goto bad;
29482df76c16SMatt Jacob 		}
29492df76c16SMatt Jacob 	}
29502df76c16SMatt Jacob 	inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
29512df76c16SMatt Jacob 	if (inot == NULL) {
29522df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of immediate notify structures for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
29532df76c16SMatt Jacob 		goto bad;
29542df76c16SMatt Jacob 	}
29552df76c16SMatt Jacob 
29562df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, notify->nt_channel, notify->nt_sid, &lp) == 0) {
29572df76c16SMatt Jacob 		inot->initiator_id = CAM_TARGET_WILDCARD;
29582df76c16SMatt Jacob 	} else {
29592df76c16SMatt Jacob 		inot->initiator_id = lp->handle;
29602df76c16SMatt Jacob 	}
29612df76c16SMatt Jacob 	inot->seq_id = notify->nt_tagval;
29622df76c16SMatt Jacob 	inot->tag_id = notify->nt_tagval >> 32;
29632df76c16SMatt Jacob 
29642df76c16SMatt Jacob 	switch (notify->nt_ncode) {
29652df76c16SMatt Jacob 	case NT_ABORT_TASK:
29662df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, inot->tag_id);
29672df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK;
29682df76c16SMatt Jacob 		break;
29692df76c16SMatt Jacob 	case NT_ABORT_TASK_SET:
29702df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, TAG_ANY);
29712df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK_SET;
29722df76c16SMatt Jacob 		break;
29732df76c16SMatt Jacob 	case NT_CLEAR_ACA:
29742df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_ACA;
29752df76c16SMatt Jacob 		break;
29762df76c16SMatt Jacob 	case NT_CLEAR_TASK_SET:
29772df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_TASK_SET;
29782df76c16SMatt Jacob 		break;
29792df76c16SMatt Jacob 	case NT_LUN_RESET:
29802df76c16SMatt Jacob 		inot->arg = MSG_LOGICAL_UNIT_RESET;
29812df76c16SMatt Jacob 		break;
29822df76c16SMatt Jacob 	case NT_TARGET_RESET:
29832df76c16SMatt Jacob 		inot->arg = MSG_TARGET_RESET;
29842df76c16SMatt Jacob 		break;
29852df76c16SMatt Jacob 	default:
29862df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: unknown TMF code 0x%x for chan %d lun 0x%x", __func__, notify->nt_ncode, notify->nt_channel, lun);
29872df76c16SMatt Jacob 		goto bad;
29882df76c16SMatt Jacob 	}
29892df76c16SMatt Jacob 
29902df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
29912df76c16SMatt Jacob 	if (ntp == NULL) {
29922df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of inotify private structures", __func__);
29932df76c16SMatt Jacob 		goto bad;
29942df76c16SMatt Jacob 	}
29952df76c16SMatt Jacob 	ISP_MEMCPY(&ntp->rd.nt, notify, sizeof (isp_notify_t));
29962df76c16SMatt Jacob 	if (notify->nt_lreserved) {
29972df76c16SMatt Jacob 		ISP_MEMCPY(&ntp->rd.data, notify->nt_lreserved, QENTRY_LEN);
29982df76c16SMatt Jacob 		ntp->rd.nt.nt_lreserved = &ntp->rd.data;
29992df76c16SMatt Jacob 	}
30002df76c16SMatt Jacob 	ntp->rd.seq_id = notify->nt_tagval;
30012df76c16SMatt Jacob 	ntp->rd.tag_id = notify->nt_tagval >> 32;
30022df76c16SMatt Jacob 
30032df76c16SMatt Jacob 	tptr->inot_count--;
30042df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
30052df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
30062df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
30072df76c16SMatt Jacob 	inot->ccb_h.status = CAM_MESSAGE_RECV;
30082df76c16SMatt Jacob 	xpt_done((union ccb *)inot);
30092df76c16SMatt Jacob 	return;
30102df76c16SMatt Jacob bad:
30112df76c16SMatt Jacob 	if (tptr) {
30122df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
30132df76c16SMatt Jacob 	}
30142df76c16SMatt Jacob 	if (notify->nt_need_ack && notify->nt_lreserved) {
30152df76c16SMatt Jacob 		if (((isphdr_t *)notify->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
30162df76c16SMatt Jacob 			(void) isp_acknak_abts(isp, notify->nt_lreserved, ENOMEM);
30172df76c16SMatt Jacob 		} else {
30182df76c16SMatt Jacob 			(void) isp_notify_ack(isp, notify->nt_lreserved);
30192df76c16SMatt Jacob 		}
30202df76c16SMatt Jacob 	}
30212df76c16SMatt Jacob }
30222df76c16SMatt Jacob 
30232df76c16SMatt Jacob /*
3024b1ce21c6SRebecca Cran  * Find the associated private data and mark it as dead so
30252df76c16SMatt Jacob  * we don't try to work on it any further.
30262df76c16SMatt Jacob  */
30272df76c16SMatt Jacob static void
30282df76c16SMatt Jacob isp_target_mark_aborted(ispsoftc_t *isp, union ccb *ccb)
30292df76c16SMatt Jacob {
30302df76c16SMatt Jacob 	tstate_t *tptr;
30312df76c16SMatt Jacob 	atio_private_data_t *atp;
303245210a25SAlexander Motin 	union ccb *accb = ccb->cab.abort_ccb;
30332df76c16SMatt Jacob 
303445210a25SAlexander Motin 	tptr = get_lun_statep(isp, XS_CHANNEL(accb), XS_LUN(accb));
30352df76c16SMatt Jacob 	if (tptr == NULL) {
303645210a25SAlexander Motin 		tptr = get_lun_statep(isp, XS_CHANNEL(accb), CAM_LUN_WILDCARD);
30372df76c16SMatt Jacob 		if (tptr == NULL) {
30382df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
30392df76c16SMatt Jacob 			return;
30402df76c16SMatt Jacob 		}
30412df76c16SMatt Jacob 	}
30422df76c16SMatt Jacob 
304345210a25SAlexander Motin 	atp = isp_get_atpd(isp, tptr, accb->atio.tag_id);
30442df76c16SMatt Jacob 	if (atp == NULL) {
30452df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INVALID;
304645210a25SAlexander Motin 	} else {
30472df76c16SMatt Jacob 		atp->dead = 1;
30482df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
30492df76c16SMatt Jacob 	}
305045210a25SAlexander Motin 	rls_lun_statep(isp, tptr);
305145210a25SAlexander Motin }
30522df76c16SMatt Jacob 
30532df76c16SMatt Jacob static void
30542df76c16SMatt Jacob isp_target_mark_aborted_early(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id)
30552df76c16SMatt Jacob {
30562df76c16SMatt Jacob 	atio_private_data_t *atp;
30572df76c16SMatt Jacob 	inot_private_data_t *restart_queue = tptr->restart_queue;
30582df76c16SMatt Jacob 
30592df76c16SMatt Jacob 	/*
30602df76c16SMatt Jacob 	 * First, clean any commands pending restart
30612df76c16SMatt Jacob 	 */
30622df76c16SMatt Jacob 	tptr->restart_queue = NULL;
30632df76c16SMatt Jacob 	while (restart_queue) {
30642df76c16SMatt Jacob 		uint32_t this_tag_id;
30652df76c16SMatt Jacob 		inot_private_data_t *ntp = restart_queue;
30662df76c16SMatt Jacob 
30672df76c16SMatt Jacob 		restart_queue = ntp->rd.nt.nt_hba;
30682df76c16SMatt Jacob 
30692df76c16SMatt Jacob 		if (IS_24XX(isp)) {
30702df76c16SMatt Jacob 			this_tag_id = ((at7_entry_t *)ntp->rd.data)->at_rxid;
30712df76c16SMatt Jacob 		} else {
30722df76c16SMatt Jacob 			this_tag_id = ((at2_entry_t *)ntp->rd.data)->at_rxid;
30732df76c16SMatt Jacob 		}
30742df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) {
30752df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
30762df76c16SMatt Jacob 		} else {
30772df76c16SMatt Jacob 			ntp->rd.nt.nt_hba = tptr->restart_queue;
30782df76c16SMatt Jacob 			tptr->restart_queue = ntp;
30792df76c16SMatt Jacob 		}
30802df76c16SMatt Jacob 	}
30812df76c16SMatt Jacob 
30822df76c16SMatt Jacob 	/*
30832df76c16SMatt Jacob 	 * Now mark other ones dead as well.
30842df76c16SMatt Jacob 	 */
30852df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
30862df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) {
30872df76c16SMatt Jacob 			atp->dead = 1;
30882df76c16SMatt Jacob 		}
30892df76c16SMatt Jacob 	}
30902df76c16SMatt Jacob }
30912df76c16SMatt Jacob 
30922df76c16SMatt Jacob 
30932df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
30942df76c16SMatt Jacob // #define	ISP_FORCE_TIMEOUT		1
3095ae5db118SMatt Jacob // #define	ISP_TEST_WWNS			1
3096ae5db118SMatt Jacob // #define	ISP_TEST_SEPARATE_STATUS	1
30972df76c16SMatt Jacob 
30982df76c16SMatt Jacob #define	ccb_data_offset		ppriv_field0
30992df76c16SMatt Jacob #define	ccb_atio		ppriv_ptr1
31002df76c16SMatt Jacob #define	ccb_inot		ppriv_ptr1
31012df76c16SMatt Jacob 
31022df76c16SMatt Jacob #define	MAX_ISP_TARG_TRANSFER	(2 << 20)
31032df76c16SMatt Jacob #define	NISP_TARG_CMDS		1024
31042df76c16SMatt Jacob #define	NISP_TARG_NOTIFIES	1024
31052df76c16SMatt Jacob #define	DISK_SHIFT		9
31062df76c16SMatt Jacob #define	JUNK_SIZE		256
31072df76c16SMatt Jacob 
31082df76c16SMatt Jacob #ifndef	VERIFY_10
31092df76c16SMatt Jacob #define	VERIFY_10	0x2f
31102df76c16SMatt Jacob #endif
31112df76c16SMatt Jacob 
31122df76c16SMatt Jacob TAILQ_HEAD(ccb_queue, ccb_hdr);
31132df76c16SMatt Jacob extern u_int vm_kmem_size;
31142df76c16SMatt Jacob static int ca;
31152df76c16SMatt Jacob static uint32_t disk_size;
31162df76c16SMatt Jacob static uint8_t *disk_data = NULL;
31172df76c16SMatt Jacob static uint8_t *junk_data;
31182df76c16SMatt Jacob static MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data");
31192df76c16SMatt Jacob struct isptarg_softc {
31202df76c16SMatt Jacob 	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
31212df76c16SMatt Jacob 	struct ccb_queue	work_queue;
31222df76c16SMatt Jacob 	struct ccb_queue	rework_queue;
31232df76c16SMatt Jacob 	struct ccb_queue	running_queue;
31242df76c16SMatt Jacob 	struct ccb_queue	inot_queue;
31252df76c16SMatt Jacob 	struct cam_periph       *periph;
31262df76c16SMatt Jacob 	struct cam_path	 	*path;
31272df76c16SMatt Jacob 	ispsoftc_t		*isp;
31282df76c16SMatt Jacob };
31292df76c16SMatt Jacob static periph_ctor_t	isptargctor;
31302df76c16SMatt Jacob static periph_dtor_t	isptargdtor;
31312df76c16SMatt Jacob static periph_start_t	isptargstart;
31322df76c16SMatt Jacob static periph_init_t	isptarginit;
31332df76c16SMatt Jacob static void		isptarg_done(struct cam_periph *, union ccb *);
31342df76c16SMatt Jacob static void		isptargasync(void *, u_int32_t, struct cam_path *, void *);
31352df76c16SMatt Jacob 
31362df76c16SMatt Jacob 
31372df76c16SMatt Jacob static int isptarg_rwparm(uint8_t *, uint8_t *, uint64_t, uint32_t, uint8_t **, uint32_t *, int *);
31382df76c16SMatt Jacob 
31392df76c16SMatt Jacob static struct periph_driver isptargdriver =
31402df76c16SMatt Jacob {
31412df76c16SMatt Jacob 	isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), /* generation */ 0
31422df76c16SMatt Jacob };
31432df76c16SMatt Jacob 
31442df76c16SMatt Jacob static void
31452df76c16SMatt Jacob isptarginit(void)
31462df76c16SMatt Jacob {
31472df76c16SMatt Jacob }
31482df76c16SMatt Jacob 
31492df76c16SMatt Jacob static void
31502df76c16SMatt Jacob isptargnotify(ispsoftc_t *isp, union ccb *iccb, struct ccb_immediate_notify *inot)
31512df76c16SMatt Jacob {
31522df76c16SMatt Jacob 	struct ccb_notify_acknowledge *ack = &iccb->cna2;
31532df76c16SMatt Jacob 
31542df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: [0x%x] immediate notify for 0x%x from 0x%x status 0x%x arg 0x%x\n", __func__,
31552df76c16SMatt Jacob 	    inot->tag_id, inot->initiator_id, inot->seq_id, inot->ccb_h.status, inot->arg);
31562df76c16SMatt Jacob 	ack->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE;
31572df76c16SMatt Jacob 	ack->ccb_h.flags = 0;
31582df76c16SMatt Jacob 	ack->ccb_h.retry_count = 0;
31592df76c16SMatt Jacob 	ack->ccb_h.cbfcnp = isptarg_done;
31602df76c16SMatt Jacob 	ack->ccb_h.timeout = 0;
31612df76c16SMatt Jacob 	ack->ccb_h.ccb_inot = inot;
31622df76c16SMatt Jacob 	ack->tag_id = inot->tag_id;
31632df76c16SMatt Jacob 	ack->seq_id = inot->seq_id;
31642df76c16SMatt Jacob 	ack->initiator_id = inot->initiator_id;
31652df76c16SMatt Jacob 	xpt_action(iccb);
31662df76c16SMatt Jacob }
31672df76c16SMatt Jacob 
31682df76c16SMatt Jacob static void
31692df76c16SMatt Jacob isptargstart(struct cam_periph *periph, union ccb *iccb)
31702df76c16SMatt Jacob {
31710a100e5bSMatt Jacob 	const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = {
31720a100e5bSMatt Jacob 		0x7f, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
31730a100e5bSMatt Jacob 		'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ',
31740a100e5bSMatt Jacob 		'S', 'C', 'S', 'I', ' ', 'N', 'U', 'L',
31750a100e5bSMatt Jacob 		'L', ' ', 'D', 'E', 'V', 'I', 'C', 'E',
31760a100e5bSMatt Jacob 		'0', '0', '0', '1'
31770a100e5bSMatt Jacob 	};
31782df76c16SMatt Jacob 	const uint8_t iqd[SHORT_INQUIRY_LENGTH] = {
31790a100e5bSMatt Jacob 		0, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
31802df76c16SMatt Jacob 		'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ',
31812df76c16SMatt Jacob 		'S', 'C', 'S', 'I', ' ', 'M', 'E', 'M',
31822df76c16SMatt Jacob 		'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
31832df76c16SMatt Jacob 		'0', '0', '0', '1'
31842df76c16SMatt Jacob 	};
31852df76c16SMatt Jacob 	int i, more = 0, last;
31862df76c16SMatt Jacob 	struct isptarg_softc *softc = periph->softc;
31872df76c16SMatt Jacob 	struct ccb_scsiio *csio;
31882df76c16SMatt Jacob 	lun_id_t return_lun;
31892df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
31902df76c16SMatt Jacob 	uint8_t *cdb, *ptr, status;
31912df76c16SMatt Jacob 	uint8_t *data_ptr;
31922df76c16SMatt Jacob 	uint32_t data_len, flags;
31932df76c16SMatt Jacob 	struct ccb_hdr *ccbh;
31942df76c16SMatt Jacob 
31952df76c16SMatt Jacob 	mtx_assert(periph->sim->mtx, MA_OWNED);
31962df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: function code 0x%x INOTQ=%c WORKQ=%c REWORKQ=%c\n", __func__, iccb->ccb_h.func_code,
31972df76c16SMatt Jacob 	    TAILQ_FIRST(&softc->inot_queue)? 'y' : 'n', TAILQ_FIRST(&softc->work_queue)? 'y' : 'n', TAILQ_FIRST(&softc->rework_queue)? 'y' : 'n');
31982df76c16SMatt Jacob 	/*
31992df76c16SMatt Jacob 	 * Check for immediate notifies first
32002df76c16SMatt Jacob 	 */
32012df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->inot_queue);
32022df76c16SMatt Jacob 	if (ccbh) {
32032df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->inot_queue, ccbh, periph_links.tqe);
32042df76c16SMatt Jacob 		if (TAILQ_FIRST(&softc->inot_queue) || TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue)) {
32052df76c16SMatt Jacob 			xpt_schedule(periph, 1);
32062df76c16SMatt Jacob 		}
32072df76c16SMatt Jacob 		isptargnotify(softc->isp, iccb, (struct ccb_immediate_notify *)ccbh);
32082df76c16SMatt Jacob 		return;
32092df76c16SMatt Jacob 	}
32102df76c16SMatt Jacob 
32112df76c16SMatt Jacob 	/*
32122df76c16SMatt Jacob 	 * Check the rework (continuation) work queue first.
32132df76c16SMatt Jacob 	 */
32142df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->rework_queue);
32152df76c16SMatt Jacob 	if (ccbh) {
32162df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
32172df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe);
32182df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue);
32192df76c16SMatt Jacob 	} else {
32202df76c16SMatt Jacob 		ccbh = TAILQ_FIRST(&softc->work_queue);
32212df76c16SMatt Jacob 		if (ccbh == NULL) {
32222df76c16SMatt Jacob 			ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: woken up but no work?\n", __func__);
32232df76c16SMatt Jacob 			xpt_release_ccb(iccb);
32242df76c16SMatt Jacob 			return;
32252df76c16SMatt Jacob 		}
32262df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
32272df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
32282df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) != NULL;
32292df76c16SMatt Jacob 		atio->ccb_h.ccb_data_offset = 0;
32302df76c16SMatt Jacob 	}
32312df76c16SMatt Jacob 
32322df76c16SMatt Jacob 	if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) {
32332df76c16SMatt Jacob 		panic("BAD ATIO");
32342df76c16SMatt Jacob 	}
32352df76c16SMatt Jacob 
32362df76c16SMatt Jacob 	data_ptr = NULL;
32372df76c16SMatt Jacob 	data_len = 0;
32382df76c16SMatt Jacob 	csio = &iccb->csio;
32392df76c16SMatt Jacob 	status = SCSI_STATUS_OK;
32402df76c16SMatt Jacob 	flags = CAM_SEND_STATUS;
32412df76c16SMatt Jacob 	memset(&atio->sense_data, 0, sizeof (atio->sense_data));
32422df76c16SMatt Jacob 	cdb = atio->cdb_io.cdb_bytes;
32432df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, ccbh->path, "%s: [0x%x] processing ATIO from 0x%x CDB=0x%x data_offset=%u\n", __func__, atio->tag_id, atio->init_id,
32442df76c16SMatt Jacob 	    cdb[0], atio->ccb_h.ccb_data_offset);
32452df76c16SMatt Jacob 
32462df76c16SMatt Jacob 	return_lun = XS_LUN(atio);
32472df76c16SMatt Jacob 	if (return_lun != 0) {
32482df76c16SMatt Jacob 		xpt_print(atio->ccb_h.path, "[0x%x] Non-Zero Lun %d: cdb0=0x%x\n", atio->tag_id, return_lun, cdb[0]);
32492df76c16SMatt Jacob 		if (cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
32502df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3251f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_ILLEGAL_REQUEST;
3252f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x25;
3253f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x0;
3254f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
32552df76c16SMatt Jacob 		}
32562df76c16SMatt Jacob 		return_lun = CAM_LUN_WILDCARD;
32572df76c16SMatt Jacob 	}
32582df76c16SMatt Jacob 
32592df76c16SMatt Jacob 	switch (cdb[0]) {
32602df76c16SMatt Jacob 	case REQUEST_SENSE:
32612df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32622df76c16SMatt Jacob 		data_len = sizeof (atio->sense_data);
32632df76c16SMatt Jacob 		junk_data[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_NO_SENSE;
32642df76c16SMatt Jacob 		memset(junk_data+1, 0, data_len-1);
32652df76c16SMatt Jacob 		if (data_len > cdb[4]) {
32662df76c16SMatt Jacob 			data_len = cdb[4];
32672df76c16SMatt Jacob 		}
32682df76c16SMatt Jacob 		if (data_len) {
32692df76c16SMatt Jacob 			data_ptr = junk_data;
32702df76c16SMatt Jacob 		}
32712df76c16SMatt Jacob 		break;
32722df76c16SMatt Jacob 	case READ_6:
32732df76c16SMatt Jacob 	case READ_10:
32742df76c16SMatt Jacob 	case READ_12:
32752df76c16SMatt Jacob 	case READ_16:
32762df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
32772df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3278f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3279f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x5;
3280f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x24;
3281f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
32822df76c16SMatt Jacob 		} else {
32832df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
32842df76c16SMatt Jacob 			{
32852df76c16SMatt Jacob 				static int foo;
32862df76c16SMatt Jacob 				if (foo++ == 500) {
32872df76c16SMatt Jacob 					if (more) {
32882df76c16SMatt Jacob 						xpt_schedule(periph, 1);
32892df76c16SMatt Jacob 					}
32902df76c16SMatt Jacob 					foo = 0;
32912df76c16SMatt Jacob 					return;
32922df76c16SMatt Jacob 				}
32932df76c16SMatt Jacob 			}
32942df76c16SMatt Jacob #endif
32952df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
32962df76c16SMatt Jacob 			if (last && data_len) {
32972df76c16SMatt Jacob 				last = 0;
32982df76c16SMatt Jacob 			}
32992df76c16SMatt Jacob #endif
33002df76c16SMatt Jacob 			if (last == 0) {
33012df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
33022df76c16SMatt Jacob 			}
33032df76c16SMatt Jacob 			if (data_len) {
33042df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
33052df76c16SMatt Jacob 				flags |= CAM_DIR_IN;
33062df76c16SMatt Jacob 			} else {
33072df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
33082df76c16SMatt Jacob 			}
33092df76c16SMatt Jacob 		}
33102df76c16SMatt Jacob 		break;
33112df76c16SMatt Jacob 	case WRITE_6:
33122df76c16SMatt Jacob 	case WRITE_10:
33132df76c16SMatt Jacob 	case WRITE_12:
33142df76c16SMatt Jacob 	case WRITE_16:
33152df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
33162df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3317f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3318f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x5;
3319f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x24;
3320f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
33212df76c16SMatt Jacob 		} else {
33222df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
33232df76c16SMatt Jacob 			{
33242df76c16SMatt Jacob 				static int foo;
33252df76c16SMatt Jacob 				if (foo++ == 500) {
33262df76c16SMatt Jacob 					if (more) {
33272df76c16SMatt Jacob 						xpt_schedule(periph, 1);
33282df76c16SMatt Jacob 					}
33292df76c16SMatt Jacob 					foo = 0;
33302df76c16SMatt Jacob 					return;
33312df76c16SMatt Jacob 				}
33322df76c16SMatt Jacob 			}
33332df76c16SMatt Jacob #endif
33342df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
33352df76c16SMatt Jacob 			if (last && data_len) {
33362df76c16SMatt Jacob 				last = 0;
33372df76c16SMatt Jacob 			}
33382df76c16SMatt Jacob #endif
33392df76c16SMatt Jacob 			if (last == 0) {
33402df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
33412df76c16SMatt Jacob 			}
33422df76c16SMatt Jacob 			if (data_len) {
33432df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
33442df76c16SMatt Jacob 				flags |= CAM_DIR_OUT;
33452df76c16SMatt Jacob 			} else {
33462df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
33472df76c16SMatt Jacob 			}
33482df76c16SMatt Jacob 		}
33492df76c16SMatt Jacob 		break;
33502df76c16SMatt Jacob 	case INQUIRY:
33512df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
33522df76c16SMatt Jacob 		if (cdb[1] || cdb[2] || cdb[3]) {
33532df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3354f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3355f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x5;
3356f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x20;
3357f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
33582df76c16SMatt Jacob 			break;
33592df76c16SMatt Jacob 		}
33602df76c16SMatt Jacob 		data_len = sizeof (iqd);
33612df76c16SMatt Jacob 		if (data_len > cdb[4]) {
33622df76c16SMatt Jacob 			data_len = cdb[4];
33632df76c16SMatt Jacob 		}
33642df76c16SMatt Jacob 		if (data_len) {
33652df76c16SMatt Jacob 			if (XS_LUN(iccb) != 0) {
33662df76c16SMatt Jacob 				memcpy(junk_data, niliqd, sizeof (iqd));
33672df76c16SMatt Jacob 			} else {
33682df76c16SMatt Jacob 				memcpy(junk_data, iqd, sizeof (iqd));
33692df76c16SMatt Jacob 			}
33702df76c16SMatt Jacob 			data_ptr = junk_data;
33712df76c16SMatt Jacob 		}
33722df76c16SMatt Jacob 		break;
33732df76c16SMatt Jacob 	case TEST_UNIT_READY:
33742df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
33752df76c16SMatt Jacob 		if (ca) {
33762df76c16SMatt Jacob 			ca = 0;
33772df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3378f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3379f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x28;
3380f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x0;
3381f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
33822df76c16SMatt Jacob 		}
33832df76c16SMatt Jacob 		break;
33842df76c16SMatt Jacob 	case SYNCHRONIZE_CACHE:
33852df76c16SMatt Jacob 	case START_STOP:
33862df76c16SMatt Jacob 	case RESERVE:
33872df76c16SMatt Jacob 	case RELEASE:
33882df76c16SMatt Jacob 	case VERIFY_10:
33892df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
33902df76c16SMatt Jacob 		break;
33912df76c16SMatt Jacob 
33922df76c16SMatt Jacob 	case READ_CAPACITY:
33932df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
33942df76c16SMatt Jacob 		if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
33952df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
3396f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3397f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code = 0x5;
3398f6683e55SMatt Jacob 			SDFIXED(atio->sense_data)->add_sense_code_qual = 0x24;
3399f6683e55SMatt Jacob 			atio->sense_len = SSD_MIN_SIZE;
34002df76c16SMatt Jacob 			break;
34012df76c16SMatt Jacob 		}
34022df76c16SMatt Jacob 		if (cdb[8] & 0x1) { /* PMI */
34032df76c16SMatt Jacob 			junk_data[0] = 0xff;
34042df76c16SMatt Jacob 			junk_data[1] = 0xff;
34052df76c16SMatt Jacob 			junk_data[2] = 0xff;
34062df76c16SMatt Jacob 			junk_data[3] = 0xff;
34072df76c16SMatt Jacob 		} else {
34082df76c16SMatt Jacob 			uint64_t last_blk = (disk_size >> DISK_SHIFT) - 1;
34092df76c16SMatt Jacob 			if (last_blk < 0xffffffffULL) {
34102df76c16SMatt Jacob 			    junk_data[0] = (last_blk >> 24) & 0xff;
34112df76c16SMatt Jacob 			    junk_data[1] = (last_blk >> 16) & 0xff;
34122df76c16SMatt Jacob 			    junk_data[2] = (last_blk >>  8) & 0xff;
34132df76c16SMatt Jacob 			    junk_data[3] = (last_blk) & 0xff;
34142df76c16SMatt Jacob 			} else {
34152df76c16SMatt Jacob 			    junk_data[0] = 0xff;
34162df76c16SMatt Jacob 			    junk_data[1] = 0xff;
34172df76c16SMatt Jacob 			    junk_data[2] = 0xff;
34182df76c16SMatt Jacob 			    junk_data[3] = 0xff;
34192df76c16SMatt Jacob 			}
34202df76c16SMatt Jacob 		}
34212df76c16SMatt Jacob 		junk_data[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
34222df76c16SMatt Jacob 		junk_data[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
34232df76c16SMatt Jacob 		junk_data[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
34242df76c16SMatt Jacob 		junk_data[7] = ((1 << DISK_SHIFT)) & 0xff;
34252df76c16SMatt Jacob 		data_ptr = junk_data;
34262df76c16SMatt Jacob 		data_len = 8;
34272df76c16SMatt Jacob 		break;
34282df76c16SMatt Jacob 	case REPORT_LUNS:
34292df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
34302df76c16SMatt Jacob 		memset(junk_data, 0, JUNK_SIZE);
34312df76c16SMatt Jacob 		junk_data[0] = (1 << 3) >> 24;
34322df76c16SMatt Jacob 		junk_data[1] = (1 << 3) >> 16;
34332df76c16SMatt Jacob 		junk_data[2] = (1 << 3) >> 8;
34342df76c16SMatt Jacob 		junk_data[3] = (1 << 3);
34352df76c16SMatt Jacob 		ptr = NULL;
34362df76c16SMatt Jacob 		for (i = 0; i < 1; i++) {
34372df76c16SMatt Jacob 			ptr = &junk_data[8 + (1 << 3)];
34382df76c16SMatt Jacob 			if (i >= 256) {
34392df76c16SMatt Jacob 				ptr[0] = 0x40 | ((i >> 8) & 0x3f);
34402df76c16SMatt Jacob 			}
34412df76c16SMatt Jacob 			ptr[1] = i;
34422df76c16SMatt Jacob 		}
34432df76c16SMatt Jacob 		data_ptr = junk_data;
34442df76c16SMatt Jacob 		data_len = (ptr + 8) - junk_data;
34452df76c16SMatt Jacob 		break;
34462df76c16SMatt Jacob 
34472df76c16SMatt Jacob 	default:
34482df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
34492df76c16SMatt Jacob 		status = SCSI_STATUS_CHECK_COND;
3450f6683e55SMatt Jacob 		SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
3451f6683e55SMatt Jacob 		SDFIXED(atio->sense_data)->add_sense_code = 0x5;
3452f6683e55SMatt Jacob 		SDFIXED(atio->sense_data)->add_sense_code_qual = 0x20;
3453f6683e55SMatt Jacob 		atio->sense_len = SSD_MIN_SIZE;
34542df76c16SMatt Jacob 		break;
34552df76c16SMatt Jacob 	}
34562df76c16SMatt Jacob 
34572df76c16SMatt Jacob 	/*
34582df76c16SMatt Jacob 	 * If we are done with the transaction, tell the
34592df76c16SMatt Jacob 	 * controller to send status and perform a CMD_CMPLT.
34602df76c16SMatt Jacob 	 * If we have associated sense data, see if we can
34612df76c16SMatt Jacob 	 * send that too.
34622df76c16SMatt Jacob 	 */
34632df76c16SMatt Jacob 	if (status == SCSI_STATUS_CHECK_COND) {
34642df76c16SMatt Jacob 		flags |= CAM_SEND_SENSE;
34652df76c16SMatt Jacob 		csio->sense_len = atio->sense_len;
34662df76c16SMatt Jacob 		csio->sense_data = atio->sense_data;
34672df76c16SMatt Jacob 		flags &= ~CAM_DIR_MASK;
34682df76c16SMatt Jacob 		data_len = 0;
34692df76c16SMatt Jacob 		data_ptr = NULL;
34702df76c16SMatt Jacob 	}
34712df76c16SMatt Jacob 	cam_fill_ctio(csio, 0, isptarg_done, flags, MSG_SIMPLE_Q_TAG, atio->tag_id, atio->init_id, status, data_ptr, data_len, 0);
34722df76c16SMatt Jacob 	iccb->ccb_h.target_id = atio->ccb_h.target_id;
34732df76c16SMatt Jacob 	iccb->ccb_h.target_lun = return_lun;
34742df76c16SMatt Jacob 	iccb->ccb_h.ccb_atio = atio;
34752df76c16SMatt Jacob 	xpt_action(iccb);
34762df76c16SMatt Jacob 
34772df76c16SMatt Jacob 	if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
34782df76c16SMatt Jacob 		cam_release_devq(periph->path, 0, 0, 0, 0);
34792df76c16SMatt Jacob 		atio->ccb_h.status &= ~CAM_DEV_QFRZN;
34802df76c16SMatt Jacob 	}
34812df76c16SMatt Jacob 	if (more) {
34822df76c16SMatt Jacob 		xpt_schedule(periph, 1);
34832df76c16SMatt Jacob 	}
34842df76c16SMatt Jacob }
34852df76c16SMatt Jacob 
34862df76c16SMatt Jacob static cam_status
34872df76c16SMatt Jacob isptargctor(struct cam_periph *periph, void *arg)
34882df76c16SMatt Jacob {
34892df76c16SMatt Jacob 	struct isptarg_softc *softc;
34902df76c16SMatt Jacob 
34912df76c16SMatt Jacob 	softc = (struct isptarg_softc *)arg;
34922df76c16SMatt Jacob 	periph->softc = softc;
34932df76c16SMatt Jacob 	softc->periph = periph;
34942df76c16SMatt Jacob 	softc->path = periph->path;
34952df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
34962df76c16SMatt Jacob 	return (CAM_REQ_CMP);
34972df76c16SMatt Jacob }
34982df76c16SMatt Jacob 
34992df76c16SMatt Jacob static void
35002df76c16SMatt Jacob isptargdtor(struct cam_periph *periph)
35012df76c16SMatt Jacob {
35022df76c16SMatt Jacob 	struct isptarg_softc *softc;
35032df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
35042df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
35052df76c16SMatt Jacob 	softc->periph = NULL;
35062df76c16SMatt Jacob 	softc->path = NULL;
35072df76c16SMatt Jacob 	periph->softc = NULL;
35082df76c16SMatt Jacob }
35092df76c16SMatt Jacob 
35102df76c16SMatt Jacob static void
35112df76c16SMatt Jacob isptarg_done(struct cam_periph *periph, union ccb *ccb)
35122df76c16SMatt Jacob {
35132df76c16SMatt Jacob 	struct isptarg_softc *softc;
35142df76c16SMatt Jacob 	ispsoftc_t *isp;
35152df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
35162df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
35172df76c16SMatt Jacob 	cam_status status;
35182df76c16SMatt Jacob 
35192df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
35202df76c16SMatt Jacob 	isp = softc->isp;
35212df76c16SMatt Jacob 	status = ccb->ccb_h.status & CAM_STATUS_MASK;
35222df76c16SMatt Jacob 
35232df76c16SMatt Jacob 	switch (ccb->ccb_h.func_code) {
35242df76c16SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:
35252df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *) ccb;
35262df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__);
35272df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe);
35282df76c16SMatt Jacob 		xpt_schedule(periph, 1);
35292df76c16SMatt Jacob 		break;
35302df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:
35312df76c16SMatt Jacob 		inot = (struct ccb_immediate_notify *) ccb;
35322df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] INOT for 0x%x seen in %s\n", inot->tag_id, inot->seq_id, __func__);
35332df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe);
35342df76c16SMatt Jacob 		xpt_schedule(periph, 1);
35352df76c16SMatt Jacob 		break;
35362df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
35372df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
35382df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
35392df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
35402df76c16SMatt Jacob 		}
35412df76c16SMatt Jacob 		atio = ccb->ccb_h.ccb_atio;
35422df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
35432df76c16SMatt Jacob 			cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
35442df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
35452df76c16SMatt Jacob 		} else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
35462df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO seen in %s\n", atio->tag_id, __func__);
35472df76c16SMatt Jacob 			TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe);
35482df76c16SMatt Jacob 			xpt_schedule(periph, 1);
35492df76c16SMatt Jacob 		} else {
35502df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO seen in %s\n", atio->tag_id, __func__);
35512df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
35522df76c16SMatt Jacob 		}
35532df76c16SMatt Jacob 		xpt_release_ccb(ccb);
35542df76c16SMatt Jacob 		break;
35552df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:
35562df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
35572df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
35582df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
35592df76c16SMatt Jacob 		}
35602df76c16SMatt Jacob 		inot = ccb->ccb_h.ccb_inot;
35612df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "[0x%x] recycle notify for tag 0x%x\n", inot->tag_id, inot->seq_id);
35622df76c16SMatt Jacob 		xpt_release_ccb(ccb);
35632df76c16SMatt Jacob 		xpt_action((union ccb *)inot);
35642df76c16SMatt Jacob 		break;
35652df76c16SMatt Jacob 	default:
35662df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "unexpected code 0x%x\n", ccb->ccb_h.func_code);
35672df76c16SMatt Jacob 		break;
35682df76c16SMatt Jacob 	}
35692df76c16SMatt Jacob }
35702df76c16SMatt Jacob 
35712df76c16SMatt Jacob static void
35722df76c16SMatt Jacob isptargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
35732df76c16SMatt Jacob {
35742df76c16SMatt Jacob 	struct ac_contract *acp = arg;
35752df76c16SMatt Jacob 	struct ac_device_changed *fc = (struct ac_device_changed *) acp->contract_data;
35762df76c16SMatt Jacob 
35772df76c16SMatt Jacob 	if (code != AC_CONTRACT) {
35782df76c16SMatt Jacob 		return;
35792df76c16SMatt Jacob 	}
35802df76c16SMatt Jacob 	xpt_print(path, "0x%016llx Port ID 0x%06x %s\n", (unsigned long long) fc->wwpn, fc->port, fc->arrived? "arrived" : "departed");
35812df76c16SMatt Jacob }
35822df76c16SMatt Jacob 
35832df76c16SMatt Jacob static void
35842df76c16SMatt Jacob isp_target_thread(ispsoftc_t *isp, int chan)
35852df76c16SMatt Jacob {
35862df76c16SMatt Jacob 	union ccb *ccb = NULL;
35872df76c16SMatt Jacob 	int i;
35882df76c16SMatt Jacob 	void *wchan;
35892df76c16SMatt Jacob 	cam_status status;
35902df76c16SMatt Jacob 	struct isptarg_softc *softc = NULL;
35912df76c16SMatt Jacob 	struct cam_periph *periph = NULL, *wperiph = NULL;
35922df76c16SMatt Jacob 	struct cam_path *path, *wpath;
35932df76c16SMatt Jacob 	struct cam_sim *sim;
35942df76c16SMatt Jacob 
35952df76c16SMatt Jacob 	if (disk_data == NULL) {
35962df76c16SMatt Jacob 		disk_size = roundup2(vm_kmem_size >> 1, (1ULL << 20));
35972df76c16SMatt Jacob 		if (disk_size < (50 << 20)) {
35982df76c16SMatt Jacob 			disk_size = 50 << 20;
35992df76c16SMatt Jacob 		}
36002df76c16SMatt Jacob 		disk_data = malloc(disk_size, M_ISPTARG, M_WAITOK | M_ZERO);
36012df76c16SMatt Jacob 		if (disk_data == NULL) {
36022df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: could not allocate disk data", __func__);
36032df76c16SMatt Jacob 			goto out;
36042df76c16SMatt Jacob 		}
36052df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "allocated a %ju MiB disk", (uintmax_t) (disk_size >> 20));
36062df76c16SMatt Jacob 	}
36072df76c16SMatt Jacob 	junk_data = malloc(JUNK_SIZE, M_ISPTARG, M_WAITOK | M_ZERO);
36082df76c16SMatt Jacob 	if (junk_data == NULL) {
36092df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate junk", __func__);
36102df76c16SMatt Jacob 		goto out;
36112df76c16SMatt Jacob 	}
36122df76c16SMatt Jacob 
36132df76c16SMatt Jacob 
36142df76c16SMatt Jacob 	softc = malloc(sizeof (*softc), M_ISPTARG, M_WAITOK | M_ZERO);
36152df76c16SMatt Jacob 	if (softc == NULL) {
36162df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate softc", __func__);
36172df76c16SMatt Jacob 		goto out;
36182df76c16SMatt Jacob 	}
36192df76c16SMatt Jacob 	TAILQ_INIT(&softc->work_queue);
36202df76c16SMatt Jacob 	TAILQ_INIT(&softc->rework_queue);
36212df76c16SMatt Jacob 	TAILQ_INIT(&softc->running_queue);
36222df76c16SMatt Jacob 	TAILQ_INIT(&softc->inot_queue);
36232df76c16SMatt Jacob 	softc->isp = isp;
36242df76c16SMatt Jacob 
36252df76c16SMatt Jacob 	periphdriver_register(&isptargdriver);
36262df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, sim, sim);
36272df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, path,  path);
36282df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&wpath, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
36292df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
36302df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate wildcard path", __func__);
36312df76c16SMatt Jacob 		return;
36322df76c16SMatt Jacob 	}
36332df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), 0, 0);
36342df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
36352df76c16SMatt Jacob 		xpt_free_path(wpath);
36362df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate path", __func__);
36372df76c16SMatt Jacob 		return;
36382df76c16SMatt Jacob 	}
36392df76c16SMatt Jacob 
36402df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
36412df76c16SMatt Jacob 
36422df76c16SMatt Jacob 	ISP_LOCK(isp);
36432df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, wpath, NULL, 0, softc);
36442df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
36452df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36462df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc for wildcard failed", __func__);
36472df76c16SMatt Jacob 		goto out;
36482df76c16SMatt Jacob 	}
36492df76c16SMatt Jacob 	wperiph = cam_periph_find(wpath, "isptarg");
36502df76c16SMatt Jacob 	if (wperiph == NULL) {
36512df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36522df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: wildcard periph already allocated but doesn't exist", __func__);
36532df76c16SMatt Jacob 		goto out;
36542df76c16SMatt Jacob 	}
36552df76c16SMatt Jacob 
36562df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, path, NULL, 0, softc);
36572df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
36582df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36592df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc failed", __func__);
36602df76c16SMatt Jacob 		goto out;
36612df76c16SMatt Jacob 	}
36622df76c16SMatt Jacob 
36632df76c16SMatt Jacob 	periph = cam_periph_find(path, "isptarg");
36642df76c16SMatt Jacob 	if (periph == NULL) {
36652df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36662df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: periph already allocated but doesn't exist", __func__);
36672df76c16SMatt Jacob 		goto out;
36682df76c16SMatt Jacob 	}
36692df76c16SMatt Jacob 
36702df76c16SMatt Jacob 	status = xpt_register_async(AC_CONTRACT, isptargasync, isp, wpath);
36712df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
36722df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36732df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: xpt_register_async failed", __func__);
36742df76c16SMatt Jacob 		goto out;
36752df76c16SMatt Jacob 	}
36762df76c16SMatt Jacob 
36772df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36782df76c16SMatt Jacob 
36792df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
36802df76c16SMatt Jacob 
36812df76c16SMatt Jacob 	/*
36822df76c16SMatt Jacob 	 * Make sure role is none.
36832df76c16SMatt Jacob 	 */
36842df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
36852df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
36862df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE;
36872df76c16SMatt Jacob #ifdef	ISP_TEST_WWNS
36882df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE | KNOB_VALID_ADDRESS;
36892df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwnn = 0x508004d000000000ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
36902df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwpn = 0x508004d000000001ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
36912df76c16SMatt Jacob #else
36922df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
36932df76c16SMatt Jacob #endif
36942df76c16SMatt Jacob 
36952df76c16SMatt Jacob 	ISP_LOCK(isp);
36962df76c16SMatt Jacob 	xpt_action(ccb);
36972df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36982df76c16SMatt Jacob 
36992df76c16SMatt Jacob 	/*
37002df76c16SMatt Jacob 	 * Now enable luns
37012df76c16SMatt Jacob 	 */
37022df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
37032df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
37042df76c16SMatt Jacob 	ccb->cel.enable = 1;
37052df76c16SMatt Jacob 	ISP_LOCK(isp);
37062df76c16SMatt Jacob 	xpt_action(ccb);
37072df76c16SMatt Jacob 	ISP_UNLOCK(isp);
37082df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
37092df76c16SMatt Jacob 		xpt_free_ccb(ccb);
37102df76c16SMatt Jacob 		xpt_print(periph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
37112df76c16SMatt Jacob 		goto out;
37122df76c16SMatt Jacob 	}
37132df76c16SMatt Jacob 
37142df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 10);
37152df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
37162df76c16SMatt Jacob 	ccb->cel.enable = 1;
37172df76c16SMatt Jacob 	ISP_LOCK(isp);
37182df76c16SMatt Jacob 	xpt_action(ccb);
37192df76c16SMatt Jacob 	ISP_UNLOCK(isp);
37202df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
37212df76c16SMatt Jacob 		xpt_free_ccb(ccb);
37222df76c16SMatt Jacob 		xpt_print(wperiph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
37232df76c16SMatt Jacob 		goto out;
37242df76c16SMatt Jacob 	}
37252df76c16SMatt Jacob 	xpt_free_ccb(ccb);
37262df76c16SMatt Jacob 
37272df76c16SMatt Jacob 	/*
37282df76c16SMatt Jacob 	 * Add resources
37292df76c16SMatt Jacob 	 */
37302df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, chan, target_proc, wchan);
37312df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
37322df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
37332df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
37342df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
37352df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
37362df76c16SMatt Jacob 		ISP_LOCK(isp);
37372df76c16SMatt Jacob 		xpt_action(ccb);
37382df76c16SMatt Jacob 		ISP_UNLOCK(isp);
37392df76c16SMatt Jacob 	}
37402df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_CMDS; i++) {
37412df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
37422df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
37432df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
37442df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
37452df76c16SMatt Jacob 		ISP_LOCK(isp);
37462df76c16SMatt Jacob 		xpt_action(ccb);
37472df76c16SMatt Jacob 		ISP_UNLOCK(isp);
37482df76c16SMatt Jacob 	}
37492df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
37502df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
37512df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
37522df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
37532df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
37542df76c16SMatt Jacob 		ISP_LOCK(isp);
37552df76c16SMatt Jacob 		xpt_action(ccb);
37562df76c16SMatt Jacob 		ISP_UNLOCK(isp);
37572df76c16SMatt Jacob 	}
37582df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_NOTIFIES; i++) {
37592df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
37602df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
37612df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
37622df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
37632df76c16SMatt Jacob 		ISP_LOCK(isp);
37642df76c16SMatt Jacob 		xpt_action(ccb);
37652df76c16SMatt Jacob 		ISP_UNLOCK(isp);
37662df76c16SMatt Jacob 	}
37672df76c16SMatt Jacob 
37682df76c16SMatt Jacob 	/*
37692df76c16SMatt Jacob 	 * Now turn it all back on
37702df76c16SMatt Jacob 	 */
37712df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
37722df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
37732df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
37742df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_TARGET;
37752df76c16SMatt Jacob 	ISP_LOCK(isp);
37762df76c16SMatt Jacob 	xpt_action(ccb);
37772df76c16SMatt Jacob 	ISP_UNLOCK(isp);
37782df76c16SMatt Jacob 
37792df76c16SMatt Jacob 	/*
37802df76c16SMatt Jacob 	 * Okay, while things are still active, sleep...
37812df76c16SMatt Jacob 	 */
37822df76c16SMatt Jacob 	ISP_LOCK(isp);
37832df76c16SMatt Jacob 	for (;;) {
37842df76c16SMatt Jacob 		ISP_GET_PC(isp, chan, proc_active, i);
37852df76c16SMatt Jacob 		if (i == 0) {
37862df76c16SMatt Jacob 			break;
37872df76c16SMatt Jacob 		}
37882df76c16SMatt Jacob 		msleep(wchan, &isp->isp_lock, PUSER, "tsnooze", 0);
37892df76c16SMatt Jacob 	}
37902df76c16SMatt Jacob 	ISP_UNLOCK(isp);
37912df76c16SMatt Jacob 
37922df76c16SMatt Jacob out:
37932df76c16SMatt Jacob 	if (wperiph) {
37942df76c16SMatt Jacob 		cam_periph_invalidate(wperiph);
37952df76c16SMatt Jacob 	}
37962df76c16SMatt Jacob 	if (periph) {
37972df76c16SMatt Jacob 		cam_periph_invalidate(periph);
37982df76c16SMatt Jacob 	}
37992df76c16SMatt Jacob 	if (junk_data) {
38002df76c16SMatt Jacob 		free(junk_data, M_ISPTARG);
38012df76c16SMatt Jacob 	}
38022df76c16SMatt Jacob 	if (disk_data) {
38032df76c16SMatt Jacob 		free(disk_data, M_ISPTARG);
38042df76c16SMatt Jacob 	}
38052df76c16SMatt Jacob 	if (softc) {
38062df76c16SMatt Jacob 		free(softc, M_ISPTARG);
38072df76c16SMatt Jacob 	}
38082df76c16SMatt Jacob 	xpt_free_path(path);
38092df76c16SMatt Jacob 	xpt_free_path(wpath);
38102df76c16SMatt Jacob }
38112df76c16SMatt Jacob 
38122df76c16SMatt Jacob static void
38132df76c16SMatt Jacob isp_target_thread_pi(void *arg)
38142df76c16SMatt Jacob {
38152df76c16SMatt Jacob 	struct isp_spi *pi = arg;
38162df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(pi->sim), cam_sim_bus(pi->sim));
38172df76c16SMatt Jacob }
38182df76c16SMatt Jacob 
38192df76c16SMatt Jacob static void
38202df76c16SMatt Jacob isp_target_thread_fc(void *arg)
38212df76c16SMatt Jacob {
38222df76c16SMatt Jacob 	struct isp_fc *fc = arg;
38232df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(fc->sim), cam_sim_bus(fc->sim));
38242df76c16SMatt Jacob }
38252df76c16SMatt Jacob 
38262df76c16SMatt Jacob static int
38272df76c16SMatt Jacob isptarg_rwparm(uint8_t *cdb, uint8_t *dp, uint64_t dl, uint32_t offset, uint8_t **kp, uint32_t *tl, int *lp)
38282df76c16SMatt Jacob {
38292df76c16SMatt Jacob 	uint32_t cnt, curcnt;
38302df76c16SMatt Jacob 	uint64_t lba;
38312df76c16SMatt Jacob 
38322df76c16SMatt Jacob 	switch (cdb[0]) {
38332df76c16SMatt Jacob 	case WRITE_16:
38342df76c16SMatt Jacob 	case READ_16:
38352df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[10]) <<  24) |
38362df76c16SMatt Jacob 			(((uint32_t)cdb[11]) <<  16) |
38372df76c16SMatt Jacob 			(((uint32_t)cdb[12]) <<   8) |
38382df76c16SMatt Jacob 			((uint32_t)cdb[13]);
38392df76c16SMatt Jacob 
38402df76c16SMatt Jacob 		lba =	(((uint64_t)cdb[2]) << 56) |
38412df76c16SMatt Jacob 			(((uint64_t)cdb[3]) << 48) |
38422df76c16SMatt Jacob 			(((uint64_t)cdb[4]) << 40) |
38432df76c16SMatt Jacob 			(((uint64_t)cdb[5]) << 32) |
38442df76c16SMatt Jacob 			(((uint64_t)cdb[6]) << 24) |
38452df76c16SMatt Jacob 			(((uint64_t)cdb[7]) << 16) |
38462df76c16SMatt Jacob 			(((uint64_t)cdb[8]) <<  8) |
38472df76c16SMatt Jacob 			((uint64_t)cdb[9]);
38482df76c16SMatt Jacob 		break;
38492df76c16SMatt Jacob 	case WRITE_12:
38502df76c16SMatt Jacob 	case READ_12:
38512df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[6]) <<  16) |
38522df76c16SMatt Jacob 			(((uint32_t)cdb[7]) <<   8) |
38532df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
38542df76c16SMatt Jacob 
38552df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
38562df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
38572df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
38582df76c16SMatt Jacob 			((uint32_t)cdb[5]);
38592df76c16SMatt Jacob 		break;
38602df76c16SMatt Jacob 	case WRITE_10:
38612df76c16SMatt Jacob 	case READ_10:
38622df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[7]) <<  8) |
38632df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
38642df76c16SMatt Jacob 
38652df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
38662df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
38672df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
38682df76c16SMatt Jacob 			((uint32_t)cdb[5]);
38692df76c16SMatt Jacob 		break;
38702df76c16SMatt Jacob 	case WRITE_6:
38712df76c16SMatt Jacob 	case READ_6:
38722df76c16SMatt Jacob 		cnt = cdb[4];
38732df76c16SMatt Jacob 		if (cnt == 0) {
38742df76c16SMatt Jacob 			cnt = 256;
38752df76c16SMatt Jacob 		}
38762df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[1] & 0x1f) << 16) |
38772df76c16SMatt Jacob 			(((uint32_t)cdb[2]) << 8) |
38782df76c16SMatt Jacob 			((uint32_t)cdb[3]);
38792df76c16SMatt Jacob 		break;
38802df76c16SMatt Jacob 	default:
38812df76c16SMatt Jacob 		return (-1);
38822df76c16SMatt Jacob 	}
38832df76c16SMatt Jacob 
38842df76c16SMatt Jacob 	cnt <<= DISK_SHIFT;
38852df76c16SMatt Jacob 	lba <<= DISK_SHIFT;
38862df76c16SMatt Jacob 
38872df76c16SMatt Jacob 	if (offset == cnt) {
38882df76c16SMatt Jacob 		*lp = 1;
38892df76c16SMatt Jacob 		return (0);
38902df76c16SMatt Jacob 	}
38912df76c16SMatt Jacob 
38922df76c16SMatt Jacob 	if (lba + cnt > dl) {
38932df76c16SMatt Jacob 		return (-1);
38942df76c16SMatt Jacob 	}
38952df76c16SMatt Jacob 
38962df76c16SMatt Jacob 
38972df76c16SMatt Jacob 	curcnt = MAX_ISP_TARG_TRANSFER;
38982df76c16SMatt Jacob 	if (offset + curcnt >= cnt) {
38992df76c16SMatt Jacob 		curcnt = cnt - offset;
39002df76c16SMatt Jacob 		*lp = 1;
39012df76c16SMatt Jacob 	} else {
39022df76c16SMatt Jacob 		*lp = 0;
39032df76c16SMatt Jacob 	}
39042df76c16SMatt Jacob 	*tl = curcnt;
39052df76c16SMatt Jacob 	*kp = &dp[lba + offset];
39062df76c16SMatt Jacob 	return (0);
39072df76c16SMatt Jacob }
39082df76c16SMatt Jacob 
39092df76c16SMatt Jacob #endif
3910d81ba9d5SMatt Jacob #endif
3911d81ba9d5SMatt Jacob 
3912478f8a96SJustin T. Gibbs static void
39131dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
3914478f8a96SJustin T. Gibbs {
3915478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
3916e95725cbSMatt Jacob 	int bus, tgt;
39179cd7268eSMatt Jacob 	ispsoftc_t *isp;
3918478f8a96SJustin T. Gibbs 
3919478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
39209cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
3921e95725cbSMatt Jacob 	bus = cam_sim_bus(sim);
3922e95725cbSMatt Jacob 	tgt = xpt_path_target_id(path);
3923e95725cbSMatt Jacob 
3924478f8a96SJustin T. Gibbs 	switch (code) {
3925478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
3926ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
39271dae40ebSMatt Jacob 			uint16_t oflags, nflags;
39282df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
3929478f8a96SJustin T. Gibbs 
393041ed683eSMatt Jacob 			if (tgt >= 0) {
39319ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
3932a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
39339ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
3934a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
3935478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
3936478f8a96SJustin T. Gibbs 				}
3937a1bc34c6SMatt Jacob #else
3938a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
3939a1bc34c6SMatt Jacob #endif
39409ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
39419ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
3942478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
39432df76c16SMatt Jacob 				sdp->update = 1;
39442df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
39459ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
3946478f8a96SJustin T. Gibbs 			}
394741ed683eSMatt Jacob 		}
3948478f8a96SJustin T. Gibbs 		break;
3949478f8a96SJustin T. Gibbs 	default:
39503c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
3951478f8a96SJustin T. Gibbs 		break;
3952478f8a96SJustin T. Gibbs 	}
3953478f8a96SJustin T. Gibbs }
3954478f8a96SJustin T. Gibbs 
3955478f8a96SJustin T. Gibbs static void
3956c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
3957478f8a96SJustin T. Gibbs {
39589cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
395910365e5aSMatt Jacob 	uint32_t isr;
396010365e5aSMatt Jacob 	uint16_t sema, mbox;
3961126ec864SMatt Jacob 
3962126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3963126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
3964126ec864SMatt Jacob 	}
3965478f8a96SJustin T. Gibbs }
3966478f8a96SJustin T. Gibbs 
3967ab6c4b31SMatt Jacob 
39682df76c16SMatt Jacob static void
39692df76c16SMatt Jacob isp_watchdog(void *arg)
3970cc8df88bSMatt Jacob {
39712df76c16SMatt Jacob 	struct ccb_scsiio *xs = arg;
39722df76c16SMatt Jacob 	ispsoftc_t *isp;
3973e95725cbSMatt Jacob 	uint32_t ohandle = ISP_HANDLE_FREE, handle;
3974b85389e1SMatt Jacob 
39752df76c16SMatt Jacob 	isp = XS_ISP(xs);
39762df76c16SMatt Jacob 
3977cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
3978e95725cbSMatt Jacob 
3979e95725cbSMatt Jacob 	if (handle != ISP_HANDLE_FREE && !XS_CMD_WPEND_P(xs)) {
3980e95725cbSMatt Jacob 		isp_xs_prt(isp, xs, ISP_LOGWARN, "first watchdog (handle 0x%x) timed out- deferring for grace period", handle);
3981e95725cbSMatt Jacob 		callout_reset(&PISP_PCMD(xs)->wdog, 2 * hz, isp_watchdog, xs);
3982e95725cbSMatt Jacob 		XS_CMD_S_WPEND(xs);
3983e95725cbSMatt Jacob 		return;
3984e95725cbSMatt Jacob 	}
3985e95725cbSMatt Jacob 	XS_C_TACTIVE(xs);
3986e95725cbSMatt Jacob 
3987e95725cbSMatt Jacob 	/*
3988e95725cbSMatt Jacob 	 * Hand crank the interrupt code just to be sure the command isn't stuck somewhere.
3989e95725cbSMatt Jacob 	 */
3990e95725cbSMatt Jacob 	if (handle != ISP_HANDLE_FREE) {
3991e95725cbSMatt Jacob 		uint32_t isr;
3992e95725cbSMatt Jacob 		uint16_t sema, mbox;
3993e95725cbSMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox) != 0) {
3994e95725cbSMatt Jacob 			isp_intr(isp, isr, sema, mbox);
3995e95725cbSMatt Jacob 		}
3996e95725cbSMatt Jacob 		ohandle = handle;
3997e95725cbSMatt Jacob 		handle = isp_find_handle(isp, xs);
3998e95725cbSMatt Jacob 	}
3999c8b8a2c4SMatt Jacob 	if (handle != ISP_HANDLE_FREE) {
40001fcf5debSMatt Jacob 		/*
4001c8b8a2c4SMatt Jacob 		 * Try and make sure the command is really dead before
4002c8b8a2c4SMatt Jacob 		 * we release the handle (and DMA resources) for reuse.
4003c8b8a2c4SMatt Jacob 		 *
4004c8b8a2c4SMatt Jacob 		 * If we are successful in aborting the command then
4005c8b8a2c4SMatt Jacob 		 * we're done here because we'll get the command returned
4006c8b8a2c4SMatt Jacob 		 * back separately.
40071fcf5debSMatt Jacob 		 */
4008c8b8a2c4SMatt Jacob 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) {
4009c8b8a2c4SMatt Jacob 			return;
4010c8b8a2c4SMatt Jacob 		}
40111fcf5debSMatt Jacob 
40121fcf5debSMatt Jacob 		/*
4013c8b8a2c4SMatt Jacob 		 * Note that after calling the above, the command may in
4014c8b8a2c4SMatt Jacob 		 * fact have been completed.
4015c8b8a2c4SMatt Jacob 		 */
4016c8b8a2c4SMatt Jacob 		xs = isp_find_xs(isp, handle);
4017c8b8a2c4SMatt Jacob 
4018c8b8a2c4SMatt Jacob 		/*
4019c8b8a2c4SMatt Jacob 		 * If the command no longer exists, then we won't
4020c8b8a2c4SMatt Jacob 		 * be able to find the xs again with this handle.
4021c8b8a2c4SMatt Jacob 		 */
4022c8b8a2c4SMatt Jacob 		if (xs == NULL) {
4023c8b8a2c4SMatt Jacob 			return;
4024c8b8a2c4SMatt Jacob 		}
4025c8b8a2c4SMatt Jacob 
4026c8b8a2c4SMatt Jacob 		/*
4027c8b8a2c4SMatt Jacob 		 * After this point, the command is really dead.
40281fcf5debSMatt Jacob 		 */
4029f6e75de2SMatt Jacob 		if (XS_XFRLEN(xs)) {
4030f6e75de2SMatt Jacob 			ISP_DMAFREE(isp, xs, handle);
4031f6e75de2SMatt Jacob 		}
4032cc8df88bSMatt Jacob 		isp_destroy_handle(isp, handle);
4033c8b8a2c4SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle);
4034cc8df88bSMatt Jacob 		XS_SETERR(xs, CAM_CMD_TIMEOUT);
4035e95725cbSMatt Jacob 		isp_prt_endcmd(isp, xs);
4036cc8df88bSMatt Jacob 		isp_done(xs);
4037e95725cbSMatt Jacob 	} else {
4038e95725cbSMatt Jacob 		if (ohandle != ISP_HANDLE_FREE) {
4039e95725cbSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle 0x%x, recovered during interrupt", __func__, ohandle);
4040e95725cbSMatt Jacob 		} else {
4041e95725cbSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle already free", __func__);
4042e95725cbSMatt Jacob 		}
4043b85389e1SMatt Jacob 	}
4044f7c631bcSMatt Jacob }
4045f7c631bcSMatt Jacob 
4046f7c631bcSMatt Jacob static void
40472df76c16SMatt Jacob isp_make_here(ispsoftc_t *isp, int chan, int tgt)
4048f7c631bcSMatt Jacob {
4049ffcf6651SMatt Jacob 	union ccb *ccb;
40502df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
40512df76c16SMatt Jacob 
40522df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
40532df76c16SMatt Jacob 		return;
40542df76c16SMatt Jacob 	}
40552df76c16SMatt Jacob 
4056ffcf6651SMatt Jacob 	/*
40570e85f214SMatt Jacob 	 * Allocate a CCB, create a wildcard path for this target and schedule a rescan.
4058ffcf6651SMatt Jacob 	 */
40598008a935SScott Long 	ccb = xpt_alloc_ccb_nowait();
4060ffcf6651SMatt Jacob 	if (ccb == NULL) {
40612df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan);
4062ffcf6651SMatt Jacob 		return;
4063ffcf6651SMatt Jacob 	}
40640e85f214SMatt Jacob 	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
4065ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
4066ffcf6651SMatt Jacob 		xpt_free_ccb(ccb);
4067ffcf6651SMatt Jacob 		return;
4068ffcf6651SMatt Jacob 	}
4069ffcf6651SMatt Jacob 	xpt_rescan(ccb);
4070ffcf6651SMatt Jacob }
4071ffcf6651SMatt Jacob 
4072ffcf6651SMatt Jacob static void
40732df76c16SMatt Jacob isp_make_gone(ispsoftc_t *isp, int chan, int tgt)
4074ffcf6651SMatt Jacob {
4075ffcf6651SMatt Jacob 	struct cam_path *tp;
40762df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
40772df76c16SMatt Jacob 
40782df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
40792df76c16SMatt Jacob 		return;
40802df76c16SMatt Jacob 	}
40812df76c16SMatt Jacob 	if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
4082ffcf6651SMatt Jacob 		xpt_async(AC_LOST_DEVICE, tp, NULL);
4083ffcf6651SMatt Jacob 		xpt_free_path(tp);
4084f7c631bcSMatt Jacob 	}
4085f7c631bcSMatt Jacob }
4086f7c631bcSMatt Jacob 
4087f7c631bcSMatt Jacob /*
4088f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
4089f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
4090f7c631bcSMatt Jacob  * gone away.
4091f7c631bcSMatt Jacob  *
4092f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
4093f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
4094f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
4095f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
4096f7c631bcSMatt Jacob  */
4097f7c631bcSMatt Jacob static void
4098f7c631bcSMatt Jacob isp_gdt(void *arg)
4099f7c631bcSMatt Jacob {
41002df76c16SMatt Jacob 	struct isp_fc *fc = arg;
4101de461933SMatt Jacob 	taskqueue_enqueue(taskqueue_thread, &fc->gtask);
4102de461933SMatt Jacob }
4103de461933SMatt Jacob 
4104de461933SMatt Jacob static void
4105de461933SMatt Jacob isp_gdt_task(void *arg, int pending)
4106de461933SMatt Jacob {
4107de461933SMatt Jacob 	struct isp_fc *fc = arg;
41082df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
41092df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
4110f7c631bcSMatt Jacob 	fcportdb_t *lp;
4111f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
4112f7c631bcSMatt Jacob 
4113de461933SMatt Jacob 	ISP_LOCK(isp);
4114de461933SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan);
4115f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
41162df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
4117f7c631bcSMatt Jacob 
4118f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
4119f7c631bcSMatt Jacob 			continue;
4120f7c631bcSMatt Jacob 		}
41212df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
4122f7c631bcSMatt Jacob 			continue;
4123f7c631bcSMatt Jacob 		}
4124427fa8f9SMatt Jacob 		if (lp->gone_timer != 0) {
4125de461933SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG, "%s: Chan %d more to do for target %u (timer=%u)", __func__, chan, lp->dev_map_idx - 1, lp->gone_timer);
4126427fa8f9SMatt Jacob 			lp->gone_timer -= 1;
4127f7c631bcSMatt Jacob 			more_to_do++;
4128f7c631bcSMatt Jacob 			continue;
4129f7c631bcSMatt Jacob 		}
41302df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
41312df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
41322df76c16SMatt Jacob 		lp->dev_map_idx = 0;
4133f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
41342df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout");
41352df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
4136f7c631bcSMatt Jacob 	}
4137a01f5aebSMatt Jacob 	if (fc->ready) {
4138f7c631bcSMatt Jacob 		if (more_to_do) {
41392df76c16SMatt Jacob 			callout_reset(&fc->gdt, hz, isp_gdt, fc);
4140f7c631bcSMatt Jacob 		} else {
4141de461933SMatt Jacob 			callout_deactivate(&fc->gdt);
4142de461933SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG, "Chan %d Stopping Gone Device Timer @ %lu", chan, (unsigned long) time_uptime);
4143a01f5aebSMatt Jacob 		}
4144f7c631bcSMatt Jacob 	}
4145de461933SMatt Jacob 	ISP_UNLOCK(isp);
4146f7c631bcSMatt Jacob }
4147f7c631bcSMatt Jacob 
4148f7c631bcSMatt Jacob /*
4149f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
4150f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
4151f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
4152f7c631bcSMatt Jacob  *
4153f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
4154f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
4155f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
4156f7c631bcSMatt Jacob  */
4157f7c631bcSMatt Jacob static void
4158f7c631bcSMatt Jacob isp_ldt(void *arg)
4159f7c631bcSMatt Jacob {
41602df76c16SMatt Jacob 	struct isp_fc *fc = arg;
4161de461933SMatt Jacob 	taskqueue_enqueue(taskqueue_thread, &fc->ltask);
4162de461933SMatt Jacob }
4163de461933SMatt Jacob 
4164de461933SMatt Jacob static void
4165de461933SMatt Jacob isp_ldt_task(void *arg, int pending)
4166de461933SMatt Jacob {
4167de461933SMatt Jacob 	struct isp_fc *fc = arg;
41682df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
41692df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
4170f7c631bcSMatt Jacob 	fcportdb_t *lp;
4171e95725cbSMatt Jacob 	int dbidx, tgt, i;
4172f7c631bcSMatt Jacob 
4173de461933SMatt Jacob 	ISP_LOCK(isp);
41742df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime);
4175de461933SMatt Jacob 	callout_deactivate(&fc->ldt);
41760a70657fSMatt Jacob 
4177f7c631bcSMatt Jacob 	/*
4178f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
4179f7c631bcSMatt Jacob 	 */
4180f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
41812df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
4182f7c631bcSMatt Jacob 
4183f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
4184f7c631bcSMatt Jacob 			continue;
4185f7c631bcSMatt Jacob 		}
41862df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
4187f7c631bcSMatt Jacob 			continue;
4188f7c631bcSMatt Jacob 		}
4189f7c631bcSMatt Jacob 
4190f7c631bcSMatt Jacob 		/*
4191f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
4192f7c631bcSMatt Jacob 		 */
4193f7c631bcSMatt Jacob 
4194e95725cbSMatt Jacob 
4195e95725cbSMatt Jacob 		for (i = 0; i < isp->isp_maxcmds; i++) {
4196e95725cbSMatt Jacob 			struct ccb_scsiio *xs;
4197e95725cbSMatt Jacob 
4198e95725cbSMatt Jacob 			if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) {
4199e95725cbSMatt Jacob 				continue;
4200e95725cbSMatt Jacob 			}
4201e95725cbSMatt Jacob 			if ((xs = isp->isp_xflist[i].cmd) == NULL) {
4202e95725cbSMatt Jacob 				continue;
4203e95725cbSMatt Jacob                         }
4204e95725cbSMatt Jacob 			if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) {
4205e95725cbSMatt Jacob 				continue;
4206e95725cbSMatt Jacob 			}
4207e95725cbSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "command handle 0x%08x for %d.%d.%d orphaned by loop down timeout",
4208e95725cbSMatt Jacob 			    isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs));
4209e95725cbSMatt Jacob 		}
4210e95725cbSMatt Jacob 
4211f7c631bcSMatt Jacob 		/*
4212f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
4213f7c631bcSMatt Jacob 		 */
4214f7c631bcSMatt Jacob 		lp->reserved = 1;
4215f7c631bcSMatt Jacob 
4216f7c631bcSMatt Jacob 		/*
4217f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
4218f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
4219f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
4220f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
4221f7c631bcSMatt Jacob 		 */
4222f7c631bcSMatt Jacob 
42232df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
42242df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
42252df76c16SMatt Jacob 		lp->dev_map_idx = 0;
42262df76c16SMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
42272df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout");
42282df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
4229f7c631bcSMatt Jacob 	}
4230f7c631bcSMatt Jacob 
4231e95725cbSMatt Jacob 	if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) {
4232e95725cbSMatt Jacob 		isp_unfreeze_loopdown(isp, chan);
4233e95725cbSMatt Jacob 	}
4234f7c631bcSMatt Jacob 	/*
4235f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
4236f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
4237f7c631bcSMatt Jacob 	 */
42382df76c16SMatt Jacob 	fc->loop_dead = 1;
42392df76c16SMatt Jacob 	fc->loop_down_time = fc->loop_down_limit+1;
42402df76c16SMatt Jacob 	wakeup(fc);
4241e95725cbSMatt Jacob 	ISP_UNLOCK(isp);
4242cc8df88bSMatt Jacob }
4243cc8df88bSMatt Jacob 
42445d571944SMatt Jacob static void
42455d571944SMatt Jacob isp_kthread(void *arg)
42465d571944SMatt Jacob {
42472df76c16SMatt Jacob 	struct isp_fc *fc = arg;
42482df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
42492df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
4250f7c631bcSMatt Jacob 	int slp = 0;
4251a01f5aebSMatt Jacob 
42520a70657fSMatt Jacob 	mtx_lock(&isp->isp_osinfo.lock);
42532df76c16SMatt Jacob 
42545d571944SMatt Jacob 	for (;;) {
4255e95725cbSMatt Jacob 		int lb, lim;
4256fdeb9f2fSMatt Jacob 
42572df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan);
42582df76c16SMatt Jacob 		lb = isp_fc_runstate(isp, chan, 250000);
42592df76c16SMatt Jacob 
42602df76c16SMatt Jacob 		/*
42612df76c16SMatt Jacob 		 * Our action is different based upon whether we're supporting
42622df76c16SMatt Jacob 		 * Initiator mode or not. If we are, we might freeze the simq
42632df76c16SMatt Jacob 		 * when loop is down and set all sorts of different delays to
42642df76c16SMatt Jacob 		 * check again.
42652df76c16SMatt Jacob 		 *
42662df76c16SMatt Jacob 		 * If not, we simply just wait for loop to come up.
42672df76c16SMatt Jacob 		 */
42684ecb1d4aSMatt Jacob 		if (lb && (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR)) {
4269f7c631bcSMatt Jacob 			/*
4270f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
4271f7c631bcSMatt Jacob 			 */
42722df76c16SMatt Jacob 			fc->loop_down_time += slp;
427310365e5aSMatt Jacob 
427410365e5aSMatt Jacob 			if (lb < 0) {
42752df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time);
427610365e5aSMatt Jacob 			} else {
42772df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC got to %d (down count %d)", __func__, chan, lb, fc->loop_down_time);
4278f44257c2SMatt Jacob 			}
427910365e5aSMatt Jacob 
428010365e5aSMatt Jacob 			/*
428110365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
4282f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
4283f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
4284f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
428510365e5aSMatt Jacob 			 */
42862df76c16SMatt Jacob 			if (FCPARAM(isp, chan)->loop_seen_once == 0) {
4287f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
428810365e5aSMatt Jacob 			} else {
42892df76c16SMatt Jacob 				lim = fc->loop_down_limit;
4290f7c631bcSMatt Jacob 			}
42912df76c16SMatt Jacob 			if (fc->loop_down_time >= lim) {
42922df76c16SMatt Jacob 				isp_freeze_loopdown(isp, chan, "loop limit hit");
4293f7c631bcSMatt Jacob 				slp = 0;
42942df76c16SMatt Jacob 			} else if (fc->loop_down_time < 10) {
429510365e5aSMatt Jacob 				slp = 1;
42962df76c16SMatt Jacob 			} else if (fc->loop_down_time < 30) {
4297f7c631bcSMatt Jacob 				slp = 5;
42982df76c16SMatt Jacob 			} else if (fc->loop_down_time < 60) {
4299f7c631bcSMatt Jacob 				slp = 10;
43002df76c16SMatt Jacob 			} else if (fc->loop_down_time < 120) {
4301f7c631bcSMatt Jacob 				slp = 20;
4302f7c631bcSMatt Jacob 			} else {
4303f7c631bcSMatt Jacob 				slp = 30;
4304f44257c2SMatt Jacob 			}
430510365e5aSMatt Jacob 
43062df76c16SMatt Jacob 		} else if (lb) {
43072df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan);
43082df76c16SMatt Jacob 			fc->loop_down_time += slp;
43092df76c16SMatt Jacob 			slp = 60;
431010365e5aSMatt Jacob 		} else {
43112df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan);
43122df76c16SMatt Jacob 			fc->loop_down_time = 0;
431310365e5aSMatt Jacob 			slp = 0;
43145d571944SMatt Jacob 		}
4315fdeb9f2fSMatt Jacob 
43162df76c16SMatt Jacob 
4317f44257c2SMatt Jacob 		/*
43182df76c16SMatt Jacob 		 * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it
43192df76c16SMatt Jacob 		 * now so that CAM can start sending us commands.
43202df76c16SMatt Jacob 		 *
43212df76c16SMatt Jacob 		 * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again
43222df76c16SMatt Jacob 		 * or kill the commands, as appropriate.
4323f44257c2SMatt Jacob 		 */
43242df76c16SMatt Jacob 
43252df76c16SMatt Jacob 		if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) {
4326e95725cbSMatt Jacob 			isp_unfreeze_loopdown(isp, chan);
43272df76c16SMatt Jacob 		}
43282df76c16SMatt Jacob 
43292df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp);
43302df76c16SMatt Jacob 
43312df76c16SMatt Jacob 		msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz);
43322df76c16SMatt Jacob 
433310365e5aSMatt Jacob 		/*
433410365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
433510365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
433610365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
433710365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
433810365e5aSMatt Jacob 		 * to settle.
433910365e5aSMatt Jacob 		 */
43402df76c16SMatt Jacob 		if (slp == 0 && fc->hysteresis) {
43412df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz);
43424962e51bSMatt Jacob 			mtx_unlock(&isp->isp_osinfo.lock);
43434962e51bSMatt Jacob 			pause("ispt", fc->hysteresis * hz);
43444962e51bSMatt Jacob 			mtx_lock(&isp->isp_osinfo.lock);
434510365e5aSMatt Jacob 		}
43465d571944SMatt Jacob 	}
43470a70657fSMatt Jacob 	mtx_unlock(&isp->isp_osinfo.lock);
43485d571944SMatt Jacob }
43495d571944SMatt Jacob 
4350cc8df88bSMatt Jacob static void
4351c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
4352478f8a96SJustin T. Gibbs {
43530a70657fSMatt Jacob 	int bus, tgt, ts, error, lim;
43549cd7268eSMatt Jacob 	ispsoftc_t *isp;
43554663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
4356478f8a96SJustin T. Gibbs 
4357478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
4358478f8a96SJustin T. Gibbs 
43599cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
43602df76c16SMatt Jacob 	mtx_assert(&isp->isp_lock, MA_OWNED);
43612df76c16SMatt Jacob 
43622df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE && ccb->ccb_h.func_code == XPT_SCSI_IO) {
436357c801f5SMatt Jacob 		isp_init(isp);
436457c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
436557c801f5SMatt Jacob 			/*
436657c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
436757c801f5SMatt Jacob 			 */
4368b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
43690470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
437057c801f5SMatt Jacob 			xpt_done(ccb);
437157c801f5SMatt Jacob 			return;
437257c801f5SMatt Jacob 		}
437357c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
437457c801f5SMatt Jacob 	}
4375b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
43760a70657fSMatt Jacob 	ISP_PCMD(ccb) = NULL;
43775d571944SMatt Jacob 
4378478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
4379478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
43802df76c16SMatt Jacob 		bus = XS_CHANNEL(ccb);
4381478f8a96SJustin T. Gibbs 		/*
4382478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
4383478f8a96SJustin T. Gibbs 		 */
4384478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
4385478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
4386478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
4387478f8a96SJustin T. Gibbs 				xpt_done(ccb);
4388478f8a96SJustin T. Gibbs 				break;
4389478f8a96SJustin T. Gibbs 			}
4390478f8a96SJustin T. Gibbs 		}
43910470d791SMatt Jacob #ifdef	DIAGNOSTIC
43920470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
4393dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
4394478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
43950470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
4396dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
4397478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
4398478f8a96SJustin T. Gibbs 		}
4399478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
4400478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4401478f8a96SJustin T. Gibbs 			break;
4402478f8a96SJustin T. Gibbs 		}
44030470d791SMatt Jacob #endif
44040a70657fSMatt Jacob 		ccb->csio.scsi_status = SCSI_STATUS_OK;
44050a70657fSMatt Jacob 		if (isp_get_pcmd(isp, ccb)) {
44060a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "out of PCMDs");
44070a70657fSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
44082df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
44090a70657fSMatt Jacob 			xpt_done(ccb);
44100a70657fSMatt Jacob 			break;
44110a70657fSMatt Jacob 		}
4412b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
44130470d791SMatt Jacob 		switch (error) {
4414478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
4415f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
4416478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
44170a70657fSMatt Jacob 			if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) {
44180a70657fSMatt Jacob 				break;
4419d69a5f7dSMatt Jacob 			}
44200a70657fSMatt Jacob 			ts = ccb->ccb_h.timeout;
44210a70657fSMatt Jacob 			if (ts == CAM_TIME_DEFAULT) {
44220a70657fSMatt Jacob 				ts = 60*1000;
4423cc8df88bSMatt Jacob 			}
44240a70657fSMatt Jacob 			ts = isp_mstohz(ts);
4425e95725cbSMatt Jacob 			XS_S_TACTIVE(ccb);
44262df76c16SMatt Jacob 			callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb);
4427478f8a96SJustin T. Gibbs 			break;
44280470d791SMatt Jacob 		case CMD_RQLATER:
4429f44257c2SMatt Jacob 			/*
44302df76c16SMatt Jacob 			 * We get this result for FC devices if the loop state isn't ready yet
44312df76c16SMatt Jacob 			 * or if the device in question has gone zombie on us.
44322df76c16SMatt Jacob 			 *
44332df76c16SMatt Jacob 			 * If we've never seen Loop UP at all, we requeue this request and wait
44342df76c16SMatt Jacob 			 * for the initial loop up delay to expire.
443510365e5aSMatt Jacob 			 */
44362df76c16SMatt Jacob 			lim = ISP_FC_PC(isp, bus)->loop_down_limit;
44372df76c16SMatt Jacob 			if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) {
44382df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->loop_seen_once == 0) {
44392df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGDEBUG0, "%d.%d loop not seen yet @ %lu", XS_TGT(ccb), XS_LUN(ccb), (unsigned long) time_uptime);
4440f7c631bcSMatt Jacob 				} else {
44412df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGDEBUG0, "%d.%d downtime (%d) > lim (%d)", XS_TGT(ccb), XS_LUN(ccb), ISP_FC_PC(isp, bus)->loop_down_time, lim);
4442f7c631bcSMatt Jacob 				}
44432df76c16SMatt Jacob 				ccb->ccb_h.status = CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
4444f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
44450a70657fSMatt Jacob 				isp_free_pcmd(isp, ccb);
4446f44257c2SMatt Jacob 				xpt_done(ccb);
4447f44257c2SMatt Jacob 				break;
4448f44257c2SMatt Jacob 			}
44492df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
4450f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
44512df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
4452f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
44530a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
4454478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4455478f8a96SJustin T. Gibbs 			break;
44560470d791SMatt Jacob 		case CMD_EAGAIN:
44570a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
44582df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
44592df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0);
44602df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
4461478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4462478f8a96SJustin T. Gibbs 			break;
44630470d791SMatt Jacob 		case CMD_COMPLETE:
44640470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
44650470d791SMatt Jacob 			break;
44660470d791SMatt Jacob 		default:
44672df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "What's this? 0x%x at %d in file %s", error, __LINE__, __FILE__);
4468b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
44690a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
44700470d791SMatt Jacob 			xpt_done(ccb);
4471478f8a96SJustin T. Gibbs 		}
4472478f8a96SJustin T. Gibbs 		break;
4473478f8a96SJustin T. Gibbs 
4474d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
44752df76c16SMatt Jacob 	case XPT_EN_LUN:		/* Enable/Disable LUN as a target */
44762df76c16SMatt Jacob 		if (ccb->cel.enable) {
44772df76c16SMatt Jacob 			isp_enable_lun(isp, ccb);
44782df76c16SMatt Jacob 		} else {
44792df76c16SMatt Jacob 			isp_disable_lun(isp, ccb);
448067ff51f1SMatt Jacob 		}
448167ff51f1SMatt Jacob 		break;
4482ae5db118SMatt Jacob 	case XPT_IMMED_NOTIFY:
44832df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
4484d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
4485d81ba9d5SMatt Jacob 	{
44862df76c16SMatt Jacob 		tstate_t *tptr = get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
4487d81ba9d5SMatt Jacob 		if (tptr == NULL) {
44882df76c16SMatt Jacob 			tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
44892df76c16SMatt Jacob 		}
44902df76c16SMatt Jacob 		if (tptr == NULL) {
44912df76c16SMatt Jacob 			const char *str;
44922df76c16SMatt Jacob 			uint32_t tag;
44932df76c16SMatt Jacob 
44942df76c16SMatt Jacob 			if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
44952df76c16SMatt Jacob 				str = "XPT_IMMEDIATE_NOTIFY";
44962df76c16SMatt Jacob 				tag = ccb->cin1.seq_id;
44972df76c16SMatt Jacob 			} else {
44982df76c16SMatt Jacob 				tag = ccb->atio.tag_id;
44992df76c16SMatt Jacob 				str = "XPT_ACCEPT_TARGET_IO";
45002df76c16SMatt Jacob 			}
45012df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] no state pointer found for %s\n", __func__, tag, str);
45022df76c16SMatt Jacob 			dump_tstates(isp, XS_CHANNEL(ccb));
45032df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
4504d81ba9d5SMatt Jacob 			break;
4505d81ba9d5SMatt Jacob 		}
4506f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
4507f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
4508570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
4509570c7a3fSMatt Jacob 
4510d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
45112df76c16SMatt Jacob 			if (ccb->atio.tag_id) {
45122df76c16SMatt Jacob 				atio_private_data_t *atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id);
45132df76c16SMatt Jacob 				if (atp) {
45142df76c16SMatt Jacob 					isp_put_atpd(isp, tptr, atp);
45152df76c16SMatt Jacob 				}
45162df76c16SMatt Jacob 			}
4517570c7a3fSMatt Jacob 			tptr->atio_count++;
45182df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle);
45192df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n",
4520e2873b76SMatt Jacob 			    ccb->atio.tag_id, tptr->atio_count);
45212df76c16SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
45222df76c16SMatt Jacob 			if (ccb->cin1.tag_id) {
45232df76c16SMatt Jacob 				inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id);
45242df76c16SMatt Jacob 				if (ntp) {
45252df76c16SMatt Jacob 					isp_put_ntpd(isp, tptr, ntp);
45262df76c16SMatt Jacob 				}
45272df76c16SMatt Jacob 			}
4528746e9c85SMatt Jacob 			tptr->inot_count++;
45292df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
45302df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
4531e2873b76SMatt Jacob 			    ccb->cin1.seq_id, tptr->inot_count);
4532ae5db118SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
4533ae5db118SMatt Jacob 			tptr->inot_count++;
4534ae5db118SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
4535ae5db118SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
4536e2873b76SMatt Jacob 			    ccb->cin1.seq_id, tptr->inot_count);
4537d81ba9d5SMatt Jacob 		}
4538d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
4539d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
4540d81ba9d5SMatt Jacob 		break;
4541d81ba9d5SMatt Jacob 	}
4542ae5db118SMatt Jacob 	case XPT_NOTIFY_ACK:
4543ae5db118SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4544ae5db118SMatt Jacob 		break;
45452df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:		/* notify ack */
4546d81ba9d5SMatt Jacob 	{
45472df76c16SMatt Jacob 		tstate_t *tptr;
45482df76c16SMatt Jacob 		inot_private_data_t *ntp;
45492df76c16SMatt Jacob 
45502df76c16SMatt Jacob 		/*
45512df76c16SMatt Jacob 		 * XXX: Because we cannot guarantee that the path information in the notify acknowledge ccb
45522df76c16SMatt Jacob 		 * XXX: matches that for the immediate notify, we have to *search* for the notify structure
45532df76c16SMatt Jacob 		 */
45542df76c16SMatt Jacob 		/*
45552df76c16SMatt Jacob 		 * All the relevant path information is in the associated immediate notify
45562df76c16SMatt Jacob 		 */
45572df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] NOTIFY ACKNOWLEDGE for 0x%x seen\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id);
45582df76c16SMatt Jacob 		ntp = get_ntp_from_tagdata(isp, ccb->cna2.tag_id, ccb->cna2.seq_id, &tptr);
45592df76c16SMatt Jacob 		if (ntp == NULL) {
45602df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] XPT_NOTIFY_ACKNOWLEDGE of 0x%x cannot find ntp private data\n", __func__,
45612df76c16SMatt Jacob 			     ccb->cna2.tag_id, ccb->cna2.seq_id);
45622df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
45632df76c16SMatt Jacob 			xpt_done(ccb);
4564d81ba9d5SMatt Jacob 			break;
4565d81ba9d5SMatt Jacob 		}
45662df76c16SMatt Jacob 		if (isp_handle_platform_target_notify_ack(isp, &ntp->rd.nt)) {
45672df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
45682df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
45692df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
45702df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
45712df76c16SMatt Jacob 			break;
45722df76c16SMatt Jacob 		}
45732df76c16SMatt Jacob 		isp_put_ntpd(isp, tptr, ntp);
45742df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
45752df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
45762df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: [0x%x] calling xpt_done for tag 0x%x\n", __func__, ccb->cna2.tag_id, ccb->cna2.seq_id);
45772df76c16SMatt Jacob 		xpt_done(ccb);
45782df76c16SMatt Jacob 		break;
45792df76c16SMatt Jacob 	}
45802df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
45812df76c16SMatt Jacob 		isp_target_start_ctio(isp, ccb);
45822df76c16SMatt Jacob 		break;
4583d81ba9d5SMatt Jacob #endif
4584478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
4585d81ba9d5SMatt Jacob 
4586d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
4587d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
4588d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
4589d81ba9d5SMatt Jacob 
45902df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt);
4591478f8a96SJustin T. Gibbs 		if (error) {
4592478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4593478f8a96SJustin T. Gibbs 		} else {
4594478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
4595478f8a96SJustin T. Gibbs 		}
4596478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4597478f8a96SJustin T. Gibbs 		break;
4598478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
4599d81ba9d5SMatt Jacob 	{
4600d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
4601d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
4602d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4603d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
460445210a25SAlexander Motin 			isp_target_mark_aborted(isp, ccb);
4605d81ba9d5SMatt Jacob 			break;
4606d81ba9d5SMatt Jacob #endif
4607d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
4608478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
4609478f8a96SJustin T. Gibbs 			if (error) {
4610d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
4611478f8a96SJustin T. Gibbs 			} else {
4612478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
4613478f8a96SJustin T. Gibbs 			}
4614d81ba9d5SMatt Jacob 			break;
4615d81ba9d5SMatt Jacob 		default:
4616d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
4617d81ba9d5SMatt Jacob 			break;
4618d81ba9d5SMatt Jacob 		}
46191c0a1eb2SMatt Jacob 		/*
46201c0a1eb2SMatt Jacob 		 * This is not a queued CCB, so the caller expects it to be
46211c0a1eb2SMatt Jacob 		 * complete when control is returned.
46221c0a1eb2SMatt Jacob 		 */
4623478f8a96SJustin T. Gibbs 		break;
4624d81ba9d5SMatt Jacob 	}
4625ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
4626478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
4627478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
46289ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
46299ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
46309ce9bdafSMatt Jacob 			xpt_done(ccb);
46319ce9bdafSMatt Jacob 			break;
46329ce9bdafSMatt Jacob 		}
4633478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
4634805e1f82SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
46352df76c16SMatt Jacob 		if (IS_SCSI(isp)) {
46362df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
46372df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
46382df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
46391dae40ebSMatt Jacob 			uint16_t *dptr;
4640ab163f5fSMatt Jacob 
4641b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
4642b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
4643b61386a4SMatt Jacob 				xpt_done(ccb);
4644b61386a4SMatt Jacob 				break;
4645b61386a4SMatt Jacob 			}
4646b61386a4SMatt Jacob 
4647ab163f5fSMatt Jacob 			/*
46489ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
4649ab163f5fSMatt Jacob 			 * so any request to change settings just gets
4650ab163f5fSMatt Jacob 			 * vectored to that location.
4651ab163f5fSMatt Jacob 			 */
46529ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
4653ab163f5fSMatt Jacob 
4654ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
4655ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
4656ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
4657ab163f5fSMatt Jacob 				else
4658ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
4659ab163f5fSMatt Jacob 			}
4660ab163f5fSMatt Jacob 
4661ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
4662ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
4663ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
4664ab163f5fSMatt Jacob 				else
4665ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
4666ab163f5fSMatt Jacob 			}
4667ab163f5fSMatt Jacob 
4668ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
4669ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
4670ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
4671ab163f5fSMatt Jacob 				else
4672ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
4673ab163f5fSMatt Jacob 			}
4674ab163f5fSMatt Jacob 
4675ab163f5fSMatt Jacob 			/*
4676ab163f5fSMatt Jacob 			 * XXX: FIX ME
4677ab163f5fSMatt Jacob 			 */
46782df76c16SMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && (spi->valid & CTS_SPI_VALID_SYNC_RATE) && (spi->sync_period && spi->sync_offset)) {
4679ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
46809ce9bdafSMatt Jacob 				/*
46819ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
46829ce9bdafSMatt Jacob 				 */
46832df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_period = spi->sync_period;
46842df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_offset = spi->sync_offset;
4685ab163f5fSMatt Jacob 			} else {
4686ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
4687ab163f5fSMatt Jacob 			}
46882df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "SET (%d.%d.%d) to flags %x off %x per %x", bus, tgt, cts->ccb_h.target_lun, sdp->isp_devparam[tgt].goal_flags,
46892df76c16SMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset, sdp->isp_devparam[tgt].goal_period);
4690478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
46912df76c16SMatt Jacob 			sdp->update = 1;
4692478f8a96SJustin T. Gibbs 		}
4693478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4694478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4695478f8a96SJustin T. Gibbs 		break;
4696478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
4697478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
4698478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
46992df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
4700ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
47012df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
47022df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
47032df76c16SMatt Jacob 			struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc;
470495f7dfb2SMatt Jacob 			unsigned int hdlidx;
4705478f8a96SJustin T. Gibbs 
4706ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4707ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4708ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
4709ab163f5fSMatt Jacob 			cts->transport_version = 0;
4710ab163f5fSMatt Jacob 
47119b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
47129b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
4713ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
4714ab163f5fSMatt Jacob 			fc->bitrate = 100000;
4715fada2376SJung-uk Kim 			fc->bitrate *= fcp->isp_gbspeed;
471695f7dfb2SMatt Jacob 			hdlidx = fcp->isp_dev_map[tgt] - 1;
471795f7dfb2SMatt Jacob 			if (hdlidx < MAX_FC_TARG) {
471895f7dfb2SMatt Jacob 				fcportdb_t *lp = &fcp->portdb[hdlidx];
4719ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
4720ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
4721ab163f5fSMatt Jacob 				fc->port = lp->portid;
47222df76c16SMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
4723ab163f5fSMatt Jacob 			}
4724ab163f5fSMatt Jacob 		} else {
47252df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
47262df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
47272df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
47281dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
4729ab163f5fSMatt Jacob 
4730ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
473183ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
47322df76c16SMatt Jacob 				sdp->update = 1;
47332df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
47349ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
47359ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
47369ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
47374394c92fSMatt Jacob 			} else {
47389ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
47399ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
47409ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
47414394c92fSMatt Jacob 			}
4742478f8a96SJustin T. Gibbs 
4743ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4744ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4745ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
4746ab163f5fSMatt Jacob 			cts->transport_version = 2;
4747ab163f5fSMatt Jacob 
4748b61386a4SMatt Jacob 			spi->valid = 0;
4749b61386a4SMatt Jacob 			scsi->valid = 0;
4750b61386a4SMatt Jacob 			spi->flags = 0;
4751b61386a4SMatt Jacob 			scsi->flags = 0;
4752ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
4753ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
4754ab163f5fSMatt Jacob 			}
47559ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
4756ab163f5fSMatt Jacob 				spi->sync_offset = oval;
4757ab163f5fSMatt Jacob 				spi->sync_period = pval;
4758b61386a4SMatt Jacob 			} else {
4759b61386a4SMatt Jacob 				spi->sync_offset = 0;
4760b61386a4SMatt Jacob 				spi->sync_period = 0;
4761b61386a4SMatt Jacob 			}
4762ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
4763ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
4764ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
4765ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
4766ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
4767ab163f5fSMatt Jacob 			} else {
4768ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
4769ab163f5fSMatt Jacob 			}
4770ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
4771ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
4772b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
4773b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
4774b61386a4SMatt Jacob 				}
4775ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
4776ab163f5fSMatt Jacob 			}
47772df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "GET %s (%d.%d.%d) to flags %x off %x per %x", IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
4778b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
4779478f8a96SJustin T. Gibbs 		}
4780478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4781478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4782478f8a96SJustin T. Gibbs 		break;
4783478f8a96SJustin T. Gibbs 
4784478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
47852df76c16SMatt Jacob 		cam_calc_geometry(&ccb->ccg, 1);
47862df76c16SMatt Jacob 		xpt_done(ccb);
47872df76c16SMatt Jacob 		break;
4788478f8a96SJustin T. Gibbs 
4789478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
4790ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
47912df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, bus);
47922df76c16SMatt Jacob 		if (error) {
4793478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
47942df76c16SMatt Jacob 			xpt_done(ccb);
47952df76c16SMatt Jacob 			break;
47962df76c16SMatt Jacob 		}
47970a70657fSMatt Jacob 		if (bootverbose) {
47982df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "reset bus on channel %d\n", bus);
47990a70657fSMatt Jacob 		}
48002df76c16SMatt Jacob 		if (IS_FC(isp)) {
48012df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, 0);
48022df76c16SMatt Jacob 		} else {
48032df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, 0);
48042df76c16SMatt Jacob 		}
4805478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4806478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4807478f8a96SJustin T. Gibbs 		break;
4808478f8a96SJustin T. Gibbs 
4809478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
4810478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4811478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4812478f8a96SJustin T. Gibbs 		break;
4813478f8a96SJustin T. Gibbs 
48142df76c16SMatt Jacob 	case XPT_SET_SIM_KNOB:		/* Set SIM knobs */
48152df76c16SMatt Jacob 	{
48162df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
48172df76c16SMatt Jacob 		fcparam *fcp;
48182df76c16SMatt Jacob 
48192df76c16SMatt Jacob 		if (!IS_FC(isp)) {
48202df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
48212df76c16SMatt Jacob 			xpt_done(ccb);
48222df76c16SMatt Jacob 			break;
48232df76c16SMatt Jacob 		}
48242df76c16SMatt Jacob 
48252df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
48262df76c16SMatt Jacob 		fcp = FCPARAM(isp, bus);
48272df76c16SMatt Jacob 
48282df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) {
48292df76c16SMatt Jacob 			fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn;
48302df76c16SMatt Jacob 			fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn;
48312df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn);
48322df76c16SMatt Jacob 		}
48332df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
48342df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) {
48352df76c16SMatt Jacob 			int rchange = 0;
48362df76c16SMatt Jacob 			int newrole = 0;
48372df76c16SMatt Jacob 
48382df76c16SMatt Jacob 			switch (kp->xport_specific.fc.role) {
48392df76c16SMatt Jacob 			case KNOB_ROLE_NONE:
48402df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_NONE) {
48412df76c16SMatt Jacob 					rchange = 1;
48422df76c16SMatt Jacob 					newrole = ISP_ROLE_NONE;
48432df76c16SMatt Jacob 				}
48442df76c16SMatt Jacob 				break;
48452df76c16SMatt Jacob 			case KNOB_ROLE_TARGET:
48462df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_TARGET) {
48472df76c16SMatt Jacob 					rchange = 1;
48482df76c16SMatt Jacob 					newrole = ISP_ROLE_TARGET;
48492df76c16SMatt Jacob 				}
48502df76c16SMatt Jacob 				break;
48512df76c16SMatt Jacob 			case KNOB_ROLE_INITIATOR:
48522df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_INITIATOR) {
48532df76c16SMatt Jacob 					rchange = 1;
48542df76c16SMatt Jacob 					newrole = ISP_ROLE_INITIATOR;
48552df76c16SMatt Jacob 				}
48562df76c16SMatt Jacob 				break;
48572df76c16SMatt Jacob 			case KNOB_ROLE_BOTH:
4858ae5db118SMatt Jacob #if 0
48592df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_BOTH) {
48602df76c16SMatt Jacob 					rchange = 1;
48612df76c16SMatt Jacob 					newrole = ISP_ROLE_BOTH;
48622df76c16SMatt Jacob 				}
4863ae5db118SMatt Jacob #else
4864ae5db118SMatt Jacob 				/*
4865ae5db118SMatt Jacob 				 * We don't really support dual role at present on FC cards.
4866ae5db118SMatt Jacob 				 *
4867ae5db118SMatt Jacob 				 * We should, but a bunch of things are currently broken,
4868ae5db118SMatt Jacob 				 * so don't allow it.
4869ae5db118SMatt Jacob 				 */
4870ae5db118SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "cannot support dual role at present");
4871ae5db118SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_INVALID;
4872ae5db118SMatt Jacob #endif
48732df76c16SMatt Jacob 				break;
48742df76c16SMatt Jacob 			}
48752df76c16SMatt Jacob 			if (rchange) {
4876e2873b76SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGCONFIG, ccb->ccb_h.path, "changing role on from %d to %d\n", fcp->role, newrole);
48772df76c16SMatt Jacob 				if (isp_fc_change_role(isp, bus, newrole) != 0) {
48782df76c16SMatt Jacob 					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
48792df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
48802df76c16SMatt Jacob 				} else if (newrole == ISP_ROLE_TARGET || newrole == ISP_ROLE_BOTH) {
4881e2873b76SMatt Jacob 					ccb->ccb_h.status = isp_enable_deferred_luns(isp, bus);
48822df76c16SMatt Jacob #endif
48832df76c16SMatt Jacob 				}
48842df76c16SMatt Jacob 			}
48852df76c16SMatt Jacob 		}
48862df76c16SMatt Jacob 		xpt_done(ccb);
48872df76c16SMatt Jacob 		break;
48882df76c16SMatt Jacob 	}
4889e2873b76SMatt Jacob 	case XPT_GET_SIM_KNOB:		/* Get SIM knobs */
48902df76c16SMatt Jacob 	{
48912df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
48922df76c16SMatt Jacob 
48932df76c16SMatt Jacob 		if (IS_FC(isp)) {
48942df76c16SMatt Jacob 			fcparam *fcp;
48952df76c16SMatt Jacob 
48962df76c16SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
48972df76c16SMatt Jacob 			fcp = FCPARAM(isp, bus);
48982df76c16SMatt Jacob 
48992df76c16SMatt Jacob 			kp->xport_specific.fc.wwnn = fcp->isp_wwnn;
49002df76c16SMatt Jacob 			kp->xport_specific.fc.wwpn = fcp->isp_wwpn;
49012df76c16SMatt Jacob 			switch (fcp->role) {
49022df76c16SMatt Jacob 			case ISP_ROLE_NONE:
49032df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_NONE;
49042df76c16SMatt Jacob 				break;
49052df76c16SMatt Jacob 			case ISP_ROLE_TARGET:
49062df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_TARGET;
49072df76c16SMatt Jacob 				break;
49082df76c16SMatt Jacob 			case ISP_ROLE_INITIATOR:
49092df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_INITIATOR;
49102df76c16SMatt Jacob 				break;
49112df76c16SMatt Jacob 			case ISP_ROLE_BOTH:
49122df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_BOTH;
49132df76c16SMatt Jacob 				break;
49142df76c16SMatt Jacob 			}
49152df76c16SMatt Jacob 			kp->xport_specific.fc.valid = KNOB_VALID_ADDRESS | KNOB_VALID_ROLE;
49162df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_CMP;
49172df76c16SMatt Jacob 		} else {
49182df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
49192df76c16SMatt Jacob 		}
49202df76c16SMatt Jacob 		xpt_done(ccb);
49212df76c16SMatt Jacob 		break;
49222df76c16SMatt Jacob 	}
4923478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
4924478f8a96SJustin T. Gibbs 	{
4925478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
4926478f8a96SJustin T. Gibbs 
4927478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
4928d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4929a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
4930d81ba9d5SMatt Jacob #else
4931478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
4932d81ba9d5SMatt Jacob #endif
4933478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
49340470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
49350470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
49360470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
49372df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
49384394c92fSMatt Jacob 		if (IS_FC(isp)) {
49392df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
49402df76c16SMatt Jacob 
49414394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
49422df76c16SMatt Jacob 
49430470d791SMatt Jacob 			/*
49440470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
49450470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
49460470d791SMatt Jacob 			 */
49470470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
49480470d791SMatt Jacob 
49499deea857SKenneth D. Merry 			/*
49502df76c16SMatt Jacob 			 * Set base transfer capabilities for Fibre Channel, for this HBA.
49519deea857SKenneth D. Merry 			 */
4952e95725cbSMatt Jacob 			if (IS_25XX(isp)) {
4953e95725cbSMatt Jacob 				cpi->base_transfer_speed = 8000000;
4954e95725cbSMatt Jacob 			} else if (IS_24XX(isp)) {
49552df76c16SMatt Jacob 				cpi->base_transfer_speed = 4000000;
49562df76c16SMatt Jacob 			} else if (IS_23XX(isp)) {
49572df76c16SMatt Jacob 				cpi->base_transfer_speed = 2000000;
49582df76c16SMatt Jacob 			} else {
49592df76c16SMatt Jacob 				cpi->base_transfer_speed = 1000000;
49602df76c16SMatt Jacob 			}
49610470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
4962ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
4963805e1f82SMatt Jacob 			cpi->transport_version = 0;
49642df76c16SMatt Jacob 			cpi->xport_specific.fc.wwnn = fcp->isp_wwnn;
49652df76c16SMatt Jacob 			cpi->xport_specific.fc.wwpn = fcp->isp_wwpn;
49662df76c16SMatt Jacob 			cpi->xport_specific.fc.port = fcp->isp_portid;
49672df76c16SMatt Jacob 			cpi->xport_specific.fc.bitrate = fcp->isp_gbspeed * 1000;
4968478f8a96SJustin T. Gibbs 		} else {
49692df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
49700470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
49714394c92fSMatt Jacob 			cpi->hba_misc = 0;
4972ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
49739deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
4974ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
4975805e1f82SMatt Jacob 			cpi->transport_version = 2;
4976478f8a96SJustin T. Gibbs 		}
4977ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
4978ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
4979478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
4980478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
4981478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
4982478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
4983478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
4984478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4985478f8a96SJustin T. Gibbs 		break;
4986478f8a96SJustin T. Gibbs 	}
4987478f8a96SJustin T. Gibbs 	default:
4988478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4989478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4990478f8a96SJustin T. Gibbs 		break;
4991478f8a96SJustin T. Gibbs 	}
4992478f8a96SJustin T. Gibbs }
4993d3a9eb2eSMatt Jacob 
4994d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
4995f7c631bcSMatt Jacob 
4996d3a9eb2eSMatt Jacob void
49972df76c16SMatt Jacob isp_done(XS_T *sccb)
4998d3a9eb2eSMatt Jacob {
49999cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
5000e95725cbSMatt Jacob 	uint32_t status;
5001d3a9eb2eSMatt Jacob 
5002d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
5003d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
5004b85389e1SMatt Jacob 
50052df76c16SMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && (sccb->scsi_status != SCSI_STATUS_OK)) {
5006d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
50072df76c16SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
500892a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
500992a1e549SMatt Jacob 		} else {
5010d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
5011d3a9eb2eSMatt Jacob 		}
501292a1e549SMatt Jacob 	}
5013b85389e1SMatt Jacob 
50140470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
5015e95725cbSMatt Jacob 	status = sccb->ccb_h.status & CAM_STATUS_MASK;
5016e95725cbSMatt Jacob 	if (status != CAM_REQ_CMP) {
5017e95725cbSMatt Jacob 		if (status != CAM_SEL_TIMEOUT)
50182df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status);
5019d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
5020d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
50210470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
5022d3a9eb2eSMatt Jacob 		}
5023d3a9eb2eSMatt Jacob 	}
5024b85389e1SMatt Jacob 
50252df76c16SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
50262df76c16SMatt Jacob 		xpt_print(sccb->ccb_h.path, "cam completion status 0x%x\n", sccb->ccb_h.status);
5027d3a9eb2eSMatt Jacob 	}
5028b85389e1SMatt Jacob 
5029b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
5030e95725cbSMatt Jacob 	if (XS_TACTIVE_P(sccb))
50310ec60713SMarius Strobl 		callout_stop(&PISP_PCMD(sccb)->wdog);
5032b85389e1SMatt Jacob 	XS_CMD_S_CLEAR(sccb);
50330a70657fSMatt Jacob 	isp_free_pcmd(isp, (union ccb *) sccb);
5034d3a9eb2eSMatt Jacob 	xpt_done((union ccb *) sccb);
5035d3a9eb2eSMatt Jacob }
5036d3a9eb2eSMatt Jacob 
50372df76c16SMatt Jacob void
50382df76c16SMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
5039cbf57b47SMatt Jacob {
50402df76c16SMatt Jacob 	int bus;
50412df76c16SMatt Jacob 	static const char prom[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s WWPN 0x%08x%08x";
50422df76c16SMatt Jacob 	static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s tgt %u WWPN 0x%08x%08x";
5043f7c631bcSMatt Jacob 	char *msg = NULL;
504410365e5aSMatt Jacob 	target_id_t tgt;
504510365e5aSMatt Jacob 	fcportdb_t *lp;
5046a01f5aebSMatt Jacob 	struct isp_fc *fc;
504710365e5aSMatt Jacob 	struct cam_path *tmppath;
50482df76c16SMatt Jacob 	va_list ap;
504910365e5aSMatt Jacob 
5050cbf57b47SMatt Jacob 	switch (cmd) {
5051cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
50520470d791SMatt Jacob 	{
5053ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
5054ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
5055cbf57b47SMatt Jacob 		int flags, tgt;
50562df76c16SMatt Jacob 		sdparam *sdp;
5057ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
5058cbf57b47SMatt Jacob 
505929f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
5060ab163f5fSMatt Jacob 
50612df76c16SMatt Jacob 		va_start(ap, cmd);
50622df76c16SMatt Jacob 		bus = va_arg(ap, int);
50632df76c16SMatt Jacob 		tgt = va_arg(ap, int);
50642df76c16SMatt Jacob 		va_end(ap);
50652df76c16SMatt Jacob 		sdp = SDPARAM(isp, bus);
50662df76c16SMatt Jacob 
50672df76c16SMatt Jacob 		if (xpt_create_path(&tmppath, NULL, cam_sim_path(ISP_SPI_PC(isp, bus)->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
50682df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "isp_async cannot make temp path for %d.%d", tgt, bus);
5069cbf57b47SMatt Jacob 			break;
5070cbf57b47SMatt Jacob 		}
50719ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
5072ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
5073ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
5074ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
5075ab163f5fSMatt Jacob 
5076ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
5077ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
5078ab163f5fSMatt Jacob 
5079ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
5080ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
5081ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
5082ab163f5fSMatt Jacob 		}
5083ab163f5fSMatt Jacob 
5084cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
5085ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
5086ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
5087ab163f5fSMatt Jacob 		}
5088ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
5089ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
5090ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
5091ab163f5fSMatt Jacob 		} else {
5092ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
5093ab163f5fSMatt Jacob 		}
5094ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
5095ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
5096ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
50979ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
50989ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
5099ab163f5fSMatt Jacob 		}
51002df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2, "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x", bus, tgt, sdp->isp_devparam[tgt].actv_period, sdp->isp_devparam[tgt].actv_offset, flags);
5101ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
5102ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
5103cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
5104cbf57b47SMatt Jacob 		break;
51050470d791SMatt Jacob 	}
510657c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
51072df76c16SMatt Jacob 	{
51082df76c16SMatt Jacob 		va_start(ap, cmd);
51092df76c16SMatt Jacob 		bus = va_arg(ap, int);
51102df76c16SMatt Jacob 		va_end(ap);
51112df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", bus);
51122df76c16SMatt Jacob 		if (IS_FC(isp)) {
51132df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, NULL);
51142df76c16SMatt Jacob 		} else {
51152df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, NULL);
511657c801f5SMatt Jacob 		}
511757c801f5SMatt Jacob 		break;
51182df76c16SMatt Jacob 	}
51195d571944SMatt Jacob 	case ISPASYNC_LIP:
5120f7c631bcSMatt Jacob 		if (msg == NULL) {
5121f7c631bcSMatt Jacob 			msg = "LIP Received";
51225d571944SMatt Jacob 		}
5123f7c631bcSMatt Jacob 		/* FALLTHROUGH */
51245d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
5125f7c631bcSMatt Jacob 		if (msg == NULL) {
5126f7c631bcSMatt Jacob 			msg = "LOOP Reset";
51275d571944SMatt Jacob 		}
5128f7c631bcSMatt Jacob 		/* FALLTHROUGH */
512957c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
51302df76c16SMatt Jacob 	{
5131f7c631bcSMatt Jacob 		if (msg == NULL) {
5132f7c631bcSMatt Jacob 			msg = "LOOP Down";
513357c801f5SMatt Jacob 		}
51342df76c16SMatt Jacob 		va_start(ap, cmd);
51352df76c16SMatt Jacob 		bus = va_arg(ap, int);
51362df76c16SMatt Jacob 		va_end(ap);
51372df76c16SMatt Jacob 
5138a01f5aebSMatt Jacob 		FCPARAM(isp, bus)->link_active = 0;
51392df76c16SMatt Jacob 
51402df76c16SMatt Jacob 		fc = ISP_FC_PC(isp, bus);
5141a01f5aebSMatt Jacob 		if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
51422df76c16SMatt Jacob 			/*
51432df76c16SMatt Jacob 			 * We don't do any simq freezing if we are only in target mode
51442df76c16SMatt Jacob 			 */
51454ecb1d4aSMatt Jacob 			if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
51462df76c16SMatt Jacob 				if (fc->path) {
51472df76c16SMatt Jacob 					isp_freeze_loopdown(isp, bus, msg);
5148f7c631bcSMatt Jacob 				}
5149a01f5aebSMatt Jacob 				if (!callout_active(&fc->ldt)) {
51502df76c16SMatt Jacob 					callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
5151427fa8f9SMatt Jacob 					isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
5152f7c631bcSMatt Jacob 				}
51532df76c16SMatt Jacob 			}
5154a01f5aebSMatt Jacob 		}
51552df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
515657c801f5SMatt Jacob 		break;
51572df76c16SMatt Jacob 	}
515857c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
51592df76c16SMatt Jacob 		va_start(ap, cmd);
51602df76c16SMatt Jacob 		bus = va_arg(ap, int);
51612df76c16SMatt Jacob 		va_end(ap);
5162a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
51635d571944SMatt Jacob 		/*
51645d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
51655d571944SMatt Jacob 		 * actually do anything because we're waiting for a
51665d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
51675d571944SMatt Jacob 		 * thread to look at the state of the loop again.
51685d571944SMatt Jacob 		 */
51692df76c16SMatt Jacob 		FCPARAM(isp, bus)->link_active = 1;
5170a01f5aebSMatt Jacob 		fc->loop_dead = 0;
5171a01f5aebSMatt Jacob 		fc->loop_down_time = 0;
51722df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
517357c801f5SMatt Jacob 		break;
517410365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
51752df76c16SMatt Jacob 		va_start(ap, cmd);
51762df76c16SMatt Jacob 		bus = va_arg(ap, int);
51772df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
51782df76c16SMatt Jacob 		va_end(ap);
5179a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
5180f7c631bcSMatt Jacob 		lp->reserved = 0;
5181427fa8f9SMatt Jacob 		lp->gone_timer = 0;
51824ecb1d4aSMatt Jacob 		if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
51832df76c16SMatt Jacob 			int dbidx = lp - FCPARAM(isp, bus)->portdb;
5184f7c631bcSMatt Jacob 			int i;
518502ab3379SMatt Jacob 
5186f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
5187f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
5188f7c631bcSMatt Jacob 					continue;
5189f7c631bcSMatt Jacob 				}
51902df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->isp_dev_map[i] == 0) {
5191f7c631bcSMatt Jacob 					break;
5192f7c631bcSMatt Jacob 				}
5193f7c631bcSMatt Jacob 			}
5194f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
51952df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[i] = dbidx + 1;
51962df76c16SMatt Jacob 				lp->dev_map_idx = i + 1;
5197f7c631bcSMatt Jacob 			} else {
5198f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
51992df76c16SMatt Jacob 				isp_dump_portdb(isp, bus);
5200f7c631bcSMatt Jacob 			}
5201f7c631bcSMatt Jacob 		}
52022df76c16SMatt Jacob 		if (lp->dev_map_idx) {
52032df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
52042df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "arrived at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
52052df76c16SMatt Jacob 			isp_make_here(isp, bus, tgt);
520610365e5aSMatt Jacob 		} else {
52072df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "arrived", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
520810365e5aSMatt Jacob 		}
520910365e5aSMatt Jacob 		break;
521010365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
52112df76c16SMatt Jacob 		va_start(ap, cmd);
52122df76c16SMatt Jacob 		bus = va_arg(ap, int);
52132df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
52142df76c16SMatt Jacob 		va_end(ap);
5215a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
52162df76c16SMatt Jacob 		lp->reserved = 0;
5217427fa8f9SMatt Jacob 		lp->gone_timer = 0;
5218f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
5219f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
52202df76c16SMatt Jacob 			if (lp->dev_map_idx) {
52212df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
52222df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[tgt] = 0;
52232df76c16SMatt Jacob 				lp->dev_map_idx = 0;
52242df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad");
52252df76c16SMatt Jacob 				isp_make_gone(isp, bus, tgt);
5226f7c631bcSMatt Jacob 			} else {
52272df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed and departed",
52282df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
5229f7c631bcSMatt Jacob 			}
5230f7c631bcSMatt Jacob 		} else {
5231f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
5232f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
52332df76c16SMatt Jacob 			if (lp->dev_map_idx) {
52342df76c16SMatt Jacob 				int t = lp->dev_map_idx - 1;
52352df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[t] = (lp - FCPARAM(isp, bus)->portdb) + 1;
52362df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
52372df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "changed at", tgt,
52382df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
523910365e5aSMatt Jacob 			} else {
52402df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
524110365e5aSMatt Jacob 			}
5242f7c631bcSMatt Jacob 		}
524310365e5aSMatt Jacob 		break;
524410365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
52452df76c16SMatt Jacob 		va_start(ap, cmd);
52462df76c16SMatt Jacob 		bus = va_arg(ap, int);
52472df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
52482df76c16SMatt Jacob 		va_end(ap);
52492df76c16SMatt Jacob 		if (lp->dev_map_idx) {
52502df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
52512df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "stayed at", tgt,
52522df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
525310365e5aSMatt Jacob 		} else {
52542df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "stayed",
52552df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
525610365e5aSMatt Jacob 		}
525710365e5aSMatt Jacob 		break;
525810365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
52592df76c16SMatt Jacob 		va_start(ap, cmd);
52602df76c16SMatt Jacob 		bus = va_arg(ap, int);
52612df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
52622df76c16SMatt Jacob 		va_end(ap);
5263a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
5264f7c631bcSMatt Jacob 		/*
5265f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
5266f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
5267f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
5268f7c631bcSMatt Jacob 		 *
5269f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
5270f7c631bcSMatt Jacob 		 * announce that it's gone.
52714ecb1d4aSMatt Jacob 		 *
5272f7c631bcSMatt Jacob 		 */
52732df76c16SMatt Jacob 		if (lp->dev_map_idx && lp->reserved == 0) {
5274f7c631bcSMatt Jacob 			lp->reserved = 1;
5275f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
5276427fa8f9SMatt Jacob 			lp->gone_timer = ISP_FC_PC(isp, bus)->gone_device_time;
5277a01f5aebSMatt Jacob 			if (fc->ready && !callout_active(&fc->gdt)) {
5278a6119ff6SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Starting Gone Device Timer with %u seconds time now %lu", bus, lp->gone_timer, (unsigned long)time_uptime);
5279a01f5aebSMatt Jacob 				callout_reset(&fc->gdt, hz, isp_gdt, fc);
5280f7c631bcSMatt Jacob 			}
52812df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
52822df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
5283f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
52842df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "departed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
52854b9d588eSMatt Jacob 		}
528610365e5aSMatt Jacob 		break;
528710365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
528810365e5aSMatt Jacob 	{
528910365e5aSMatt Jacob 		char *msg;
52902df76c16SMatt Jacob 		int evt, nphdl, nlstate, reason;
52912df76c16SMatt Jacob 
52922df76c16SMatt Jacob 		va_start(ap, cmd);
52932df76c16SMatt Jacob 		bus = va_arg(ap, int);
52942df76c16SMatt Jacob 		evt = va_arg(ap, int);
52952df76c16SMatt Jacob 		if (IS_24XX(isp) && evt == ISPASYNC_CHANGE_PDB) {
52962df76c16SMatt Jacob 			nphdl = va_arg(ap, int);
52972df76c16SMatt Jacob 			nlstate = va_arg(ap, int);
52982df76c16SMatt Jacob 			reason = va_arg(ap, int);
529910365e5aSMatt Jacob 		} else {
53002df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
53012df76c16SMatt Jacob 			nlstate = reason = 0;
530210365e5aSMatt Jacob 		}
53032df76c16SMatt Jacob 		va_end(ap);
5304a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
53052df76c16SMatt Jacob 
53062df76c16SMatt Jacob 		if (evt == ISPASYNC_CHANGE_PDB) {
53072df76c16SMatt Jacob 			msg = "Chan %d Port Database Changed";
53082df76c16SMatt Jacob 		} else if (evt == ISPASYNC_CHANGE_SNS) {
53092df76c16SMatt Jacob 			msg = "Chan %d Name Server Database Changed";
53102df76c16SMatt Jacob 		} else {
53112df76c16SMatt Jacob 			msg = "Chan %d Other Change Notify";
53122df76c16SMatt Jacob 		}
53132df76c16SMatt Jacob 
5314f7c631bcSMatt Jacob 		/*
5315f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
5316f7c631bcSMatt Jacob 		 */
5317a01f5aebSMatt Jacob 		if (fc->ready && callout_active(&fc->ldt)) {
53182df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
5319a01f5aebSMatt Jacob 			callout_stop(&fc->ldt);
5320f7c631bcSMatt Jacob 		}
53212df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg, bus);
53224ecb1d4aSMatt Jacob 		if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
53232df76c16SMatt Jacob 			isp_freeze_loopdown(isp, bus, msg);
53242df76c16SMatt Jacob 		}
5325a01f5aebSMatt Jacob 		wakeup(fc);
532657c801f5SMatt Jacob 		break;
532702ab3379SMatt Jacob 	}
5328d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
5329e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
5330d81ba9d5SMatt Jacob 	{
53312df76c16SMatt Jacob 		isp_notify_t *notify;
53322df76c16SMatt Jacob 		va_start(ap, cmd);
53332df76c16SMatt Jacob 		notify = va_arg(ap, isp_notify_t *);
53342df76c16SMatt Jacob 		va_end(ap);
53352df76c16SMatt Jacob 		switch (notify->nt_ncode) {
53362df76c16SMatt Jacob 		case NT_ABORT_TASK:
53372df76c16SMatt Jacob 		case NT_ABORT_TASK_SET:
53382df76c16SMatt Jacob 		case NT_CLEAR_ACA:
53392df76c16SMatt Jacob 		case NT_CLEAR_TASK_SET:
53402df76c16SMatt Jacob 		case NT_LUN_RESET:
53412df76c16SMatt Jacob 		case NT_TARGET_RESET:
53422df76c16SMatt Jacob 			/*
53432df76c16SMatt Jacob 			 * These are task management functions.
53442df76c16SMatt Jacob 			 */
53452df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, notify);
53462df76c16SMatt Jacob 			break;
53472df76c16SMatt Jacob 		case NT_BUS_RESET:
53482df76c16SMatt Jacob 		case NT_LIP_RESET:
53492df76c16SMatt Jacob 		case NT_LINK_UP:
53502df76c16SMatt Jacob 		case NT_LINK_DOWN:
53512df76c16SMatt Jacob 			/*
53522df76c16SMatt Jacob 			 * No action need be taken here.
53532df76c16SMatt Jacob 			 */
53542df76c16SMatt Jacob 			break;
53552df76c16SMatt Jacob 		case NT_HBA_RESET:
53562df76c16SMatt Jacob 			isp_del_all_wwn_entries(isp, ISP_NOCHAN);
53572df76c16SMatt Jacob 			break;
53582df76c16SMatt Jacob 		case NT_LOGOUT:
53592df76c16SMatt Jacob 			/*
53602df76c16SMatt Jacob 			 * This is device arrival/departure notification
53612df76c16SMatt Jacob 			 */
53622df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
53632df76c16SMatt Jacob 			break;
53642df76c16SMatt Jacob 		case NT_ARRIVED:
53652df76c16SMatt Jacob 		{
53662df76c16SMatt Jacob 			struct ac_contract ac;
53672df76c16SMatt Jacob 			struct ac_device_changed *fc;
53682df76c16SMatt Jacob 
53692df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
53702df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
53712df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
53722df76c16SMatt Jacob 			fc->port = notify->nt_sid;
53732df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
53742df76c16SMatt Jacob 			fc->arrived = 1;
53752df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
53762df76c16SMatt Jacob 			break;
53772df76c16SMatt Jacob 		}
53782df76c16SMatt Jacob 		case NT_DEPARTED:
53792df76c16SMatt Jacob 		{
53802df76c16SMatt Jacob 			struct ac_contract ac;
53812df76c16SMatt Jacob 			struct ac_device_changed *fc;
53822df76c16SMatt Jacob 
53832df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
53842df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
53852df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
53862df76c16SMatt Jacob 			fc->port = notify->nt_sid;
53872df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
53882df76c16SMatt Jacob 			fc->arrived = 0;
53892df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
53902df76c16SMatt Jacob 			break;
53912df76c16SMatt Jacob 		}
53922df76c16SMatt Jacob 		default:
53932df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode);
53942df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
53952df76c16SMatt Jacob 			break;
53962df76c16SMatt Jacob 		}
5397d81ba9d5SMatt Jacob 		break;
5398d81ba9d5SMatt Jacob 	}
5399d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
54002df76c16SMatt Jacob 	{
54012df76c16SMatt Jacob 		isphdr_t *hp;
54022df76c16SMatt Jacob 
54032df76c16SMatt Jacob 		va_start(ap, cmd);
54042df76c16SMatt Jacob 		hp = va_arg(ap, isphdr_t *);
54052df76c16SMatt Jacob 		va_end(ap);
54062df76c16SMatt Jacob 		switch (hp->rqs_entry_type) {
5407cbf57b47SMatt Jacob 		default:
54082df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: unhandled target action 0x%x", __func__, hp->rqs_entry_type);
5409d81ba9d5SMatt Jacob 			break;
5410570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
5411570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
54122df76c16SMatt Jacob 				isp_handle_platform_notify_scsi(isp, (in_entry_t *) hp);
54132df76c16SMatt Jacob 			} else if (IS_24XX(isp)) {
54142df76c16SMatt Jacob 				isp_handle_platform_notify_24xx(isp, (in_fcentry_24xx_t *) hp);
5415570c7a3fSMatt Jacob 			} else {
54162df76c16SMatt Jacob 				isp_handle_platform_notify_fc(isp, (in_fcentry_t *) hp);
5417570c7a3fSMatt Jacob 			}
5418570c7a3fSMatt Jacob 			break;
5419d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
54202df76c16SMatt Jacob 			if (IS_24XX(isp)) {
54212df76c16SMatt Jacob 				isp_handle_platform_atio7(isp, (at7_entry_t *) hp);
54222df76c16SMatt Jacob 			} else {
54232df76c16SMatt Jacob 				isp_handle_platform_atio(isp, (at_entry_t *) hp);
54242df76c16SMatt Jacob 			}
5425d81ba9d5SMatt Jacob 			break;
5426d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
54272df76c16SMatt Jacob 			isp_handle_platform_atio2(isp, (at2_entry_t *) hp);
5428d81ba9d5SMatt Jacob 			break;
54292df76c16SMatt Jacob 		case RQSTYPE_CTIO7:
5430d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
5431d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
5432d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
54332df76c16SMatt Jacob 			isp_handle_platform_ctio(isp, hp);
5434d81ba9d5SMatt Jacob 			break;
54352df76c16SMatt Jacob 		case RQSTYPE_ABTS_RCVD:
54362df76c16SMatt Jacob 		{
54372df76c16SMatt Jacob 			abts_t *abts = (abts_t *)hp;
54382df76c16SMatt Jacob 			isp_notify_t notify, *nt = &notify;
54392df76c16SMatt Jacob 			tstate_t *tptr;
54402df76c16SMatt Jacob 			fcportdb_t *lp;
54412df76c16SMatt Jacob 			uint16_t chan;
54422df76c16SMatt Jacob 			uint32_t sid, did;
54432df76c16SMatt Jacob 
54442df76c16SMatt Jacob 			did = (abts->abts_did_hi << 16) | abts->abts_did_lo;
54452df76c16SMatt Jacob 			sid = (abts->abts_sid_hi << 16) | abts->abts_sid_lo;
54462df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
54472df76c16SMatt Jacob 
54482df76c16SMatt Jacob 			nt->nt_hba = isp;
54492df76c16SMatt Jacob 			nt->nt_did = did;
54502df76c16SMatt Jacob 			nt->nt_nphdl = abts->abts_nphdl;
54512df76c16SMatt Jacob 			nt->nt_sid = sid;
54522df76c16SMatt Jacob 			isp_find_chan_by_did(isp, did, &chan);
54532df76c16SMatt Jacob 			if (chan == ISP_NOCHAN) {
54542df76c16SMatt Jacob 				nt->nt_tgt = TGT_ANY;
54552df76c16SMatt Jacob 			} else {
54562df76c16SMatt Jacob 				nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
54572df76c16SMatt Jacob 				if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) {
54582df76c16SMatt Jacob 					nt->nt_wwn = lp->port_wwn;
54592df76c16SMatt Jacob 				} else {
54602df76c16SMatt Jacob 					nt->nt_wwn = INI_ANY;
54612df76c16SMatt Jacob 				}
54622df76c16SMatt Jacob 			}
54632df76c16SMatt Jacob 			/*
54642df76c16SMatt Jacob 			 * Try hard to find the lun for this command.
54652df76c16SMatt Jacob 			 */
54662df76c16SMatt Jacob 			tptr = get_lun_statep_from_tag(isp, chan, abts->abts_rxid_task);
54672df76c16SMatt Jacob 			if (tptr) {
54682df76c16SMatt Jacob 				nt->nt_lun = xpt_path_lun_id(tptr->owner);
54692df76c16SMatt Jacob 				rls_lun_statep(isp, tptr);
54702df76c16SMatt Jacob 			} else {
54712df76c16SMatt Jacob 				nt->nt_lun = LUN_ANY;
54722df76c16SMatt Jacob 			}
54732df76c16SMatt Jacob 			nt->nt_need_ack = 1;
54742df76c16SMatt Jacob 			nt->nt_tagval = abts->abts_rxid_task;
54752df76c16SMatt Jacob 			nt->nt_tagval |= (((uint64_t) abts->abts_rxid_abts) << 32);
54762df76c16SMatt Jacob 			if (abts->abts_rxid_task == ISP24XX_NO_TASK) {
54772df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x has no task id (rx_id 0x%04x ox_id 0x%04x)",
54782df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rx_id, abts->abts_ox_id);
54792df76c16SMatt Jacob 			} else {
54802df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS from N-Port handle 0x%x Port 0x%06x for task 0x%x (rx_id 0x%04x ox_id 0x%04x)",
54812df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rxid_task, abts->abts_rx_id, abts->abts_ox_id);
54822df76c16SMatt Jacob 			}
54832df76c16SMatt Jacob 			nt->nt_channel = chan;
54842df76c16SMatt Jacob 			nt->nt_ncode = NT_ABORT_TASK;
54852df76c16SMatt Jacob 			nt->nt_lreserved = hp;
54862df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
54872df76c16SMatt Jacob 			break;
54882df76c16SMatt Jacob 		}
5489d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
5490d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
54912df76c16SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) hp);
5492d81ba9d5SMatt Jacob 			break;
5493d81ba9d5SMatt Jacob 		}
5494d81ba9d5SMatt Jacob 		break;
54952df76c16SMatt Jacob 	}
5496d81ba9d5SMatt Jacob #endif
5497ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
5498ab163f5fSMatt Jacob 	{
54991dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
5500ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
5501ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
5502ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
5503ab163f5fSMatt Jacob 		} else {
5504ab163f5fSMatt Jacob 			mbox6 = 0;
5505ab163f5fSMatt Jacob 		}
55062df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "Internal Firmware Error on bus %d @ RISC Address 0x%x", mbox6, mbox1);
55070a70657fSMatt Jacob 		mbox1 = isp->isp_osinfo.mbox_sleep_ok;
55080a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
55092df76c16SMatt Jacob 		isp_reinit(isp, 1);
55100a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = mbox1;
55110a70657fSMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
5512ab163f5fSMatt Jacob 		break;
5513ab163f5fSMatt Jacob 	}
5514d81ba9d5SMatt Jacob 	default:
5515b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
5516cbf57b47SMatt Jacob 		break;
5517cbf57b47SMatt Jacob 	}
5518cbf57b47SMatt Jacob }
5519cbf57b47SMatt Jacob 
552092718a7fSMatt Jacob 
552192718a7fSMatt Jacob /*
552292718a7fSMatt Jacob  * Locks are held before coming here.
552392718a7fSMatt Jacob  */
552492718a7fSMatt Jacob void
55259cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
552692718a7fSMatt Jacob {
552710365e5aSMatt Jacob 	if (IS_24XX(isp)) {
552810365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
552910365e5aSMatt Jacob 	} else {
5530ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
553110365e5aSMatt Jacob 	}
553210365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
553392718a7fSMatt Jacob }
5534b09b0095SMatt Jacob 
55352df76c16SMatt Jacob /*
55362df76c16SMatt Jacob  * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them
55372df76c16SMatt Jacob  * up from our platform default (defww{p|n}n) and morph them based upon
55382df76c16SMatt Jacob  * channel.
55392df76c16SMatt Jacob  *
55402df76c16SMatt Jacob  * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them
55412df76c16SMatt Jacob  * based upon channel.
55422df76c16SMatt Jacob  */
55432df76c16SMatt Jacob 
55442df76c16SMatt Jacob uint64_t
55452df76c16SMatt Jacob isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn)
55462df76c16SMatt Jacob {
55472df76c16SMatt Jacob 	uint64_t seed;
55482df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
55492df76c16SMatt Jacob 
55502df76c16SMatt Jacob 	/*
55512df76c16SMatt Jacob 	 * If we're asking for a active WWN, the default overrides get
55522df76c16SMatt Jacob 	 * returned, otherwise the NVRAM value is picked.
55532df76c16SMatt Jacob 	 *
55542df76c16SMatt Jacob 	 * If we're asking for a default WWN, we just pick the default override.
55552df76c16SMatt Jacob 	 */
55562df76c16SMatt Jacob 	if (isactive) {
55572df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
55582df76c16SMatt Jacob 		if (seed) {
55592df76c16SMatt Jacob 			return (seed);
55602df76c16SMatt Jacob 		}
55612df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram;
55625cc3786cSMatt Jacob 		if (seed) {
55635cc3786cSMatt Jacob 			return (seed);
55645cc3786cSMatt Jacob 		}
55655cc3786cSMatt Jacob 		return (0x400000007F000009ull);
55662df76c16SMatt Jacob 	} else {
55672df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
55682df76c16SMatt Jacob 	}
55692df76c16SMatt Jacob 
55702df76c16SMatt Jacob 
55712df76c16SMatt Jacob 	/*
5572b1ce21c6SRebecca Cran 	 * For channel zero just return what we have. For either ACTIVE or
55732df76c16SMatt Jacob 	 * DEFAULT cases, we depend on default override of NVRAM values for
55742df76c16SMatt Jacob 	 * channel zero.
55752df76c16SMatt Jacob 	 */
55762df76c16SMatt Jacob 	if (chan == 0) {
55772df76c16SMatt Jacob 		return (seed);
55782df76c16SMatt Jacob 	}
55792df76c16SMatt Jacob 
55802df76c16SMatt Jacob 	/*
55812df76c16SMatt Jacob 	 * For other channels, we are doing one of three things:
55822df76c16SMatt Jacob 	 *
55832df76c16SMatt Jacob 	 * 1. If what we have now is non-zero, return it. Otherwise we morph
55842df76c16SMatt Jacob 	 * values from channel 0. 2. If we're here for a WWPN we synthesize
55852df76c16SMatt Jacob 	 * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a
55862df76c16SMatt Jacob 	 * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA.
55872df76c16SMatt Jacob 	 */
55882df76c16SMatt Jacob 
55892df76c16SMatt Jacob 	if (seed) {
55902df76c16SMatt Jacob 		return (seed);
55912df76c16SMatt Jacob 	}
55922df76c16SMatt Jacob 	if (isactive) {
55932df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram;
55942df76c16SMatt Jacob 	} else {
55952df76c16SMatt Jacob 		seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn;
55962df76c16SMatt Jacob 	}
55972df76c16SMatt Jacob 
55982df76c16SMatt Jacob 	if (((seed >> 60) & 0xf) == 2) {
55992df76c16SMatt Jacob 		/*
56002df76c16SMatt Jacob 		 * The type 2 NAA fields for QLogic cards appear be laid out
56012df76c16SMatt Jacob 		 * thusly:
56022df76c16SMatt Jacob 		 *
56032df76c16SMatt Jacob 		 * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56
56042df76c16SMatt Jacob 		 * port (1) or node (0) WWN distinguishor bit 48
56052df76c16SMatt Jacob 		 * physical port on dual-port chips (23XX/24XX)
56062df76c16SMatt Jacob 		 *
56072df76c16SMatt Jacob 		 * This is somewhat nutty, particularly since bit 48 is
5608b1ce21c6SRebecca Cran 		 * irrelevant as they assign separate serial numbers to
56092df76c16SMatt Jacob 		 * different physical ports anyway.
56102df76c16SMatt Jacob 		 *
56112df76c16SMatt Jacob 		 * We'll stick our channel number plus one first into bits
56122df76c16SMatt Jacob 		 * 57..59 and thence into bits 52..55 which allows for 8 bits
56132df76c16SMatt Jacob 		 * of channel which is comfortably more than our maximum
56142df76c16SMatt Jacob 		 * (126) now.
56152df76c16SMatt Jacob 		 */
56162df76c16SMatt Jacob 		seed &= ~0x0FF0000000000000ULL;
56172df76c16SMatt Jacob 		if (iswwnn == 0) {
56182df76c16SMatt Jacob 			seed |= ((uint64_t) (chan + 1) & 0xf) << 56;
56192df76c16SMatt Jacob 			seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52;
56202df76c16SMatt Jacob 		}
56212df76c16SMatt Jacob 	} else {
56222df76c16SMatt Jacob 		seed = 0;
56232df76c16SMatt Jacob 	}
56242df76c16SMatt Jacob 	return (seed);
56252df76c16SMatt Jacob }
56262df76c16SMatt Jacob 
5627b09b0095SMatt Jacob void
56289cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
5629b09b0095SMatt Jacob {
5630de461933SMatt Jacob 	int loc;
5631de461933SMatt Jacob 	char lbuf[128];
5632b09b0095SMatt Jacob 	va_list ap;
5633de461933SMatt Jacob 
5634b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
5635b09b0095SMatt Jacob 		return;
5636b09b0095SMatt Jacob 	}
5637de461933SMatt Jacob 	sprintf(lbuf, "%s: ", device_get_nameunit(isp->isp_dev));
5638de461933SMatt Jacob 	loc = strlen(lbuf);
5639b09b0095SMatt Jacob 	va_start(ap, fmt);
5640de461933SMatt Jacob 	vsnprintf(&lbuf[loc], sizeof (lbuf) - loc - 1, fmt, ap);
5641b09b0095SMatt Jacob 	va_end(ap);
5642de461933SMatt Jacob 	printf("%s\n", lbuf);
5643b09b0095SMatt Jacob }
5644f7c631bcSMatt Jacob 
5645670508b1SMatt Jacob void
5646670508b1SMatt Jacob isp_xs_prt(ispsoftc_t *isp, XS_T *xs, int level, const char *fmt, ...)
5647670508b1SMatt Jacob {
5648670508b1SMatt Jacob 	va_list ap;
5649670508b1SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
5650670508b1SMatt Jacob 		return;
5651670508b1SMatt Jacob 	}
5652670508b1SMatt Jacob 	xpt_print_path(xs->ccb_h.path);
5653670508b1SMatt Jacob 	va_start(ap, fmt);
5654670508b1SMatt Jacob 	vprintf(fmt, ap);
5655670508b1SMatt Jacob 	va_end(ap);
5656670508b1SMatt Jacob 	printf("\n");
5657670508b1SMatt Jacob }
5658670508b1SMatt Jacob 
5659f7c631bcSMatt Jacob uint64_t
5660f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
5661f7c631bcSMatt Jacob {
5662f7c631bcSMatt Jacob 	uint64_t elapsed;
5663f7c631bcSMatt Jacob 	struct timespec x = *b;
5664f7c631bcSMatt Jacob 	timespecsub(&x, a);
5665f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
5666f7c631bcSMatt Jacob 	if (elapsed == 0)
5667f7c631bcSMatt Jacob 		elapsed++;
5668f7c631bcSMatt Jacob 	return (elapsed);
5669f7c631bcSMatt Jacob }
5670f7c631bcSMatt Jacob 
5671f7c631bcSMatt Jacob int
5672f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
5673f7c631bcSMatt Jacob {
5674f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
5675f7c631bcSMatt Jacob 		return (1);
5676f7c631bcSMatt Jacob 	} else {
5677f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
5678f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
5679f7c631bcSMatt Jacob 		return (0);
5680f7c631bcSMatt Jacob 	}
5681f7c631bcSMatt Jacob }
5682f7c631bcSMatt Jacob 
5683f7c631bcSMatt Jacob void
5684f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
5685f7c631bcSMatt Jacob {
5686a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
5687a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
5688f7c631bcSMatt Jacob 
5689f7c631bcSMatt Jacob 	if (usecs == 0) {
5690f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
5691f7c631bcSMatt Jacob 	}
5692a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
5693a4f3a2beSMatt Jacob 
5694f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
5695a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
5696a4f3a2beSMatt Jacob 
5697f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
5698f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
5699a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
57002df76c16SMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, PRIBIO, "ispmbx_sleep", isp_mstohz(ms));
5701a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5702a4f3a2beSMatt Jacob 				break;
5703a4f3a2beSMatt Jacob 			}
5704a4f3a2beSMatt Jacob 		}
5705f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
5706f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
5707f7c631bcSMatt Jacob 	} else {
5708a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
5709a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
5710f7c631bcSMatt Jacob 				uint32_t isr;
5711f7c631bcSMatt Jacob 				uint16_t sema, mbox;
5712f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
5713f7c631bcSMatt Jacob 					break;
5714f7c631bcSMatt Jacob 				}
5715f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
5716f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
5717f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
5718f7c631bcSMatt Jacob 						break;
5719f7c631bcSMatt Jacob 					}
5720f7c631bcSMatt Jacob 				}
57212df76c16SMatt Jacob 				ISP_DELAY(100);
5722f7c631bcSMatt Jacob 			}
5723a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5724a4f3a2beSMatt Jacob 				break;
5725a4f3a2beSMatt Jacob 			}
5726a4f3a2beSMatt Jacob 		}
5727f7c631bcSMatt Jacob 	}
5728f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
57292df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s Mailbox Command (0x%x) Timeout (%uus) (started @ %s:%d)",
57302df76c16SMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", isp->isp_lastmbxcmd, usecs, mbp->func, mbp->lineno);
5731f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
5732f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
5733f7c631bcSMatt Jacob 	}
5734f7c631bcSMatt Jacob }
5735f7c631bcSMatt Jacob 
5736f7c631bcSMatt Jacob void
5737f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
5738f7c631bcSMatt Jacob {
5739f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
5740f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
5741f7c631bcSMatt Jacob 	}
5742f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
5743f7c631bcSMatt Jacob }
5744f7c631bcSMatt Jacob 
5745f7c631bcSMatt Jacob void
5746f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
5747f7c631bcSMatt Jacob {
5748f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
5749f7c631bcSMatt Jacob }
5750f7c631bcSMatt Jacob 
5751f7c631bcSMatt Jacob int
57522df76c16SMatt Jacob isp_fc_scratch_acquire(ispsoftc_t *isp, int chan)
57532df76c16SMatt Jacob {
57542df76c16SMatt Jacob 	int ret = 0;
57552df76c16SMatt Jacob 	if (isp->isp_osinfo.pc.fc[chan].fcbsy) {
57562df76c16SMatt Jacob 		ret = -1;
57572df76c16SMatt Jacob 	} else {
57582df76c16SMatt Jacob 		isp->isp_osinfo.pc.fc[chan].fcbsy = 1;
57592df76c16SMatt Jacob 	}
57602df76c16SMatt Jacob 	return (ret);
57612df76c16SMatt Jacob }
57622df76c16SMatt Jacob 
57632df76c16SMatt Jacob int
5764f7c631bcSMatt Jacob isp_mstohz(int ms)
5765f7c631bcSMatt Jacob {
5766a4f3a2beSMatt Jacob 	int hz;
5767f7c631bcSMatt Jacob 	struct timeval t;
5768f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
5769f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
5770a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
5771a4f3a2beSMatt Jacob 	if (hz < 0) {
5772a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
5773f7c631bcSMatt Jacob 	}
5774a4f3a2beSMatt Jacob 	if (hz == 0) {
5775a4f3a2beSMatt Jacob 		hz = 1;
5776a4f3a2beSMatt Jacob 	}
5777a4f3a2beSMatt Jacob 	return (hz);
5778f7c631bcSMatt Jacob }
57790a70657fSMatt Jacob 
57800a70657fSMatt Jacob void
57810a70657fSMatt Jacob isp_platform_intr(void *arg)
57820a70657fSMatt Jacob {
57830a70657fSMatt Jacob 	ispsoftc_t *isp = arg;
57840a70657fSMatt Jacob 	uint32_t isr;
57850a70657fSMatt Jacob 	uint16_t sema, mbox;
57860a70657fSMatt Jacob 
57870a70657fSMatt Jacob 	ISP_LOCK(isp);
57880a70657fSMatt Jacob 	isp->isp_intcnt++;
57890a70657fSMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
57900a70657fSMatt Jacob 		isp->isp_intbogus++;
57910a70657fSMatt Jacob 	} else {
57920a70657fSMatt Jacob 		isp_intr(isp, isr, sema, mbox);
57930a70657fSMatt Jacob 	}
57940a70657fSMatt Jacob 	ISP_UNLOCK(isp);
57950a70657fSMatt Jacob }
57960a70657fSMatt Jacob 
57970a70657fSMatt Jacob void
57980a70657fSMatt Jacob isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl)
57990a70657fSMatt Jacob {
58000a70657fSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
58012df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD);
58020a70657fSMatt Jacob 	} else {
58032df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE);
58040a70657fSMatt Jacob 	}
58050a70657fSMatt Jacob 	bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
58060a70657fSMatt Jacob }
58072df76c16SMatt Jacob 
58082df76c16SMatt Jacob void
58092df76c16SMatt Jacob isp_timer(void *arg)
58102df76c16SMatt Jacob {
58112df76c16SMatt Jacob 	ispsoftc_t *isp = arg;
58122df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
58132df76c16SMatt Jacob 	isp_tmcmd_restart(isp);
58142df76c16SMatt Jacob #endif
58152df76c16SMatt Jacob 	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
58162df76c16SMatt Jacob }
5817