xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 37bb79f1737be635aaa02e0401993e70718a3925)
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;
70f7c631bcSMatt Jacob static timeout_t isp_ldt;
715d571944SMatt Jacob static void isp_kthread(void *);
72d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
732df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
742df76c16SMatt Jacob static void isp_target_thread_pi(void *);
752df76c16SMatt Jacob static void isp_target_thread_fc(void *);
76784ed707SMatt Jacob #endif
772df76c16SMatt Jacob static void isp_timer(void *);
78cc8df88bSMatt Jacob 
795d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
80dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
817ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
827ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
835d571944SMatt Jacob };
845d571944SMatt Jacob 
852df76c16SMatt Jacob static int
862df76c16SMatt Jacob isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan)
87478f8a96SJustin T. Gibbs {
88478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
89ea6f23cdSMatt Jacob 	struct cam_sim *sim;
90ea6f23cdSMatt Jacob 	struct cam_path *path;
91478f8a96SJustin T. Gibbs 
92478f8a96SJustin T. Gibbs 	/*
932df76c16SMatt Jacob 	 * Construct our SIM entry.
94ea6f23cdSMatt Jacob 	 */
952df76c16SMatt 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);
96ea6f23cdSMatt Jacob 
972df76c16SMatt Jacob 	if (sim == NULL) {
982df76c16SMatt Jacob 		return (ENOMEM);
992df76c16SMatt Jacob 	}
1002df76c16SMatt Jacob 
1012df76c16SMatt Jacob 	ISP_LOCK(isp);
1022df76c16SMatt Jacob 	if (xpt_bus_register(sim, isp->isp_dev, chan) != CAM_SUCCESS) {
1032df76c16SMatt Jacob 		ISP_UNLOCK(isp);
1042df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
1052df76c16SMatt Jacob 		return (EIO);
1062df76c16SMatt Jacob 	}
1072df76c16SMatt Jacob 	ISP_UNLOCK(isp);
1082df76c16SMatt Jacob 
1092df76c16SMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1102df76c16SMatt Jacob 		ISP_LOCK(isp);
1112df76c16SMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
1122df76c16SMatt Jacob 		ISP_UNLOCK(isp);
1132df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
1142df76c16SMatt Jacob 		return (ENXIO);
1152df76c16SMatt Jacob 	}
1162df76c16SMatt Jacob 
1172df76c16SMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
1182df76c16SMatt Jacob 	csa.ccb_h.func_code = XPT_SASYNC_CB;
1192df76c16SMatt Jacob 	csa.event_enable = AC_LOST_DEVICE;
1202df76c16SMatt Jacob 	csa.callback = isp_cam_async;
1212df76c16SMatt Jacob 	csa.callback_arg = sim;
1222df76c16SMatt Jacob 	xpt_action((union ccb *)&csa);
1232df76c16SMatt Jacob 
1242df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
1252df76c16SMatt Jacob 		struct isp_spi *spi = ISP_SPI_PC(isp, chan);
1262df76c16SMatt Jacob 		spi->sim = sim;
1272df76c16SMatt Jacob 		spi->path = path;
1282df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
1292df76c16SMatt Jacob 		ISP_SET_PC(isp, chan, proc_active, 1);
1302df76c16SMatt 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)) {
1312df76c16SMatt Jacob 			ISP_SET_PC(isp, chan, proc_active, 0);
1322df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot create test target thread");
1332df76c16SMatt Jacob 		}
1342df76c16SMatt Jacob #endif
1352df76c16SMatt Jacob 	} else {
136a01f5aebSMatt Jacob 		fcparam *fcp = FCPARAM(isp, chan);
1372df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
1382df76c16SMatt Jacob 
139a01f5aebSMatt Jacob 		ISP_LOCK(isp);
1402df76c16SMatt Jacob 		fc->sim = sim;
1412df76c16SMatt Jacob 		fc->path = path;
1422df76c16SMatt Jacob 		fc->isp = isp;
143a01f5aebSMatt Jacob 		fc->ready = 1;
1442df76c16SMatt Jacob 		callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
1452df76c16SMatt Jacob 		callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
146427fa8f9SMatt Jacob 
1472df76c16SMatt Jacob 		/*
1482df76c16SMatt Jacob 		 * We start by being "loop down" if we have an initiator role
1492df76c16SMatt Jacob 		 */
150a01f5aebSMatt Jacob 		if (fcp->role & ISP_ROLE_INITIATOR) {
1512df76c16SMatt Jacob 			isp_freeze_loopdown(isp, chan, "isp_attach");
1522df76c16SMatt Jacob 			callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc);
1532df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime);
1542df76c16SMatt Jacob 		}
1552df76c16SMatt Jacob 		ISP_UNLOCK(isp);
156a01f5aebSMatt Jacob 		if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
157a01f5aebSMatt Jacob 			xpt_free_path(fc->path);
158a01f5aebSMatt Jacob 			ISP_LOCK(isp);
159a01f5aebSMatt Jacob 			if (callout_active(&fc->ldt)) {
160a01f5aebSMatt Jacob 				callout_stop(&fc->ldt);
161a01f5aebSMatt Jacob 			}
162a01f5aebSMatt Jacob 			xpt_bus_deregister(cam_sim_path(fc->sim));
163a01f5aebSMatt Jacob 			ISP_UNLOCK(isp);
164a01f5aebSMatt Jacob 			cam_sim_free(fc->sim, FALSE);
165a01f5aebSMatt Jacob 			return (ENOMEM);
166a01f5aebSMatt Jacob 		}
1672df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
1682df76c16SMatt Jacob 		ISP_SET_PC(isp, chan, proc_active, 1);
1692df76c16SMatt 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)) {
1702df76c16SMatt Jacob 			ISP_SET_PC(isp, chan, proc_active, 0);
1712df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot create test target thread");
1722df76c16SMatt Jacob 		}
1732df76c16SMatt Jacob #endif
1742df76c16SMatt Jacob 	}
1752df76c16SMatt Jacob 	return (0);
1762df76c16SMatt Jacob }
1772df76c16SMatt Jacob 
1782df76c16SMatt Jacob int
1792df76c16SMatt Jacob isp_attach(ispsoftc_t *isp)
1802df76c16SMatt Jacob {
1812df76c16SMatt Jacob 	const char *nu = device_get_nameunit(isp->isp_osinfo.dev);
1822df76c16SMatt Jacob 	int du = device_get_unit(isp->isp_dev);
1832df76c16SMatt Jacob 	int chan;
1842df76c16SMatt Jacob 
1852df76c16SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
1862df76c16SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
1872df76c16SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
1882df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "could not establish interrupt enable hook");
1892df76c16SMatt Jacob 		return (-EIO);
1902df76c16SMatt Jacob 	}
1912df76c16SMatt Jacob 	isp->isp_osinfo.ehook_active = 1;
1922df76c16SMatt Jacob 
193ea6f23cdSMatt Jacob 
194ea6f23cdSMatt Jacob 	/*
195ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
196478f8a96SJustin T. Gibbs 	 */
1972df76c16SMatt Jacob 	isp->isp_osinfo.devq = cam_simq_alloc(isp->isp_maxcmds);
1982df76c16SMatt Jacob 	if (isp->isp_osinfo.devq == NULL) {
1995d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2002df76c16SMatt Jacob 		return (EIO);
201478f8a96SJustin T. Gibbs 	}
202478f8a96SJustin T. Gibbs 
2032df76c16SMatt Jacob 	for (chan = 0; chan < isp->isp_nchan; chan++) {
2042df76c16SMatt Jacob 		if (isp_attach_chan(isp, isp->isp_osinfo.devq, chan)) {
2052df76c16SMatt Jacob 			goto unwind;
206ea6f23cdSMatt Jacob 		}
207ea6f23cdSMatt Jacob 	}
208ea6f23cdSMatt Jacob 
2092df76c16SMatt Jacob 	callout_init_mtx(&isp->isp_osinfo.tmo, &isp->isp_osinfo.lock, 0);
2102df76c16SMatt Jacob 	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
2112df76c16SMatt Jacob 	isp->isp_osinfo.timer_active = 1;
212ea6f23cdSMatt Jacob 
2132df76c16SMatt Jacob 	isp->isp_osinfo.cdev = make_dev(&isp_cdevsw, du, UID_ROOT, GID_OPERATOR, 0600, "%s", nu);
2142df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
2152df76c16SMatt Jacob 		isp->isp_osinfo.cdev->si_drv1 = isp;
216ea6f23cdSMatt Jacob 	}
2172df76c16SMatt Jacob 	return (0);
2185d571944SMatt Jacob 
2192df76c16SMatt Jacob unwind:
2202df76c16SMatt Jacob 	while (--chan >= 0) {
2212df76c16SMatt Jacob 		struct cam_sim *sim;
2222df76c16SMatt Jacob 		struct cam_path *path;
2230a70657fSMatt Jacob 		if (IS_FC(isp)) {
2242df76c16SMatt Jacob 			sim = ISP_FC_PC(isp, chan)->sim;
2252df76c16SMatt Jacob 			path = ISP_FC_PC(isp, chan)->path;
2262df76c16SMatt Jacob 		} else {
2272df76c16SMatt Jacob 			sim = ISP_SPI_PC(isp, chan)->sim;
2282df76c16SMatt Jacob 			path = ISP_SPI_PC(isp, chan)->path;
2292df76c16SMatt Jacob 		}
2302df76c16SMatt Jacob 		xpt_free_path(path);
2310a70657fSMatt Jacob 		ISP_LOCK(isp);
2320a70657fSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
2332df76c16SMatt Jacob 		ISP_UNLOCK(isp);
2342df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
2352df76c16SMatt Jacob 	}
2362df76c16SMatt Jacob 	if (isp->isp_osinfo.ehook_active) {
2370a70657fSMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2382df76c16SMatt Jacob 		isp->isp_osinfo.ehook_active = 0;
2390a70657fSMatt Jacob 	}
2402df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
2412df76c16SMatt Jacob 		destroy_dev(isp->isp_osinfo.cdev);
2422df76c16SMatt Jacob 		isp->isp_osinfo.cdev = NULL;
2432df76c16SMatt Jacob 	}
2442df76c16SMatt Jacob 	cam_simq_free(isp->isp_osinfo.devq);
2452df76c16SMatt Jacob 	isp->isp_osinfo.devq = NULL;
2462df76c16SMatt Jacob 	return (-1);
2472df76c16SMatt Jacob }
2482df76c16SMatt Jacob 
2492df76c16SMatt Jacob void
2502df76c16SMatt Jacob isp_detach(ispsoftc_t *isp)
2512df76c16SMatt Jacob {
2522df76c16SMatt Jacob 	int chan;
2532df76c16SMatt Jacob 
2540a70657fSMatt Jacob 	ISP_LOCK(isp);
2552df76c16SMatt Jacob 	if (isp->isp_osinfo.timer_active) {
2562df76c16SMatt Jacob 		callout_stop(&isp->isp_osinfo.tmo);
2572df76c16SMatt Jacob 		isp->isp_osinfo.timer_active = 0;
2580a70657fSMatt Jacob 	}
2592df76c16SMatt Jacob 	ISP_UNLOCK(isp);
2602df76c16SMatt Jacob 	for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) {
2612df76c16SMatt Jacob 		struct cam_sim *sim;
2622df76c16SMatt Jacob 		struct cam_path *path;
2632df76c16SMatt Jacob 		if (IS_FC(isp)) {
2642df76c16SMatt Jacob 			sim = ISP_FC_PC(isp, chan)->sim;
2652df76c16SMatt Jacob 			path = ISP_FC_PC(isp, chan)->path;
2662df76c16SMatt Jacob 		} else {
2672df76c16SMatt Jacob 			sim = ISP_SPI_PC(isp, chan)->sim;
2682df76c16SMatt Jacob 			path = ISP_SPI_PC(isp, chan)->path;
2692df76c16SMatt Jacob 		}
2702df76c16SMatt Jacob 		xpt_free_path(path);
2712df76c16SMatt Jacob 		ISP_LOCK(isp);
2722df76c16SMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
2732df76c16SMatt Jacob 		ISP_UNLOCK(isp);
2742df76c16SMatt Jacob 		cam_sim_free(sim, FALSE);
2752df76c16SMatt Jacob 	}
2762df76c16SMatt Jacob 	if (isp->isp_osinfo.cdev) {
2772df76c16SMatt Jacob 		destroy_dev(isp->isp_osinfo.cdev);
2782df76c16SMatt Jacob 		isp->isp_osinfo.cdev = NULL;
2792df76c16SMatt Jacob 	}
2802df76c16SMatt Jacob 	if (isp->isp_osinfo.ehook_active) {
2812df76c16SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2822df76c16SMatt Jacob 		isp->isp_osinfo.ehook_active = 0;
2832df76c16SMatt Jacob 	}
284a035b0afSMatt Jacob 	if (isp->isp_osinfo.devq != NULL) {
2852df76c16SMatt Jacob 		cam_simq_free(isp->isp_osinfo.devq);
2862df76c16SMatt Jacob 		isp->isp_osinfo.devq = NULL;
2870a70657fSMatt Jacob 	}
2885d571944SMatt Jacob }
2895d571944SMatt Jacob 
290f7c631bcSMatt Jacob static void
2912df76c16SMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg)
292fdeb9f2fSMatt Jacob {
2932df76c16SMatt Jacob 	if (IS_FC(isp)) {
2942df76c16SMatt Jacob 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
2952df76c16SMatt Jacob 		if (fc->simqfrozen == 0) {
2962df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown) chan %d", msg, chan);
2972df76c16SMatt Jacob 			fc->simqfrozen = SIMQFRZ_LOOPDOWN;
2982df76c16SMatt Jacob 			xpt_freeze_simq(fc->sim, 1);
299fdeb9f2fSMatt Jacob 		} else {
3002df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown) chan %d", msg, chan);
3012df76c16SMatt Jacob 			fc->simqfrozen |= SIMQFRZ_LOOPDOWN;
3022df76c16SMatt Jacob 		}
303fdeb9f2fSMatt Jacob 	}
304fdeb9f2fSMatt Jacob }
305fdeb9f2fSMatt Jacob 
3069cd7268eSMatt Jacob 
3075d571944SMatt Jacob static int
3082df76c16SMatt Jacob ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
3095d571944SMatt Jacob {
3109cd7268eSMatt Jacob 	ispsoftc_t *isp;
3112df76c16SMatt Jacob 	int nr, chan, retval = ENOTTY;
3125d571944SMatt Jacob 
3132df76c16SMatt Jacob 	isp = dev->si_drv1;
3145d571944SMatt Jacob 
315c1504bc0SMatt Jacob 	switch (c) {
3165d571944SMatt Jacob 	case ISP_SDBLEV:
3175d571944SMatt Jacob 	{
3185d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3195d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3205d571944SMatt Jacob 		*(int *)addr = olddblev;
3215d571944SMatt Jacob 		retval = 0;
3225d571944SMatt Jacob 		break;
3235d571944SMatt Jacob 	}
324746e9c85SMatt Jacob 	case ISP_GETROLE:
3252df76c16SMatt Jacob 		chan = *(int *)addr;
3262df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
3272df76c16SMatt Jacob 			retval = -ENXIO;
3282df76c16SMatt Jacob 			break;
3292df76c16SMatt Jacob 		}
3302df76c16SMatt Jacob 		if (IS_FC(isp)) {
3312df76c16SMatt Jacob 			*(int *)addr = FCPARAM(isp, chan)->role;
3322df76c16SMatt Jacob 		} else {
3332df76c16SMatt Jacob 			*(int *)addr = SDPARAM(isp, chan)->role;
3342df76c16SMatt Jacob 		}
335746e9c85SMatt Jacob 		retval = 0;
336746e9c85SMatt Jacob 		break;
337746e9c85SMatt Jacob 	case ISP_SETROLE:
338746e9c85SMatt Jacob 		nr = *(int *)addr;
3392df76c16SMatt Jacob 		chan = nr >> 8;
3402df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
3412df76c16SMatt Jacob 			retval = -ENXIO;
3422df76c16SMatt Jacob 			break;
3432df76c16SMatt Jacob 		}
3442df76c16SMatt Jacob 		nr &= 0xff;
345746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
346746e9c85SMatt Jacob 			retval = EINVAL;
347746e9c85SMatt Jacob 			break;
348746e9c85SMatt Jacob 		}
3492df76c16SMatt Jacob 		if (IS_FC(isp)) {
350ae5db118SMatt Jacob 			/*
351ae5db118SMatt Jacob 			 * We don't really support dual role at present on FC cards.
352ae5db118SMatt Jacob 			 *
353ae5db118SMatt Jacob 			 * We should, but a bunch of things are currently broken,
354ae5db118SMatt Jacob 			 * so don't allow it.
355ae5db118SMatt Jacob 			 */
356ae5db118SMatt Jacob 			if (nr == ISP_ROLE_BOTH) {
357ae5db118SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "cannot support dual role at present");
358ae5db118SMatt Jacob 				retval = EINVAL;
359ae5db118SMatt Jacob 				break;
360ae5db118SMatt Jacob 			}
3612df76c16SMatt Jacob 			*(int *)addr = FCPARAM(isp, chan)->role;
3622df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
3632df76c16SMatt Jacob 			ISP_LOCK(isp);
3642df76c16SMatt Jacob 			retval = isp_fc_change_role(isp, chan, nr);
3652df76c16SMatt Jacob 			ISP_UNLOCK(isp);
3662df76c16SMatt Jacob #else
3672df76c16SMatt Jacob 			FCPARAM(isp, chan)->role = nr;
3682df76c16SMatt Jacob #endif
3692df76c16SMatt Jacob 		} else {
3702df76c16SMatt Jacob 			*(int *)addr = SDPARAM(isp, chan)->role;
3712df76c16SMatt Jacob 			SDPARAM(isp, chan)->role = nr;
3722df76c16SMatt Jacob 		}
3732df76c16SMatt Jacob 		retval = 0;
3742df76c16SMatt Jacob 		break;
3752df76c16SMatt Jacob 
3765d571944SMatt Jacob 	case ISP_RESETHBA:
377511ced9bSMatt Jacob 		ISP_LOCK(isp);
3782df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
3792df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, ISP_NOCHAN);
3802df76c16SMatt Jacob #endif
3812df76c16SMatt Jacob 		isp_reinit(isp, 0);
382511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
3835d571944SMatt Jacob 		retval = 0;
3845d571944SMatt Jacob 		break;
3852df76c16SMatt Jacob 
386f553351eSMatt Jacob 	case ISP_RESCAN:
3875d571944SMatt Jacob 		if (IS_FC(isp)) {
3882df76c16SMatt Jacob 			chan = *(int *)addr;
3892df76c16SMatt Jacob 			if (chan < 0 || chan >= isp->isp_nchan) {
3902df76c16SMatt Jacob 				retval = -ENXIO;
3912df76c16SMatt Jacob 				break;
3922df76c16SMatt Jacob 			}
393511ced9bSMatt Jacob 			ISP_LOCK(isp);
3942df76c16SMatt Jacob 			if (isp_fc_runstate(isp, chan, 5 * 1000000)) {
3955d571944SMatt Jacob 				retval = EIO;
3965d571944SMatt Jacob 			} else {
3975d571944SMatt Jacob 				retval = 0;
3985d571944SMatt Jacob 			}
399511ced9bSMatt Jacob 			ISP_UNLOCK(isp);
4005d571944SMatt Jacob 		}
4015d571944SMatt Jacob 		break;
4022df76c16SMatt Jacob 
4035d571944SMatt Jacob 	case ISP_FC_LIP:
4045d571944SMatt Jacob 		if (IS_FC(isp)) {
4052df76c16SMatt Jacob 			chan = *(int *)addr;
4062df76c16SMatt Jacob 			if (chan < 0 || chan >= isp->isp_nchan) {
4072df76c16SMatt Jacob 				retval = -ENXIO;
4082df76c16SMatt Jacob 				break;
4092df76c16SMatt Jacob 			}
410511ced9bSMatt Jacob 			ISP_LOCK(isp);
4112df76c16SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, chan)) {
4125d571944SMatt Jacob 				retval = EIO;
4135d571944SMatt Jacob 			} else {
4145d571944SMatt Jacob 				retval = 0;
4155d571944SMatt Jacob 			}
416511ced9bSMatt Jacob 			ISP_UNLOCK(isp);
4175d571944SMatt Jacob 		}
4185d571944SMatt Jacob 		break;
4195d571944SMatt Jacob 	case ISP_FC_GETDINFO:
4205d571944SMatt Jacob 	{
4215d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
42210365e5aSMatt Jacob 		fcportdb_t *lp;
4235d571944SMatt Jacob 
42402e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
42502e2b2d9SMatt Jacob 			break;
42602e2b2d9SMatt Jacob 		}
4272e4637cdSMatt Jacob 		if (ifc->loopid >= MAX_FC_TARG) {
4285d571944SMatt Jacob 			retval = EINVAL;
4295d571944SMatt Jacob 			break;
4305d571944SMatt Jacob 		}
4312df76c16SMatt Jacob 		lp = &FCPARAM(isp, ifc->chan)->portdb[ifc->loopid];
4322df76c16SMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID || lp->target_mode) {
433c6435ff3SMatt Jacob 			ifc->role = lp->roles;
43410365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4355d571944SMatt Jacob 			ifc->portid = lp->portid;
4365d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4375d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4385d571944SMatt Jacob 			retval = 0;
4395d571944SMatt Jacob 		} else {
4405d571944SMatt Jacob 			retval = ENODEV;
4415d571944SMatt Jacob 		}
4425d571944SMatt Jacob 		break;
4435d571944SMatt Jacob 	}
4442903b272SMatt Jacob 	case ISP_GET_STATS:
4452903b272SMatt Jacob 	{
4462903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4472903b272SMatt Jacob 
4482df76c16SMatt Jacob 		ISP_MEMZERO(sp, sizeof (*sp));
4492903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4502903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
4512903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
452511ced9bSMatt Jacob 		ISP_LOCK(isp);
4532903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
4542903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
4552903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
4562903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
4572903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
4582903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
4592903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
4602903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
461511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
4622903b272SMatt Jacob 		retval = 0;
4632903b272SMatt Jacob 		break;
4642903b272SMatt Jacob 	}
4652903b272SMatt Jacob 	case ISP_CLR_STATS:
466511ced9bSMatt Jacob 		ISP_LOCK(isp);
4672903b272SMatt Jacob 		isp->isp_intcnt = 0;
4682903b272SMatt Jacob 		isp->isp_intbogus = 0;
4692903b272SMatt Jacob 		isp->isp_intmboxc = 0;
4702903b272SMatt Jacob 		isp->isp_intoasync = 0;
4712903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
4722903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
4732903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
4742903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
475511ced9bSMatt Jacob 		ISP_UNLOCK(isp);
4762903b272SMatt Jacob 		retval = 0;
4772903b272SMatt Jacob 		break;
478570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
479570c7a3fSMatt Jacob 	{
480570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
4812df76c16SMatt Jacob 		int chan = hba->fc_channel;
48202e2b2d9SMatt Jacob 
4832df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
4842df76c16SMatt Jacob 			retval = ENXIO;
4852df76c16SMatt Jacob 			break;
4862df76c16SMatt Jacob 		}
487a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
488a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
489a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
4902df76c16SMatt Jacob 		hba->fc_nchannels = isp->isp_nchan;
49102e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
4922df76c16SMatt Jacob 			hba->fc_nports = MAX_FC_TARG;
4932df76c16SMatt Jacob 			hba->fc_speed = FCPARAM(isp, hba->fc_channel)->isp_gbspeed;
4942df76c16SMatt Jacob 			hba->fc_topology = FCPARAM(isp, chan)->isp_topo + 1;
4952df76c16SMatt Jacob 			hba->fc_loopid = FCPARAM(isp, chan)->isp_loopid;
4962df76c16SMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp, chan)->isp_wwnn_nvram;
4972df76c16SMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp, chan)->isp_wwpn_nvram;
4982df76c16SMatt Jacob 			hba->active_node_wwn = FCPARAM(isp, chan)->isp_wwnn;
4992df76c16SMatt Jacob 			hba->active_port_wwn = FCPARAM(isp, chan)->isp_wwpn;
5002df76c16SMatt Jacob 		} else {
5012df76c16SMatt Jacob 			hba->fc_nports = MAX_TARGETS;
5022df76c16SMatt Jacob 			hba->fc_speed = 0;
5032df76c16SMatt Jacob 			hba->fc_topology = 0;
5042df76c16SMatt Jacob 			hba->nvram_node_wwn = 0ull;
5052df76c16SMatt Jacob 			hba->nvram_port_wwn = 0ull;
5062df76c16SMatt Jacob 			hba->active_node_wwn = 0ull;
5072df76c16SMatt Jacob 			hba->active_port_wwn = 0ull;
50802e2b2d9SMatt Jacob 		}
509570c7a3fSMatt Jacob 		retval = 0;
510570c7a3fSMatt Jacob 		break;
511570c7a3fSMatt Jacob 	}
5128e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5138e62a8acSMatt Jacob 	{
5148e62a8acSMatt Jacob 		int needmarker;
5158e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5161dae40ebSMatt Jacob 		uint16_t loopid;
5178e62a8acSMatt Jacob 		mbreg_t mbs;
5188e62a8acSMatt Jacob 
5198e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5208e62a8acSMatt Jacob 			break;
5218e62a8acSMatt Jacob 		}
5228e62a8acSMatt Jacob 
5232df76c16SMatt Jacob 		chan = fct->chan;
5242df76c16SMatt Jacob 		if (chan < 0 || chan >= isp->isp_nchan) {
5252df76c16SMatt Jacob 			retval = -ENXIO;
5262df76c16SMatt Jacob 			break;
5272df76c16SMatt Jacob 		}
5282df76c16SMatt Jacob 
5298e62a8acSMatt Jacob 		needmarker = retval = 0;
530e5265237SMatt Jacob 		loopid = fct->loopid;
5312df76c16SMatt Jacob 		ISP_LOCK(isp);
5322df76c16SMatt Jacob 		if (IS_24XX(isp)) {
5332df76c16SMatt Jacob 			uint8_t local[QENTRY_LEN];
5342df76c16SMatt Jacob 			isp24xx_tmf_t *tmf;
5352df76c16SMatt Jacob 			isp24xx_statusreq_t *sp;
5362df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, chan);
5372df76c16SMatt Jacob 			fcportdb_t *lp;
5382df76c16SMatt Jacob 			int i;
5392df76c16SMatt Jacob 
5402df76c16SMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
5412df76c16SMatt Jacob 				lp = &fcp->portdb[i];
5422df76c16SMatt Jacob 				if (lp->handle == loopid) {
5432df76c16SMatt Jacob 					break;
5442df76c16SMatt Jacob 				}
5452df76c16SMatt Jacob 			}
5462df76c16SMatt Jacob 			if (i == MAX_FC_TARG) {
5472df76c16SMatt Jacob 				retval = ENXIO;
5482df76c16SMatt Jacob 				ISP_UNLOCK(isp);
5492df76c16SMatt Jacob 				break;
5502df76c16SMatt Jacob 			}
5512df76c16SMatt Jacob 			/* XXX VALIDATE LP XXX */
5522df76c16SMatt Jacob 			tmf = (isp24xx_tmf_t *) local;
5532df76c16SMatt Jacob 			ISP_MEMZERO(tmf, QENTRY_LEN);
5542df76c16SMatt Jacob 			tmf->tmf_header.rqs_entry_type = RQSTYPE_TSK_MGMT;
5552df76c16SMatt Jacob 			tmf->tmf_header.rqs_entry_count = 1;
5562df76c16SMatt Jacob 			tmf->tmf_nphdl = lp->handle;
5572df76c16SMatt Jacob 			tmf->tmf_delay = 2;
5582df76c16SMatt Jacob 			tmf->tmf_timeout = 2;
5592df76c16SMatt Jacob 			tmf->tmf_tidlo = lp->portid;
5602df76c16SMatt Jacob 			tmf->tmf_tidhi = lp->portid >> 16;
5612df76c16SMatt Jacob 			tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan);
5622df76c16SMatt Jacob 			tmf->tmf_lun[1] = fct->lun & 0xff;
5632df76c16SMatt Jacob 			if (fct->lun >= 256) {
5642df76c16SMatt Jacob 				tmf->tmf_lun[0] = 0x40 | (fct->lun >> 8);
5652df76c16SMatt Jacob 			}
5662df76c16SMatt Jacob 			switch (fct->action) {
5672df76c16SMatt Jacob 			case IPT_CLEAR_ACA:
5682df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_CLEAR_ACA;
5692df76c16SMatt Jacob 				break;
5702df76c16SMatt Jacob 			case IPT_TARGET_RESET:
5712df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET;
5722df76c16SMatt Jacob 				needmarker = 1;
5732df76c16SMatt Jacob 				break;
5742df76c16SMatt Jacob 			case IPT_LUN_RESET:
5752df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_LUN_RESET;
5762df76c16SMatt Jacob 				needmarker = 1;
5772df76c16SMatt Jacob 				break;
5782df76c16SMatt Jacob 			case IPT_CLEAR_TASK_SET:
5792df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_CLEAR_TASK_SET;
5802df76c16SMatt Jacob 				needmarker = 1;
5812df76c16SMatt Jacob 				break;
5822df76c16SMatt Jacob 			case IPT_ABORT_TASK_SET:
5832df76c16SMatt Jacob 				tmf->tmf_flags = ISP24XX_TMF_ABORT_TASK_SET;
5842df76c16SMatt Jacob 				needmarker = 1;
5852df76c16SMatt Jacob 				break;
5862df76c16SMatt Jacob 			default:
5872df76c16SMatt Jacob 				retval = EINVAL;
5882df76c16SMatt Jacob 				break;
5892df76c16SMatt Jacob 			}
5902df76c16SMatt Jacob 			if (retval) {
5912df76c16SMatt Jacob 				ISP_UNLOCK(isp);
5922df76c16SMatt Jacob 				break;
5932df76c16SMatt Jacob 			}
5942df76c16SMatt Jacob 			MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000);
5952df76c16SMatt Jacob 			mbs.param[1] = QENTRY_LEN;
5962df76c16SMatt Jacob 			mbs.param[2] = DMA_WD1(fcp->isp_scdma);
5972df76c16SMatt Jacob 			mbs.param[3] = DMA_WD0(fcp->isp_scdma);
5982df76c16SMatt Jacob 			mbs.param[6] = DMA_WD3(fcp->isp_scdma);
5992df76c16SMatt Jacob 			mbs.param[7] = DMA_WD2(fcp->isp_scdma);
6002df76c16SMatt Jacob 
6012df76c16SMatt Jacob 			if (FC_SCRATCH_ACQUIRE(isp, chan)) {
6022df76c16SMatt Jacob 				ISP_UNLOCK(isp);
6032df76c16SMatt Jacob 				retval = ENOMEM;
6042df76c16SMatt Jacob 				break;
6052df76c16SMatt Jacob 			}
6062df76c16SMatt Jacob 			isp_put_24xx_tmf(isp, tmf, fcp->isp_scratch);
607*37bb79f1SMarius Strobl 			MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan);
6082df76c16SMatt Jacob 			sp = (isp24xx_statusreq_t *) local;
6092df76c16SMatt Jacob 			sp->req_completion_status = 1;
6102df76c16SMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
611*37bb79f1SMarius Strobl 			MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
6122df76c16SMatt Jacob 			isp_get_24xx_response(isp, &((isp24xx_statusreq_t *)fcp->isp_scratch)[1], sp);
6132df76c16SMatt Jacob 			FC_SCRATCH_RELEASE(isp, chan);
6142df76c16SMatt Jacob 			if (retval || sp->req_completion_status != 0) {
6152df76c16SMatt Jacob 				FC_SCRATCH_RELEASE(isp, chan);
6162df76c16SMatt Jacob 				retval = EIO;
6172df76c16SMatt Jacob 			}
6182df76c16SMatt Jacob 			if (retval == 0) {
6192df76c16SMatt Jacob 				if (needmarker) {
6202df76c16SMatt Jacob 					fcp->sendmarker = 1;
6212df76c16SMatt Jacob 				}
6222df76c16SMatt Jacob 			}
6232df76c16SMatt Jacob 		} else {
6242df76c16SMatt Jacob 			MBSINIT(&mbs, 0, MBLOGALL, 0);
6252df76c16SMatt Jacob 			if (ISP_CAP_2KLOGIN(isp) == 0) {
626e5265237SMatt Jacob 				loopid <<= 8;
627e5265237SMatt Jacob 			}
6288e62a8acSMatt Jacob 			switch (fct->action) {
629f0f536d1SMatt Jacob 			case IPT_CLEAR_ACA:
6308e62a8acSMatt Jacob 				mbs.param[0] = MBOX_CLEAR_ACA;
631e5265237SMatt Jacob 				mbs.param[1] = loopid;
6328e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6338e62a8acSMatt Jacob 				break;
634f0f536d1SMatt Jacob 			case IPT_TARGET_RESET:
6358e62a8acSMatt Jacob 				mbs.param[0] = MBOX_TARGET_RESET;
636e5265237SMatt Jacob 				mbs.param[1] = loopid;
6378e62a8acSMatt Jacob 				needmarker = 1;
6388e62a8acSMatt Jacob 				break;
639f0f536d1SMatt Jacob 			case IPT_LUN_RESET:
6408e62a8acSMatt Jacob 				mbs.param[0] = MBOX_LUN_RESET;
641e5265237SMatt Jacob 				mbs.param[1] = loopid;
6428e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6438e62a8acSMatt Jacob 				needmarker = 1;
6448e62a8acSMatt Jacob 				break;
645f0f536d1SMatt Jacob 			case IPT_CLEAR_TASK_SET:
6468e62a8acSMatt Jacob 				mbs.param[0] = MBOX_CLEAR_TASK_SET;
647e5265237SMatt Jacob 				mbs.param[1] = loopid;
6488e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6498e62a8acSMatt Jacob 				needmarker = 1;
6508e62a8acSMatt Jacob 				break;
651f0f536d1SMatt Jacob 			case IPT_ABORT_TASK_SET:
6528e62a8acSMatt Jacob 				mbs.param[0] = MBOX_ABORT_TASK_SET;
653e5265237SMatt Jacob 				mbs.param[1] = loopid;
6548e62a8acSMatt Jacob 				mbs.param[2] = fct->lun;
6558e62a8acSMatt Jacob 				needmarker = 1;
6568e62a8acSMatt Jacob 				break;
6578e62a8acSMatt Jacob 			default:
6588e62a8acSMatt Jacob 				retval = EINVAL;
6598e62a8acSMatt Jacob 				break;
6608e62a8acSMatt Jacob 			}
6618e62a8acSMatt Jacob 			if (retval == 0) {
6628e62a8acSMatt Jacob 				if (needmarker) {
6632df76c16SMatt Jacob 					FCPARAM(isp, chan)->sendmarker = 1;
6648e62a8acSMatt Jacob 				}
6658e62a8acSMatt Jacob 				retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6662df76c16SMatt Jacob 				if (retval) {
6678e62a8acSMatt Jacob 					retval = EIO;
6688e62a8acSMatt Jacob 				}
6692df76c16SMatt Jacob 			}
6702df76c16SMatt Jacob 		}
6712df76c16SMatt Jacob 		ISP_UNLOCK(isp);
6728e62a8acSMatt Jacob 		break;
6738e62a8acSMatt Jacob 	}
6745d571944SMatt Jacob 	default:
6755d571944SMatt Jacob 		break;
6765d571944SMatt Jacob 	}
6775d571944SMatt Jacob 	return (retval);
6780470d791SMatt Jacob }
679478f8a96SJustin T. Gibbs 
680f6e75de2SMatt Jacob static void
681f6e75de2SMatt Jacob isp_intr_enable(void *arg)
682f6e75de2SMatt Jacob {
6832df76c16SMatt Jacob 	int chan;
6849cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
6850a70657fSMatt Jacob 	ISP_LOCK(isp);
6862df76c16SMatt Jacob 	for (chan = 0; chan < isp->isp_nchan; chan++) {
6872df76c16SMatt Jacob 		if (IS_FC(isp)) {
6882df76c16SMatt Jacob 			if (FCPARAM(isp, chan)->role != ISP_ROLE_NONE) {
68910365e5aSMatt Jacob 				ISP_ENABLE_INTS(isp);
6902df76c16SMatt Jacob 				break;
6912df76c16SMatt Jacob 			}
6922df76c16SMatt Jacob 		} else {
6932df76c16SMatt Jacob 			if (SDPARAM(isp, chan)->role != ISP_ROLE_NONE) {
6942df76c16SMatt Jacob 				ISP_ENABLE_INTS(isp);
6952df76c16SMatt Jacob 				break;
6962df76c16SMatt Jacob 			}
6972df76c16SMatt Jacob 		}
698d6e5500fSMatt Jacob 	}
6990a70657fSMatt Jacob 	ISP_UNLOCK(isp);
700f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
701f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
702f6e75de2SMatt Jacob }
703d81ba9d5SMatt Jacob 
704d81ba9d5SMatt Jacob /*
7052df76c16SMatt Jacob  * Local Inlines
7062df76c16SMatt Jacob  */
7072df76c16SMatt Jacob 
7082df76c16SMatt Jacob static ISP_INLINE int isp_get_pcmd(ispsoftc_t *, union ccb *);
7092df76c16SMatt Jacob static ISP_INLINE void isp_free_pcmd(ispsoftc_t *, union ccb *);
7102df76c16SMatt Jacob 
7112df76c16SMatt Jacob static ISP_INLINE int
7122df76c16SMatt Jacob isp_get_pcmd(ispsoftc_t *isp, union ccb *ccb)
7132df76c16SMatt Jacob {
7142df76c16SMatt Jacob 	ISP_PCMD(ccb) = isp->isp_osinfo.pcmd_free;
7152df76c16SMatt Jacob 	if (ISP_PCMD(ccb) == NULL) {
7162df76c16SMatt Jacob 		return (-1);
7172df76c16SMatt Jacob 	}
7182df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_free = ((struct isp_pcmd *)ISP_PCMD(ccb))->next;
7192df76c16SMatt Jacob 	return (0);
7202df76c16SMatt Jacob }
7212df76c16SMatt Jacob 
7222df76c16SMatt Jacob static ISP_INLINE void
7232df76c16SMatt Jacob isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb)
7242df76c16SMatt Jacob {
7252df76c16SMatt Jacob 	((struct isp_pcmd *)ISP_PCMD(ccb))->next = isp->isp_osinfo.pcmd_free;
7262df76c16SMatt Jacob 	isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb);
7272df76c16SMatt Jacob 	ISP_PCMD(ccb) = NULL;
7282df76c16SMatt Jacob }
7292df76c16SMatt Jacob /*
730d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
731d81ba9d5SMatt Jacob  */
732d81ba9d5SMatt Jacob 
733d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
7342df76c16SMatt Jacob static ISP_INLINE int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7352df76c16SMatt Jacob static ISP_INLINE tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7362df76c16SMatt Jacob static ISP_INLINE tstate_t *get_lun_statep_from_tag(ispsoftc_t *, int, uint32_t);
7372df76c16SMatt Jacob static ISP_INLINE void rls_lun_statep(ispsoftc_t *, tstate_t *);
7382df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *get_ntp_from_tagdata(ispsoftc_t *, uint32_t, uint32_t, tstate_t **);
7392df76c16SMatt Jacob static ISP_INLINE atio_private_data_t *isp_get_atpd(ispsoftc_t *, tstate_t *, uint32_t);
7402df76c16SMatt Jacob static ISP_INLINE void isp_put_atpd(ispsoftc_t *, tstate_t *, atio_private_data_t *);
7412df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *isp_get_ntpd(ispsoftc_t *, tstate_t *);
7422df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *isp_find_ntpd(ispsoftc_t *, tstate_t *, uint32_t, uint32_t);
7432df76c16SMatt Jacob static ISP_INLINE void isp_put_ntpd(ispsoftc_t *, tstate_t *, inot_private_data_t *);
7442df76c16SMatt Jacob static cam_status create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7459cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7462df76c16SMatt Jacob static void isp_enable_lun(ispsoftc_t *, union ccb *);
7472df76c16SMatt Jacob static void isp_enable_deferred_luns(ispsoftc_t *, int);
7482df76c16SMatt Jacob static cam_status isp_enable_deferred(ispsoftc_t *, int, lun_id_t);
7492df76c16SMatt Jacob static void isp_disable_lun(ispsoftc_t *, union ccb *);
7502df76c16SMatt Jacob static int isp_enable_target_mode(ispsoftc_t *, int);
7519cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
752f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
753a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
754a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
7559cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
7562df76c16SMatt Jacob static void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
7572df76c16SMatt Jacob static void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
7582df76c16SMatt Jacob static void isp_handle_platform_atio7(ispsoftc_t *, at7_entry_t *);
7592df76c16SMatt Jacob static void isp_handle_platform_ctio(ispsoftc_t *, void *);
7602df76c16SMatt Jacob static void isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
7612df76c16SMatt Jacob static void isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
7622df76c16SMatt Jacob static void isp_handle_platform_notify_24xx(ispsoftc_t *, in_fcentry_24xx_t *);
7632df76c16SMatt Jacob static int isp_handle_platform_target_notify_ack(ispsoftc_t *, isp_notify_t *);
7642df76c16SMatt Jacob static void isp_handle_platform_target_tmf(ispsoftc_t *, isp_notify_t *);
7652df76c16SMatt Jacob static void isp_target_mark_aborted(ispsoftc_t *, union ccb *);
7662df76c16SMatt Jacob static void isp_target_mark_aborted_early(ispsoftc_t *, tstate_t *, uint32_t);
767d81ba9d5SMatt Jacob 
7682df76c16SMatt Jacob static ISP_INLINE int
7699cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
770d81ba9d5SMatt Jacob {
771d81ba9d5SMatt Jacob 	tstate_t *tptr;
7722df76c16SMatt Jacob 	struct tslist *lhp;
7732df76c16SMatt Jacob 
7742df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(lun)], lhp);
7752df76c16SMatt Jacob 	SLIST_FOREACH(tptr, lhp, next) {
7762df76c16SMatt Jacob 		if (xpt_path_lun_id(tptr->owner) == lun) {
777d81ba9d5SMatt Jacob 			return (1);
778d81ba9d5SMatt Jacob 		}
7792df76c16SMatt Jacob 	}
780d81ba9d5SMatt Jacob 	return (0);
781d81ba9d5SMatt Jacob }
782d81ba9d5SMatt Jacob 
7832df76c16SMatt Jacob static void
7842df76c16SMatt Jacob dump_tstates(ispsoftc_t *isp, int bus)
785d81ba9d5SMatt Jacob {
7862df76c16SMatt Jacob 	int i, j;
7872df76c16SMatt Jacob 	struct tslist *lhp;
7882df76c16SMatt Jacob 	tstate_t *tptr = NULL;
7892df76c16SMatt Jacob 
7902df76c16SMatt Jacob 	if (bus >= isp->isp_nchan) {
7912df76c16SMatt Jacob 		return;
792a1bc34c6SMatt Jacob 	}
7932df76c16SMatt Jacob 	for (i = 0; i < LUN_HASH_SIZE; i++) {
7942df76c16SMatt Jacob 		ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
7952df76c16SMatt Jacob 		j = 0;
7962df76c16SMatt Jacob 		SLIST_FOREACH(tptr, lhp, next) {
7972df76c16SMatt Jacob 			xpt_print(tptr->owner, "[%d, %d] atio_cnt=%d inot_cnt=%d\n", i, j, tptr->atio_count, tptr->inot_count);
7982df76c16SMatt Jacob 			j++;
799d81ba9d5SMatt Jacob 		}
800d81ba9d5SMatt Jacob 	}
801d81ba9d5SMatt Jacob }
802d81ba9d5SMatt Jacob 
8032df76c16SMatt Jacob static ISP_INLINE tstate_t *
8049cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
805d81ba9d5SMatt Jacob {
80664edff94SMatt Jacob 	tstate_t *tptr = NULL;
8072df76c16SMatt Jacob 	struct tslist *lhp;
8082df76c16SMatt Jacob 	int i;
809d81ba9d5SMatt Jacob 
8102df76c16SMatt Jacob 	if (bus < isp->isp_nchan) {
8112df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
8122df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
8132df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
8142df76c16SMatt Jacob 				if (xpt_path_lun_id(tptr->owner) == lun) {
815d81ba9d5SMatt Jacob 					tptr->hold++;
816d81ba9d5SMatt Jacob 					return (tptr);
817d81ba9d5SMatt Jacob 				}
81864edff94SMatt Jacob 			}
819126ec864SMatt Jacob 		}
8202df76c16SMatt Jacob 	}
8212df76c16SMatt Jacob 	return (NULL);
8222df76c16SMatt Jacob }
823d81ba9d5SMatt Jacob 
8242df76c16SMatt Jacob static ISP_INLINE tstate_t *
8252df76c16SMatt Jacob get_lun_statep_from_tag(ispsoftc_t *isp, int bus, uint32_t tagval)
8262df76c16SMatt Jacob {
8272df76c16SMatt Jacob 	tstate_t *tptr = NULL;
8282df76c16SMatt Jacob 	atio_private_data_t *atp;
8292df76c16SMatt Jacob 	struct tslist *lhp;
8302df76c16SMatt Jacob 	int i;
8312df76c16SMatt Jacob 
8322df76c16SMatt Jacob 	if (bus < isp->isp_nchan && tagval != 0) {
8332df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
8342df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
8352df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
8362df76c16SMatt Jacob 				atp = isp_get_atpd(isp, tptr, tagval);
8372df76c16SMatt Jacob 				if (atp && atp->tag == tagval) {
838d81ba9d5SMatt Jacob 					tptr->hold++;
839d81ba9d5SMatt Jacob 					return (tptr);
840d81ba9d5SMatt Jacob 				}
8412df76c16SMatt Jacob 			}
8422df76c16SMatt Jacob 		}
8432df76c16SMatt Jacob 	}
8442df76c16SMatt Jacob 	return (NULL);
845d81ba9d5SMatt Jacob }
846d81ba9d5SMatt Jacob 
8472df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
8482df76c16SMatt Jacob get_ntp_from_tagdata(ispsoftc_t *isp, uint32_t tag_id, uint32_t seq_id, tstate_t **rslt)
8492df76c16SMatt Jacob {
8502df76c16SMatt Jacob 	inot_private_data_t *ntp;
8512df76c16SMatt Jacob 	tstate_t *tptr;
8522df76c16SMatt Jacob 	struct tslist *lhp;
8532df76c16SMatt Jacob 	int bus, i;
8542df76c16SMatt Jacob 
8552df76c16SMatt Jacob 	for (bus = 0; bus < isp->isp_nchan; bus++) {
8562df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
8572df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
8582df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
8592df76c16SMatt Jacob 				ntp = isp_find_ntpd(isp, tptr, tag_id, seq_id);
8602df76c16SMatt Jacob 				if (ntp) {
8612df76c16SMatt Jacob 					*rslt = tptr;
8622df76c16SMatt Jacob 					tptr->hold++;
8632df76c16SMatt Jacob 					return (ntp);
8642df76c16SMatt Jacob 				}
8652df76c16SMatt Jacob 			}
8662df76c16SMatt Jacob 		}
8672df76c16SMatt Jacob 	}
8682df76c16SMatt Jacob 	return (NULL);
8692df76c16SMatt Jacob }
8702df76c16SMatt Jacob static ISP_INLINE void
8719cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
872d81ba9d5SMatt Jacob {
8732df76c16SMatt Jacob 	KASSERT((tptr->hold), ("tptr not held"));
874d81ba9d5SMatt Jacob 	tptr->hold--;
875d81ba9d5SMatt Jacob }
876d81ba9d5SMatt Jacob 
8772df76c16SMatt Jacob static void
8782df76c16SMatt Jacob isp_tmcmd_restart(ispsoftc_t *isp)
8792df76c16SMatt Jacob {
8802df76c16SMatt Jacob 	inot_private_data_t *ntp;
8812df76c16SMatt Jacob 	tstate_t *tptr;
8822df76c16SMatt Jacob 	struct tslist *lhp;
8832df76c16SMatt Jacob 	int bus, i;
8842df76c16SMatt Jacob 
8852df76c16SMatt Jacob 	for (bus = 0; bus < isp->isp_nchan; bus++) {
8862df76c16SMatt Jacob 		for (i = 0; i < LUN_HASH_SIZE; i++) {
8872df76c16SMatt Jacob 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
8882df76c16SMatt Jacob 			SLIST_FOREACH(tptr, lhp, next) {
8892df76c16SMatt Jacob 				inot_private_data_t *restart_queue = tptr->restart_queue;
8902df76c16SMatt Jacob 				tptr->restart_queue = NULL;
8912df76c16SMatt Jacob 				while (restart_queue) {
8922df76c16SMatt Jacob 					ntp = restart_queue;
8932df76c16SMatt Jacob 					restart_queue = ntp->rd.nt.nt_hba;
8942df76c16SMatt Jacob 					if (IS_24XX(isp)) {
8952df76c16SMatt Jacob 						isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid);
8962df76c16SMatt Jacob 						isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data);
8972df76c16SMatt Jacob 					} else {
8982df76c16SMatt Jacob 						isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid);
8992df76c16SMatt Jacob 						isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data);
9002df76c16SMatt Jacob 					}
9012df76c16SMatt Jacob 					isp_put_ntpd(isp, tptr, ntp);
9022df76c16SMatt Jacob 					if (tptr->restart_queue && restart_queue != NULL) {
9032df76c16SMatt Jacob 						ntp = tptr->restart_queue;
9042df76c16SMatt Jacob 						tptr->restart_queue = restart_queue;
9052df76c16SMatt Jacob 						while (restart_queue->rd.nt.nt_hba) {
9062df76c16SMatt Jacob 							restart_queue = restart_queue->rd.nt.nt_hba;
9072df76c16SMatt Jacob 						}
9082df76c16SMatt Jacob 						restart_queue->rd.nt.nt_hba = ntp;
9092df76c16SMatt Jacob 						break;
9102df76c16SMatt Jacob 					}
9112df76c16SMatt Jacob 				}
9122df76c16SMatt Jacob 			}
9132df76c16SMatt Jacob 		}
9142df76c16SMatt Jacob 	}
9152df76c16SMatt Jacob }
9162df76c16SMatt Jacob 
9172df76c16SMatt Jacob static ISP_INLINE atio_private_data_t *
9182df76c16SMatt Jacob isp_get_atpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag)
91953036e92SMatt Jacob {
92053036e92SMatt Jacob 	atio_private_data_t *atp;
9212df76c16SMatt Jacob 
9222df76c16SMatt Jacob 	if (tag == 0) {
9232df76c16SMatt Jacob 		atp = tptr->atfree;
9242df76c16SMatt Jacob 		if (atp) {
9252df76c16SMatt Jacob 			tptr->atfree = atp->next;
9262df76c16SMatt Jacob 		}
92753036e92SMatt Jacob 		return (atp);
92853036e92SMatt Jacob 	}
9292df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
9302df76c16SMatt Jacob 		if (atp->tag == tag) {
9312df76c16SMatt Jacob 			return (atp);
9322df76c16SMatt Jacob 		}
9332df76c16SMatt Jacob 	}
93453036e92SMatt Jacob 	return (NULL);
93553036e92SMatt Jacob }
93653036e92SMatt Jacob 
9372df76c16SMatt Jacob static ISP_INLINE void
9382df76c16SMatt Jacob isp_put_atpd(ispsoftc_t *isp, tstate_t *tptr, atio_private_data_t *atp)
9392df76c16SMatt Jacob {
9402df76c16SMatt Jacob 	atp->tag = 0;
9412df76c16SMatt Jacob 	atp->dead = 0;
9422df76c16SMatt Jacob 	atp->next = tptr->atfree;
9432df76c16SMatt Jacob 	tptr->atfree = atp;
9442df76c16SMatt Jacob }
9452df76c16SMatt Jacob 
9462df76c16SMatt Jacob static void
9472df76c16SMatt Jacob isp_dump_atpd(ispsoftc_t *isp, tstate_t *tptr)
9482df76c16SMatt Jacob {
9492df76c16SMatt Jacob 	atio_private_data_t *atp;
9502df76c16SMatt Jacob 	const char *states[8] = { "Free", "ATIO", "CAM", "CTIO", "LAST_CTIO", "PDON", "?6", "7" };
9512df76c16SMatt Jacob 
9522df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
9532df76c16SMatt Jacob 		if (atp->tag == 0) {
9542df76c16SMatt Jacob 			continue;
9552df76c16SMatt Jacob 		}
9562df76c16SMatt 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",
9572df76c16SMatt 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]);
9582df76c16SMatt Jacob 	}
9592df76c16SMatt Jacob }
9602df76c16SMatt Jacob 
9612df76c16SMatt Jacob 
9622df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
9632df76c16SMatt Jacob isp_get_ntpd(ispsoftc_t *isp, tstate_t *tptr)
9642df76c16SMatt Jacob {
9652df76c16SMatt Jacob 	inot_private_data_t *ntp;
9662df76c16SMatt Jacob 	ntp = tptr->ntfree;
9672df76c16SMatt Jacob 	if (ntp) {
9682df76c16SMatt Jacob 		tptr->ntfree = ntp->next;
9692df76c16SMatt Jacob 	}
9702df76c16SMatt Jacob 	return (ntp);
9712df76c16SMatt Jacob }
9722df76c16SMatt Jacob 
9732df76c16SMatt Jacob static ISP_INLINE inot_private_data_t *
9742df76c16SMatt Jacob isp_find_ntpd(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id, uint32_t seq_id)
9752df76c16SMatt Jacob {
9762df76c16SMatt Jacob 	inot_private_data_t *ntp;
9772df76c16SMatt Jacob 	for (ntp = tptr->ntpool; ntp < &tptr->ntpool[ATPDPSIZE]; ntp++) {
9782df76c16SMatt Jacob 		if (ntp->rd.tag_id == tag_id && ntp->rd.seq_id == seq_id) {
9792df76c16SMatt Jacob 			return (ntp);
9802df76c16SMatt Jacob 		}
9812df76c16SMatt Jacob 	}
9822df76c16SMatt Jacob 	return (NULL);
9832df76c16SMatt Jacob }
9842df76c16SMatt Jacob 
9852df76c16SMatt Jacob static ISP_INLINE void
9862df76c16SMatt Jacob isp_put_ntpd(ispsoftc_t *isp, tstate_t *tptr, inot_private_data_t *ntp)
9872df76c16SMatt Jacob {
9882df76c16SMatt Jacob 	ntp->rd.tag_id = ntp->rd.seq_id = 0;
9892df76c16SMatt Jacob 	ntp->next = tptr->ntfree;
9902df76c16SMatt Jacob 	tptr->ntfree = ntp;
9912df76c16SMatt Jacob }
9922df76c16SMatt Jacob 
993d81ba9d5SMatt Jacob static cam_status
9942df76c16SMatt Jacob create_lun_state(ispsoftc_t *isp, int bus, struct cam_path *path, tstate_t **rslt)
995d81ba9d5SMatt Jacob {
996d81ba9d5SMatt Jacob 	cam_status status;
997d81ba9d5SMatt Jacob 	lun_id_t lun;
9982df76c16SMatt Jacob 	struct tslist *lhp;
9992df76c16SMatt Jacob 	tstate_t *tptr;
10002df76c16SMatt Jacob 	int i;
1001d81ba9d5SMatt Jacob 
1002d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
10032df76c16SMatt Jacob 	if (lun != CAM_LUN_WILDCARD) {
10042e4637cdSMatt Jacob 		if (lun >= ISP_MAX_LUNS(isp)) {
1005d81ba9d5SMatt Jacob 			return (CAM_LUN_INVALID);
1006d81ba9d5SMatt Jacob 		}
10072df76c16SMatt Jacob 	}
1008a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
1009d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
1010d81ba9d5SMatt Jacob 	}
10112df76c16SMatt Jacob 	tptr = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
10122df76c16SMatt Jacob 	if (tptr == NULL) {
1013d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1014d81ba9d5SMatt Jacob 	}
10152df76c16SMatt Jacob 	status = xpt_create_path(&tptr->owner, NULL, xpt_path_path_id(path), xpt_path_target_id(path), lun);
1016d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
10172df76c16SMatt Jacob 		free(tptr, M_DEVBUF);
1018d81ba9d5SMatt Jacob 		return (status);
1019d81ba9d5SMatt Jacob 	}
10202df76c16SMatt Jacob 	SLIST_INIT(&tptr->atios);
10212df76c16SMatt Jacob 	SLIST_INIT(&tptr->inots);
10222df76c16SMatt Jacob 	for (i = 0; i < ATPDPSIZE-1; i++) {
10232df76c16SMatt Jacob 		tptr->atpool[i].next = &tptr->atpool[i+1];
10242df76c16SMatt Jacob 		tptr->ntpool[i].next = &tptr->ntpool[i+1];
1025d81ba9d5SMatt Jacob 	}
10262df76c16SMatt Jacob 	tptr->atfree = tptr->atpool;
10272df76c16SMatt Jacob 	tptr->ntfree = tptr->ntpool;
10282df76c16SMatt Jacob 	tptr->hold = 1;
10292df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, bus, lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp);
10302df76c16SMatt Jacob 	SLIST_INSERT_HEAD(lhp, tptr, next);
10312df76c16SMatt Jacob 	*rslt = tptr;
10322df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, path, "created tstate\n");
1033d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
1034d81ba9d5SMatt Jacob }
1035d81ba9d5SMatt Jacob 
10362df76c16SMatt Jacob static ISP_INLINE void
10379cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
1038d81ba9d5SMatt Jacob {
10392df76c16SMatt Jacob 	struct tslist *lhp;
10402df76c16SMatt Jacob 	KASSERT((tptr->hold == 0), ("tptr still held"));
10412df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, xpt_path_path_id(tptr->owner), lun_hash[LUN_HASH_FUNC(xpt_path_lun_id(tptr->owner))], lhp);
10422df76c16SMatt Jacob 	SLIST_REMOVE(lhp, tptr, tstate, next);
10432df76c16SMatt Jacob 	xpt_free_path(tptr->owner);
1044d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
1045d81ba9d5SMatt Jacob }
1046d81ba9d5SMatt Jacob 
10475d571944SMatt Jacob /*
10482df76c16SMatt Jacob  * Enable a lun.
10495d571944SMatt Jacob  */
10502df76c16SMatt Jacob static void
10512df76c16SMatt Jacob isp_enable_lun(ispsoftc_t *isp, union ccb *ccb)
1052d81ba9d5SMatt Jacob {
10531fd47020SMatt Jacob 	tstate_t *tptr = NULL;
10542df76c16SMatt Jacob 	int bus, tm_enabled, target_role;
10552df76c16SMatt Jacob 	target_id_t target;
1056d81ba9d5SMatt Jacob 	lun_id_t lun;
1057d81ba9d5SMatt Jacob 
1058746e9c85SMatt Jacob 	/*
10592df76c16SMatt Jacob 	 * We only support either a wildcard target/lun or a target ID of zero and a non-wildcard lun
1060746e9c85SMatt Jacob 	 */
10612df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
10622df76c16SMatt Jacob 	target = ccb->ccb_h.target_id;
10632df76c16SMatt Jacob 	lun = ccb->ccb_h.target_lun;
10642df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && target != 0) {
1065d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_TID_INVALID;
10662df76c16SMatt Jacob 		xpt_done(ccb);
10672df76c16SMatt Jacob 		return;
1068d81ba9d5SMatt Jacob 	}
10692df76c16SMatt Jacob 	if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) {
10702df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
10712df76c16SMatt Jacob 		xpt_done(ccb);
10722df76c16SMatt Jacob 		return;
10732df76c16SMatt Jacob 	}
10742df76c16SMatt Jacob 
10752df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) {
10762df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
10772df76c16SMatt Jacob 		xpt_done(ccb);
10782df76c16SMatt Jacob 		return;
10792df76c16SMatt Jacob 	}
10802df76c16SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
10812df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus);
10822df76c16SMatt Jacob 	}
10832df76c16SMatt Jacob 
10842df76c16SMatt Jacob 	/*
10852df76c16SMatt Jacob 	 * Wait until we're not busy with the lun enables subsystem
10862df76c16SMatt Jacob 	 */
10872df76c16SMatt Jacob 	while (isp->isp_osinfo.tmbusy) {
10882df76c16SMatt Jacob 		isp->isp_osinfo.tmwanted = 1;
10892df76c16SMatt Jacob 		mtx_sleep(isp, &isp->isp_lock, PRIBIO, "want_isp_enable_lun", 0);
10902df76c16SMatt Jacob 	}
10912df76c16SMatt Jacob 	isp->isp_osinfo.tmbusy = 1;
10922df76c16SMatt Jacob 
109364edff94SMatt Jacob 	/*
109464edff94SMatt Jacob 	 * This is as a good a place as any to check f/w capabilities.
109564edff94SMatt Jacob 	 */
10962df76c16SMatt Jacob 
10972df76c16SMatt Jacob 	if (IS_FC(isp)) {
10982df76c16SMatt Jacob 		if (ISP_CAP_TMODE(isp) == 0) {
10992df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "firmware does not support target mode\n");
110064edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
11012df76c16SMatt Jacob 			goto done;
110264edff94SMatt Jacob 		}
110364edff94SMatt Jacob 		/*
11042df76c16SMatt Jacob 		 * We *could* handle non-SCCLUN f/w, but we'd have to
11052df76c16SMatt Jacob 		 * dork with our already fragile enable/disable code.
110664edff94SMatt Jacob 		 */
11072df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp) == 0) {
11082df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "firmware not SCCLUN capable\n");
1109746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
11102df76c16SMatt Jacob 			goto done;
1111d81ba9d5SMatt Jacob 		}
1112d81ba9d5SMatt Jacob 
11132df76c16SMatt Jacob 		target_role = (FCPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0;
11142df76c16SMatt Jacob 
111564edff94SMatt Jacob 	} else {
11162df76c16SMatt Jacob 		target_role = (SDPARAM(isp, bus)->role & ISP_ROLE_TARGET) != 0;
1117126ec864SMatt Jacob 	}
1118126ec864SMatt Jacob 
1119126ec864SMatt Jacob 	/*
11202df76c16SMatt Jacob 	 * Create the state pointer.
11212df76c16SMatt Jacob 	 * It should not already exist.
1122126ec864SMatt Jacob 	 */
1123a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, lun);
11242df76c16SMatt Jacob 	if (tptr) {
11252df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
11262df76c16SMatt Jacob 		goto done;
1127d81ba9d5SMatt Jacob 	}
11282df76c16SMatt Jacob 	ccb->ccb_h.status = create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
11292df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
11302df76c16SMatt Jacob 		goto done;
1131d81ba9d5SMatt Jacob 	}
1132d81ba9d5SMatt Jacob 
11335d571944SMatt Jacob 	/*
11342df76c16SMatt Jacob 	 * We have a tricky maneuver to perform here.
11352df76c16SMatt Jacob 	 *
11362df76c16SMatt Jacob 	 * If target mode isn't already enabled here,
11372df76c16SMatt Jacob 	 * *and* our current role includes target mode,
11382df76c16SMatt Jacob 	 * we enable target mode here.
11392df76c16SMatt Jacob 	 *
11405d571944SMatt Jacob 	 */
11412df76c16SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, tm_enabled);
11422df76c16SMatt Jacob 	if (tm_enabled == 0 && target_role != 0) {
11432df76c16SMatt Jacob 		if (isp_enable_target_mode(isp, bus)) {
114467ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
11452df76c16SMatt Jacob 			destroy_lun_state(isp, tptr);
11462df76c16SMatt Jacob 			tptr = NULL;
11472df76c16SMatt Jacob 			goto done;
11485d571944SMatt Jacob 		}
11492df76c16SMatt Jacob 		tm_enabled = 1;
11502df76c16SMatt Jacob 	}
11512df76c16SMatt Jacob 
11522df76c16SMatt Jacob 	/*
11532df76c16SMatt Jacob 	 * Now check to see whether this bus is in target mode already.
11542df76c16SMatt Jacob 	 *
11552df76c16SMatt Jacob 	 * If not, a later role change into target mode will finish the job.
11562df76c16SMatt Jacob 	 */
11572df76c16SMatt Jacob 	if (tm_enabled == 0) {
11582df76c16SMatt Jacob 		ISP_SET_PC(isp, bus, tm_enable_defer, 1);
11592df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
11602df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Not Enabled Yet- Lun Enables Deferred\n");
11612df76c16SMatt Jacob 		goto done;
11622df76c16SMatt Jacob 	}
11632df76c16SMatt Jacob 
11642df76c16SMatt Jacob 	/*
11652df76c16SMatt Jacob 	 * Enable the lun.
11662df76c16SMatt Jacob 	 */
11672df76c16SMatt Jacob 	ccb->ccb_h.status = isp_enable_deferred(isp, bus, lun);
11682df76c16SMatt Jacob 
11692df76c16SMatt Jacob done:
11702df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP && tptr) {
11712df76c16SMatt Jacob 		destroy_lun_state(isp, tptr);
11722df76c16SMatt Jacob 		tptr = NULL;
11732df76c16SMatt Jacob 	}
11742df76c16SMatt Jacob 	if (tptr) {
11752df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
11762df76c16SMatt Jacob 	}
11772df76c16SMatt Jacob 	isp->isp_osinfo.tmbusy = 0;
11782df76c16SMatt Jacob 	if (isp->isp_osinfo.tmwanted) {
11792df76c16SMatt Jacob 		isp->isp_osinfo.tmwanted = 0;
11802df76c16SMatt Jacob 		wakeup(isp);
11812df76c16SMatt Jacob 	}
11822df76c16SMatt Jacob 	xpt_done(ccb);
11832df76c16SMatt Jacob }
11842df76c16SMatt Jacob 
11852df76c16SMatt Jacob static void
11862df76c16SMatt Jacob isp_enable_deferred_luns(ispsoftc_t *isp, int bus)
11872df76c16SMatt Jacob {
11882df76c16SMatt Jacob 	/*
11892df76c16SMatt Jacob  	 * XXX: not entirely implemented yet
11902df76c16SMatt Jacob 	 */
11912df76c16SMatt Jacob 	(void) isp_enable_deferred(isp, bus, 0);
11922df76c16SMatt Jacob }
11932df76c16SMatt Jacob 
11942df76c16SMatt Jacob static uint32_t
11952df76c16SMatt Jacob isp_enable_deferred(ispsoftc_t *isp, int bus, lun_id_t lun)
11962df76c16SMatt Jacob {
11972df76c16SMatt Jacob 	cam_status status;
11982df76c16SMatt Jacob 
11992df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTINFO, "%s: bus %d lun %u", __func__, bus, lun);
12002df76c16SMatt Jacob 	if (IS_24XX(isp) || (IS_FC(isp) && ISP_FC_PC(isp, bus)->tm_luns_enabled)) {
12012df76c16SMatt Jacob 		status = CAM_REQ_CMP;
12022df76c16SMatt Jacob 	} else {
12032df76c16SMatt Jacob 		int cmd_cnt, not_cnt;
12042df76c16SMatt Jacob 
12052df76c16SMatt Jacob 		if (IS_23XX(isp)) {
12062df76c16SMatt Jacob 			cmd_cnt = DFLT_CMND_CNT;
12072df76c16SMatt Jacob 			not_cnt = DFLT_INOT_CNT;
12082df76c16SMatt Jacob 		} else {
12092df76c16SMatt Jacob 			cmd_cnt = 64;
12102df76c16SMatt Jacob 			not_cnt = 8;
12112df76c16SMatt Jacob 		}
12122df76c16SMatt Jacob 		status = CAM_REQ_INPROG;
12132df76c16SMatt Jacob 		isp->isp_osinfo.rptr = &status;
12142df76c16SMatt Jacob 		if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, DFLT_CMND_CNT, DFLT_INOT_CNT)) {
12152df76c16SMatt Jacob 			status = CAM_RESRC_UNAVAIL;
12162df76c16SMatt Jacob 		} else {
12172df76c16SMatt Jacob 			mtx_sleep(&status, &isp->isp_lock, PRIBIO, "isp_enable_deferred", 0);
12182df76c16SMatt Jacob 		}
12192df76c16SMatt Jacob 		isp->isp_osinfo.rptr = NULL;
12202df76c16SMatt Jacob 	}
12212df76c16SMatt Jacob 
12222df76c16SMatt Jacob 	if (status == CAM_REQ_CMP) {
12232df76c16SMatt Jacob 		ISP_SET_PC(isp, bus, tm_luns_enabled, 1);
12242df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "bus %d lun %u now enabled for target mode", bus, lun);
12252df76c16SMatt Jacob 	}
12262df76c16SMatt Jacob 	return (status);
12272df76c16SMatt Jacob }
12282df76c16SMatt Jacob 
12292df76c16SMatt Jacob static void
12302df76c16SMatt Jacob isp_disable_lun(ispsoftc_t *isp, union ccb *ccb)
12312df76c16SMatt Jacob {
12322df76c16SMatt Jacob 	tstate_t *tptr = NULL;
12332df76c16SMatt Jacob 	int bus;
12342df76c16SMatt Jacob 	cam_status status;
12352df76c16SMatt Jacob 	target_id_t target;
12362df76c16SMatt Jacob 	lun_id_t lun;
12372df76c16SMatt Jacob 
12382df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
12392df76c16SMatt Jacob 	target = ccb->ccb_h.target_id;
12402df76c16SMatt Jacob 	lun = ccb->ccb_h.target_lun;
12412df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && target != 0) {
12422df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_TID_INVALID;
12432df76c16SMatt Jacob 		xpt_done(ccb);
12442df76c16SMatt Jacob 		return;
12452df76c16SMatt Jacob 	}
12462df76c16SMatt Jacob 	if (target == CAM_TARGET_WILDCARD && lun != CAM_LUN_WILDCARD) {
12472df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
12482df76c16SMatt Jacob 		xpt_done(ccb);
12492df76c16SMatt Jacob 		return;
12502df76c16SMatt Jacob 	}
12512df76c16SMatt Jacob 
12522df76c16SMatt Jacob 	if (target != CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) {
12532df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
12542df76c16SMatt Jacob 		xpt_done(ccb);
12552df76c16SMatt Jacob 		return;
12562df76c16SMatt Jacob 	}
12572df76c16SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
12582df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "enabling lun 0x%x on channel %d\n", lun, bus);
12592df76c16SMatt Jacob 	}
12602df76c16SMatt Jacob 
12612df76c16SMatt Jacob 	/*
12622df76c16SMatt Jacob 	 * See if we're busy disabling a lun now.
12632df76c16SMatt Jacob 	 */
12642df76c16SMatt Jacob 	while (isp->isp_osinfo.tmbusy) {
12652df76c16SMatt Jacob 		isp->isp_osinfo.tmwanted = 1;
12662df76c16SMatt Jacob 		mtx_sleep(isp, &isp->isp_lock, PRIBIO, "want_isp_disable_lun", 0);
12672df76c16SMatt Jacob 	}
12682df76c16SMatt Jacob 	isp->isp_osinfo.tmbusy = 1;
12692df76c16SMatt Jacob 
12702df76c16SMatt Jacob 	/*
12712df76c16SMatt Jacob 	 * Find the state pointer.
12722df76c16SMatt Jacob 	 */
12732df76c16SMatt Jacob 	if ((tptr = get_lun_statep(isp, bus, lun)) == NULL) {
12742df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_PATH_INVALID;
12752df76c16SMatt Jacob 		goto done;
12762df76c16SMatt Jacob 	}
12772df76c16SMatt Jacob 
12782df76c16SMatt Jacob 	/*
12792df76c16SMatt Jacob 	 * If we're a 24XX card, we're done.
12802df76c16SMatt Jacob 	 */
12812df76c16SMatt Jacob 	if (IS_24XX(isp)) {
12822df76c16SMatt Jacob 		status = CAM_REQ_CMP;
12832df76c16SMatt Jacob 		goto done;
12842df76c16SMatt Jacob 	}
12852df76c16SMatt Jacob 
12862df76c16SMatt Jacob 	/*
12872df76c16SMatt Jacob 	 * For SCC FW, we only deal with lun zero.
12882df76c16SMatt Jacob 	 */
12892df76c16SMatt Jacob 	if (IS_FC(isp)) {
12902df76c16SMatt Jacob 		lun = 0;
12912df76c16SMatt Jacob 	}
12922df76c16SMatt Jacob 
12932df76c16SMatt Jacob 	isp->isp_osinfo.rptr = &status;
12942df76c16SMatt Jacob 	status = CAM_REQ_INPROG;
12952df76c16SMatt Jacob 	if (isp_lun_cmd(isp, RQSTYPE_ENABLE_LUN, bus, lun, 0, 0)) {
12962df76c16SMatt Jacob 		status = CAM_RESRC_UNAVAIL;
12972df76c16SMatt Jacob 	} else {
12982df76c16SMatt Jacob 		mtx_sleep(ccb, &isp->isp_lock, PRIBIO, "isp_disable_lun", 0);
12992df76c16SMatt Jacob 	}
13002df76c16SMatt Jacob done:
13012df76c16SMatt Jacob 	if (status == CAM_REQ_CMP) {
13022df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "now disabled for target mode\n");
13032df76c16SMatt Jacob 	}
13042df76c16SMatt Jacob 	if (tptr) {
13052df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
13062df76c16SMatt Jacob 	}
13072df76c16SMatt Jacob 	isp->isp_osinfo.rptr = NULL;
13082df76c16SMatt Jacob 	isp->isp_osinfo.tmbusy = 0;
13092df76c16SMatt Jacob 	if (isp->isp_osinfo.tmwanted) {
13102df76c16SMatt Jacob 		isp->isp_osinfo.tmwanted = 0;
13112df76c16SMatt Jacob 		wakeup(isp);
13122df76c16SMatt Jacob 	}
13132df76c16SMatt Jacob 	xpt_done(ccb);
13142df76c16SMatt Jacob }
13152df76c16SMatt Jacob 
13162df76c16SMatt Jacob static int
13172df76c16SMatt Jacob isp_enable_target_mode(ispsoftc_t *isp, int bus)
13182df76c16SMatt Jacob {
13192df76c16SMatt Jacob 	int ct;
13202df76c16SMatt Jacob 
13212df76c16SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, ct);
13222df76c16SMatt Jacob 	if (ct != 0) {
13232df76c16SMatt Jacob 		return (0);
13242df76c16SMatt Jacob 	}
13252df76c16SMatt Jacob 
13262df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
13272df76c16SMatt Jacob 		mbreg_t mbs;
13282df76c16SMatt Jacob 
13292df76c16SMatt Jacob 		MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0);
13302df76c16SMatt Jacob 		mbs.param[0] = MBOX_ENABLE_TARGET_MODE;
13312df76c16SMatt Jacob 		mbs.param[1] = ENABLE_TARGET_FLAG|ENABLE_TQING_FLAG;
13322df76c16SMatt Jacob 		mbs.param[2] = bus << 7;
13332df76c16SMatt Jacob 		if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) {
13342df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Unable to add Target Role to Bus %d", bus);
13352df76c16SMatt Jacob 			return (EIO);
13362df76c16SMatt Jacob 		}
13372df76c16SMatt Jacob 		SDPARAM(isp, bus)->role |= ISP_ROLE_TARGET;
13382df76c16SMatt Jacob 	}
13392df76c16SMatt Jacob 	ISP_SET_PC(isp, bus, tm_enabled, 1);
13402df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGINFO, "Target Role added to Bus %d", bus);
13412df76c16SMatt Jacob 	return (0);
13422df76c16SMatt Jacob }
13432df76c16SMatt Jacob 
13442df76c16SMatt Jacob #ifdef	NEEDED
13452df76c16SMatt Jacob static int
13462df76c16SMatt Jacob isp_disable_target_mode(ispsoftc_t *isp, int bus)
13472df76c16SMatt Jacob {
13482df76c16SMatt Jacob 	int ct;
13492df76c16SMatt Jacob 
13502df76c16SMatt Jacob 	ISP_GET_PC(isp, bus, tm_enabled, ct);
13512df76c16SMatt Jacob 	if (ct == 0) {
13522df76c16SMatt Jacob 		return (0);
13532df76c16SMatt Jacob 	}
13542df76c16SMatt Jacob 
13552df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
13562df76c16SMatt Jacob 		mbreg_t mbs;
13572df76c16SMatt Jacob 
13582df76c16SMatt Jacob 		MBSINIT(&mbs, MBOX_ENABLE_TARGET_MODE, MBLOGALL, 0);
13592df76c16SMatt Jacob 		mbs.param[2] = bus << 7;
13602df76c16SMatt Jacob 		if (isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs) < 0 || mbs.param[0] != MBOX_COMMAND_COMPLETE) {
13612df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "Unable to subtract Target Role to Bus %d", bus);
13622df76c16SMatt Jacob 			return (EIO);
13632df76c16SMatt Jacob 		}
13642df76c16SMatt Jacob 		SDPARAM(isp, bus)->role &= ~ISP_ROLE_TARGET;
13652df76c16SMatt Jacob 	}
13662df76c16SMatt Jacob 	ISP_SET_PC(isp, bus, tm_enabled, 0);
13672df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGINFO, "Target Role subtracted from Bus %d", bus);
13682df76c16SMatt Jacob 	return (0);
13692df76c16SMatt Jacob }
13702df76c16SMatt Jacob #endif
13715d571944SMatt Jacob 
137267ff51f1SMatt Jacob static void
13739cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
137467ff51f1SMatt Jacob {
13752df76c16SMatt Jacob 	uint32_t *rptr;
1376d81ba9d5SMatt Jacob 
13772df76c16SMatt Jacob 	rptr = isp->isp_osinfo.rptr;
137867ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
13792df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "ENABLE/MODIFY LUN returned 0x%x", lep->le_status);
13802df76c16SMatt Jacob 		if (rptr) {
13812df76c16SMatt Jacob 			*rptr = CAM_REQ_CMP_ERR;
13822df76c16SMatt Jacob 			wakeup_one(rptr);
13832df76c16SMatt Jacob 		}
138467ff51f1SMatt Jacob 	} else {
13852df76c16SMatt Jacob 		if (rptr) {
13862df76c16SMatt Jacob 			*rptr = CAM_REQ_CMP;
13872df76c16SMatt Jacob 			wakeup_one(rptr);
138867ff51f1SMatt Jacob 		}
1389126ec864SMatt Jacob 	}
1390d81ba9d5SMatt Jacob }
1391d81ba9d5SMatt Jacob 
13929cd7268eSMatt Jacob static void
13939cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1394d81ba9d5SMatt Jacob {
1395d81ba9d5SMatt Jacob 	void *qe;
13962df76c16SMatt Jacob 	tstate_t *tptr;
13972df76c16SMatt Jacob 	atio_private_data_t *atp;
139800a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
13992df76c16SMatt Jacob 	uint32_t dmaresult, handle;
14001dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1401d81ba9d5SMatt Jacob 
14022df76c16SMatt Jacob 	/*
14032df76c16SMatt Jacob 	 * Do some sanity checks.
14042df76c16SMatt Jacob 	 */
14052df76c16SMatt Jacob 	if (cso->dxfer_len == 0) {
14062df76c16SMatt Jacob 		if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
14072df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n");
14082df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
14092df76c16SMatt Jacob 			xpt_done(ccb);
14102df76c16SMatt Jacob 			return;
14112df76c16SMatt Jacob 		}
14122df76c16SMatt Jacob 	}
1413f48ce188SMatt Jacob 
14142df76c16SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
14152df76c16SMatt Jacob 	if (tptr == NULL) {
14162df76c16SMatt Jacob 		tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
14172df76c16SMatt Jacob 		if (tptr == NULL) {
14182df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find tstate pointer in %s\n", __func__, cso->tag_id);
14192df76c16SMatt Jacob 			dump_tstates(isp, XS_CHANNEL(ccb));
14202df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
14212df76c16SMatt Jacob 			xpt_done(ccb);
14222df76c16SMatt Jacob 			return;
14232df76c16SMatt Jacob 		}
14242df76c16SMatt Jacob 	}
14252df76c16SMatt Jacob 
14262df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, cso->tag_id);
14272df76c16SMatt Jacob 	if (atp == NULL) {
14282df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%s: [0x%x] cannot find private data adjunct\n", __func__, cso->tag_id);
14292df76c16SMatt Jacob 		isp_dump_atpd(isp, tptr);
14302df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
14312df76c16SMatt Jacob 		xpt_done(ccb);
14322df76c16SMatt Jacob 		return;
14332df76c16SMatt Jacob 	}
14342df76c16SMatt Jacob 	if (atp->dead) {
14352df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO for a dead command\n", __func__, cso->tag_id);
14362df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_ABORTED;
14372df76c16SMatt Jacob 		xpt_done(ccb);
14382df76c16SMatt Jacob 		return;
14392df76c16SMatt Jacob 	}
14402df76c16SMatt Jacob 
14412df76c16SMatt Jacob 	/*
14422df76c16SMatt Jacob 	 * Check to make sure we're still in target mode.
14432df76c16SMatt Jacob 	 */
14442df76c16SMatt Jacob 	if ((FCPARAM(isp, XS_CHANNEL(ccb))->role & ISP_ROLE_TARGET) == 0) {
14452df76c16SMatt 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);
14462df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
14472df76c16SMatt Jacob 		xpt_done(ccb);
14482df76c16SMatt Jacob 		return;
14492df76c16SMatt Jacob 	}
14502df76c16SMatt Jacob 
14512df76c16SMatt Jacob 	/*
14522df76c16SMatt Jacob 	 * Get some resources
14532df76c16SMatt Jacob 	 */
14542df76c16SMatt Jacob 	if (isp_get_pcmd(isp, ccb)) {
14552df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
14562df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "out of PCMDs\n");
14572df76c16SMatt Jacob 		cam_freeze_devq(ccb->ccb_h.path);
14582df76c16SMatt Jacob 		cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
14592df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
14602df76c16SMatt Jacob 		xpt_done(ccb);
14612df76c16SMatt Jacob 		return;
14622df76c16SMatt Jacob 	}
14632df76c16SMatt Jacob 	qe = isp_getrqentry(isp);
14642df76c16SMatt Jacob 	if (qe == NULL) {
14652df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, rqo, __func__);
14662df76c16SMatt Jacob 		cam_freeze_devq(ccb->ccb_h.path);
14672df76c16SMatt Jacob 		cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
14682df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
14699cd7268eSMatt Jacob 		goto out;
1470d81ba9d5SMatt Jacob 	}
147129f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1472d81ba9d5SMatt Jacob 
1473d81ba9d5SMatt Jacob 	/*
1474d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1475d81ba9d5SMatt Jacob 	 */
14762df76c16SMatt Jacob 	if (IS_24XX(isp)) {
14772df76c16SMatt Jacob 		ct7_entry_t *cto = (ct7_entry_t *) local;
1478d81ba9d5SMatt Jacob 
14792df76c16SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
14802df76c16SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
14812df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
14822df76c16SMatt Jacob 		cto->ct_nphdl = atp->nphdl;
14832df76c16SMatt Jacob 		cto->ct_rxid = atp->tag;
14842df76c16SMatt Jacob 		cto->ct_iid_lo = atp->portid;
14852df76c16SMatt Jacob 		cto->ct_iid_hi = atp->portid >> 16;
14862df76c16SMatt Jacob 		cto->ct_oxid = atp->oxid;
14872df76c16SMatt Jacob 		cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb));
14882df76c16SMatt Jacob 		cto->ct_scsi_status = cso->scsi_status;
14892df76c16SMatt Jacob 		cto->ct_timeout = 120;
14902df76c16SMatt Jacob 		cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT;
14912df76c16SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
14922df76c16SMatt Jacob 			cto->ct_flags |= CT7_SENDSTATUS;
14932df76c16SMatt Jacob 		}
14942df76c16SMatt Jacob 		if (cso->dxfer_len == 0) {
14952df76c16SMatt Jacob 			cto->ct_flags |= CT7_FLAG_MODE1 | CT7_NO_DATA;
14962df76c16SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
14972df76c16SMatt Jacob 				int m = min(cso->sense_len, sizeof (struct scsi_sense_data));
14982df76c16SMatt Jacob 				cto->rsp.m1.ct_resplen = cto->ct_senselen = min(m, MAXRESPLEN_24XX);
14992df76c16SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, cto->ct_senselen);
15002df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8);
15012df76c16SMatt Jacob 			}
15022df76c16SMatt Jacob 		} else {
15032df76c16SMatt Jacob 			cto->ct_flags |= CT7_FLAG_MODE0;
15042df76c16SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
15052df76c16SMatt Jacob 				cto->ct_flags |= CT7_DATA_IN;
15062df76c16SMatt Jacob 			} else {
15072df76c16SMatt Jacob 				cto->ct_flags |= CT7_DATA_OUT;
15082df76c16SMatt Jacob 			}
15092df76c16SMatt Jacob 			cto->rsp.m0.reloff = atp->bytes_xfered;
15102df76c16SMatt Jacob 			/*
15112df76c16SMatt Jacob 			 * Don't overrun the limits placed on us
15122df76c16SMatt Jacob 			 */
15132df76c16SMatt Jacob 			if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) {
15142df76c16SMatt Jacob 				cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered;
15152df76c16SMatt Jacob 			}
15162df76c16SMatt Jacob 			atp->last_xframt = cso->dxfer_len;
15172df76c16SMatt Jacob 			cto->rsp.m0.ct_xfrlen = cso->dxfer_len;
15182df76c16SMatt Jacob 		}
15192df76c16SMatt Jacob 		if (cto->ct_flags & CT7_SENDSTATUS) {
15202df76c16SMatt Jacob 			int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0;
15212df76c16SMatt Jacob 			cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len);
15222df76c16SMatt Jacob 			if (cto->ct_resid < 0) {
15232df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
15242df76c16SMatt Jacob 			} else if (cto->ct_resid > 0) {
15252df76c16SMatt Jacob 				cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
15262df76c16SMatt Jacob 			}
15272df76c16SMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
15282df76c16SMatt 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,
15292df76c16SMatt Jacob 			    atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
15302df76c16SMatt Jacob 		} else {
15312df76c16SMatt Jacob 			cto->ct_resid = 0;
15322df76c16SMatt 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,
15332df76c16SMatt Jacob 			    cso->dxfer_len, atp->bytes_xfered);
15342df76c16SMatt Jacob 			atp->state = ATPD_STATE_CTIO;
15352df76c16SMatt Jacob 		}
15362df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
15374fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
153800a8e174SMatt Jacob 
1539d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1540d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
15412df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
15422df76c16SMatt Jacob 		if (ISP_CAP_2KLOGIN(isp) == 0) {
154329f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
154429f76675SMatt Jacob 		} else {
154500a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
15462df76c16SMatt Jacob 			if (ISP_CAP_SCCFW(isp) == 0) {
1547d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
15482ad50ca5SMatt Jacob 			}
154929f76675SMatt Jacob 		}
155053036e92SMatt Jacob 
1551f48ce188SMatt Jacob 
155200a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
155300a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
15542df76c16SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA | CT2_SENDSTATUS;
1555f48ce188SMatt Jacob 			cto->rsp.m1.ct_scsi_status = cso->scsi_status;
15562df76c16SMatt Jacob 			cto->ct_resid = atp->orig_datalen - atp->bytes_xfered;
1557570c7a3fSMatt Jacob 			if (cto->ct_resid < 0) {
15582df76c16SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER;
1559570c7a3fSMatt Jacob 			} else if (cto->ct_resid > 0) {
15602df76c16SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
1561f48ce188SMatt Jacob 			}
156200a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
156300a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
15642df76c16SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, m);
156500a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
156600a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
15672df76c16SMatt Jacob 			} else if (cso->scsi_status == SCSI_STATUS_CHECK_COND) {
15682df76c16SMatt Jacob 				/*
15692df76c16SMatt Jacob 				 * XXX: DEBUG
15702df76c16SMatt Jacob 				 */
15712df76c16SMatt Jacob 				xpt_print(ccb->ccb_h.path, "CHECK CONDITION being sent without associated SENSE DATA for CDB=0x%x\n", atp->cdb0);
157200a8e174SMatt Jacob 			}
157300a8e174SMatt Jacob 		} else {
157400a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
157500a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
157600a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
157700a8e174SMatt Jacob 			} else {
157800a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1579d81ba9d5SMatt Jacob 			}
1580570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
15812df76c16SMatt Jacob 			cto->rsp.m0.ct_xfrlen = cso->dxfer_len;
15822df76c16SMatt Jacob 			/*
15832df76c16SMatt Jacob 			 * Don't overrun the limits placed on us
15842df76c16SMatt Jacob 			 */
15852df76c16SMatt Jacob 			if (atp->bytes_xfered + cso->dxfer_len > atp->orig_datalen) {
15862df76c16SMatt Jacob 				cso->dxfer_len = atp->orig_datalen - atp->bytes_xfered;
15872df76c16SMatt Jacob 			}
1588d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1589d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
159000a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
15912df76c16SMatt Jacob 				cto->ct_resid = atp->orig_datalen - (atp->bytes_xfered + cso->dxfer_len);
1592570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
15932df76c16SMatt Jacob 					cto->rsp.m0.ct_scsi_status |= CT2_DATA_OVER;
1594570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
15952df76c16SMatt Jacob 					cto->rsp.m0.ct_scsi_status |= CT2_DATA_UNDER;
1596570c7a3fSMatt Jacob 				}
159753036e92SMatt Jacob 			} else {
159853036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1599d81ba9d5SMatt Jacob 			}
1600f48ce188SMatt Jacob 			/*
1601f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1602f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1603f48ce188SMatt Jacob 			 */
160400a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
160500a8e174SMatt Jacob 		}
160653036e92SMatt Jacob 
1607290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
16082df76c16SMatt Jacob 			int lvl = (cso->scsi_status)? ISP_LOGTINFO : ISP_LOGTDEBUG0;
1609a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1610570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
16112df76c16SMatt 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,
16122df76c16SMatt Jacob 			    atp->cdb0, cto->rsp.m0.ct_scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
16139cd7268eSMatt Jacob 		} else {
16142df76c16SMatt Jacob 			cto->ct_resid = 0;
1615570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
16162df76c16SMatt 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,
16172df76c16SMatt Jacob 			    cso->dxfer_len, atp->bytes_xfered);
16189cd7268eSMatt Jacob 		}
1619a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1620d81ba9d5SMatt Jacob 	} else {
16214fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
162200a8e174SMatt Jacob 
1623d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1624d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
16252df76c16SMatt Jacob 		cto->ct_header.rqs_seqno = 1;
162600a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1627a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1628d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1629d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
16302df76c16SMatt Jacob 		cto->ct_fwhandle = cso->tag_id >> 16;
1631a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
16322df76c16SMatt Jacob 			cto->ct_tag_val = cso->tag_id;
1633f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1634f48ce188SMatt Jacob 		}
1635f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1636f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1637f48ce188SMatt Jacob 		}
1638f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1639d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
164000a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
164100a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
164200a8e174SMatt Jacob 		} else {
164300a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1644d81ba9d5SMatt Jacob 		}
1645f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
164653036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
164700a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
164800a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
16492df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "%s: CTIO[%x] scsi status %x resid %d tag_id %x\n", __func__,
16502df76c16SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid, cso->tag_id);
165192a1e549SMatt Jacob 		}
165264edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1653a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1654d81ba9d5SMatt Jacob 	}
1655d81ba9d5SMatt Jacob 
1656c8b8a2c4SMatt Jacob 	if (isp_allocate_xs_tgt(isp, ccb, &handle)) {
16572df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__);
16582df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
16599cd7268eSMatt Jacob 		goto out;
1660d81ba9d5SMatt Jacob 	}
1661d81ba9d5SMatt Jacob 
1662d81ba9d5SMatt Jacob 
1663d81ba9d5SMatt Jacob 	/*
1664d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1665d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1666b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1667d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1668d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1669d81ba9d5SMatt Jacob 	 * format.
1670d81ba9d5SMatt Jacob 	 */
1671d81ba9d5SMatt Jacob 
16722df76c16SMatt Jacob 	if (IS_24XX(isp)) {
16732df76c16SMatt Jacob 		ct7_entry_t *cto = (ct7_entry_t *) local;
16742df76c16SMatt Jacob 		cto->ct_syshandle = handle;
16752df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
167610365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
167710365e5aSMatt Jacob 		cto->ct_syshandle = handle;
167810365e5aSMatt Jacob 	} else {
167910365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
168010365e5aSMatt Jacob 		cto->ct_syshandle = handle;
168110365e5aSMatt Jacob 	}
1682a1bc34c6SMatt Jacob 
16832df76c16SMatt Jacob 	dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local);
16842df76c16SMatt Jacob 	if (dmaresult == CMD_QUEUED) {
16852df76c16SMatt Jacob 		isp->isp_nactive++;
16869cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
16872df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
16889cd7268eSMatt Jacob 		return;
16892df76c16SMatt Jacob 	}
16902df76c16SMatt Jacob 	if (dmaresult == CMD_EAGAIN) {
16912df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
16922df76c16SMatt Jacob 	} else {
16932df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1694d81ba9d5SMatt Jacob 	}
169510365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
16969cd7268eSMatt Jacob out:
16972df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
16982df76c16SMatt Jacob 	isp_free_pcmd(isp, ccb);
16999cd7268eSMatt Jacob 	xpt_done(ccb);
1700d81ba9d5SMatt Jacob }
1701d81ba9d5SMatt Jacob 
1702a1bc34c6SMatt Jacob static void
1703a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1704f48ce188SMatt Jacob {
17052df76c16SMatt Jacob 	union ccb *ccb = arg;
17062df76c16SMatt Jacob 	ispsoftc_t *isp = XS_ISP(ccb);
17072df76c16SMatt Jacob 	ISP_LOCK(isp);
17082df76c16SMatt Jacob 	isp_target_putback_atio(ccb);
17092df76c16SMatt Jacob 	ISP_UNLOCK(isp);
1710a1bc34c6SMatt Jacob }
1711a1bc34c6SMatt Jacob 
1712a1bc34c6SMatt Jacob static void
1713a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1714a1bc34c6SMatt Jacob {
17159cd7268eSMatt Jacob 	ispsoftc_t *isp;
1716a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
1717a1bc34c6SMatt Jacob 	void *qe;
1718a1bc34c6SMatt Jacob 
1719a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1720f48ce188SMatt Jacob 
17212df76c16SMatt Jacob 	qe = isp_getrqentry(isp);
17222df76c16SMatt Jacob 	if (qe == NULL) {
17232df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, rqo, __func__);
1724a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1725a1bc34c6SMatt Jacob 		return;
1726f48ce188SMatt Jacob 	}
172729f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1728a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1729f48ce188SMatt Jacob 	if (IS_FC(isp)) {
17304fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
17312df76c16SMatt Jacob 		ISP_MEMZERO(at, sizeof (at2_entry_t));
1732f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1733f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
17342df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp)) {
1735a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1736f48ce188SMatt Jacob 		} else {
1737a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1738f48ce188SMatt Jacob 		}
1739f48ce188SMatt Jacob 		at->at_status = CT_OK;
1740a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1741570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
17424fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1743f48ce188SMatt Jacob 	} else {
17444fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
17452df76c16SMatt Jacob 		ISP_MEMZERO(at, sizeof (at_entry_t));
1746f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1747f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1748a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1749a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1750a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1751a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1752f48ce188SMatt Jacob 		at->at_status = CT_OK;
1753a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1754a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
17554fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1756f48ce188SMatt Jacob 	}
17572df76c16SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe);
17582df76c16SMatt Jacob 	ISP_SYNC_REQUEST(isp);
1759a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1760f48ce188SMatt Jacob }
1761f48ce188SMatt Jacob 
1762f48ce188SMatt Jacob static void
1763a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1764f48ce188SMatt Jacob {
1765a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1766a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1767f48ce188SMatt Jacob 	}
1768a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
17692df76c16SMatt Jacob 	isp_free_pcmd(XS_ISP(ccb), ccb);
1770a1bc34c6SMatt Jacob 	xpt_done(ccb);
1771f48ce188SMatt Jacob }
1772f48ce188SMatt Jacob 
1773d81ba9d5SMatt Jacob /*
1774d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1775d81ba9d5SMatt Jacob  * This means handling CDBs.
1776d81ba9d5SMatt Jacob  */
1777d81ba9d5SMatt Jacob 
17782df76c16SMatt Jacob static void
17799cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1780d81ba9d5SMatt Jacob {
1781d81ba9d5SMatt Jacob 	tstate_t *tptr;
17822df76c16SMatt Jacob 	int status, bus;
1783d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
17842df76c16SMatt Jacob 	atio_private_data_t *atp;
1785d81ba9d5SMatt Jacob 
1786d81ba9d5SMatt Jacob 	/*
1787d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1788d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1789d81ba9d5SMatt Jacob 	 *
1790b1ce21c6SRebecca Cran 	 * If QLTM_SVALID is set, the firmware has recommended Sense Data.
1791d81ba9d5SMatt Jacob 	 *
1792d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
17935d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1794d81ba9d5SMatt Jacob 	 */
1795d81ba9d5SMatt Jacob 	status = aep->at_status;
1796d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1797d81ba9d5SMatt Jacob 		/*
1798d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1799d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1800d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1801d81ba9d5SMatt Jacob 		 */
18023c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1803d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
18042df76c16SMatt Jacob 		return;
1805d81ba9d5SMatt Jacob 	}
1806d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
18072df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform", status);
1808d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
18092df76c16SMatt Jacob 		return;
1810d81ba9d5SMatt Jacob 	}
1811d81ba9d5SMatt Jacob 
18125d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1813a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1814d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1815a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1816746e9c85SMatt Jacob 		if (tptr == NULL) {
1817d81ba9d5SMatt Jacob 			/*
1818d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1819d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1820d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1821d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1822d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1823d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1824d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1825d81ba9d5SMatt Jacob 			 */
1826d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
18272df76c16SMatt Jacob 			return;
1828d81ba9d5SMatt Jacob 		}
18298c4e89e2SMatt Jacob 	}
1830d81ba9d5SMatt Jacob 
18312df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
1832d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
18332df76c16SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1834d81ba9d5SMatt Jacob 		/*
1835d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1836d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1837d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1838d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1839d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1840d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1841d81ba9d5SMatt Jacob 		 */
18422df76c16SMatt Jacob 		xpt_print(tptr->owner, "no %s for lun %d from initiator %d\n", (atp == NULL && atiop == NULL)? "ATIOs *or* ATPS" :
18432df76c16SMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIOs"), aep->at_lun, aep->at_iid);
1844d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
18452df76c16SMatt Jacob 		if (atp) {
18462df76c16SMatt Jacob 			isp_put_atpd(isp, tptr, atp);
1847d81ba9d5SMatt Jacob 		}
18482df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
18492df76c16SMatt Jacob 		return;
18502df76c16SMatt Jacob 	}
18512df76c16SMatt Jacob 	atp->tag = aep->at_tag_val;
18522df76c16SMatt Jacob 	if (atp->tag == 0) {
18532df76c16SMatt Jacob 		atp->tag = ~0;
18542df76c16SMatt Jacob 	}
18552df76c16SMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1856d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1857746e9c85SMatt Jacob 	tptr->atio_count--;
18582df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
1859d81ba9d5SMatt Jacob 	atiop->ccb_h.target_id = aep->at_tgt;
1860d81ba9d5SMatt Jacob 	atiop->ccb_h.target_lun = aep->at_lun;
1861d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1862f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1863f48ce188SMatt Jacob 	} else {
1864f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1865d81ba9d5SMatt Jacob 	}
1866d81ba9d5SMatt Jacob 
1867f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1868f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1869f48ce188SMatt Jacob 		atiop->sense_len = amt;
18702df76c16SMatt Jacob 		ISP_MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1871f48ce188SMatt Jacob 	} else {
1872f48ce188SMatt Jacob 		atiop->sense_len = 0;
1873f48ce188SMatt Jacob 	}
1874d81ba9d5SMatt Jacob 
18755d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1876d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
18772df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1878d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1879a1bc34c6SMatt Jacob 	/*
1880a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1881a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1882a1bc34c6SMatt Jacob 	 */
18832df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
1884a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1885a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1886d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1887d81ba9d5SMatt Jacob 	}
18882df76c16SMatt Jacob 	atp->orig_datalen = 0;
18892df76c16SMatt Jacob 	atp->bytes_xfered = 0;
18902df76c16SMatt Jacob 	atp->last_xframt = 0;
18912df76c16SMatt Jacob 	atp->lun = aep->at_lun;
18922df76c16SMatt Jacob 	atp->nphdl = aep->at_iid;
18932df76c16SMatt Jacob 	atp->portid = PORT_NONE;
18942df76c16SMatt Jacob 	atp->oxid = 0;
18952df76c16SMatt Jacob 	atp->cdb0 = atiop->cdb_io.cdb_bytes[0];
18962df76c16SMatt Jacob 	atp->tattr = aep->at_tag_type;
18972df76c16SMatt Jacob 	atp->state = ATPD_STATE_CAM;
18982df76c16SMatt 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);
1899d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1900d81ba9d5SMatt Jacob }
1901d81ba9d5SMatt Jacob 
19022df76c16SMatt Jacob static void
19039cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
1904d81ba9d5SMatt Jacob {
190592a1e549SMatt Jacob 	lun_id_t lun;
19062df76c16SMatt Jacob 	fcportdb_t *lp;
1907d81ba9d5SMatt Jacob 	tstate_t *tptr;
1908d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
19092df76c16SMatt Jacob 	uint16_t nphdl;
1910a035b0afSMatt Jacob 	atio_private_data_t *atp;
19112df76c16SMatt Jacob 	inot_private_data_t *ntp;
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 ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
19202df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bogus atio (0x%x) leaked to platform", aep->at_status);
1921d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
19222df76c16SMatt Jacob 		return;
1923d81ba9d5SMatt Jacob 	}
1924d81ba9d5SMatt Jacob 
19252df76c16SMatt Jacob 	if (ISP_CAP_SCCFW(isp)) {
192692a1e549SMatt Jacob 		lun = aep->at_scclun;
19272ad50ca5SMatt Jacob 	} else {
192892a1e549SMatt Jacob 		lun = aep->at_lun;
19292ad50ca5SMatt Jacob 	}
19302df76c16SMatt Jacob 	if (ISP_CAP_2KLOGIN(isp)) {
19312df76c16SMatt Jacob 		nphdl = ((at2e_entry_t *)aep)->at_iid;
19322df76c16SMatt Jacob 	} else {
19332df76c16SMatt Jacob 		nphdl = aep->at_iid;
19342df76c16SMatt Jacob 	}
1935a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1936d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1937a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1938746e9c85SMatt Jacob 		if (tptr == NULL) {
19392df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
19402df76c16SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0);
19412df76c16SMatt Jacob 			return;
1942746e9c85SMatt Jacob 		}
1943d81ba9d5SMatt Jacob 	}
1944d81ba9d5SMatt Jacob 
1945d81ba9d5SMatt Jacob 	/*
19462df76c16SMatt Jacob 	 * Start any commands pending resources first.
1947d81ba9d5SMatt Jacob 	 */
19482df76c16SMatt Jacob 	if (tptr->restart_queue) {
19492df76c16SMatt Jacob 		inot_private_data_t *restart_queue = tptr->restart_queue;
19502df76c16SMatt Jacob 		tptr->restart_queue = NULL;
19512df76c16SMatt Jacob 		while (restart_queue) {
19522df76c16SMatt Jacob 			ntp = restart_queue;
19532df76c16SMatt Jacob 			restart_queue = ntp->rd.nt.nt_hba;
19542df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at2_entry_t *)ntp->rd.data)->at_rxid);
19552df76c16SMatt Jacob 			isp_handle_platform_atio2(isp, (at2_entry_t *) ntp->rd.data);
19562df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
19572df76c16SMatt Jacob 			/*
19582df76c16SMatt Jacob 			 * If a recursion caused the restart queue to start to fill again,
19592df76c16SMatt Jacob 			 * stop and splice the new list on top of the old list and restore
19602df76c16SMatt Jacob 			 * it and go to noresrc.
19612df76c16SMatt Jacob 			 */
19622df76c16SMatt Jacob 			if (tptr->restart_queue) {
19632df76c16SMatt Jacob 				ntp = tptr->restart_queue;
19642df76c16SMatt Jacob 				tptr->restart_queue = restart_queue;
19652df76c16SMatt Jacob 				while (restart_queue->rd.nt.nt_hba) {
19662df76c16SMatt Jacob 					restart_queue = restart_queue->rd.nt.nt_hba;
1967d81ba9d5SMatt Jacob 				}
19682df76c16SMatt Jacob 				restart_queue->rd.nt.nt_hba = ntp;
19692df76c16SMatt Jacob 				goto noresrc;
19702df76c16SMatt Jacob 			}
19712df76c16SMatt Jacob 		}
19722df76c16SMatt Jacob 	}
19732df76c16SMatt Jacob 
19742df76c16SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
19752df76c16SMatt Jacob 	if (atiop == NULL) {
19762df76c16SMatt Jacob 		goto noresrc;
19772df76c16SMatt Jacob 	}
19782df76c16SMatt Jacob 
19792df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
19802df76c16SMatt Jacob 	if (atp == NULL) {
19812df76c16SMatt Jacob 		goto noresrc;
19822df76c16SMatt Jacob 	}
19832df76c16SMatt Jacob 
19842df76c16SMatt Jacob 	atp->tag = aep->at_rxid;
1985570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1986d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1987570c7a3fSMatt Jacob 	tptr->atio_count--;
19882df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
19892df76c16SMatt Jacob 	atiop->ccb_h.target_id = FCPARAM(isp, 0)->isp_loopid;
199092a1e549SMatt Jacob 	atiop->ccb_h.target_lun = lun;
19912df76c16SMatt Jacob 
1992b0a3ba7eSMatt Jacob 	/*
1993b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1994b0a3ba7eSMatt Jacob 	 */
1995f48ce188SMatt Jacob 	atiop->sense_len = 0;
19962df76c16SMatt Jacob 	if (ISP_CAP_2KLOGIN(isp)) {
19972df76c16SMatt Jacob 		/*
19982df76c16SMatt Jacob 		 * NB: We could not possibly have 2K logins if we
19992df76c16SMatt Jacob 		 * NB: also did not have SCC FW.
20002df76c16SMatt Jacob 		 */
20012df76c16SMatt Jacob 		atiop->init_id = ((at2e_entry_t *)aep)->at_iid;
20022df76c16SMatt Jacob 	} else {
2003d81ba9d5SMatt Jacob 		atiop->init_id = aep->at_iid;
20042df76c16SMatt Jacob 	}
20052df76c16SMatt Jacob 
20062df76c16SMatt Jacob 	/*
20072df76c16SMatt Jacob 	 * If we're not in the port database, add ourselves.
20082df76c16SMatt Jacob 	 */
20092df76c16SMatt Jacob 	if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) {
20102df76c16SMatt Jacob     		uint64_t iid =
20112df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[0]) << 48) |
20122df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[1]) << 32) |
20132df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[2]) << 16) |
20142df76c16SMatt Jacob 			(((uint64_t) aep->at_wwpn[3]) <<  0);
20152df76c16SMatt Jacob 		/*
20162df76c16SMatt Jacob 		 * However, make sure we delete ourselves if otherwise
20172df76c16SMatt Jacob 		 * we were there but at a different loop id.
20182df76c16SMatt Jacob 		 */
20192df76c16SMatt Jacob 		if (isp_find_pdb_by_wwn(isp, 0, iid, &lp)) {
20202df76c16SMatt Jacob 			isp_del_wwn_entry(isp, 0, iid, lp->handle, lp->portid);
20212df76c16SMatt Jacob 		}
20222df76c16SMatt Jacob 		isp_add_wwn_entry(isp, 0, iid, atiop->init_id, PORT_ANY);
20232df76c16SMatt Jacob 	}
2024d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
20252df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
2026d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
20272df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
2028d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
2029d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
20302df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2031d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
2032d81ba9d5SMatt Jacob 		break;
2033d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_HEADOFQ:
20342df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2035d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
2036d81ba9d5SMatt Jacob 		break;
2037d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_ORDERED:
20382df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
2039d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
2040d81ba9d5SMatt Jacob 		break;
2041d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_ACAQ:		/* ?? */
2042d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
2043d81ba9d5SMatt Jacob 	default:
2044d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
2045d81ba9d5SMatt Jacob 		break;
2046d81ba9d5SMatt Jacob 	}
2047f48ce188SMatt Jacob 
204853036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
204953036e92SMatt Jacob 	atp->bytes_xfered = 0;
20502df76c16SMatt Jacob 	atp->last_xframt = 0;
20512df76c16SMatt Jacob 	atp->lun = lun;
20522df76c16SMatt Jacob 	atp->nphdl = atiop->init_id;
20532df76c16SMatt Jacob 	atp->sid = PORT_ANY;
20542df76c16SMatt Jacob 	atp->oxid = aep->at_oxid;
20552df76c16SMatt Jacob 	atp->cdb0 = aep->at_cdb[0];
20562df76c16SMatt Jacob 	atp->tattr = aep->at_taskflags & ATIO2_TC_ATTR_MASK;
2057570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
2058d81ba9d5SMatt Jacob 	xpt_done((union ccb *)atiop);
20592df76c16SMatt 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);
2060d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
20612df76c16SMatt Jacob 	return;
20622df76c16SMatt Jacob noresrc:
20632df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
20642df76c16SMatt Jacob 	if (ntp == NULL) {
20652df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
20662df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, 0, SCSI_STATUS_BUSY, 0);
20672df76c16SMatt Jacob 		return;
20682df76c16SMatt Jacob 	}
20692df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
20702df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
20712df76c16SMatt Jacob 	tptr->restart_queue = ntp;
20722df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
2073d81ba9d5SMatt Jacob }
2074d81ba9d5SMatt Jacob 
20752df76c16SMatt Jacob static void
20762df76c16SMatt Jacob isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep)
20772df76c16SMatt Jacob {
20782df76c16SMatt Jacob 	int cdbxlen;
20792df76c16SMatt Jacob 	uint16_t lun, chan, nphdl = NIL_HANDLE;
20802df76c16SMatt Jacob 	uint32_t did, sid;
20812df76c16SMatt Jacob 	uint64_t wwn = INI_NONE;
20822df76c16SMatt Jacob 	fcportdb_t *lp;
20832df76c16SMatt Jacob 	tstate_t *tptr;
20842df76c16SMatt Jacob 	struct ccb_accept_tio *atiop;
20852df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
20862df76c16SMatt Jacob 	inot_private_data_t *ntp;
20872df76c16SMatt Jacob 
20882df76c16SMatt Jacob 	did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2];
20892df76c16SMatt Jacob 	sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
20902df76c16SMatt Jacob 	lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | aep->at_cmnd.fcp_cmnd_lun[1];
20912df76c16SMatt Jacob 
20922df76c16SMatt Jacob 	/*
20932df76c16SMatt Jacob 	 * Find the N-port handle, and Virtual Port Index for this command.
20942df76c16SMatt Jacob 	 *
20952df76c16SMatt Jacob 	 * If we can't, we're somewhat in trouble because we can't actually respond w/o that information.
20962df76c16SMatt Jacob 	 * We also, as a matter of course, need to know the WWN of the initiator too.
20972df76c16SMatt Jacob 	 */
20982df76c16SMatt Jacob 	if (ISP_CAP_MULTI_ID(isp)) {
20992df76c16SMatt Jacob 		/*
21002df76c16SMatt Jacob 		 * Find the right channel based upon D_ID
21012df76c16SMatt Jacob 		 */
21022df76c16SMatt Jacob 		isp_find_chan_by_did(isp, did, &chan);
21032df76c16SMatt Jacob 
21042df76c16SMatt Jacob 		if (chan == ISP_NOCHAN) {
21052df76c16SMatt Jacob 			NANOTIME_T now;
21062df76c16SMatt Jacob 
21072df76c16SMatt Jacob 			/*
21082df76c16SMatt Jacob 			 * If we don't recognizer our own D_DID, terminate the exchange, unless we're within 2 seconds of startup
21092df76c16SMatt Jacob 			 * It's a bit tricky here as we need to stash this command *somewhere*.
21102df76c16SMatt Jacob 			 */
21112df76c16SMatt Jacob 			GET_NANOTIME(&now);
21122df76c16SMatt Jacob 			if (NANOTIME_SUB(&isp->isp_init_time, &now) > 2000000000ULL) {
21132df76c16SMatt 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);
21142df76c16SMatt Jacob 				isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
21152df76c16SMatt Jacob 				return;
21162df76c16SMatt Jacob 			}
21172df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, 0);
21182df76c16SMatt Jacob 			if (tptr == NULL) {
21192df76c16SMatt Jacob 				tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
21202df76c16SMatt Jacob 				if (tptr == NULL) {
21212df76c16SMatt 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);
21222df76c16SMatt Jacob 					isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
21232df76c16SMatt Jacob 					return;
21242df76c16SMatt Jacob 				}
21252df76c16SMatt Jacob 			}
21262df76c16SMatt 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);
21272df76c16SMatt Jacob 			goto noresrc;
21282df76c16SMatt Jacob 		}
21292df76c16SMatt 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);
21302df76c16SMatt Jacob 	} else {
21312df76c16SMatt Jacob 		chan = 0;
21322df76c16SMatt Jacob 	}
21332df76c16SMatt Jacob 
21342df76c16SMatt Jacob 	/*
21352df76c16SMatt Jacob 	 * Find the PDB entry for this initiator
21362df76c16SMatt Jacob 	 */
21372df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, chan, sid, &lp) == 0) {
21382df76c16SMatt Jacob 		/*
21392df76c16SMatt Jacob 		 * If we're not in the port database terminate the exchange.
21402df76c16SMatt Jacob 		 */
21412df76c16SMatt 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",
21422df76c16SMatt Jacob 		    __func__, aep->at_rxid, did, chan, sid);
21432df76c16SMatt Jacob 		isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0);
21442df76c16SMatt Jacob 		return;
21452df76c16SMatt Jacob 	}
21462df76c16SMatt Jacob 	nphdl = lp->handle;
21472df76c16SMatt Jacob 	wwn = lp->port_wwn;
21482df76c16SMatt Jacob 
21492df76c16SMatt Jacob 	/*
21502df76c16SMatt Jacob 	 * Get the tstate pointer
21512df76c16SMatt Jacob 	 */
21522df76c16SMatt Jacob 	tptr = get_lun_statep(isp, chan, lun);
21532df76c16SMatt Jacob 	if (tptr == NULL) {
21542df76c16SMatt Jacob 		tptr = get_lun_statep(isp, chan, CAM_LUN_WILDCARD);
21552df76c16SMatt Jacob 		if (tptr == NULL) {
21562df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d or wildcard", aep->at_rxid, lun);
21572df76c16SMatt Jacob 			isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0);
21582df76c16SMatt Jacob 			return;
21592df76c16SMatt Jacob 		}
21602df76c16SMatt Jacob 	}
21612df76c16SMatt Jacob 
21622df76c16SMatt Jacob 	/*
21632df76c16SMatt Jacob 	 * Start any commands pending resources first.
21642df76c16SMatt Jacob 	 */
21652df76c16SMatt Jacob 	if (tptr->restart_queue) {
21662df76c16SMatt Jacob 		inot_private_data_t *restart_queue = tptr->restart_queue;
21672df76c16SMatt Jacob 		tptr->restart_queue = NULL;
21682df76c16SMatt Jacob 		while (restart_queue) {
21692df76c16SMatt Jacob 			ntp = restart_queue;
21702df76c16SMatt Jacob 			restart_queue = ntp->rd.nt.nt_hba;
21712df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid);
21722df76c16SMatt Jacob 			isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data);
21732df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
21742df76c16SMatt Jacob 			/*
21752df76c16SMatt Jacob 			 * If a recursion caused the restart queue to start to fill again,
21762df76c16SMatt Jacob 			 * stop and splice the new list on top of the old list and restore
21772df76c16SMatt Jacob 			 * it and go to noresrc.
21782df76c16SMatt Jacob 			 */
21792df76c16SMatt Jacob 			if (tptr->restart_queue) {
21802df76c16SMatt Jacob 				if (restart_queue) {
21812df76c16SMatt Jacob 					ntp = tptr->restart_queue;
21822df76c16SMatt Jacob 					tptr->restart_queue = restart_queue;
21832df76c16SMatt Jacob 					while (restart_queue->rd.nt.nt_hba) {
21842df76c16SMatt Jacob 						restart_queue = restart_queue->rd.nt.nt_hba;
21852df76c16SMatt Jacob 					}
21862df76c16SMatt Jacob 					restart_queue->rd.nt.nt_hba = ntp;
21872df76c16SMatt Jacob 				}
21882df76c16SMatt Jacob 				goto noresrc;
21892df76c16SMatt Jacob 			}
21902df76c16SMatt Jacob 		}
21912df76c16SMatt Jacob 	}
21922df76c16SMatt Jacob 
21932df76c16SMatt Jacob 	/*
21942df76c16SMatt Jacob 	 * If the f/w is out of resources, just send a BUSY status back.
21952df76c16SMatt Jacob 	 */
21962df76c16SMatt Jacob 	if (aep->at_rxid == AT7_NORESRC_RXID) {
21972df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
21982df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0);
21992df76c16SMatt Jacob 		return;
22002df76c16SMatt Jacob 	}
22012df76c16SMatt Jacob 
22022df76c16SMatt Jacob 	/*
22032df76c16SMatt Jacob 	 * If we're out of resources, just send a BUSY status back.
22042df76c16SMatt Jacob 	 */
22052df76c16SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
22062df76c16SMatt Jacob 	if (atiop == NULL) {
22072df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atios", aep->at_rxid);
22082df76c16SMatt Jacob 		goto noresrc;
22092df76c16SMatt Jacob 	}
22102df76c16SMatt Jacob 
22112df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
22122df76c16SMatt Jacob 	if (atp == NULL) {
22132df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid);
22142df76c16SMatt Jacob 		goto noresrc;
22152df76c16SMatt Jacob 	}
22162df76c16SMatt Jacob 	if (isp_get_atpd(isp, tptr, aep->at_rxid)) {
22172df76c16SMatt 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)\n",
22182df76c16SMatt Jacob 		    aep->at_rxid, nphdl, sid, aep->at_hdr.ox_id);
22192df76c16SMatt Jacob 		/*
22202df76c16SMatt Jacob 		 * It's not a "no resource" condition- but we can treat it like one
22212df76c16SMatt Jacob 		 */
22222df76c16SMatt Jacob 		goto noresrc;
22232df76c16SMatt Jacob 	}
22242df76c16SMatt Jacob 
22252df76c16SMatt Jacob 	atp->tag = aep->at_rxid;
22262df76c16SMatt Jacob 	atp->state = ATPD_STATE_ATIO;
22272df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
22282df76c16SMatt Jacob 	tptr->atio_count--;
22292df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
22302df76c16SMatt Jacob 	atiop->init_id = nphdl;
22312df76c16SMatt Jacob 	atiop->ccb_h.target_id = FCPARAM(isp, chan)->isp_loopid;
22322df76c16SMatt Jacob 	atiop->ccb_h.target_lun = lun;
22332df76c16SMatt Jacob 	atiop->sense_len = 0;
22342df76c16SMatt Jacob 	cdbxlen = aep->at_cmnd.fcp_cmnd_alen_datadir >> FCP_CMND_ADDTL_CDBLEN_SHIFT;
22352df76c16SMatt Jacob 	if (cdbxlen) {
22362df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "additional CDBLEN ignored");
22372df76c16SMatt Jacob 	}
22382df76c16SMatt Jacob 	cdbxlen = sizeof (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb);
22392df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb, cdbxlen);
22402df76c16SMatt Jacob 	atiop->cdb_len = cdbxlen;
22412df76c16SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
22422df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
22432df76c16SMatt Jacob 	switch (aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK) {
22442df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_SIMPLE:
22452df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22462df76c16SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
22472df76c16SMatt Jacob 		break;
22482df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_HEAD:
22492df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22502df76c16SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
22512df76c16SMatt Jacob 		break;
22522df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ORDERED:
22532df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22542df76c16SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
22552df76c16SMatt Jacob 		break;
22562df76c16SMatt Jacob 	default:
22572df76c16SMatt Jacob 		/* FALLTHROUGH */
22582df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ACA:
22592df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_UNTAGGED:
22602df76c16SMatt Jacob 		atiop->tag_action = 0;
22612df76c16SMatt Jacob 		break;
22622df76c16SMatt Jacob 	}
22632df76c16SMatt Jacob 	atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl;
22642df76c16SMatt Jacob 	atp->bytes_xfered = 0;
22652df76c16SMatt Jacob 	atp->last_xframt = 0;
22662df76c16SMatt Jacob 	atp->lun = lun;
22672df76c16SMatt Jacob 	atp->nphdl = nphdl;
22682df76c16SMatt Jacob 	atp->portid = sid;
22692df76c16SMatt Jacob 	atp->oxid = aep->at_hdr.ox_id;
22702df76c16SMatt Jacob 	atp->cdb0 = atiop->cdb_io.cdb_bytes[0];
22712df76c16SMatt Jacob 	atp->tattr = aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK;
22722df76c16SMatt Jacob 	atp->state = ATPD_STATE_CAM;
22732df76c16SMatt 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);
22742df76c16SMatt Jacob 	xpt_done((union ccb *)atiop);
22752df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
22762df76c16SMatt Jacob 	return;
22772df76c16SMatt Jacob noresrc:
22782df76c16SMatt Jacob 	if (atp) {
22792df76c16SMatt Jacob 		isp_put_atpd(isp, tptr, atp);
22802df76c16SMatt Jacob 	}
22812df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
22822df76c16SMatt Jacob 	if (ntp == NULL) {
22832df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
22842df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_BUSY, 0);
22852df76c16SMatt Jacob 		return;
22862df76c16SMatt Jacob 	}
22872df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
22882df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
22892df76c16SMatt Jacob 	tptr->restart_queue = ntp;
22902df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
22912df76c16SMatt Jacob }
22922df76c16SMatt Jacob 
22932df76c16SMatt Jacob static void
22949cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
2295d81ba9d5SMatt Jacob {
2296d81ba9d5SMatt Jacob 	union ccb *ccb;
2297a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
22982df76c16SMatt Jacob 	tstate_t *tptr = NULL;
22992df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
23002df76c16SMatt Jacob 	int bus;
23012df76c16SMatt Jacob 	uint32_t tval, handle;
2302d81ba9d5SMatt Jacob 
2303d81ba9d5SMatt Jacob 	/*
2304443e752dSMatt Jacob 	 * CTIO handles are 16 bits.
2305443e752dSMatt Jacob 	 * CTIO2 and CTIO7 are 32 bits.
2306d81ba9d5SMatt Jacob 	 */
2307d81ba9d5SMatt Jacob 
23082df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
23092df76c16SMatt Jacob 		handle = ((ct_entry_t *)arg)->ct_syshandle;
23102df76c16SMatt Jacob 	} else {
23112df76c16SMatt Jacob 		handle = ((ct2_entry_t *)arg)->ct_syshandle;
23122df76c16SMatt Jacob 	}
23132df76c16SMatt Jacob 	ccb = isp_find_xs_tgt(isp, handle);
23142df76c16SMatt Jacob 	if (ccb == NULL) {
23152df76c16SMatt Jacob 		isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg);
23162df76c16SMatt Jacob 		return;
23172df76c16SMatt Jacob 	}
23182df76c16SMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
23192df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
23202df76c16SMatt Jacob 	tptr = get_lun_statep(isp, bus, XS_LUN(ccb));
23212df76c16SMatt Jacob 	if (tptr == NULL) {
23222df76c16SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
23232df76c16SMatt Jacob 	}
23242df76c16SMatt Jacob 	KASSERT((tptr != NULL), ("cannot get state pointer"));
23252df76c16SMatt Jacob 	if (isp->isp_nactive) {
23262df76c16SMatt Jacob 		isp->isp_nactive++;
23272df76c16SMatt Jacob 	}
23282df76c16SMatt Jacob 	if (IS_24XX(isp)) {
23292df76c16SMatt Jacob 		ct7_entry_t *ct = arg;
2330d81ba9d5SMatt Jacob 
23312df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
2332570c7a3fSMatt Jacob 		if (atp == NULL) {
23332df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
23342df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
23352df76c16SMatt Jacob 			return;
23362df76c16SMatt Jacob 		}
23372df76c16SMatt Jacob 
23382df76c16SMatt Jacob 		sentstatus = ct->ct_flags & CT7_SENDSTATUS;
23392df76c16SMatt Jacob 		ok = (ct->ct_nphdl == CT7_OK);
23402df76c16SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
23412df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
23422df76c16SMatt Jacob 		}
23432df76c16SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
23442df76c16SMatt Jacob 		if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) {
23452df76c16SMatt Jacob 			resid = ct->ct_resid;
23462df76c16SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
23472df76c16SMatt Jacob 			atp->last_xframt = 0;
23482df76c16SMatt Jacob 		}
23492df76c16SMatt Jacob 		if (ct->ct_nphdl == CT_HBA_RESET) {
23502df76c16SMatt Jacob 			ok = 0;
23512df76c16SMatt Jacob 			notify_cam = 1;
23522df76c16SMatt Jacob 			sentstatus = 1;
23532df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
23542df76c16SMatt Jacob 		} else if (!ok) {
23552df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
23562df76c16SMatt Jacob 		}
23572df76c16SMatt Jacob 		tval = atp->tag;
23582df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
23592df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
23602df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
23612df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
23622df76c16SMatt Jacob 		ct2_entry_t *ct = arg;
23632df76c16SMatt Jacob 
23642df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
23652df76c16SMatt Jacob 		if (atp == NULL) {
23662df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
23672df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
23682df76c16SMatt Jacob 			return;
2369570c7a3fSMatt Jacob 		}
2370d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
2371d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
2372a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
237300a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
237400a8e174SMatt Jacob 		}
2375a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
23765d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
2377a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
237853036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
237953036e92SMatt Jacob 			atp->last_xframt = 0;
2380570c7a3fSMatt Jacob 		}
23812df76c16SMatt Jacob 		if (ct->ct_status == CT_HBA_RESET) {
23822df76c16SMatt Jacob 			ok = 0;
23832df76c16SMatt Jacob 			notify_cam = 1;
23842df76c16SMatt Jacob 			sentstatus = 1;
23852df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
23862df76c16SMatt Jacob 		} else if (!ok) {
23872df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
238853036e92SMatt Jacob 		}
23892df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
23902df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
23912df76c16SMatt Jacob 		tval = atp->tag;
23922df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
2393d81ba9d5SMatt Jacob 	} else {
2394d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
2395d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
2396d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
2397d81ba9d5SMatt Jacob 		/*
2398a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
2399a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
2400a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
2401a1bc34c6SMatt Jacob 		 * private data.
2402a1bc34c6SMatt Jacob 		 *
2403a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
2404a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
2405a1bc34c6SMatt Jacob 		 */
2406a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
24072df76c16SMatt Jacob 		if (ct->ct_status == (CT_HBA_RESET & 0xff)) {
24082df76c16SMatt Jacob 			ok = 0;
24092df76c16SMatt Jacob 			notify_cam = 1;
24102df76c16SMatt Jacob 			sentstatus = 1;
24112df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
24122df76c16SMatt Jacob 		} else if (!ok) {
24132df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
24142df76c16SMatt Jacob 		} else if (ct->ct_status & QLTM_SVALID) {
2415a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
2416a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
24172df76c16SMatt Jacob 			ccb->csio.sense_len = min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
24182df76c16SMatt Jacob 			ISP_MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
2419a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2420a1bc34c6SMatt Jacob 		}
24215d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
2422a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
2423a1bc34c6SMatt Jacob 		}
24242df76c16SMatt 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__,
24252df76c16SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID");
242664edff94SMatt Jacob 		tval = ct->ct_fwhandle;
24275d571944SMatt Jacob 	}
2428a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
2429a1bc34c6SMatt Jacob 
2430a1bc34c6SMatt Jacob 	/*
2431a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
2432a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
2433a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
2434d81ba9d5SMatt Jacob 	 *
2435d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
2436d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
2437a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
2438a1bc34c6SMatt Jacob 	 * freed.
2439d81ba9d5SMatt Jacob 	 */
2440f48ce188SMatt Jacob 	if (notify_cam == 0) {
244164edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
24422df76c16SMatt Jacob 		return;
2443f48ce188SMatt Jacob 	}
24442df76c16SMatt Jacob 	if (tptr) {
24452df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
24462df76c16SMatt Jacob 	}
24472df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", (sentstatus)? "  FINAL " : "MIDTERM ", tval);
2448d81ba9d5SMatt Jacob 
24492df76c16SMatt Jacob 	if (!ok && !IS_24XX(isp)) {
2450a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
2451d81ba9d5SMatt Jacob 	} else {
2452a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
2453d81ba9d5SMatt Jacob 	}
2454d81ba9d5SMatt Jacob }
2455570c7a3fSMatt Jacob 
24562df76c16SMatt Jacob static void
24572df76c16SMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inot)
2458570c7a3fSMatt Jacob {
24592df76c16SMatt Jacob 	(void) isp_notify_ack(isp, inot);
2460570c7a3fSMatt Jacob }
2461570c7a3fSMatt Jacob 
24622df76c16SMatt Jacob static void
24639cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
2464570c7a3fSMatt Jacob {
24652df76c16SMatt Jacob 	int needack = 1;
2466570c7a3fSMatt Jacob 	switch (inp->in_status) {
2467570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
24682df76c16SMatt Jacob 		/*
24692df76c16SMatt Jacob 		 * XXX: Need to delete this initiator's WWN from the database
24702df76c16SMatt Jacob 		 * XXX: Need to send this LOGOUT upstream
24712df76c16SMatt Jacob 		 */
24722df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of S_ID 0x%x", inp->in_iid);
2473570c7a3fSMatt Jacob 		break;
2474570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
24752df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for S_ID 0x%x", inp->in_iid);
2476570c7a3fSMatt Jacob 		break;
2477570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
24782df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, 0);
2479570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
2480570c7a3fSMatt Jacob 		break;
2481570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
2482570c7a3fSMatt Jacob 	{
24832df76c16SMatt Jacob 		tstate_t *tptr;
24842df76c16SMatt Jacob 		uint16_t lun;
24852df76c16SMatt Jacob 		uint32_t loopid;
24862df76c16SMatt Jacob 		uint64_t wwn;
24872df76c16SMatt Jacob 		atio_private_data_t *atp;
24882df76c16SMatt Jacob 		fcportdb_t *lp;
24892df76c16SMatt Jacob 		struct ccb_immediate_notify *inot = NULL;
24902df76c16SMatt Jacob 
24912df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp)) {
24922df76c16SMatt Jacob 			lun = inp->in_scclun;
24932df76c16SMatt Jacob 		} else {
24942df76c16SMatt Jacob 			lun = inp->in_lun;
24952df76c16SMatt Jacob 		}
24962df76c16SMatt Jacob 		if (ISP_CAP_2KLOGIN(isp)) {
2497a035b0afSMatt Jacob 			loopid = ((in_fcentry_e_t *)inp)->in_iid;
24982df76c16SMatt Jacob 		} else {
24992df76c16SMatt Jacob 			loopid = inp->in_iid;
25002df76c16SMatt Jacob 		}
25012df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) {
25022df76c16SMatt Jacob 			wwn = lp->port_wwn;
25032df76c16SMatt Jacob 		} else {
25042df76c16SMatt Jacob 			wwn = INI_ANY;
25052df76c16SMatt Jacob 		}
25062df76c16SMatt Jacob 		tptr = get_lun_statep(isp, 0, lun);
25072df76c16SMatt Jacob 		if (tptr == NULL) {
25082df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
25092df76c16SMatt Jacob 			if (tptr == NULL) {
25102df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "ABORT TASK for lun %u- but no tstate", lun);
25112df76c16SMatt Jacob 				return;
25122df76c16SMatt Jacob 			}
25132df76c16SMatt Jacob 		}
25142df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, inp->in_seqid);
2515570c7a3fSMatt Jacob 
2516570c7a3fSMatt Jacob 		if (atp) {
25172df76c16SMatt Jacob 			inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
25182df76c16SMatt 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);
2519570c7a3fSMatt Jacob 			if (inot) {
2520746e9c85SMatt Jacob 				tptr->inot_count--;
25212df76c16SMatt Jacob 				SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
25222df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
2523570c7a3fSMatt Jacob 			} else {
25242df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "out of INOT structures\n");
25252df76c16SMatt Jacob 			}
25262df76c16SMatt Jacob 		} else {
25272df76c16SMatt 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);
2528570c7a3fSMatt Jacob 		}
2529570c7a3fSMatt Jacob 		if (inot) {
25302df76c16SMatt Jacob 			isp_notify_t tmp, *nt = &tmp;
25312df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
25322df76c16SMatt Jacob     			nt->nt_hba = isp;
25332df76c16SMatt Jacob 			nt->nt_tgt = FCPARAM(isp, 0)->isp_wwpn;
25342df76c16SMatt Jacob 			nt->nt_wwn = wwn;
25352df76c16SMatt Jacob 			nt->nt_nphdl = loopid;
25362df76c16SMatt Jacob 			nt->nt_sid = PORT_ANY;
25372df76c16SMatt Jacob 			nt->nt_did = PORT_ANY;
25382df76c16SMatt Jacob     			nt->nt_lun = lun;
25392df76c16SMatt Jacob             		nt->nt_need_ack = 1;
25402df76c16SMatt Jacob     			nt->nt_channel = 0;
25412df76c16SMatt Jacob     			nt->nt_ncode = NT_ABORT_TASK;
25422df76c16SMatt Jacob     			nt->nt_lreserved = inot;
25432df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
25442df76c16SMatt Jacob 			needack = 0;
2545570c7a3fSMatt Jacob 		}
25462df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
2547570c7a3fSMatt Jacob 		break;
2548570c7a3fSMatt Jacob 	}
2549570c7a3fSMatt Jacob 	default:
2550570c7a3fSMatt Jacob 		break;
2551570c7a3fSMatt Jacob 	}
25522df76c16SMatt Jacob 	if (needack) {
25532df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inp);
25542df76c16SMatt Jacob 	}
25552df76c16SMatt Jacob }
25562df76c16SMatt Jacob 
25572df76c16SMatt Jacob static void
25582df76c16SMatt Jacob isp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot)
25592df76c16SMatt Jacob {
25602df76c16SMatt Jacob 	uint16_t nphdl;
25612df76c16SMatt Jacob 	uint32_t portid;
25622df76c16SMatt Jacob 	fcportdb_t *lp;
25632df76c16SMatt Jacob 	uint8_t *ptr = NULL;
25642df76c16SMatt Jacob 	uint64_t wwn;
25652df76c16SMatt Jacob 
25662df76c16SMatt Jacob 	nphdl = inot->in_nphdl;
25672df76c16SMatt Jacob 	if (nphdl != NIL_HANDLE) {
25682df76c16SMatt Jacob 		portid = inot->in_portid_hi << 16 | inot->in_portid_lo;
25692df76c16SMatt Jacob 	} else {
25702df76c16SMatt Jacob 		portid = PORT_ANY;
25712df76c16SMatt Jacob 	}
25722df76c16SMatt Jacob 
25732df76c16SMatt Jacob 	switch (inot->in_status) {
25742df76c16SMatt Jacob 	case IN24XX_ELS_RCVD:
25752df76c16SMatt Jacob 	{
25762df76c16SMatt Jacob 		char buf[16], *msg;
25772df76c16SMatt Jacob 		int chan = ISP_GET_VPIDX(isp, inot->in_vpidx);
25782df76c16SMatt Jacob 
25792df76c16SMatt Jacob 		/*
25802df76c16SMatt Jacob 		 * Note that we're just getting notification that an ELS was received
2581b1ce21c6SRebecca Cran 		 * (possibly with some associated information sent upstream). This is
25822df76c16SMatt Jacob 		 * *not* the same as being given the ELS frame to accept or reject.
25832df76c16SMatt Jacob 		 */
25842df76c16SMatt Jacob 		switch (inot->in_status_subcode) {
25852df76c16SMatt Jacob 		case LOGO:
25862df76c16SMatt Jacob 			msg = "LOGO";
25872df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
25882df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
25892df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF])   << 56) |
25902df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+1]) << 48) |
25912df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+2]) << 40) |
25922df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+3]) << 32) |
25932df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+4]) << 24) |
25942df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+5]) << 16) |
25952df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+6]) <<  8) |
25962df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+7]));
25972df76c16SMatt Jacob 			} else {
25982df76c16SMatt Jacob 				wwn = INI_ANY;
25992df76c16SMatt Jacob 			}
26002df76c16SMatt Jacob 			isp_del_wwn_entry(isp, chan, wwn, nphdl, portid);
26012df76c16SMatt Jacob 			break;
26022df76c16SMatt Jacob 		case PRLO:
26032df76c16SMatt Jacob 			msg = "PRLO";
26042df76c16SMatt Jacob 			break;
26052df76c16SMatt Jacob 		case PLOGI:
2606dad28623SMatt Jacob 		case PRLI:
2607dad28623SMatt Jacob 			/*
2608dad28623SMatt Jacob 			 * Treat PRLI the same as PLOGI and make a database entry for it.
2609dad28623SMatt Jacob 			 */
2610dad28623SMatt Jacob 			if (inot->in_status_subcode == PLOGI)
26112df76c16SMatt Jacob 				msg = "PLOGI";
2612dad28623SMatt Jacob 			else
2613dad28623SMatt Jacob 				msg = "PRLI";
26142df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
26152df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
26162df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF])   << 56) |
26172df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+1]) << 48) |
26182df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+2]) << 40) |
26192df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+3]) << 32) |
26202df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+4]) << 24) |
26212df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+5]) << 16) |
26222df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+6]) <<  8) |
26232df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+7]));
26242df76c16SMatt Jacob 			} else {
26252df76c16SMatt Jacob 				wwn = INI_NONE;
26262df76c16SMatt Jacob 			}
26272df76c16SMatt Jacob 			isp_add_wwn_entry(isp, chan, wwn, nphdl, portid);
26282df76c16SMatt Jacob 			break;
26292df76c16SMatt Jacob 		case PDISC:
26302df76c16SMatt Jacob 			msg = "PDISC";
26312df76c16SMatt Jacob 			break;
26322df76c16SMatt Jacob 		case ADISC:
26332df76c16SMatt Jacob 			msg = "ADISC";
26342df76c16SMatt Jacob 			break;
26352df76c16SMatt Jacob 		default:
26362df76c16SMatt Jacob 			ISP_SNPRINTF(buf, sizeof (buf), "ELS 0x%x", inot->in_status_subcode);
26372df76c16SMatt Jacob 			msg = buf;
26382df76c16SMatt Jacob 			break;
26392df76c16SMatt Jacob 		}
26402df76c16SMatt Jacob 		if (inot->in_flags & IN24XX_FLAG_PUREX_IOCB) {
26412df76c16SMatt 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);
26422df76c16SMatt Jacob 			break;
26432df76c16SMatt Jacob 		}
26442df76c16SMatt 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,
26452df76c16SMatt Jacob 		    inot->in_rxid, inot->in_oxid);
26462df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26472df76c16SMatt Jacob 		break;
26482df76c16SMatt Jacob 	}
26492df76c16SMatt Jacob 
26502df76c16SMatt Jacob 	case IN24XX_PORT_LOGOUT:
26512df76c16SMatt Jacob 		ptr = "PORT LOGOUT";
26522df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) {
26532df76c16SMatt Jacob 			isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid);
26542df76c16SMatt Jacob 		}
26552df76c16SMatt Jacob 		/* FALLTHROUGH */
26562df76c16SMatt Jacob 	case IN24XX_PORT_CHANGED:
26572df76c16SMatt Jacob 		if (ptr == NULL) {
26582df76c16SMatt Jacob 			ptr = "PORT CHANGED";
26592df76c16SMatt Jacob 		}
26602df76c16SMatt Jacob 		/* FALLTHROUGH */
26612df76c16SMatt Jacob 	case IN24XX_LIP_RESET:
26622df76c16SMatt Jacob 		if (ptr == NULL) {
26632df76c16SMatt Jacob 			ptr = "LIP RESET";
26642df76c16SMatt Jacob 		}
26652df76c16SMatt 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);
26662df76c16SMatt Jacob 
26672df76c16SMatt Jacob 		/*
26682df76c16SMatt Jacob 		 * All subcodes here are irrelevant. What is relevant
26692df76c16SMatt Jacob 		 * is that we need to terminate all active commands from
26702df76c16SMatt Jacob 		 * this initiator (known by N-port handle).
26712df76c16SMatt Jacob 		 */
26722df76c16SMatt Jacob 		/* XXX IMPLEMENT XXX */
26732df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26742df76c16SMatt Jacob 		break;
26752df76c16SMatt Jacob 
26762df76c16SMatt Jacob 	case IN24XX_LINK_RESET:
26772df76c16SMatt Jacob 	case IN24XX_LINK_FAILED:
26782df76c16SMatt Jacob 	case IN24XX_SRR_RCVD:
26792df76c16SMatt Jacob 	default:
26802df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26812df76c16SMatt Jacob 		break;
26822df76c16SMatt Jacob 	}
26832df76c16SMatt Jacob }
26842df76c16SMatt Jacob 
26852df76c16SMatt Jacob static int
26862df76c16SMatt Jacob isp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp)
26872df76c16SMatt Jacob {
26882df76c16SMatt Jacob 
26892df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
26902df76c16SMatt 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);
2691570c7a3fSMatt Jacob 		return (0);
2692570c7a3fSMatt Jacob 	}
26932df76c16SMatt Jacob 
26942df76c16SMatt Jacob 	/*
26952df76c16SMatt Jacob 	 * This case is for a Task Management Function, which shows up as an ATIO7 entry.
26962df76c16SMatt Jacob 	 */
26972df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ATIO) {
26982df76c16SMatt Jacob 		ct7_entry_t local, *cto = &local;
26992df76c16SMatt Jacob 		at7_entry_t *aep = (at7_entry_t *)mp->nt_lreserved;
27002df76c16SMatt Jacob 		fcportdb_t *lp;
27012df76c16SMatt Jacob 		uint32_t sid;
27022df76c16SMatt Jacob 		uint16_t nphdl;
27032df76c16SMatt Jacob 
27042df76c16SMatt Jacob 		sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
27052df76c16SMatt Jacob 		if (isp_find_pdb_by_sid(isp, mp->nt_channel, sid, &lp)) {
27062df76c16SMatt Jacob 			nphdl = lp->handle;
27072df76c16SMatt Jacob 		} else {
27082df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
27092df76c16SMatt Jacob 		}
27102df76c16SMatt Jacob 		ISP_MEMZERO(&local, sizeof (local));
27112df76c16SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
27122df76c16SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
27132df76c16SMatt Jacob 		cto->ct_nphdl = nphdl;
27142df76c16SMatt Jacob 		cto->ct_rxid = aep->at_rxid;
27152df76c16SMatt Jacob 		cto->ct_vpidx = mp->nt_channel;
27162df76c16SMatt Jacob 		cto->ct_iid_lo = sid;
27172df76c16SMatt Jacob 		cto->ct_iid_hi = sid >> 16;
27182df76c16SMatt Jacob 		cto->ct_oxid = aep->at_hdr.ox_id;
27192df76c16SMatt Jacob 		cto->ct_flags = CT7_SENDSTATUS|CT7_NOACK|CT7_NO_DATA|CT7_FLAG_MODE1;
27202df76c16SMatt Jacob 		cto->ct_flags |= (aep->at_ta_len >> 12) << CT7_TASK_ATTR_SHIFT;
27212df76c16SMatt Jacob 		return (isp_target_put_entry(isp, &local));
27222df76c16SMatt Jacob 	}
27232df76c16SMatt Jacob 
27242df76c16SMatt Jacob 	/*
27252df76c16SMatt Jacob 	 * This case is for a responding to an ABTS frame
27262df76c16SMatt Jacob 	 */
27272df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
27282df76c16SMatt Jacob 
27292df76c16SMatt Jacob 		/*
27302df76c16SMatt Jacob 		 * Overload nt_need_ack here to mark whether we've terminated the associated command.
27312df76c16SMatt Jacob 		 */
27322df76c16SMatt Jacob 		if (mp->nt_need_ack) {
27332df76c16SMatt Jacob 			uint8_t storage[QENTRY_LEN];
27342df76c16SMatt Jacob 			ct7_entry_t *cto = (ct7_entry_t *) storage;
27352df76c16SMatt Jacob 			abts_t *abts = (abts_t *)mp->nt_lreserved;
27362df76c16SMatt Jacob 
27372df76c16SMatt Jacob 			ISP_MEMZERO(cto, sizeof (ct7_entry_t));
27382df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task);
27392df76c16SMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
27402df76c16SMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
27412df76c16SMatt Jacob 			cto->ct_nphdl = mp->nt_nphdl;
27422df76c16SMatt Jacob 			cto->ct_rxid = abts->abts_rxid_task;
27432df76c16SMatt Jacob 			cto->ct_iid_lo = mp->nt_sid;
27442df76c16SMatt Jacob 			cto->ct_iid_hi = mp->nt_sid >> 16;
27452df76c16SMatt Jacob 			cto->ct_oxid = abts->abts_ox_id;
27462df76c16SMatt Jacob 			cto->ct_vpidx = mp->nt_channel;
27472df76c16SMatt Jacob 			cto->ct_flags = CT7_NOACK|CT7_TERMINATE;
27482df76c16SMatt Jacob 			if (isp_target_put_entry(isp, cto)) {
27492df76c16SMatt Jacob 				return (ENOMEM);
27502df76c16SMatt Jacob 			}
27512df76c16SMatt Jacob 			mp->nt_need_ack = 0;
27522df76c16SMatt Jacob 		}
27532df76c16SMatt Jacob 		if (isp_acknak_abts(isp, mp->nt_lreserved, 0) == ENOMEM) {
27542df76c16SMatt Jacob 			return (ENOMEM);
27552df76c16SMatt Jacob 		} else {
27562df76c16SMatt Jacob 			return (0);
27572df76c16SMatt Jacob 		}
27582df76c16SMatt Jacob 	}
27592df76c16SMatt Jacob 
27602df76c16SMatt Jacob 	/*
27612df76c16SMatt Jacob 	 * Handle logout cases here
27622df76c16SMatt Jacob 	 */
27632df76c16SMatt Jacob 	if (mp->nt_ncode == NT_GLOBAL_LOGOUT) {
27642df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, mp->nt_channel);
27652df76c16SMatt Jacob 	}
27662df76c16SMatt Jacob 
27672df76c16SMatt Jacob 	if (mp->nt_ncode == NT_LOGOUT) {
27682df76c16SMatt Jacob 		if (!IS_2100(isp) && IS_FC(isp)) {
27692df76c16SMatt Jacob 			isp_del_wwn_entries(isp, mp);
27702df76c16SMatt Jacob 		}
27712df76c16SMatt Jacob 	}
27722df76c16SMatt Jacob 
27732df76c16SMatt Jacob 	/*
27742df76c16SMatt Jacob 	 * General purpose acknowledgement
27752df76c16SMatt Jacob 	 */
27762df76c16SMatt Jacob 	if (mp->nt_need_ack) {
27772df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) being acked", mp->nt_ncode, mp->nt_lreserved != NULL);
27782df76c16SMatt Jacob 		return (isp_notify_ack(isp, mp->nt_lreserved));
27792df76c16SMatt Jacob 	}
27802df76c16SMatt Jacob 	return (0);
27812df76c16SMatt Jacob }
27822df76c16SMatt Jacob 
27832df76c16SMatt Jacob /*
2784b1ce21c6SRebecca Cran  * Handle task management functions.
27852df76c16SMatt Jacob  *
27862df76c16SMatt Jacob  * We show up here with a notify structure filled out.
27872df76c16SMatt Jacob  *
27882df76c16SMatt Jacob  * The nt_lreserved tag points to the original queue entry
27892df76c16SMatt Jacob  */
27902df76c16SMatt Jacob static void
27912df76c16SMatt Jacob isp_handle_platform_target_tmf(ispsoftc_t *isp, isp_notify_t *notify)
27922df76c16SMatt Jacob {
27932df76c16SMatt Jacob 	tstate_t *tptr;
27942df76c16SMatt Jacob 	fcportdb_t *lp;
27952df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
27962df76c16SMatt Jacob 	inot_private_data_t *ntp = NULL;
27972df76c16SMatt Jacob 	lun_id_t lun;
27982df76c16SMatt Jacob 
27992df76c16SMatt 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,
28002df76c16SMatt Jacob 	    notify->nt_sid, (unsigned long long) notify->nt_tagval, notify->nt_channel, notify->nt_lun);
28012df76c16SMatt Jacob 	/*
28022df76c16SMatt Jacob 	 * NB: This assignment is necessary because of tricky type conversion.
28032df76c16SMatt Jacob 	 * XXX: This is tricky and I need to check this. If the lun isn't known
28042df76c16SMatt Jacob 	 * XXX: for the task management function, it does not of necessity follow
28052df76c16SMatt Jacob 	 * XXX: that it should go up stream to the wildcard listener.
28062df76c16SMatt Jacob 	 */
28072df76c16SMatt Jacob 	if (notify->nt_lun == LUN_ANY) {
28082df76c16SMatt Jacob 		lun = CAM_LUN_WILDCARD;
28092df76c16SMatt Jacob 	} else {
28102df76c16SMatt Jacob 		lun = notify->nt_lun;
28112df76c16SMatt Jacob 	}
28122df76c16SMatt Jacob 	tptr = get_lun_statep(isp, notify->nt_channel, lun);
28132df76c16SMatt Jacob 	if (tptr == NULL) {
28142df76c16SMatt Jacob 		tptr = get_lun_statep(isp, notify->nt_channel, CAM_LUN_WILDCARD);
28152df76c16SMatt Jacob 		if (tptr == NULL) {
28162df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: no state pointer found for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
28172df76c16SMatt Jacob 			goto bad;
28182df76c16SMatt Jacob 		}
28192df76c16SMatt Jacob 	}
28202df76c16SMatt Jacob 	inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
28212df76c16SMatt Jacob 	if (inot == NULL) {
28222df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of immediate notify structures for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
28232df76c16SMatt Jacob 		goto bad;
28242df76c16SMatt Jacob 	}
28252df76c16SMatt Jacob 
28262df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, notify->nt_channel, notify->nt_sid, &lp) == 0) {
28272df76c16SMatt Jacob 		inot->initiator_id = CAM_TARGET_WILDCARD;
28282df76c16SMatt Jacob 	} else {
28292df76c16SMatt Jacob 		inot->initiator_id = lp->handle;
28302df76c16SMatt Jacob 	}
28312df76c16SMatt Jacob 	inot->seq_id = notify->nt_tagval;
28322df76c16SMatt Jacob 	inot->tag_id = notify->nt_tagval >> 32;
28332df76c16SMatt Jacob 
28342df76c16SMatt Jacob 	switch (notify->nt_ncode) {
28352df76c16SMatt Jacob 	case NT_ABORT_TASK:
28362df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, inot->tag_id);
28372df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK;
28382df76c16SMatt Jacob 		break;
28392df76c16SMatt Jacob 	case NT_ABORT_TASK_SET:
28402df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, TAG_ANY);
28412df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK_SET;
28422df76c16SMatt Jacob 		break;
28432df76c16SMatt Jacob 	case NT_CLEAR_ACA:
28442df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_ACA;
28452df76c16SMatt Jacob 		break;
28462df76c16SMatt Jacob 	case NT_CLEAR_TASK_SET:
28472df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_TASK_SET;
28482df76c16SMatt Jacob 		break;
28492df76c16SMatt Jacob 	case NT_LUN_RESET:
28502df76c16SMatt Jacob 		inot->arg = MSG_LOGICAL_UNIT_RESET;
28512df76c16SMatt Jacob 		break;
28522df76c16SMatt Jacob 	case NT_TARGET_RESET:
28532df76c16SMatt Jacob 		inot->arg = MSG_TARGET_RESET;
28542df76c16SMatt Jacob 		break;
28552df76c16SMatt Jacob 	default:
28562df76c16SMatt 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);
28572df76c16SMatt Jacob 		goto bad;
28582df76c16SMatt Jacob 	}
28592df76c16SMatt Jacob 
28602df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
28612df76c16SMatt Jacob 	if (ntp == NULL) {
28622df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of inotify private structures", __func__);
28632df76c16SMatt Jacob 		goto bad;
28642df76c16SMatt Jacob 	}
28652df76c16SMatt Jacob 	ISP_MEMCPY(&ntp->rd.nt, notify, sizeof (isp_notify_t));
28662df76c16SMatt Jacob 	if (notify->nt_lreserved) {
28672df76c16SMatt Jacob 		ISP_MEMCPY(&ntp->rd.data, notify->nt_lreserved, QENTRY_LEN);
28682df76c16SMatt Jacob 		ntp->rd.nt.nt_lreserved = &ntp->rd.data;
28692df76c16SMatt Jacob 	}
28702df76c16SMatt Jacob 	ntp->rd.seq_id = notify->nt_tagval;
28712df76c16SMatt Jacob 	ntp->rd.tag_id = notify->nt_tagval >> 32;
28722df76c16SMatt Jacob 
28732df76c16SMatt Jacob 	tptr->inot_count--;
28742df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
28752df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
28762df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
28772df76c16SMatt Jacob 	inot->ccb_h.status = CAM_MESSAGE_RECV;
28782df76c16SMatt Jacob 	xpt_done((union ccb *)inot);
28792df76c16SMatt Jacob 	return;
28802df76c16SMatt Jacob bad:
28812df76c16SMatt Jacob 	if (tptr) {
28822df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
28832df76c16SMatt Jacob 	}
28842df76c16SMatt Jacob 	if (notify->nt_need_ack && notify->nt_lreserved) {
28852df76c16SMatt Jacob 		if (((isphdr_t *)notify->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
28862df76c16SMatt Jacob 			(void) isp_acknak_abts(isp, notify->nt_lreserved, ENOMEM);
28872df76c16SMatt Jacob 		} else {
28882df76c16SMatt Jacob 			(void) isp_notify_ack(isp, notify->nt_lreserved);
28892df76c16SMatt Jacob 		}
28902df76c16SMatt Jacob 	}
28912df76c16SMatt Jacob }
28922df76c16SMatt Jacob 
28932df76c16SMatt Jacob /*
2894b1ce21c6SRebecca Cran  * Find the associated private data and mark it as dead so
28952df76c16SMatt Jacob  * we don't try to work on it any further.
28962df76c16SMatt Jacob  */
28972df76c16SMatt Jacob static void
28982df76c16SMatt Jacob isp_target_mark_aborted(ispsoftc_t *isp, union ccb *ccb)
28992df76c16SMatt Jacob {
29002df76c16SMatt Jacob 	tstate_t *tptr;
29012df76c16SMatt Jacob 	atio_private_data_t *atp;
29022df76c16SMatt Jacob 
29032df76c16SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
29042df76c16SMatt Jacob 	if (tptr == NULL) {
29052df76c16SMatt Jacob 		tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
29062df76c16SMatt Jacob 		if (tptr == NULL) {
29072df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
29082df76c16SMatt Jacob 			return;
29092df76c16SMatt Jacob 		}
29102df76c16SMatt Jacob 	}
29112df76c16SMatt Jacob 
29122df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id);
29132df76c16SMatt Jacob 	if (atp == NULL) {
29142df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INVALID;
29152df76c16SMatt Jacob 		return;
29162df76c16SMatt Jacob 	}
29172df76c16SMatt Jacob 	atp->dead = 1;
29182df76c16SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
29192df76c16SMatt Jacob }
29202df76c16SMatt Jacob 
29212df76c16SMatt Jacob static void
29222df76c16SMatt Jacob isp_target_mark_aborted_early(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id)
29232df76c16SMatt Jacob {
29242df76c16SMatt Jacob 	atio_private_data_t *atp;
29252df76c16SMatt Jacob 	inot_private_data_t *restart_queue = tptr->restart_queue;
29262df76c16SMatt Jacob 
29272df76c16SMatt Jacob 	/*
29282df76c16SMatt Jacob 	 * First, clean any commands pending restart
29292df76c16SMatt Jacob 	 */
29302df76c16SMatt Jacob 	tptr->restart_queue = NULL;
29312df76c16SMatt Jacob 	while (restart_queue) {
29322df76c16SMatt Jacob 		uint32_t this_tag_id;
29332df76c16SMatt Jacob 		inot_private_data_t *ntp = restart_queue;
29342df76c16SMatt Jacob 
29352df76c16SMatt Jacob 		restart_queue = ntp->rd.nt.nt_hba;
29362df76c16SMatt Jacob 
29372df76c16SMatt Jacob 		if (IS_24XX(isp)) {
29382df76c16SMatt Jacob 			this_tag_id = ((at7_entry_t *)ntp->rd.data)->at_rxid;
29392df76c16SMatt Jacob 		} else {
29402df76c16SMatt Jacob 			this_tag_id = ((at2_entry_t *)ntp->rd.data)->at_rxid;
29412df76c16SMatt Jacob 		}
29422df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) {
29432df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
29442df76c16SMatt Jacob 		} else {
29452df76c16SMatt Jacob 			ntp->rd.nt.nt_hba = tptr->restart_queue;
29462df76c16SMatt Jacob 			tptr->restart_queue = ntp;
29472df76c16SMatt Jacob 		}
29482df76c16SMatt Jacob 	}
29492df76c16SMatt Jacob 
29502df76c16SMatt Jacob 	/*
29512df76c16SMatt Jacob 	 * Now mark other ones dead as well.
29522df76c16SMatt Jacob 	 */
29532df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
29542df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) {
29552df76c16SMatt Jacob 			atp->dead = 1;
29562df76c16SMatt Jacob 		}
29572df76c16SMatt Jacob 	}
29582df76c16SMatt Jacob }
29592df76c16SMatt Jacob 
29602df76c16SMatt Jacob 
29612df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
29622df76c16SMatt Jacob // #define	ISP_FORCE_TIMEOUT		1
2963ae5db118SMatt Jacob // #define	ISP_TEST_WWNS			1
2964ae5db118SMatt Jacob // #define	ISP_TEST_SEPARATE_STATUS	1
29652df76c16SMatt Jacob 
29662df76c16SMatt Jacob #define	ccb_data_offset		ppriv_field0
29672df76c16SMatt Jacob #define	ccb_atio		ppriv_ptr1
29682df76c16SMatt Jacob #define	ccb_inot		ppriv_ptr1
29692df76c16SMatt Jacob 
29702df76c16SMatt Jacob #define	MAX_ISP_TARG_TRANSFER	(2 << 20)
29712df76c16SMatt Jacob #define	NISP_TARG_CMDS		1024
29722df76c16SMatt Jacob #define	NISP_TARG_NOTIFIES	1024
29732df76c16SMatt Jacob #define	DISK_SHIFT		9
29742df76c16SMatt Jacob #define	JUNK_SIZE		256
29752df76c16SMatt Jacob 
29762df76c16SMatt Jacob #ifndef	VERIFY_10
29772df76c16SMatt Jacob #define	VERIFY_10	0x2f
29782df76c16SMatt Jacob #endif
29792df76c16SMatt Jacob 
29802df76c16SMatt Jacob TAILQ_HEAD(ccb_queue, ccb_hdr);
29812df76c16SMatt Jacob extern u_int vm_kmem_size;
29822df76c16SMatt Jacob static int ca;
29832df76c16SMatt Jacob static uint32_t disk_size;
29842df76c16SMatt Jacob static uint8_t *disk_data = NULL;
29852df76c16SMatt Jacob static uint8_t *junk_data;
29862df76c16SMatt Jacob static MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data");
29872df76c16SMatt Jacob struct isptarg_softc {
29882df76c16SMatt Jacob 	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
29892df76c16SMatt Jacob 	struct ccb_queue	work_queue;
29902df76c16SMatt Jacob 	struct ccb_queue	rework_queue;
29912df76c16SMatt Jacob 	struct ccb_queue	running_queue;
29922df76c16SMatt Jacob 	struct ccb_queue	inot_queue;
29932df76c16SMatt Jacob 	struct cam_periph       *periph;
29942df76c16SMatt Jacob 	struct cam_path	 	*path;
29952df76c16SMatt Jacob 	ispsoftc_t		*isp;
29962df76c16SMatt Jacob };
29972df76c16SMatt Jacob static periph_ctor_t	isptargctor;
29982df76c16SMatt Jacob static periph_dtor_t	isptargdtor;
29992df76c16SMatt Jacob static periph_start_t	isptargstart;
30002df76c16SMatt Jacob static periph_init_t	isptarginit;
30012df76c16SMatt Jacob static void		isptarg_done(struct cam_periph *, union ccb *);
30022df76c16SMatt Jacob static void		isptargasync(void *, u_int32_t, struct cam_path *, void *);
30032df76c16SMatt Jacob 
30042df76c16SMatt Jacob 
30052df76c16SMatt Jacob static int isptarg_rwparm(uint8_t *, uint8_t *, uint64_t, uint32_t, uint8_t **, uint32_t *, int *);
30062df76c16SMatt Jacob 
30072df76c16SMatt Jacob static struct periph_driver isptargdriver =
30082df76c16SMatt Jacob {
30092df76c16SMatt Jacob 	isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), /* generation */ 0
30102df76c16SMatt Jacob };
30112df76c16SMatt Jacob 
30122df76c16SMatt Jacob static void
30132df76c16SMatt Jacob isptarginit(void)
30142df76c16SMatt Jacob {
30152df76c16SMatt Jacob }
30162df76c16SMatt Jacob 
30172df76c16SMatt Jacob static void
30182df76c16SMatt Jacob isptargnotify(ispsoftc_t *isp, union ccb *iccb, struct ccb_immediate_notify *inot)
30192df76c16SMatt Jacob {
30202df76c16SMatt Jacob 	struct ccb_notify_acknowledge *ack = &iccb->cna2;
30212df76c16SMatt Jacob 
30222df76c16SMatt 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__,
30232df76c16SMatt Jacob 	    inot->tag_id, inot->initiator_id, inot->seq_id, inot->ccb_h.status, inot->arg);
30242df76c16SMatt Jacob 	ack->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE;
30252df76c16SMatt Jacob 	ack->ccb_h.flags = 0;
30262df76c16SMatt Jacob 	ack->ccb_h.retry_count = 0;
30272df76c16SMatt Jacob 	ack->ccb_h.cbfcnp = isptarg_done;
30282df76c16SMatt Jacob 	ack->ccb_h.timeout = 0;
30292df76c16SMatt Jacob 	ack->ccb_h.ccb_inot = inot;
30302df76c16SMatt Jacob 	ack->tag_id = inot->tag_id;
30312df76c16SMatt Jacob 	ack->seq_id = inot->seq_id;
30322df76c16SMatt Jacob 	ack->initiator_id = inot->initiator_id;
30332df76c16SMatt Jacob 	xpt_action(iccb);
30342df76c16SMatt Jacob }
30352df76c16SMatt Jacob 
30362df76c16SMatt Jacob static void
30372df76c16SMatt Jacob isptargstart(struct cam_periph *periph, union ccb *iccb)
30382df76c16SMatt Jacob {
30390a100e5bSMatt Jacob 	const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = {
30400a100e5bSMatt Jacob 		0x7f, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
30410a100e5bSMatt Jacob 		'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ',
30420a100e5bSMatt Jacob 		'S', 'C', 'S', 'I', ' ', 'N', 'U', 'L',
30430a100e5bSMatt Jacob 		'L', ' ', 'D', 'E', 'V', 'I', 'C', 'E',
30440a100e5bSMatt Jacob 		'0', '0', '0', '1'
30450a100e5bSMatt Jacob 	};
30462df76c16SMatt Jacob 	const uint8_t iqd[SHORT_INQUIRY_LENGTH] = {
30470a100e5bSMatt Jacob 		0, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
30482df76c16SMatt Jacob 		'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ',
30492df76c16SMatt Jacob 		'S', 'C', 'S', 'I', ' ', 'M', 'E', 'M',
30502df76c16SMatt Jacob 		'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
30512df76c16SMatt Jacob 		'0', '0', '0', '1'
30522df76c16SMatt Jacob 	};
30532df76c16SMatt Jacob 	int i, more = 0, last;
30542df76c16SMatt Jacob 	struct isptarg_softc *softc = periph->softc;
30552df76c16SMatt Jacob 	struct ccb_scsiio *csio;
30562df76c16SMatt Jacob 	lun_id_t return_lun;
30572df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
30582df76c16SMatt Jacob 	uint8_t *cdb, *ptr, status;
30592df76c16SMatt Jacob 	uint8_t *data_ptr;
30602df76c16SMatt Jacob 	uint32_t data_len, flags;
30612df76c16SMatt Jacob 	struct ccb_hdr *ccbh;
30622df76c16SMatt Jacob 
30632df76c16SMatt Jacob 	mtx_assert(periph->sim->mtx, MA_OWNED);
30642df76c16SMatt 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,
30652df76c16SMatt Jacob 	    TAILQ_FIRST(&softc->inot_queue)? 'y' : 'n', TAILQ_FIRST(&softc->work_queue)? 'y' : 'n', TAILQ_FIRST(&softc->rework_queue)? 'y' : 'n');
30662df76c16SMatt Jacob 	/*
30672df76c16SMatt Jacob 	 * Check for immediate notifies first
30682df76c16SMatt Jacob 	 */
30692df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->inot_queue);
30702df76c16SMatt Jacob 	if (ccbh) {
30712df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->inot_queue, ccbh, periph_links.tqe);
30722df76c16SMatt Jacob 		if (TAILQ_FIRST(&softc->inot_queue) || TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue)) {
30732df76c16SMatt Jacob 			xpt_schedule(periph, 1);
30742df76c16SMatt Jacob 		}
30752df76c16SMatt Jacob 		isptargnotify(softc->isp, iccb, (struct ccb_immediate_notify *)ccbh);
30762df76c16SMatt Jacob 		return;
30772df76c16SMatt Jacob 	}
30782df76c16SMatt Jacob 
30792df76c16SMatt Jacob 	/*
30802df76c16SMatt Jacob 	 * Check the rework (continuation) work queue first.
30812df76c16SMatt Jacob 	 */
30822df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->rework_queue);
30832df76c16SMatt Jacob 	if (ccbh) {
30842df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
30852df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe);
30862df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue);
30872df76c16SMatt Jacob 	} else {
30882df76c16SMatt Jacob 		ccbh = TAILQ_FIRST(&softc->work_queue);
30892df76c16SMatt Jacob 		if (ccbh == NULL) {
30902df76c16SMatt Jacob 			ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: woken up but no work?\n", __func__);
30912df76c16SMatt Jacob 			xpt_release_ccb(iccb);
30922df76c16SMatt Jacob 			return;
30932df76c16SMatt Jacob 		}
30942df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
30952df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
30962df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) != NULL;
30972df76c16SMatt Jacob 		atio->ccb_h.ccb_data_offset = 0;
30982df76c16SMatt Jacob 	}
30992df76c16SMatt Jacob 
31002df76c16SMatt Jacob 	if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) {
31012df76c16SMatt Jacob 		panic("BAD ATIO");
31022df76c16SMatt Jacob 	}
31032df76c16SMatt Jacob 
31042df76c16SMatt Jacob 	data_ptr = NULL;
31052df76c16SMatt Jacob 	data_len = 0;
31062df76c16SMatt Jacob 	csio = &iccb->csio;
31072df76c16SMatt Jacob 	status = SCSI_STATUS_OK;
31082df76c16SMatt Jacob 	flags = CAM_SEND_STATUS;
31092df76c16SMatt Jacob 	memset(&atio->sense_data, 0, sizeof (atio->sense_data));
31102df76c16SMatt Jacob 	cdb = atio->cdb_io.cdb_bytes;
31112df76c16SMatt 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,
31122df76c16SMatt Jacob 	    cdb[0], atio->ccb_h.ccb_data_offset);
31132df76c16SMatt Jacob 
31142df76c16SMatt Jacob 	return_lun = XS_LUN(atio);
31152df76c16SMatt Jacob 	if (return_lun != 0) {
31162df76c16SMatt Jacob 		xpt_print(atio->ccb_h.path, "[0x%x] Non-Zero Lun %d: cdb0=0x%x\n", atio->tag_id, return_lun, cdb[0]);
31172df76c16SMatt Jacob 		if (cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
31182df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31192df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_ILLEGAL_REQUEST;
31202df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x25;
31212df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x0;
31222df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31232df76c16SMatt Jacob 		}
31242df76c16SMatt Jacob 		return_lun = CAM_LUN_WILDCARD;
31252df76c16SMatt Jacob 	}
31262df76c16SMatt Jacob 
31272df76c16SMatt Jacob 	switch (cdb[0]) {
31282df76c16SMatt Jacob 	case REQUEST_SENSE:
31292df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
31302df76c16SMatt Jacob 		data_len = sizeof (atio->sense_data);
31312df76c16SMatt Jacob 		junk_data[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_NO_SENSE;
31322df76c16SMatt Jacob 		memset(junk_data+1, 0, data_len-1);
31332df76c16SMatt Jacob 		if (data_len > cdb[4]) {
31342df76c16SMatt Jacob 			data_len = cdb[4];
31352df76c16SMatt Jacob 		}
31362df76c16SMatt Jacob 		if (data_len) {
31372df76c16SMatt Jacob 			data_ptr = junk_data;
31382df76c16SMatt Jacob 		}
31392df76c16SMatt Jacob 		break;
31402df76c16SMatt Jacob 	case READ_6:
31412df76c16SMatt Jacob 	case READ_10:
31422df76c16SMatt Jacob 	case READ_12:
31432df76c16SMatt Jacob 	case READ_16:
31442df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
31452df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31462df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
31472df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
31482df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
31492df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31502df76c16SMatt Jacob 		} else {
31512df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
31522df76c16SMatt Jacob 			{
31532df76c16SMatt Jacob 				static int foo;
31542df76c16SMatt Jacob 				if (foo++ == 500) {
31552df76c16SMatt Jacob 					if (more) {
31562df76c16SMatt Jacob 						xpt_schedule(periph, 1);
31572df76c16SMatt Jacob 					}
31582df76c16SMatt Jacob 					foo = 0;
31592df76c16SMatt Jacob 					return;
31602df76c16SMatt Jacob 				}
31612df76c16SMatt Jacob 			}
31622df76c16SMatt Jacob #endif
31632df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
31642df76c16SMatt Jacob 			if (last && data_len) {
31652df76c16SMatt Jacob 				last = 0;
31662df76c16SMatt Jacob 			}
31672df76c16SMatt Jacob #endif
31682df76c16SMatt Jacob 			if (last == 0) {
31692df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
31702df76c16SMatt Jacob 			}
31712df76c16SMatt Jacob 			if (data_len) {
31722df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
31732df76c16SMatt Jacob 				flags |= CAM_DIR_IN;
31742df76c16SMatt Jacob 			} else {
31752df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
31762df76c16SMatt Jacob 			}
31772df76c16SMatt Jacob 		}
31782df76c16SMatt Jacob 		break;
31792df76c16SMatt Jacob 	case WRITE_6:
31802df76c16SMatt Jacob 	case WRITE_10:
31812df76c16SMatt Jacob 	case WRITE_12:
31822df76c16SMatt Jacob 	case WRITE_16:
31832df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
31842df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31852df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
31862df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
31872df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
31882df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31892df76c16SMatt Jacob 		} else {
31902df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
31912df76c16SMatt Jacob 			{
31922df76c16SMatt Jacob 				static int foo;
31932df76c16SMatt Jacob 				if (foo++ == 500) {
31942df76c16SMatt Jacob 					if (more) {
31952df76c16SMatt Jacob 						xpt_schedule(periph, 1);
31962df76c16SMatt Jacob 					}
31972df76c16SMatt Jacob 					foo = 0;
31982df76c16SMatt Jacob 					return;
31992df76c16SMatt Jacob 				}
32002df76c16SMatt Jacob 			}
32012df76c16SMatt Jacob #endif
32022df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
32032df76c16SMatt Jacob 			if (last && data_len) {
32042df76c16SMatt Jacob 				last = 0;
32052df76c16SMatt Jacob 			}
32062df76c16SMatt Jacob #endif
32072df76c16SMatt Jacob 			if (last == 0) {
32082df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
32092df76c16SMatt Jacob 			}
32102df76c16SMatt Jacob 			if (data_len) {
32112df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
32122df76c16SMatt Jacob 				flags |= CAM_DIR_OUT;
32132df76c16SMatt Jacob 			} else {
32142df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
32152df76c16SMatt Jacob 			}
32162df76c16SMatt Jacob 		}
32172df76c16SMatt Jacob 		break;
32182df76c16SMatt Jacob 	case INQUIRY:
32192df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32202df76c16SMatt Jacob 		if (cdb[1] || cdb[2] || cdb[3]) {
32212df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32222df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32232df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
32242df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x20;
32252df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32262df76c16SMatt Jacob 			break;
32272df76c16SMatt Jacob 		}
32282df76c16SMatt Jacob 		data_len = sizeof (iqd);
32292df76c16SMatt Jacob 		if (data_len > cdb[4]) {
32302df76c16SMatt Jacob 			data_len = cdb[4];
32312df76c16SMatt Jacob 		}
32322df76c16SMatt Jacob 		if (data_len) {
32332df76c16SMatt Jacob 			if (XS_LUN(iccb) != 0) {
32342df76c16SMatt Jacob 				memcpy(junk_data, niliqd, sizeof (iqd));
32352df76c16SMatt Jacob 			} else {
32362df76c16SMatt Jacob 				memcpy(junk_data, iqd, sizeof (iqd));
32372df76c16SMatt Jacob 			}
32382df76c16SMatt Jacob 			data_ptr = junk_data;
32392df76c16SMatt Jacob 		}
32402df76c16SMatt Jacob 		break;
32412df76c16SMatt Jacob 	case TEST_UNIT_READY:
32422df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
32432df76c16SMatt Jacob 		if (ca) {
32442df76c16SMatt Jacob 			ca = 0;
32452df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32462df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32472df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x28;
32482df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x0;
32492df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32502df76c16SMatt Jacob 		}
32512df76c16SMatt Jacob 		break;
32522df76c16SMatt Jacob 	case SYNCHRONIZE_CACHE:
32532df76c16SMatt Jacob 	case START_STOP:
32542df76c16SMatt Jacob 	case RESERVE:
32552df76c16SMatt Jacob 	case RELEASE:
32562df76c16SMatt Jacob 	case VERIFY_10:
32572df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
32582df76c16SMatt Jacob 		break;
32592df76c16SMatt Jacob 
32602df76c16SMatt Jacob 	case READ_CAPACITY:
32612df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32622df76c16SMatt Jacob 		if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
32632df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32642df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32652df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
32662df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
32672df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32682df76c16SMatt Jacob 			break;
32692df76c16SMatt Jacob 		}
32702df76c16SMatt Jacob 		if (cdb[8] & 0x1) { /* PMI */
32712df76c16SMatt Jacob 			junk_data[0] = 0xff;
32722df76c16SMatt Jacob 			junk_data[1] = 0xff;
32732df76c16SMatt Jacob 			junk_data[2] = 0xff;
32742df76c16SMatt Jacob 			junk_data[3] = 0xff;
32752df76c16SMatt Jacob 		} else {
32762df76c16SMatt Jacob 			uint64_t last_blk = (disk_size >> DISK_SHIFT) - 1;
32772df76c16SMatt Jacob 			if (last_blk < 0xffffffffULL) {
32782df76c16SMatt Jacob 			    junk_data[0] = (last_blk >> 24) & 0xff;
32792df76c16SMatt Jacob 			    junk_data[1] = (last_blk >> 16) & 0xff;
32802df76c16SMatt Jacob 			    junk_data[2] = (last_blk >>  8) & 0xff;
32812df76c16SMatt Jacob 			    junk_data[3] = (last_blk) & 0xff;
32822df76c16SMatt Jacob 			} else {
32832df76c16SMatt Jacob 			    junk_data[0] = 0xff;
32842df76c16SMatt Jacob 			    junk_data[1] = 0xff;
32852df76c16SMatt Jacob 			    junk_data[2] = 0xff;
32862df76c16SMatt Jacob 			    junk_data[3] = 0xff;
32872df76c16SMatt Jacob 			}
32882df76c16SMatt Jacob 		}
32892df76c16SMatt Jacob 		junk_data[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
32902df76c16SMatt Jacob 		junk_data[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
32912df76c16SMatt Jacob 		junk_data[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
32922df76c16SMatt Jacob 		junk_data[7] = ((1 << DISK_SHIFT)) & 0xff;
32932df76c16SMatt Jacob 		data_ptr = junk_data;
32942df76c16SMatt Jacob 		data_len = 8;
32952df76c16SMatt Jacob 		break;
32962df76c16SMatt Jacob 	case REPORT_LUNS:
32972df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32982df76c16SMatt Jacob 		memset(junk_data, 0, JUNK_SIZE);
32992df76c16SMatt Jacob 		junk_data[0] = (1 << 3) >> 24;
33002df76c16SMatt Jacob 		junk_data[1] = (1 << 3) >> 16;
33012df76c16SMatt Jacob 		junk_data[2] = (1 << 3) >> 8;
33022df76c16SMatt Jacob 		junk_data[3] = (1 << 3);
33032df76c16SMatt Jacob 		ptr = NULL;
33042df76c16SMatt Jacob 		for (i = 0; i < 1; i++) {
33052df76c16SMatt Jacob 			ptr = &junk_data[8 + (1 << 3)];
33062df76c16SMatt Jacob 			if (i >= 256) {
33072df76c16SMatt Jacob 				ptr[0] = 0x40 | ((i >> 8) & 0x3f);
33082df76c16SMatt Jacob 			}
33092df76c16SMatt Jacob 			ptr[1] = i;
33102df76c16SMatt Jacob 		}
33112df76c16SMatt Jacob 		data_ptr = junk_data;
33122df76c16SMatt Jacob 		data_len = (ptr + 8) - junk_data;
33132df76c16SMatt Jacob 		break;
33142df76c16SMatt Jacob 
33152df76c16SMatt Jacob 	default:
33162df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
33172df76c16SMatt Jacob 		status = SCSI_STATUS_CHECK_COND;
33182df76c16SMatt Jacob 		atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
33192df76c16SMatt Jacob 		atio->sense_data.add_sense_code = 0x5;
33202df76c16SMatt Jacob 		atio->sense_data.add_sense_code_qual = 0x20;
33212df76c16SMatt Jacob 		atio->sense_len = sizeof (atio->sense_data);
33222df76c16SMatt Jacob 		break;
33232df76c16SMatt Jacob 	}
33242df76c16SMatt Jacob 
33252df76c16SMatt Jacob 	/*
33262df76c16SMatt Jacob 	 * If we are done with the transaction, tell the
33272df76c16SMatt Jacob 	 * controller to send status and perform a CMD_CMPLT.
33282df76c16SMatt Jacob 	 * If we have associated sense data, see if we can
33292df76c16SMatt Jacob 	 * send that too.
33302df76c16SMatt Jacob 	 */
33312df76c16SMatt Jacob 	if (status == SCSI_STATUS_CHECK_COND) {
33322df76c16SMatt Jacob 		flags |= CAM_SEND_SENSE;
33332df76c16SMatt Jacob 		csio->sense_len = atio->sense_len;
33342df76c16SMatt Jacob 		csio->sense_data = atio->sense_data;
33352df76c16SMatt Jacob 		flags &= ~CAM_DIR_MASK;
33362df76c16SMatt Jacob 		data_len = 0;
33372df76c16SMatt Jacob 		data_ptr = NULL;
33382df76c16SMatt Jacob 	}
33392df76c16SMatt 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);
33402df76c16SMatt Jacob 	iccb->ccb_h.target_id = atio->ccb_h.target_id;
33412df76c16SMatt Jacob 	iccb->ccb_h.target_lun = return_lun;
33422df76c16SMatt Jacob 	iccb->ccb_h.ccb_atio = atio;
33432df76c16SMatt Jacob 	xpt_action(iccb);
33442df76c16SMatt Jacob 
33452df76c16SMatt Jacob 	if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
33462df76c16SMatt Jacob 		cam_release_devq(periph->path, 0, 0, 0, 0);
33472df76c16SMatt Jacob 		atio->ccb_h.status &= ~CAM_DEV_QFRZN;
33482df76c16SMatt Jacob 	}
33492df76c16SMatt Jacob 	if (more) {
33502df76c16SMatt Jacob 		xpt_schedule(periph, 1);
33512df76c16SMatt Jacob 	}
33522df76c16SMatt Jacob }
33532df76c16SMatt Jacob 
33542df76c16SMatt Jacob static cam_status
33552df76c16SMatt Jacob isptargctor(struct cam_periph *periph, void *arg)
33562df76c16SMatt Jacob {
33572df76c16SMatt Jacob 	struct isptarg_softc *softc;
33582df76c16SMatt Jacob 
33592df76c16SMatt Jacob 	softc = (struct isptarg_softc *)arg;
33602df76c16SMatt Jacob 	periph->softc = softc;
33612df76c16SMatt Jacob 	softc->periph = periph;
33622df76c16SMatt Jacob 	softc->path = periph->path;
33632df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
33642df76c16SMatt Jacob 	return (CAM_REQ_CMP);
33652df76c16SMatt Jacob }
33662df76c16SMatt Jacob 
33672df76c16SMatt Jacob static void
33682df76c16SMatt Jacob isptargdtor(struct cam_periph *periph)
33692df76c16SMatt Jacob {
33702df76c16SMatt Jacob 	struct isptarg_softc *softc;
33712df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
33722df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
33732df76c16SMatt Jacob 	softc->periph = NULL;
33742df76c16SMatt Jacob 	softc->path = NULL;
33752df76c16SMatt Jacob 	periph->softc = NULL;
33762df76c16SMatt Jacob }
33772df76c16SMatt Jacob 
33782df76c16SMatt Jacob static void
33792df76c16SMatt Jacob isptarg_done(struct cam_periph *periph, union ccb *ccb)
33802df76c16SMatt Jacob {
33812df76c16SMatt Jacob 	struct isptarg_softc *softc;
33822df76c16SMatt Jacob 	ispsoftc_t *isp;
33832df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
33842df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
33852df76c16SMatt Jacob 	cam_status status;
33862df76c16SMatt Jacob 
33872df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
33882df76c16SMatt Jacob 	isp = softc->isp;
33892df76c16SMatt Jacob 	status = ccb->ccb_h.status & CAM_STATUS_MASK;
33902df76c16SMatt Jacob 
33912df76c16SMatt Jacob 	switch (ccb->ccb_h.func_code) {
33922df76c16SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:
33932df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *) ccb;
33942df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__);
33952df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe);
33962df76c16SMatt Jacob 		xpt_schedule(periph, 1);
33972df76c16SMatt Jacob 		break;
33982df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:
33992df76c16SMatt Jacob 		inot = (struct ccb_immediate_notify *) ccb;
34002df76c16SMatt 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__);
34012df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe);
34022df76c16SMatt Jacob 		xpt_schedule(periph, 1);
34032df76c16SMatt Jacob 		break;
34042df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
34052df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
34062df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
34072df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
34082df76c16SMatt Jacob 		}
34092df76c16SMatt Jacob 		atio = ccb->ccb_h.ccb_atio;
34102df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
34112df76c16SMatt Jacob 			cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
34122df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
34132df76c16SMatt Jacob 		} else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
34142df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO seen in %s\n", atio->tag_id, __func__);
34152df76c16SMatt Jacob 			TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe);
34162df76c16SMatt Jacob 			xpt_schedule(periph, 1);
34172df76c16SMatt Jacob 		} else {
34182df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO seen in %s\n", atio->tag_id, __func__);
34192df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
34202df76c16SMatt Jacob 		}
34212df76c16SMatt Jacob 		xpt_release_ccb(ccb);
34222df76c16SMatt Jacob 		break;
34232df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:
34242df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
34252df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
34262df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
34272df76c16SMatt Jacob 		}
34282df76c16SMatt Jacob 		inot = ccb->ccb_h.ccb_inot;
34292df76c16SMatt 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);
34302df76c16SMatt Jacob 		xpt_release_ccb(ccb);
34312df76c16SMatt Jacob 		xpt_action((union ccb *)inot);
34322df76c16SMatt Jacob 		break;
34332df76c16SMatt Jacob 	default:
34342df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "unexpected code 0x%x\n", ccb->ccb_h.func_code);
34352df76c16SMatt Jacob 		break;
34362df76c16SMatt Jacob 	}
34372df76c16SMatt Jacob }
34382df76c16SMatt Jacob 
34392df76c16SMatt Jacob static void
34402df76c16SMatt Jacob isptargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
34412df76c16SMatt Jacob {
34422df76c16SMatt Jacob 	struct ac_contract *acp = arg;
34432df76c16SMatt Jacob 	struct ac_device_changed *fc = (struct ac_device_changed *) acp->contract_data;
34442df76c16SMatt Jacob 
34452df76c16SMatt Jacob 	if (code != AC_CONTRACT) {
34462df76c16SMatt Jacob 		return;
34472df76c16SMatt Jacob 	}
34482df76c16SMatt Jacob 	xpt_print(path, "0x%016llx Port ID 0x%06x %s\n", (unsigned long long) fc->wwpn, fc->port, fc->arrived? "arrived" : "departed");
34492df76c16SMatt Jacob }
34502df76c16SMatt Jacob 
34512df76c16SMatt Jacob static void
34522df76c16SMatt Jacob isp_target_thread(ispsoftc_t *isp, int chan)
34532df76c16SMatt Jacob {
34542df76c16SMatt Jacob 	union ccb *ccb = NULL;
34552df76c16SMatt Jacob 	int i;
34562df76c16SMatt Jacob 	void *wchan;
34572df76c16SMatt Jacob 	cam_status status;
34582df76c16SMatt Jacob 	struct isptarg_softc *softc = NULL;
34592df76c16SMatt Jacob 	struct cam_periph *periph = NULL, *wperiph = NULL;
34602df76c16SMatt Jacob 	struct cam_path *path, *wpath;
34612df76c16SMatt Jacob 	struct cam_sim *sim;
34622df76c16SMatt Jacob 
34632df76c16SMatt Jacob 	if (disk_data == NULL) {
34642df76c16SMatt Jacob 		disk_size = roundup2(vm_kmem_size >> 1, (1ULL << 20));
34652df76c16SMatt Jacob 		if (disk_size < (50 << 20)) {
34662df76c16SMatt Jacob 			disk_size = 50 << 20;
34672df76c16SMatt Jacob 		}
34682df76c16SMatt Jacob 		disk_data = malloc(disk_size, M_ISPTARG, M_WAITOK | M_ZERO);
34692df76c16SMatt Jacob 		if (disk_data == NULL) {
34702df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: could not allocate disk data", __func__);
34712df76c16SMatt Jacob 			goto out;
34722df76c16SMatt Jacob 		}
34732df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "allocated a %ju MiB disk", (uintmax_t) (disk_size >> 20));
34742df76c16SMatt Jacob 	}
34752df76c16SMatt Jacob 	junk_data = malloc(JUNK_SIZE, M_ISPTARG, M_WAITOK | M_ZERO);
34762df76c16SMatt Jacob 	if (junk_data == NULL) {
34772df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate junk", __func__);
34782df76c16SMatt Jacob 		goto out;
34792df76c16SMatt Jacob 	}
34802df76c16SMatt Jacob 
34812df76c16SMatt Jacob 
34822df76c16SMatt Jacob 	softc = malloc(sizeof (*softc), M_ISPTARG, M_WAITOK | M_ZERO);
34832df76c16SMatt Jacob 	if (softc == NULL) {
34842df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate softc", __func__);
34852df76c16SMatt Jacob 		goto out;
34862df76c16SMatt Jacob 	}
34872df76c16SMatt Jacob 	TAILQ_INIT(&softc->work_queue);
34882df76c16SMatt Jacob 	TAILQ_INIT(&softc->rework_queue);
34892df76c16SMatt Jacob 	TAILQ_INIT(&softc->running_queue);
34902df76c16SMatt Jacob 	TAILQ_INIT(&softc->inot_queue);
34912df76c16SMatt Jacob 	softc->isp = isp;
34922df76c16SMatt Jacob 
34932df76c16SMatt Jacob 	periphdriver_register(&isptargdriver);
34942df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, sim, sim);
34952df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, path,  path);
34962df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&wpath, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
34972df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
34982df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate wildcard path", __func__);
34992df76c16SMatt Jacob 		return;
35002df76c16SMatt Jacob 	}
35012df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), 0, 0);
35022df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35032df76c16SMatt Jacob 		xpt_free_path(wpath);
35042df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate path", __func__);
35052df76c16SMatt Jacob 		return;
35062df76c16SMatt Jacob 	}
35072df76c16SMatt Jacob 
35082df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
35092df76c16SMatt Jacob 
35102df76c16SMatt Jacob 	ISP_LOCK(isp);
35112df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, wpath, NULL, 0, softc);
35122df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35132df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35142df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc for wildcard failed", __func__);
35152df76c16SMatt Jacob 		goto out;
35162df76c16SMatt Jacob 	}
35172df76c16SMatt Jacob 	wperiph = cam_periph_find(wpath, "isptarg");
35182df76c16SMatt Jacob 	if (wperiph == NULL) {
35192df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35202df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: wildcard periph already allocated but doesn't exist", __func__);
35212df76c16SMatt Jacob 		goto out;
35222df76c16SMatt Jacob 	}
35232df76c16SMatt Jacob 
35242df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, path, NULL, 0, softc);
35252df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35262df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35272df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc failed", __func__);
35282df76c16SMatt Jacob 		goto out;
35292df76c16SMatt Jacob 	}
35302df76c16SMatt Jacob 
35312df76c16SMatt Jacob 	periph = cam_periph_find(path, "isptarg");
35322df76c16SMatt Jacob 	if (periph == NULL) {
35332df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35342df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: periph already allocated but doesn't exist", __func__);
35352df76c16SMatt Jacob 		goto out;
35362df76c16SMatt Jacob 	}
35372df76c16SMatt Jacob 
35382df76c16SMatt Jacob 	status = xpt_register_async(AC_CONTRACT, isptargasync, isp, wpath);
35392df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35402df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35412df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: xpt_register_async failed", __func__);
35422df76c16SMatt Jacob 		goto out;
35432df76c16SMatt Jacob 	}
35442df76c16SMatt Jacob 
35452df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35462df76c16SMatt Jacob 
35472df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
35482df76c16SMatt Jacob 
35492df76c16SMatt Jacob 	/*
35502df76c16SMatt Jacob 	 * Make sure role is none.
35512df76c16SMatt Jacob 	 */
35522df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
35532df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
35542df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE;
35552df76c16SMatt Jacob #ifdef	ISP_TEST_WWNS
35562df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE | KNOB_VALID_ADDRESS;
35572df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwnn = 0x508004d000000000ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
35582df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwpn = 0x508004d000000001ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
35592df76c16SMatt Jacob #else
35602df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
35612df76c16SMatt Jacob #endif
35622df76c16SMatt Jacob 
35632df76c16SMatt Jacob 	ISP_LOCK(isp);
35642df76c16SMatt Jacob 	xpt_action(ccb);
35652df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35662df76c16SMatt Jacob 
35672df76c16SMatt Jacob 	/*
35682df76c16SMatt Jacob 	 * Now enable luns
35692df76c16SMatt Jacob 	 */
35702df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
35712df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
35722df76c16SMatt Jacob 	ccb->cel.enable = 1;
35732df76c16SMatt Jacob 	ISP_LOCK(isp);
35742df76c16SMatt Jacob 	xpt_action(ccb);
35752df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35762df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
35772df76c16SMatt Jacob 		xpt_free_ccb(ccb);
35782df76c16SMatt Jacob 		xpt_print(periph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
35792df76c16SMatt Jacob 		goto out;
35802df76c16SMatt Jacob 	}
35812df76c16SMatt Jacob 
35822df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 10);
35832df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
35842df76c16SMatt Jacob 	ccb->cel.enable = 1;
35852df76c16SMatt Jacob 	ISP_LOCK(isp);
35862df76c16SMatt Jacob 	xpt_action(ccb);
35872df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35882df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
35892df76c16SMatt Jacob 		xpt_free_ccb(ccb);
35902df76c16SMatt Jacob 		xpt_print(wperiph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
35912df76c16SMatt Jacob 		goto out;
35922df76c16SMatt Jacob 	}
35932df76c16SMatt Jacob 	xpt_free_ccb(ccb);
35942df76c16SMatt Jacob 
35952df76c16SMatt Jacob 	/*
35962df76c16SMatt Jacob 	 * Add resources
35972df76c16SMatt Jacob 	 */
35982df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, chan, target_proc, wchan);
35992df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
36002df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36012df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
36022df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
36032df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36042df76c16SMatt Jacob 		ISP_LOCK(isp);
36052df76c16SMatt Jacob 		xpt_action(ccb);
36062df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36072df76c16SMatt Jacob 	}
36082df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_CMDS; i++) {
36092df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36102df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
36112df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
36122df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36132df76c16SMatt Jacob 		ISP_LOCK(isp);
36142df76c16SMatt Jacob 		xpt_action(ccb);
36152df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36162df76c16SMatt Jacob 	}
36172df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
36182df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36192df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
36202df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
36212df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36222df76c16SMatt Jacob 		ISP_LOCK(isp);
36232df76c16SMatt Jacob 		xpt_action(ccb);
36242df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36252df76c16SMatt Jacob 	}
36262df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_NOTIFIES; i++) {
36272df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36282df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
36292df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
36302df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36312df76c16SMatt Jacob 		ISP_LOCK(isp);
36322df76c16SMatt Jacob 		xpt_action(ccb);
36332df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36342df76c16SMatt Jacob 	}
36352df76c16SMatt Jacob 
36362df76c16SMatt Jacob 	/*
36372df76c16SMatt Jacob 	 * Now turn it all back on
36382df76c16SMatt Jacob 	 */
36392df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
36402df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
36412df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
36422df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_TARGET;
36432df76c16SMatt Jacob 	ISP_LOCK(isp);
36442df76c16SMatt Jacob 	xpt_action(ccb);
36452df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36462df76c16SMatt Jacob 
36472df76c16SMatt Jacob 	/*
36482df76c16SMatt Jacob 	 * Okay, while things are still active, sleep...
36492df76c16SMatt Jacob 	 */
36502df76c16SMatt Jacob 	ISP_LOCK(isp);
36512df76c16SMatt Jacob 	for (;;) {
36522df76c16SMatt Jacob 		ISP_GET_PC(isp, chan, proc_active, i);
36532df76c16SMatt Jacob 		if (i == 0) {
36542df76c16SMatt Jacob 			break;
36552df76c16SMatt Jacob 		}
36562df76c16SMatt Jacob 		msleep(wchan, &isp->isp_lock, PUSER, "tsnooze", 0);
36572df76c16SMatt Jacob 	}
36582df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36592df76c16SMatt Jacob 
36602df76c16SMatt Jacob out:
36612df76c16SMatt Jacob 	if (wperiph) {
36622df76c16SMatt Jacob 		cam_periph_invalidate(wperiph);
36632df76c16SMatt Jacob 	}
36642df76c16SMatt Jacob 	if (periph) {
36652df76c16SMatt Jacob 		cam_periph_invalidate(periph);
36662df76c16SMatt Jacob 	}
36672df76c16SMatt Jacob 	if (junk_data) {
36682df76c16SMatt Jacob 		free(junk_data, M_ISPTARG);
36692df76c16SMatt Jacob 	}
36702df76c16SMatt Jacob 	if (disk_data) {
36712df76c16SMatt Jacob 		free(disk_data, M_ISPTARG);
36722df76c16SMatt Jacob 	}
36732df76c16SMatt Jacob 	if (softc) {
36742df76c16SMatt Jacob 		free(softc, M_ISPTARG);
36752df76c16SMatt Jacob 	}
36762df76c16SMatt Jacob 	xpt_free_path(path);
36772df76c16SMatt Jacob 	xpt_free_path(wpath);
36782df76c16SMatt Jacob }
36792df76c16SMatt Jacob 
36802df76c16SMatt Jacob static void
36812df76c16SMatt Jacob isp_target_thread_pi(void *arg)
36822df76c16SMatt Jacob {
36832df76c16SMatt Jacob 	struct isp_spi *pi = arg;
36842df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(pi->sim), cam_sim_bus(pi->sim));
36852df76c16SMatt Jacob }
36862df76c16SMatt Jacob 
36872df76c16SMatt Jacob static void
36882df76c16SMatt Jacob isp_target_thread_fc(void *arg)
36892df76c16SMatt Jacob {
36902df76c16SMatt Jacob 	struct isp_fc *fc = arg;
36912df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(fc->sim), cam_sim_bus(fc->sim));
36922df76c16SMatt Jacob }
36932df76c16SMatt Jacob 
36942df76c16SMatt Jacob static int
36952df76c16SMatt Jacob isptarg_rwparm(uint8_t *cdb, uint8_t *dp, uint64_t dl, uint32_t offset, uint8_t **kp, uint32_t *tl, int *lp)
36962df76c16SMatt Jacob {
36972df76c16SMatt Jacob 	uint32_t cnt, curcnt;
36982df76c16SMatt Jacob 	uint64_t lba;
36992df76c16SMatt Jacob 
37002df76c16SMatt Jacob 	switch (cdb[0]) {
37012df76c16SMatt Jacob 	case WRITE_16:
37022df76c16SMatt Jacob 	case READ_16:
37032df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[10]) <<  24) |
37042df76c16SMatt Jacob 			(((uint32_t)cdb[11]) <<  16) |
37052df76c16SMatt Jacob 			(((uint32_t)cdb[12]) <<   8) |
37062df76c16SMatt Jacob 			((uint32_t)cdb[13]);
37072df76c16SMatt Jacob 
37082df76c16SMatt Jacob 		lba =	(((uint64_t)cdb[2]) << 56) |
37092df76c16SMatt Jacob 			(((uint64_t)cdb[3]) << 48) |
37102df76c16SMatt Jacob 			(((uint64_t)cdb[4]) << 40) |
37112df76c16SMatt Jacob 			(((uint64_t)cdb[5]) << 32) |
37122df76c16SMatt Jacob 			(((uint64_t)cdb[6]) << 24) |
37132df76c16SMatt Jacob 			(((uint64_t)cdb[7]) << 16) |
37142df76c16SMatt Jacob 			(((uint64_t)cdb[8]) <<  8) |
37152df76c16SMatt Jacob 			((uint64_t)cdb[9]);
37162df76c16SMatt Jacob 		break;
37172df76c16SMatt Jacob 	case WRITE_12:
37182df76c16SMatt Jacob 	case READ_12:
37192df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[6]) <<  16) |
37202df76c16SMatt Jacob 			(((uint32_t)cdb[7]) <<   8) |
37212df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
37222df76c16SMatt Jacob 
37232df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
37242df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
37252df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
37262df76c16SMatt Jacob 			((uint32_t)cdb[5]);
37272df76c16SMatt Jacob 		break;
37282df76c16SMatt Jacob 	case WRITE_10:
37292df76c16SMatt Jacob 	case READ_10:
37302df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[7]) <<  8) |
37312df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
37322df76c16SMatt Jacob 
37332df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
37342df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
37352df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
37362df76c16SMatt Jacob 			((uint32_t)cdb[5]);
37372df76c16SMatt Jacob 		break;
37382df76c16SMatt Jacob 	case WRITE_6:
37392df76c16SMatt Jacob 	case READ_6:
37402df76c16SMatt Jacob 		cnt = cdb[4];
37412df76c16SMatt Jacob 		if (cnt == 0) {
37422df76c16SMatt Jacob 			cnt = 256;
37432df76c16SMatt Jacob 		}
37442df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[1] & 0x1f) << 16) |
37452df76c16SMatt Jacob 			(((uint32_t)cdb[2]) << 8) |
37462df76c16SMatt Jacob 			((uint32_t)cdb[3]);
37472df76c16SMatt Jacob 		break;
37482df76c16SMatt Jacob 	default:
37492df76c16SMatt Jacob 		return (-1);
37502df76c16SMatt Jacob 	}
37512df76c16SMatt Jacob 
37522df76c16SMatt Jacob 	cnt <<= DISK_SHIFT;
37532df76c16SMatt Jacob 	lba <<= DISK_SHIFT;
37542df76c16SMatt Jacob 
37552df76c16SMatt Jacob 	if (offset == cnt) {
37562df76c16SMatt Jacob 		*lp = 1;
37572df76c16SMatt Jacob 		return (0);
37582df76c16SMatt Jacob 	}
37592df76c16SMatt Jacob 
37602df76c16SMatt Jacob 	if (lba + cnt > dl) {
37612df76c16SMatt Jacob 		return (-1);
37622df76c16SMatt Jacob 	}
37632df76c16SMatt Jacob 
37642df76c16SMatt Jacob 
37652df76c16SMatt Jacob 	curcnt = MAX_ISP_TARG_TRANSFER;
37662df76c16SMatt Jacob 	if (offset + curcnt >= cnt) {
37672df76c16SMatt Jacob 		curcnt = cnt - offset;
37682df76c16SMatt Jacob 		*lp = 1;
37692df76c16SMatt Jacob 	} else {
37702df76c16SMatt Jacob 		*lp = 0;
37712df76c16SMatt Jacob 	}
37722df76c16SMatt Jacob 	*tl = curcnt;
37732df76c16SMatt Jacob 	*kp = &dp[lba + offset];
37742df76c16SMatt Jacob 	return (0);
37752df76c16SMatt Jacob }
37762df76c16SMatt Jacob 
37772df76c16SMatt Jacob #endif
3778d81ba9d5SMatt Jacob #endif
3779d81ba9d5SMatt Jacob 
3780478f8a96SJustin T. Gibbs static void
37811dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
3782478f8a96SJustin T. Gibbs {
3783478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
37849cd7268eSMatt Jacob 	ispsoftc_t *isp;
3785478f8a96SJustin T. Gibbs 
3786478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
37879cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
3788478f8a96SJustin T. Gibbs 	switch (code) {
3789478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
3790ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
37911dae40ebSMatt Jacob 			uint16_t oflags, nflags;
37922df76c16SMatt Jacob 			int bus = cam_sim_bus(sim);
37932df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
3794a1bc34c6SMatt Jacob 			int tgt;
3795478f8a96SJustin T. Gibbs 
3796f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
379741ed683eSMatt Jacob 			if (tgt >= 0) {
37989ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
3799a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
38009ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
3801a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
3802478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
3803478f8a96SJustin T. Gibbs 				}
3804a1bc34c6SMatt Jacob #else
3805a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
3806a1bc34c6SMatt Jacob #endif
38079ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
38089ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
3809478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
38102df76c16SMatt Jacob 				sdp->update = 1;
38112df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
38129ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
3813478f8a96SJustin T. Gibbs 			}
381441ed683eSMatt Jacob 		}
3815478f8a96SJustin T. Gibbs 		break;
3816478f8a96SJustin T. Gibbs 	default:
38173c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
3818478f8a96SJustin T. Gibbs 		break;
3819478f8a96SJustin T. Gibbs 	}
3820478f8a96SJustin T. Gibbs }
3821478f8a96SJustin T. Gibbs 
3822478f8a96SJustin T. Gibbs static void
3823c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
3824478f8a96SJustin T. Gibbs {
38259cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
382610365e5aSMatt Jacob 	uint32_t isr;
382710365e5aSMatt Jacob 	uint16_t sema, mbox;
3828126ec864SMatt Jacob 
3829126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3830126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
3831126ec864SMatt Jacob 	}
3832478f8a96SJustin T. Gibbs }
3833478f8a96SJustin T. Gibbs 
3834ab6c4b31SMatt Jacob 
38352df76c16SMatt Jacob static void
38362df76c16SMatt Jacob isp_watchdog(void *arg)
3837cc8df88bSMatt Jacob {
38382df76c16SMatt Jacob 	struct ccb_scsiio *xs = arg;
38392df76c16SMatt Jacob 	ispsoftc_t *isp;
38401dae40ebSMatt Jacob 	uint32_t handle;
3841b85389e1SMatt Jacob 
38422df76c16SMatt Jacob 	isp = XS_ISP(xs);
38432df76c16SMatt Jacob 
3844cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
3845c8b8a2c4SMatt Jacob 	if (handle != ISP_HANDLE_FREE) {
38461fcf5debSMatt Jacob 		/*
3847c8b8a2c4SMatt Jacob 		 * Try and make sure the command is really dead before
3848c8b8a2c4SMatt Jacob 		 * we release the handle (and DMA resources) for reuse.
3849c8b8a2c4SMatt Jacob 		 *
3850c8b8a2c4SMatt Jacob 		 * If we are successful in aborting the command then
3851c8b8a2c4SMatt Jacob 		 * we're done here because we'll get the command returned
3852c8b8a2c4SMatt Jacob 		 * back separately.
38531fcf5debSMatt Jacob 		 */
3854c8b8a2c4SMatt Jacob 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) {
3855c8b8a2c4SMatt Jacob 			return;
3856c8b8a2c4SMatt Jacob 		}
38571fcf5debSMatt Jacob 
38581fcf5debSMatt Jacob 		/*
3859c8b8a2c4SMatt Jacob 		 * Note that after calling the above, the command may in
3860c8b8a2c4SMatt Jacob 		 * fact have been completed.
3861c8b8a2c4SMatt Jacob 		 */
3862c8b8a2c4SMatt Jacob 		xs = isp_find_xs(isp, handle);
3863c8b8a2c4SMatt Jacob 
3864c8b8a2c4SMatt Jacob 		/*
3865c8b8a2c4SMatt Jacob 		 * If the command no longer exists, then we won't
3866c8b8a2c4SMatt Jacob 		 * be able to find the xs again with this handle.
3867c8b8a2c4SMatt Jacob 		 */
3868c8b8a2c4SMatt Jacob 		if (xs == NULL) {
3869c8b8a2c4SMatt Jacob 			return;
3870c8b8a2c4SMatt Jacob 		}
3871c8b8a2c4SMatt Jacob 
3872c8b8a2c4SMatt Jacob 		/*
3873c8b8a2c4SMatt Jacob 		 * After this point, the command is really dead.
38741fcf5debSMatt Jacob 		 */
3875f6e75de2SMatt Jacob 		if (XS_XFRLEN(xs)) {
3876f6e75de2SMatt Jacob 			ISP_DMAFREE(isp, xs, handle);
3877f6e75de2SMatt Jacob 		}
3878cc8df88bSMatt Jacob 		isp_destroy_handle(isp, handle);
3879c8b8a2c4SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle);
3880cc8df88bSMatt Jacob 		XS_SETERR(xs, CAM_CMD_TIMEOUT);
3881cc8df88bSMatt Jacob 		isp_done(xs);
3882b85389e1SMatt Jacob 	}
3883f7c631bcSMatt Jacob }
3884f7c631bcSMatt Jacob 
3885f7c631bcSMatt Jacob static void
38862df76c16SMatt Jacob isp_make_here(ispsoftc_t *isp, int chan, int tgt)
3887f7c631bcSMatt Jacob {
3888ffcf6651SMatt Jacob 	union ccb *ccb;
38892df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
38902df76c16SMatt Jacob 
38912df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
38922df76c16SMatt Jacob 		return;
38932df76c16SMatt Jacob 	}
38942df76c16SMatt Jacob 
3895ffcf6651SMatt Jacob 	/*
38960e85f214SMatt Jacob 	 * Allocate a CCB, create a wildcard path for this target and schedule a rescan.
3897ffcf6651SMatt Jacob 	 */
38988008a935SScott Long 	ccb = xpt_alloc_ccb_nowait();
3899ffcf6651SMatt Jacob 	if (ccb == NULL) {
39002df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan);
3901ffcf6651SMatt Jacob 		return;
3902ffcf6651SMatt Jacob 	}
39030e85f214SMatt Jacob 	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
3904ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
3905ffcf6651SMatt Jacob 		xpt_free_ccb(ccb);
3906ffcf6651SMatt Jacob 		return;
3907ffcf6651SMatt Jacob 	}
3908ffcf6651SMatt Jacob 	xpt_rescan(ccb);
3909ffcf6651SMatt Jacob }
3910ffcf6651SMatt Jacob 
3911ffcf6651SMatt Jacob static void
39122df76c16SMatt Jacob isp_make_gone(ispsoftc_t *isp, int chan, int tgt)
3913ffcf6651SMatt Jacob {
3914ffcf6651SMatt Jacob 	struct cam_path *tp;
39152df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
39162df76c16SMatt Jacob 
39172df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
39182df76c16SMatt Jacob 		return;
39192df76c16SMatt Jacob 	}
39202df76c16SMatt Jacob 	if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
3921ffcf6651SMatt Jacob 		xpt_async(AC_LOST_DEVICE, tp, NULL);
3922ffcf6651SMatt Jacob 		xpt_free_path(tp);
3923f7c631bcSMatt Jacob 	}
3924f7c631bcSMatt Jacob }
3925f7c631bcSMatt Jacob 
3926f7c631bcSMatt Jacob /*
3927f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
3928f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
3929f7c631bcSMatt Jacob  * gone away.
3930f7c631bcSMatt Jacob  *
3931f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
3932f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
3933f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
3934f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
3935f7c631bcSMatt Jacob  */
3936f7c631bcSMatt Jacob static void
3937f7c631bcSMatt Jacob isp_gdt(void *arg)
3938f7c631bcSMatt Jacob {
39392df76c16SMatt Jacob 	struct isp_fc *fc = arg;
39402df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
39412df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
3942f7c631bcSMatt Jacob 	fcportdb_t *lp;
3943f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
3944f7c631bcSMatt Jacob 
3945a6119ff6SMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d GDT timer expired @ %lu", chan, (unsigned long) time_uptime);
3946f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
39472df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
3948f7c631bcSMatt Jacob 
3949f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
3950f7c631bcSMatt Jacob 			continue;
3951f7c631bcSMatt Jacob 		}
39522df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
3953f7c631bcSMatt Jacob 			continue;
3954f7c631bcSMatt Jacob 		}
3955427fa8f9SMatt Jacob 		if (lp->gone_timer != 0) {
3956427fa8f9SMatt Jacob 			lp->gone_timer -= 1;
3957f7c631bcSMatt Jacob 			more_to_do++;
3958f7c631bcSMatt Jacob 			continue;
3959f7c631bcSMatt Jacob 		}
39602df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
39612df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
39622df76c16SMatt Jacob 		lp->dev_map_idx = 0;
3963f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
39642df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout");
39652df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
3966f7c631bcSMatt Jacob 	}
3967a01f5aebSMatt Jacob 	if (fc->ready) {
3968f7c631bcSMatt Jacob 		if (more_to_do) {
39692df76c16SMatt Jacob 			callout_reset(&fc->gdt, hz, isp_gdt, fc);
3970f7c631bcSMatt Jacob 		} else {
3971427fa8f9SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Stopping Gone Device Timer", chan);
3972a01f5aebSMatt Jacob 		}
3973f7c631bcSMatt Jacob 	}
3974f7c631bcSMatt Jacob }
3975f7c631bcSMatt Jacob 
3976f7c631bcSMatt Jacob /*
3977f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
3978f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
3979f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
3980f7c631bcSMatt Jacob  *
3981f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
3982f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
3983f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
3984f7c631bcSMatt Jacob  */
3985f7c631bcSMatt Jacob static void
3986f7c631bcSMatt Jacob isp_ldt(void *arg)
3987f7c631bcSMatt Jacob {
39882df76c16SMatt Jacob 	struct isp_fc *fc = arg;
39892df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
39902df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
3991f7c631bcSMatt Jacob 	fcportdb_t *lp;
3992f7c631bcSMatt Jacob 	int dbidx, tgt;
3993f7c631bcSMatt Jacob 
39942df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime);
39950a70657fSMatt Jacob 
3996f7c631bcSMatt Jacob 	/*
3997f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
3998f7c631bcSMatt Jacob 	 */
3999f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
40002df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
4001f7c631bcSMatt Jacob 
4002f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
4003f7c631bcSMatt Jacob 			continue;
4004f7c631bcSMatt Jacob 		}
40052df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
4006f7c631bcSMatt Jacob 			continue;
4007f7c631bcSMatt Jacob 		}
4008f7c631bcSMatt Jacob 
4009f7c631bcSMatt Jacob 		/*
4010f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
4011f7c631bcSMatt Jacob 		 */
4012f7c631bcSMatt Jacob 
4013f7c631bcSMatt Jacob 		/*
4014f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
4015f7c631bcSMatt Jacob 		 */
4016f7c631bcSMatt Jacob 		lp->reserved = 1;
4017f7c631bcSMatt Jacob 
4018f7c631bcSMatt Jacob 		/*
4019f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
4020f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
4021f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
4022f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
4023f7c631bcSMatt Jacob 		 */
4024f7c631bcSMatt Jacob 
40252df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
40262df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
40272df76c16SMatt Jacob 		lp->dev_map_idx = 0;
40282df76c16SMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
40292df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout");
40302df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
4031f7c631bcSMatt Jacob 	}
4032f7c631bcSMatt Jacob 
4033f7c631bcSMatt Jacob 	/*
4034f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
4035f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
4036f7c631bcSMatt Jacob 	 */
40372df76c16SMatt Jacob 	fc->loop_dead = 1;
40382df76c16SMatt Jacob 	fc->loop_down_time = fc->loop_down_limit+1;
40392df76c16SMatt Jacob 	wakeup(fc);
4040cc8df88bSMatt Jacob }
4041cc8df88bSMatt Jacob 
40425d571944SMatt Jacob static void
40435d571944SMatt Jacob isp_kthread(void *arg)
40445d571944SMatt Jacob {
40452df76c16SMatt Jacob 	struct isp_fc *fc = arg;
40462df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
40472df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
4048f7c631bcSMatt Jacob 	int slp = 0;
4049a01f5aebSMatt Jacob 
40500a70657fSMatt Jacob 	mtx_lock(&isp->isp_osinfo.lock);
40512df76c16SMatt Jacob 
40525d571944SMatt Jacob 	for (;;) {
4053f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
4054fdeb9f2fSMatt Jacob 
40552df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan);
40562df76c16SMatt Jacob 		lb = isp_fc_runstate(isp, chan, 250000);
40572df76c16SMatt Jacob 
40582df76c16SMatt Jacob 		/*
40592df76c16SMatt Jacob 		 * Our action is different based upon whether we're supporting
40602df76c16SMatt Jacob 		 * Initiator mode or not. If we are, we might freeze the simq
40612df76c16SMatt Jacob 		 * when loop is down and set all sorts of different delays to
40622df76c16SMatt Jacob 		 * check again.
40632df76c16SMatt Jacob 		 *
40642df76c16SMatt Jacob 		 * If not, we simply just wait for loop to come up.
40652df76c16SMatt Jacob 		 */
40664ecb1d4aSMatt Jacob 		if (lb && (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR)) {
4067f7c631bcSMatt Jacob 			/*
4068f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
4069f7c631bcSMatt Jacob 			 */
40702df76c16SMatt Jacob 			fc->loop_down_time += slp;
407110365e5aSMatt Jacob 
407210365e5aSMatt Jacob 			if (lb < 0) {
40732df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time);
407410365e5aSMatt Jacob 			} else {
40752df76c16SMatt 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);
4076f44257c2SMatt Jacob 			}
407710365e5aSMatt Jacob 
407810365e5aSMatt Jacob 			/*
407910365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
4080f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
4081f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
4082f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
408310365e5aSMatt Jacob 			 */
40842df76c16SMatt Jacob 			if (FCPARAM(isp, chan)->loop_seen_once == 0) {
4085f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
408610365e5aSMatt Jacob 			} else {
40872df76c16SMatt Jacob 				lim = fc->loop_down_limit;
4088f7c631bcSMatt Jacob 			}
40892df76c16SMatt Jacob 			if (fc->loop_down_time >= lim) {
40902df76c16SMatt Jacob 				isp_freeze_loopdown(isp, chan, "loop limit hit");
4091f7c631bcSMatt Jacob 				slp = 0;
40922df76c16SMatt Jacob 			} else if (fc->loop_down_time < 10) {
409310365e5aSMatt Jacob 				slp = 1;
40942df76c16SMatt Jacob 			} else if (fc->loop_down_time < 30) {
4095f7c631bcSMatt Jacob 				slp = 5;
40962df76c16SMatt Jacob 			} else if (fc->loop_down_time < 60) {
4097f7c631bcSMatt Jacob 				slp = 10;
40982df76c16SMatt Jacob 			} else if (fc->loop_down_time < 120) {
4099f7c631bcSMatt Jacob 				slp = 20;
4100f7c631bcSMatt Jacob 			} else {
4101f7c631bcSMatt Jacob 				slp = 30;
4102f44257c2SMatt Jacob 			}
410310365e5aSMatt Jacob 
41042df76c16SMatt Jacob 		} else if (lb) {
41052df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan);
41062df76c16SMatt Jacob 			fc->loop_down_time += slp;
41072df76c16SMatt Jacob 			slp = 60;
410810365e5aSMatt Jacob 		} else {
41092df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan);
41102df76c16SMatt Jacob 			fc->loop_down_time = 0;
411110365e5aSMatt Jacob 			slp = 0;
41125d571944SMatt Jacob 		}
4113fdeb9f2fSMatt Jacob 
41142df76c16SMatt Jacob 
4115f44257c2SMatt Jacob 		/*
41162df76c16SMatt Jacob 		 * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it
41172df76c16SMatt Jacob 		 * now so that CAM can start sending us commands.
41182df76c16SMatt Jacob 		 *
41192df76c16SMatt Jacob 		 * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again
41202df76c16SMatt Jacob 		 * or kill the commands, as appropriate.
4121f44257c2SMatt Jacob 		 */
41222df76c16SMatt Jacob 
41232df76c16SMatt Jacob 		if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) {
41242df76c16SMatt Jacob 			wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
41252df76c16SMatt Jacob 			fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
41262df76c16SMatt Jacob 			if (wasfrozen && fc->simqfrozen == 0) {
41272df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
41282df76c16SMatt Jacob 				xpt_release_simq(fc->sim, 1);
41295d571944SMatt Jacob 			}
41302df76c16SMatt Jacob 		}
41312df76c16SMatt Jacob 
41322df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp);
41332df76c16SMatt Jacob 
41342df76c16SMatt Jacob 		msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz);
41352df76c16SMatt Jacob 
413610365e5aSMatt Jacob 		/*
413710365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
413810365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
413910365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
414010365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
414110365e5aSMatt Jacob 		 * to settle.
414210365e5aSMatt Jacob 		 */
41432df76c16SMatt Jacob 		if (slp == 0 && fc->hysteresis) {
41442df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz);
41454962e51bSMatt Jacob 			mtx_unlock(&isp->isp_osinfo.lock);
41464962e51bSMatt Jacob 			pause("ispt", fc->hysteresis * hz);
41474962e51bSMatt Jacob 			mtx_lock(&isp->isp_osinfo.lock);
414810365e5aSMatt Jacob 		}
41495d571944SMatt Jacob 	}
41500a70657fSMatt Jacob 	mtx_unlock(&isp->isp_osinfo.lock);
41515d571944SMatt Jacob }
41525d571944SMatt Jacob 
4153cc8df88bSMatt Jacob static void
4154c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
4155478f8a96SJustin T. Gibbs {
41560a70657fSMatt Jacob 	int bus, tgt, ts, error, lim;
41579cd7268eSMatt Jacob 	ispsoftc_t *isp;
41584663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
4159478f8a96SJustin T. Gibbs 
4160478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
4161478f8a96SJustin T. Gibbs 
41629cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
41632df76c16SMatt Jacob 	mtx_assert(&isp->isp_lock, MA_OWNED);
41642df76c16SMatt Jacob 
41652df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE && ccb->ccb_h.func_code == XPT_SCSI_IO) {
416657c801f5SMatt Jacob 		isp_init(isp);
416757c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
416857c801f5SMatt Jacob 			/*
416957c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
417057c801f5SMatt Jacob 			 */
4171b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
41720470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
417357c801f5SMatt Jacob 			xpt_done(ccb);
417457c801f5SMatt Jacob 			return;
417557c801f5SMatt Jacob 		}
417657c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
417757c801f5SMatt Jacob 	}
4178b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
41790a70657fSMatt Jacob 	ISP_PCMD(ccb) = NULL;
41805d571944SMatt Jacob 
4181478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
4182478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
41832df76c16SMatt Jacob 		bus = XS_CHANNEL(ccb);
4184478f8a96SJustin T. Gibbs 		/*
4185478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
4186478f8a96SJustin T. Gibbs 		 */
4187478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
4188478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
4189478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
4190478f8a96SJustin T. Gibbs 				xpt_done(ccb);
4191478f8a96SJustin T. Gibbs 				break;
4192478f8a96SJustin T. Gibbs 			}
4193478f8a96SJustin T. Gibbs 		}
41940470d791SMatt Jacob #ifdef	DIAGNOSTIC
41950470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
4196dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
4197478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
41980470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
4199dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
4200478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
4201478f8a96SJustin T. Gibbs 		}
4202478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
4203478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4204478f8a96SJustin T. Gibbs 			break;
4205478f8a96SJustin T. Gibbs 		}
42060470d791SMatt Jacob #endif
42070a70657fSMatt Jacob 		ccb->csio.scsi_status = SCSI_STATUS_OK;
42080a70657fSMatt Jacob 		if (isp_get_pcmd(isp, ccb)) {
42090a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "out of PCMDs");
42100a70657fSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42112df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
42120a70657fSMatt Jacob 			xpt_done(ccb);
42130a70657fSMatt Jacob 			break;
42140a70657fSMatt Jacob 		}
4215b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
42160470d791SMatt Jacob 		switch (error) {
4217478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
4218f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
4219478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
42200a70657fSMatt Jacob 			if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) {
42210a70657fSMatt Jacob 				break;
4222d69a5f7dSMatt Jacob 			}
42230a70657fSMatt Jacob 			ts = ccb->ccb_h.timeout;
42240a70657fSMatt Jacob 			if (ts == CAM_TIME_DEFAULT) {
42250a70657fSMatt Jacob 				ts = 60*1000;
4226cc8df88bSMatt Jacob 			}
42270a70657fSMatt Jacob 			ts = isp_mstohz(ts);
42282df76c16SMatt Jacob 			callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb);
4229478f8a96SJustin T. Gibbs 			break;
42300470d791SMatt Jacob 		case CMD_RQLATER:
4231f44257c2SMatt Jacob 			/*
42322df76c16SMatt Jacob 			 * We get this result for FC devices if the loop state isn't ready yet
42332df76c16SMatt Jacob 			 * or if the device in question has gone zombie on us.
42342df76c16SMatt Jacob 			 *
42352df76c16SMatt Jacob 			 * If we've never seen Loop UP at all, we requeue this request and wait
42362df76c16SMatt Jacob 			 * for the initial loop up delay to expire.
423710365e5aSMatt Jacob 			 */
42382df76c16SMatt Jacob 			lim = ISP_FC_PC(isp, bus)->loop_down_limit;
42392df76c16SMatt Jacob 			if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) {
42402df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->loop_seen_once == 0) {
42412df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGDEBUG0, "%d.%d loop not seen yet @ %lu", XS_TGT(ccb), XS_LUN(ccb), (unsigned long) time_uptime);
4242f7c631bcSMatt Jacob 				} else {
42432df76c16SMatt 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);
4244f7c631bcSMatt Jacob 				}
42452df76c16SMatt Jacob 				ccb->ccb_h.status = CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
4246f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
42470a70657fSMatt Jacob 				isp_free_pcmd(isp, ccb);
4248f44257c2SMatt Jacob 				xpt_done(ccb);
4249f44257c2SMatt Jacob 				break;
4250f44257c2SMatt Jacob 			}
42512df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
4252f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42532df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
4254f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
42550a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
4256478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4257478f8a96SJustin T. Gibbs 			break;
42580470d791SMatt Jacob 		case CMD_EAGAIN:
42590a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
42602df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42612df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0);
42622df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
4263478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4264478f8a96SJustin T. Gibbs 			break;
42650470d791SMatt Jacob 		case CMD_COMPLETE:
42660470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
42670470d791SMatt Jacob 			break;
42680470d791SMatt Jacob 		default:
42692df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "What's this? 0x%x at %d in file %s", error, __LINE__, __FILE__);
4270b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
42710a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
42720470d791SMatt Jacob 			xpt_done(ccb);
4273478f8a96SJustin T. Gibbs 		}
4274478f8a96SJustin T. Gibbs 		break;
4275478f8a96SJustin T. Gibbs 
4276d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
42772df76c16SMatt Jacob 	case XPT_EN_LUN:		/* Enable/Disable LUN as a target */
42782df76c16SMatt Jacob 		if (ccb->cel.enable) {
42792df76c16SMatt Jacob 			isp_enable_lun(isp, ccb);
42802df76c16SMatt Jacob 		} else {
42812df76c16SMatt Jacob 			isp_disable_lun(isp, ccb);
428267ff51f1SMatt Jacob 		}
428367ff51f1SMatt Jacob 		break;
4284ae5db118SMatt Jacob 	case XPT_IMMED_NOTIFY:
42852df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
4286d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
4287d81ba9d5SMatt Jacob 	{
42882df76c16SMatt Jacob 		tstate_t *tptr = get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
4289d81ba9d5SMatt Jacob 		if (tptr == NULL) {
42902df76c16SMatt Jacob 			tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
42912df76c16SMatt Jacob 		}
42922df76c16SMatt Jacob 		if (tptr == NULL) {
42932df76c16SMatt Jacob 			const char *str;
42942df76c16SMatt Jacob 			uint32_t tag;
42952df76c16SMatt Jacob 
42962df76c16SMatt Jacob 			if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
42972df76c16SMatt Jacob 				str = "XPT_IMMEDIATE_NOTIFY";
42982df76c16SMatt Jacob 				tag = ccb->cin1.seq_id;
42992df76c16SMatt Jacob 			} else {
43002df76c16SMatt Jacob 				tag = ccb->atio.tag_id;
43012df76c16SMatt Jacob 				str = "XPT_ACCEPT_TARGET_IO";
43022df76c16SMatt Jacob 			}
43032df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] no state pointer found for %s\n", __func__, tag, str);
43042df76c16SMatt Jacob 			dump_tstates(isp, XS_CHANNEL(ccb));
43052df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
4306d81ba9d5SMatt Jacob 			break;
4307d81ba9d5SMatt Jacob 		}
4308f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
4309f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
4310570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
4311570c7a3fSMatt Jacob 
4312d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
43132df76c16SMatt Jacob 			if (ccb->atio.tag_id) {
43142df76c16SMatt Jacob 				atio_private_data_t *atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id);
43152df76c16SMatt Jacob 				if (atp) {
43162df76c16SMatt Jacob 					isp_put_atpd(isp, tptr, atp);
43172df76c16SMatt Jacob 				}
43182df76c16SMatt Jacob 			}
4319570c7a3fSMatt Jacob 			tptr->atio_count++;
43202df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle);
43212df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n",
43222df76c16SMatt Jacob 			    ((struct ccb_accept_tio *)ccb)->tag_id, tptr->atio_count);
43232df76c16SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
43242df76c16SMatt Jacob 			if (ccb->cin1.tag_id) {
43252df76c16SMatt Jacob 				inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id);
43262df76c16SMatt Jacob 				if (ntp) {
43272df76c16SMatt Jacob 					isp_put_ntpd(isp, tptr, ntp);
43282df76c16SMatt Jacob 				}
43292df76c16SMatt Jacob 			}
4330746e9c85SMatt Jacob 			tptr->inot_count++;
43312df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
43322df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
43332df76c16SMatt Jacob 			    ((struct ccb_immediate_notify *)ccb)->seq_id, tptr->inot_count);
4334ae5db118SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
4335ae5db118SMatt Jacob 			tptr->inot_count++;
4336ae5db118SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
4337ae5db118SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
4338ae5db118SMatt Jacob 			    ((struct ccb_immediate_notify *)ccb)->seq_id, tptr->inot_count);
4339d81ba9d5SMatt Jacob 		}
4340d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
4341d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
4342d81ba9d5SMatt Jacob 		break;
4343d81ba9d5SMatt Jacob 	}
4344ae5db118SMatt Jacob 	case XPT_NOTIFY_ACK:
4345ae5db118SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4346ae5db118SMatt Jacob 		break;
43472df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:		/* notify ack */
4348d81ba9d5SMatt Jacob 	{
43492df76c16SMatt Jacob 		tstate_t *tptr;
43502df76c16SMatt Jacob 		inot_private_data_t *ntp;
43512df76c16SMatt Jacob 
43522df76c16SMatt Jacob 		/*
43532df76c16SMatt Jacob 		 * XXX: Because we cannot guarantee that the path information in the notify acknowledge ccb
43542df76c16SMatt Jacob 		 * XXX: matches that for the immediate notify, we have to *search* for the notify structure
43552df76c16SMatt Jacob 		 */
43562df76c16SMatt Jacob 		/*
43572df76c16SMatt Jacob 		 * All the relevant path information is in the associated immediate notify
43582df76c16SMatt Jacob 		 */
43592df76c16SMatt 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);
43602df76c16SMatt Jacob 		ntp = get_ntp_from_tagdata(isp, ccb->cna2.tag_id, ccb->cna2.seq_id, &tptr);
43612df76c16SMatt Jacob 		if (ntp == NULL) {
43622df76c16SMatt 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__,
43632df76c16SMatt Jacob 			     ccb->cna2.tag_id, ccb->cna2.seq_id);
43642df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
43652df76c16SMatt Jacob 			xpt_done(ccb);
4366d81ba9d5SMatt Jacob 			break;
4367d81ba9d5SMatt Jacob 		}
43682df76c16SMatt Jacob 		if (isp_handle_platform_target_notify_ack(isp, &ntp->rd.nt)) {
43692df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
43702df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
43712df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
43722df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
43732df76c16SMatt Jacob 			break;
43742df76c16SMatt Jacob 		}
43752df76c16SMatt Jacob 		isp_put_ntpd(isp, tptr, ntp);
43762df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
43772df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
43782df76c16SMatt 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);
43792df76c16SMatt Jacob 		xpt_done(ccb);
43802df76c16SMatt Jacob 		break;
43812df76c16SMatt Jacob 	}
43822df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
43832df76c16SMatt Jacob 		isp_target_start_ctio(isp, ccb);
43842df76c16SMatt Jacob 		break;
4385d81ba9d5SMatt Jacob #endif
4386478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
4387d81ba9d5SMatt Jacob 
4388d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
4389d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
4390d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
4391d81ba9d5SMatt Jacob 
43922df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt);
4393478f8a96SJustin T. Gibbs 		if (error) {
4394478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4395478f8a96SJustin T. Gibbs 		} else {
4396478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
4397478f8a96SJustin T. Gibbs 		}
4398478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4399478f8a96SJustin T. Gibbs 		break;
4400478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
4401d81ba9d5SMatt Jacob 	{
4402d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
4403d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
4404d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4405d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
44062df76c16SMatt Jacob 			isp_target_mark_aborted(isp, accb);
4407d81ba9d5SMatt Jacob 			break;
4408d81ba9d5SMatt Jacob #endif
4409d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
4410478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
4411478f8a96SJustin T. Gibbs 			if (error) {
4412d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
4413478f8a96SJustin T. Gibbs 			} else {
4414478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
4415478f8a96SJustin T. Gibbs 			}
4416d81ba9d5SMatt Jacob 			break;
4417d81ba9d5SMatt Jacob 		default:
4418d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
4419d81ba9d5SMatt Jacob 			break;
4420d81ba9d5SMatt Jacob 		}
44211c0a1eb2SMatt Jacob 		/*
44221c0a1eb2SMatt Jacob 		 * This is not a queued CCB, so the caller expects it to be
44231c0a1eb2SMatt Jacob 		 * complete when control is returned.
44241c0a1eb2SMatt Jacob 		 */
4425478f8a96SJustin T. Gibbs 		break;
4426d81ba9d5SMatt Jacob 	}
4427ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
4428478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
4429478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
44309ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
44319ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
44329ce9bdafSMatt Jacob 			xpt_done(ccb);
44339ce9bdafSMatt Jacob 			break;
44349ce9bdafSMatt Jacob 		}
4435478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
4436805e1f82SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
44372df76c16SMatt Jacob 		if (IS_SCSI(isp)) {
44382df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
44392df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
44402df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
44411dae40ebSMatt Jacob 			uint16_t *dptr;
4442ab163f5fSMatt Jacob 
4443b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
4444b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
4445b61386a4SMatt Jacob 				xpt_done(ccb);
4446b61386a4SMatt Jacob 				break;
4447b61386a4SMatt Jacob 			}
4448b61386a4SMatt Jacob 
4449ab163f5fSMatt Jacob 			/*
44509ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
4451ab163f5fSMatt Jacob 			 * so any request to change settings just gets
4452ab163f5fSMatt Jacob 			 * vectored to that location.
4453ab163f5fSMatt Jacob 			 */
44549ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
4455ab163f5fSMatt Jacob 
4456ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
4457ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
4458ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
4459ab163f5fSMatt Jacob 				else
4460ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
4461ab163f5fSMatt Jacob 			}
4462ab163f5fSMatt Jacob 
4463ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
4464ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
4465ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
4466ab163f5fSMatt Jacob 				else
4467ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
4468ab163f5fSMatt Jacob 			}
4469ab163f5fSMatt Jacob 
4470ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
4471ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
4472ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
4473ab163f5fSMatt Jacob 				else
4474ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
4475ab163f5fSMatt Jacob 			}
4476ab163f5fSMatt Jacob 
4477ab163f5fSMatt Jacob 			/*
4478ab163f5fSMatt Jacob 			 * XXX: FIX ME
4479ab163f5fSMatt Jacob 			 */
44802df76c16SMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && (spi->valid & CTS_SPI_VALID_SYNC_RATE) && (spi->sync_period && spi->sync_offset)) {
4481ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
44829ce9bdafSMatt Jacob 				/*
44839ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
44849ce9bdafSMatt Jacob 				 */
44852df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_period = spi->sync_period;
44862df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_offset = spi->sync_offset;
4487ab163f5fSMatt Jacob 			} else {
4488ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
4489ab163f5fSMatt Jacob 			}
44902df76c16SMatt 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,
44912df76c16SMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset, sdp->isp_devparam[tgt].goal_period);
4492478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
44932df76c16SMatt Jacob 			sdp->update = 1;
4494478f8a96SJustin T. Gibbs 		}
4495478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4496478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4497478f8a96SJustin T. Gibbs 		break;
4498478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
4499478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
4500478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
45012df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
4502ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
45032df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
45042df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
45052df76c16SMatt Jacob 			struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc;
450695f7dfb2SMatt Jacob 			unsigned int hdlidx;
4507478f8a96SJustin T. Gibbs 
4508ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4509ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4510ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
4511ab163f5fSMatt Jacob 			cts->transport_version = 0;
4512ab163f5fSMatt Jacob 
45139b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
45149b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
4515ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
4516ab163f5fSMatt Jacob 			fc->bitrate = 100000;
4517fada2376SJung-uk Kim 			fc->bitrate *= fcp->isp_gbspeed;
451895f7dfb2SMatt Jacob 			hdlidx = fcp->isp_dev_map[tgt] - 1;
451995f7dfb2SMatt Jacob 			if (hdlidx < MAX_FC_TARG) {
452095f7dfb2SMatt Jacob 				fcportdb_t *lp = &fcp->portdb[hdlidx];
4521ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
4522ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
4523ab163f5fSMatt Jacob 				fc->port = lp->portid;
45242df76c16SMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
4525ab163f5fSMatt Jacob 			}
4526ab163f5fSMatt Jacob 		} else {
45272df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
45282df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
45292df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
45301dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
4531ab163f5fSMatt Jacob 
4532ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
453383ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
45342df76c16SMatt Jacob 				sdp->update = 1;
45352df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
45369ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
45379ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
45389ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
45394394c92fSMatt Jacob 			} else {
45409ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
45419ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
45429ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
45434394c92fSMatt Jacob 			}
4544478f8a96SJustin T. Gibbs 
4545ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4546ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4547ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
4548ab163f5fSMatt Jacob 			cts->transport_version = 2;
4549ab163f5fSMatt Jacob 
4550b61386a4SMatt Jacob 			spi->valid = 0;
4551b61386a4SMatt Jacob 			scsi->valid = 0;
4552b61386a4SMatt Jacob 			spi->flags = 0;
4553b61386a4SMatt Jacob 			scsi->flags = 0;
4554ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
4555ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
4556ab163f5fSMatt Jacob 			}
45579ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
4558ab163f5fSMatt Jacob 				spi->sync_offset = oval;
4559ab163f5fSMatt Jacob 				spi->sync_period = pval;
4560b61386a4SMatt Jacob 			} else {
4561b61386a4SMatt Jacob 				spi->sync_offset = 0;
4562b61386a4SMatt Jacob 				spi->sync_period = 0;
4563b61386a4SMatt Jacob 			}
4564ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
4565ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
4566ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
4567ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
4568ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
4569ab163f5fSMatt Jacob 			} else {
4570ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
4571ab163f5fSMatt Jacob 			}
4572ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
4573ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
4574b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
4575b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
4576b61386a4SMatt Jacob 				}
4577ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
4578ab163f5fSMatt Jacob 			}
45792df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "GET %s (%d.%d.%d) to flags %x off %x per %x", IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
4580b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
4581478f8a96SJustin T. Gibbs 		}
4582478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4583478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4584478f8a96SJustin T. Gibbs 		break;
4585478f8a96SJustin T. Gibbs 
4586478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
45872df76c16SMatt Jacob 		cam_calc_geometry(&ccb->ccg, 1);
45882df76c16SMatt Jacob 		xpt_done(ccb);
45892df76c16SMatt Jacob 		break;
4590478f8a96SJustin T. Gibbs 
4591478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
4592ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
45932df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, bus);
45942df76c16SMatt Jacob 		if (error) {
4595478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
45962df76c16SMatt Jacob 			xpt_done(ccb);
45972df76c16SMatt Jacob 			break;
45982df76c16SMatt Jacob 		}
45990a70657fSMatt Jacob 		if (bootverbose) {
46002df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "reset bus on channel %d\n", bus);
46010a70657fSMatt Jacob 		}
46022df76c16SMatt Jacob 		if (IS_FC(isp)) {
46032df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, 0);
46042df76c16SMatt Jacob 		} else {
46052df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, 0);
46062df76c16SMatt Jacob 		}
4607478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4608478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4609478f8a96SJustin T. Gibbs 		break;
4610478f8a96SJustin T. Gibbs 
4611478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
4612478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4613478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4614478f8a96SJustin T. Gibbs 		break;
4615478f8a96SJustin T. Gibbs 
46162df76c16SMatt Jacob 	case XPT_SET_SIM_KNOB:		/* Set SIM knobs */
46172df76c16SMatt Jacob 	{
46182df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
46192df76c16SMatt Jacob 		fcparam *fcp;
46202df76c16SMatt Jacob 
46212df76c16SMatt Jacob 
46222df76c16SMatt Jacob 		if (!IS_FC(isp)) {
46232df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
46242df76c16SMatt Jacob 			xpt_done(ccb);
46252df76c16SMatt Jacob 			break;
46262df76c16SMatt Jacob 		}
46272df76c16SMatt Jacob 
46282df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
46292df76c16SMatt Jacob 		fcp = FCPARAM(isp, bus);
46302df76c16SMatt Jacob 
46312df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) {
46322df76c16SMatt Jacob 			fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn;
46332df76c16SMatt Jacob 			fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn;
46342df76c16SMatt Jacob isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn);
46352df76c16SMatt Jacob 		}
46362df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
46372df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) {
46382df76c16SMatt Jacob 			int rchange = 0;
46392df76c16SMatt Jacob 			int newrole = 0;
46402df76c16SMatt Jacob 
46412df76c16SMatt Jacob 			switch (kp->xport_specific.fc.role) {
46422df76c16SMatt Jacob 			case KNOB_ROLE_NONE:
46432df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_NONE) {
46442df76c16SMatt Jacob 					rchange = 1;
46452df76c16SMatt Jacob 					newrole = ISP_ROLE_NONE;
46462df76c16SMatt Jacob 				}
46472df76c16SMatt Jacob 				break;
46482df76c16SMatt Jacob 			case KNOB_ROLE_TARGET:
46492df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_TARGET) {
46502df76c16SMatt Jacob 					rchange = 1;
46512df76c16SMatt Jacob 					newrole = ISP_ROLE_TARGET;
46522df76c16SMatt Jacob 				}
46532df76c16SMatt Jacob 				break;
46542df76c16SMatt Jacob 			case KNOB_ROLE_INITIATOR:
46552df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_INITIATOR) {
46562df76c16SMatt Jacob 					rchange = 1;
46572df76c16SMatt Jacob 					newrole = ISP_ROLE_INITIATOR;
46582df76c16SMatt Jacob 				}
46592df76c16SMatt Jacob 				break;
46602df76c16SMatt Jacob 			case KNOB_ROLE_BOTH:
4661ae5db118SMatt Jacob #if 0
46622df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_BOTH) {
46632df76c16SMatt Jacob 					rchange = 1;
46642df76c16SMatt Jacob 					newrole = ISP_ROLE_BOTH;
46652df76c16SMatt Jacob 				}
4666ae5db118SMatt Jacob #else
4667ae5db118SMatt Jacob 				/*
4668ae5db118SMatt Jacob 				 * We don't really support dual role at present on FC cards.
4669ae5db118SMatt Jacob 				 *
4670ae5db118SMatt Jacob 				 * We should, but a bunch of things are currently broken,
4671ae5db118SMatt Jacob 				 * so don't allow it.
4672ae5db118SMatt Jacob 				 */
4673ae5db118SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "cannot support dual role at present");
4674ae5db118SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_INVALID;
4675ae5db118SMatt Jacob #endif
46762df76c16SMatt Jacob 				break;
46772df76c16SMatt Jacob 			}
46782df76c16SMatt Jacob 			if (rchange) {
46792df76c16SMatt Jacob 				if (isp_fc_change_role(isp, bus, newrole) != 0) {
46802df76c16SMatt Jacob 					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
46812df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
46822df76c16SMatt Jacob 				} else if (newrole == ISP_ROLE_TARGET || newrole == ISP_ROLE_BOTH) {
46832df76c16SMatt Jacob 					isp_enable_deferred_luns(isp, bus);
46842df76c16SMatt Jacob #endif
46852df76c16SMatt Jacob 				}
46862df76c16SMatt Jacob 			}
46872df76c16SMatt Jacob 		}
46882df76c16SMatt Jacob 		xpt_done(ccb);
46892df76c16SMatt Jacob 		break;
46902df76c16SMatt Jacob 	}
46912df76c16SMatt Jacob 	case XPT_GET_SIM_KNOB:		/* Set SIM knobs */
46922df76c16SMatt Jacob 	{
46932df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
46942df76c16SMatt Jacob 
46952df76c16SMatt Jacob 		if (IS_FC(isp)) {
46962df76c16SMatt Jacob 			fcparam *fcp;
46972df76c16SMatt Jacob 
46982df76c16SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
46992df76c16SMatt Jacob 			fcp = FCPARAM(isp, bus);
47002df76c16SMatt Jacob 
47012df76c16SMatt Jacob 			kp->xport_specific.fc.wwnn = fcp->isp_wwnn;
47022df76c16SMatt Jacob 			kp->xport_specific.fc.wwpn = fcp->isp_wwpn;
47032df76c16SMatt Jacob 			switch (fcp->role) {
47042df76c16SMatt Jacob 			case ISP_ROLE_NONE:
47052df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_NONE;
47062df76c16SMatt Jacob 				break;
47072df76c16SMatt Jacob 			case ISP_ROLE_TARGET:
47082df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_TARGET;
47092df76c16SMatt Jacob 				break;
47102df76c16SMatt Jacob 			case ISP_ROLE_INITIATOR:
47112df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_INITIATOR;
47122df76c16SMatt Jacob 				break;
47132df76c16SMatt Jacob 			case ISP_ROLE_BOTH:
47142df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_BOTH;
47152df76c16SMatt Jacob 				break;
47162df76c16SMatt Jacob 			}
47172df76c16SMatt Jacob 			kp->xport_specific.fc.valid = KNOB_VALID_ADDRESS | KNOB_VALID_ROLE;
47182df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_CMP;
47192df76c16SMatt Jacob 		} else {
47202df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
47212df76c16SMatt Jacob 		}
47222df76c16SMatt Jacob 		xpt_done(ccb);
47232df76c16SMatt Jacob 		break;
47242df76c16SMatt Jacob 	}
4725478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
4726478f8a96SJustin T. Gibbs 	{
4727478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
4728478f8a96SJustin T. Gibbs 
4729478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
4730d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4731a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
4732d81ba9d5SMatt Jacob #else
4733478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
4734d81ba9d5SMatt Jacob #endif
4735478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
47360470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
47370470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
47380470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
47392df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
47404394c92fSMatt Jacob 		if (IS_FC(isp)) {
47412df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
47422df76c16SMatt Jacob 
47434394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
47442df76c16SMatt Jacob 
47450470d791SMatt Jacob 			/*
47460470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
47470470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
47480470d791SMatt Jacob 			 */
47490470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
47500470d791SMatt Jacob 
47519deea857SKenneth D. Merry 			/*
47522df76c16SMatt Jacob 			 * Set base transfer capabilities for Fibre Channel, for this HBA.
47539deea857SKenneth D. Merry 			 */
47542df76c16SMatt Jacob 			if (IS_24XX(isp)) {
47552df76c16SMatt Jacob 				cpi->base_transfer_speed = 4000000;
47562df76c16SMatt Jacob 			} else if (IS_23XX(isp)) {
47572df76c16SMatt Jacob 				cpi->base_transfer_speed = 2000000;
47582df76c16SMatt Jacob 			} else {
47592df76c16SMatt Jacob 				cpi->base_transfer_speed = 1000000;
47602df76c16SMatt Jacob 			}
47610470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
4762ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
4763805e1f82SMatt Jacob 			cpi->transport_version = 0;
47642df76c16SMatt Jacob 			cpi->xport_specific.fc.wwnn = fcp->isp_wwnn;
47652df76c16SMatt Jacob 			cpi->xport_specific.fc.wwpn = fcp->isp_wwpn;
47662df76c16SMatt Jacob 			cpi->xport_specific.fc.port = fcp->isp_portid;
47672df76c16SMatt Jacob 			cpi->xport_specific.fc.bitrate = fcp->isp_gbspeed * 1000;
4768478f8a96SJustin T. Gibbs 		} else {
47692df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
47700470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
47714394c92fSMatt Jacob 			cpi->hba_misc = 0;
4772ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
47739deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
4774ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
4775805e1f82SMatt Jacob 			cpi->transport_version = 2;
4776478f8a96SJustin T. Gibbs 		}
4777ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
4778ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
4779478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
4780478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
4781478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
4782478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
4783478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
4784478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4785478f8a96SJustin T. Gibbs 		break;
4786478f8a96SJustin T. Gibbs 	}
4787478f8a96SJustin T. Gibbs 	default:
4788478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4789478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4790478f8a96SJustin T. Gibbs 		break;
4791478f8a96SJustin T. Gibbs 	}
4792478f8a96SJustin T. Gibbs }
4793d3a9eb2eSMatt Jacob 
4794d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
4795f7c631bcSMatt Jacob 
4796d3a9eb2eSMatt Jacob void
47972df76c16SMatt Jacob isp_done(XS_T *sccb)
4798d3a9eb2eSMatt Jacob {
47999cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
4800d3a9eb2eSMatt Jacob 
4801d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
4802d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
4803b85389e1SMatt Jacob 
48042df76c16SMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && (sccb->scsi_status != SCSI_STATUS_OK)) {
4805d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
48062df76c16SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
480792a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
480892a1e549SMatt Jacob 		} else {
4809d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
4810d3a9eb2eSMatt Jacob 		}
481192a1e549SMatt Jacob 	}
4812b85389e1SMatt Jacob 
48130470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
4814d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48152df76c16SMatt 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);
4816d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
4817d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
48180470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
4819d3a9eb2eSMatt Jacob 		}
4820d3a9eb2eSMatt Jacob 	}
4821b85389e1SMatt Jacob 
48222df76c16SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48232df76c16SMatt Jacob 		xpt_print(sccb->ccb_h.path, "cam completion status 0x%x\n", sccb->ccb_h.status);
4824d3a9eb2eSMatt Jacob 	}
4825b85389e1SMatt Jacob 
4826b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
48270ec60713SMarius Strobl 	callout_stop(&PISP_PCMD(sccb)->wdog);
4828b85389e1SMatt Jacob 	XS_CMD_S_CLEAR(sccb);
48290a70657fSMatt Jacob 	isp_free_pcmd(isp, (union ccb *) sccb);
4830d3a9eb2eSMatt Jacob 	xpt_done((union ccb *) sccb);
4831d3a9eb2eSMatt Jacob }
4832d3a9eb2eSMatt Jacob 
48332df76c16SMatt Jacob void
48342df76c16SMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
4835cbf57b47SMatt Jacob {
48362df76c16SMatt Jacob 	int bus;
48372df76c16SMatt Jacob 	static const char prom[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s WWPN 0x%08x%08x";
48382df76c16SMatt Jacob 	static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s tgt %u WWPN 0x%08x%08x";
4839f7c631bcSMatt Jacob 	char *msg = NULL;
484010365e5aSMatt Jacob 	target_id_t tgt;
484110365e5aSMatt Jacob 	fcportdb_t *lp;
4842a01f5aebSMatt Jacob 	struct isp_fc *fc;
484310365e5aSMatt Jacob 	struct cam_path *tmppath;
48442df76c16SMatt Jacob 	va_list ap;
484510365e5aSMatt Jacob 
4846cbf57b47SMatt Jacob 	switch (cmd) {
4847cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
48480470d791SMatt Jacob 	{
4849ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
4850ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
4851cbf57b47SMatt Jacob 		int flags, tgt;
48522df76c16SMatt Jacob 		sdparam *sdp;
4853ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
4854cbf57b47SMatt Jacob 
485529f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
4856ab163f5fSMatt Jacob 
48572df76c16SMatt Jacob 		va_start(ap, cmd);
48582df76c16SMatt Jacob 		bus = va_arg(ap, int);
48592df76c16SMatt Jacob 		tgt = va_arg(ap, int);
48602df76c16SMatt Jacob 		va_end(ap);
48612df76c16SMatt Jacob 		sdp = SDPARAM(isp, bus);
48622df76c16SMatt Jacob 
48632df76c16SMatt Jacob 		if (xpt_create_path(&tmppath, NULL, cam_sim_path(ISP_SPI_PC(isp, bus)->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
48642df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "isp_async cannot make temp path for %d.%d", tgt, bus);
4865cbf57b47SMatt Jacob 			break;
4866cbf57b47SMatt Jacob 		}
48679ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
4868ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
4869ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
4870ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
4871ab163f5fSMatt Jacob 
4872ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
4873ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
4874ab163f5fSMatt Jacob 
4875ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
4876ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
4877ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
4878ab163f5fSMatt Jacob 		}
4879ab163f5fSMatt Jacob 
4880cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
4881ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
4882ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
4883ab163f5fSMatt Jacob 		}
4884ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
4885ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
4886ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
4887ab163f5fSMatt Jacob 		} else {
4888ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
4889ab163f5fSMatt Jacob 		}
4890ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
4891ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
4892ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
48939ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
48949ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
4895ab163f5fSMatt Jacob 		}
48962df76c16SMatt 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);
4897ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
4898ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
4899cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
4900cbf57b47SMatt Jacob 		break;
49010470d791SMatt Jacob 	}
490257c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
49032df76c16SMatt Jacob 	{
49042df76c16SMatt Jacob 		va_start(ap, cmd);
49052df76c16SMatt Jacob 		bus = va_arg(ap, int);
49062df76c16SMatt Jacob 		va_end(ap);
49072df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", bus);
49082df76c16SMatt Jacob 		if (IS_FC(isp)) {
49092df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, NULL);
49102df76c16SMatt Jacob 		} else {
49112df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, NULL);
491257c801f5SMatt Jacob 		}
491357c801f5SMatt Jacob 		break;
49142df76c16SMatt Jacob 	}
49155d571944SMatt Jacob 	case ISPASYNC_LIP:
4916f7c631bcSMatt Jacob 		if (msg == NULL) {
4917f7c631bcSMatt Jacob 			msg = "LIP Received";
49185d571944SMatt Jacob 		}
4919f7c631bcSMatt Jacob 		/* FALLTHROUGH */
49205d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
4921f7c631bcSMatt Jacob 		if (msg == NULL) {
4922f7c631bcSMatt Jacob 			msg = "LOOP Reset";
49235d571944SMatt Jacob 		}
4924f7c631bcSMatt Jacob 		/* FALLTHROUGH */
492557c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
49262df76c16SMatt Jacob 	{
4927f7c631bcSMatt Jacob 		if (msg == NULL) {
4928f7c631bcSMatt Jacob 			msg = "LOOP Down";
492957c801f5SMatt Jacob 		}
49302df76c16SMatt Jacob 		va_start(ap, cmd);
49312df76c16SMatt Jacob 		bus = va_arg(ap, int);
49322df76c16SMatt Jacob 		va_end(ap);
49332df76c16SMatt Jacob 
4934a01f5aebSMatt Jacob 		FCPARAM(isp, bus)->link_active = 0;
49352df76c16SMatt Jacob 
49362df76c16SMatt Jacob 		fc = ISP_FC_PC(isp, bus);
4937a01f5aebSMatt Jacob 		if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
49382df76c16SMatt Jacob 			/*
49392df76c16SMatt Jacob 			 * We don't do any simq freezing if we are only in target mode
49402df76c16SMatt Jacob 			 */
49414ecb1d4aSMatt Jacob 			if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
49422df76c16SMatt Jacob 				if (fc->path) {
49432df76c16SMatt Jacob 					isp_freeze_loopdown(isp, bus, msg);
4944f7c631bcSMatt Jacob 				}
4945a01f5aebSMatt Jacob 				if (!callout_active(&fc->ldt)) {
49462df76c16SMatt Jacob 					callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
4947427fa8f9SMatt Jacob 					isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
4948f7c631bcSMatt Jacob 				}
49492df76c16SMatt Jacob 			}
4950a01f5aebSMatt Jacob 		}
49512df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
495257c801f5SMatt Jacob 		break;
49532df76c16SMatt Jacob 	}
495457c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
49552df76c16SMatt Jacob 		va_start(ap, cmd);
49562df76c16SMatt Jacob 		bus = va_arg(ap, int);
49572df76c16SMatt Jacob 		va_end(ap);
4958a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
49595d571944SMatt Jacob 		/*
49605d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
49615d571944SMatt Jacob 		 * actually do anything because we're waiting for a
49625d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
49635d571944SMatt Jacob 		 * thread to look at the state of the loop again.
49645d571944SMatt Jacob 		 */
49652df76c16SMatt Jacob 		FCPARAM(isp, bus)->link_active = 1;
4966a01f5aebSMatt Jacob 		fc->loop_dead = 0;
4967a01f5aebSMatt Jacob 		fc->loop_down_time = 0;
49682df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
496957c801f5SMatt Jacob 		break;
497010365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
49712df76c16SMatt Jacob 		va_start(ap, cmd);
49722df76c16SMatt Jacob 		bus = va_arg(ap, int);
49732df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
49742df76c16SMatt Jacob 		va_end(ap);
4975a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
4976f7c631bcSMatt Jacob 		lp->reserved = 0;
4977427fa8f9SMatt Jacob 		lp->gone_timer = 0;
49784ecb1d4aSMatt Jacob 		if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
49792df76c16SMatt Jacob 			int dbidx = lp - FCPARAM(isp, bus)->portdb;
4980f7c631bcSMatt Jacob 			int i;
498102ab3379SMatt Jacob 
4982f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
4983f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
4984f7c631bcSMatt Jacob 					continue;
4985f7c631bcSMatt Jacob 				}
49862df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->isp_dev_map[i] == 0) {
4987f7c631bcSMatt Jacob 					break;
4988f7c631bcSMatt Jacob 				}
4989f7c631bcSMatt Jacob 			}
4990f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
49912df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[i] = dbidx + 1;
49922df76c16SMatt Jacob 				lp->dev_map_idx = i + 1;
4993f7c631bcSMatt Jacob 			} else {
4994f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
49952df76c16SMatt Jacob 				isp_dump_portdb(isp, bus);
4996f7c631bcSMatt Jacob 			}
4997f7c631bcSMatt Jacob 		}
49982df76c16SMatt Jacob 		if (lp->dev_map_idx) {
49992df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
50002df76c16SMatt 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);
50012df76c16SMatt Jacob 			isp_make_here(isp, bus, tgt);
500210365e5aSMatt Jacob 		} else {
50032df76c16SMatt 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);
500410365e5aSMatt Jacob 		}
500510365e5aSMatt Jacob 		break;
500610365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
50072df76c16SMatt Jacob 		va_start(ap, cmd);
50082df76c16SMatt Jacob 		bus = va_arg(ap, int);
50092df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50102df76c16SMatt Jacob 		va_end(ap);
5011a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
50122df76c16SMatt Jacob 		lp->reserved = 0;
5013427fa8f9SMatt Jacob 		lp->gone_timer = 0;
5014f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
5015f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
50162df76c16SMatt Jacob 			if (lp->dev_map_idx) {
50172df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
50182df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[tgt] = 0;
50192df76c16SMatt Jacob 				lp->dev_map_idx = 0;
50202df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad");
50212df76c16SMatt Jacob 				isp_make_gone(isp, bus, tgt);
5022f7c631bcSMatt Jacob 			} else {
50232df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed and departed",
50242df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
5025f7c631bcSMatt Jacob 			}
5026f7c631bcSMatt Jacob 		} else {
5027f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
5028f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
50292df76c16SMatt Jacob 			if (lp->dev_map_idx) {
50302df76c16SMatt Jacob 				int t = lp->dev_map_idx - 1;
50312df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[t] = (lp - FCPARAM(isp, bus)->portdb) + 1;
50322df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
50332df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "changed at", tgt,
50342df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
503510365e5aSMatt Jacob 			} else {
50362df76c16SMatt 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);
503710365e5aSMatt Jacob 			}
5038f7c631bcSMatt Jacob 		}
503910365e5aSMatt Jacob 		break;
504010365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
50412df76c16SMatt Jacob 		va_start(ap, cmd);
50422df76c16SMatt Jacob 		bus = va_arg(ap, int);
50432df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50442df76c16SMatt Jacob 		va_end(ap);
50452df76c16SMatt Jacob 		if (lp->dev_map_idx) {
50462df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
50472df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "stayed at", tgt,
50482df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
504910365e5aSMatt Jacob 		} else {
50502df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "stayed",
50512df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
505210365e5aSMatt Jacob 		}
505310365e5aSMatt Jacob 		break;
505410365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
50552df76c16SMatt Jacob 		va_start(ap, cmd);
50562df76c16SMatt Jacob 		bus = va_arg(ap, int);
50572df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50582df76c16SMatt Jacob 		va_end(ap);
5059a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
5060f7c631bcSMatt Jacob 		/*
5061f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
5062f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
5063f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
5064f7c631bcSMatt Jacob 		 *
5065f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
5066f7c631bcSMatt Jacob 		 * announce that it's gone.
50674ecb1d4aSMatt Jacob 		 *
5068f7c631bcSMatt Jacob 		 */
50692df76c16SMatt Jacob 		if (lp->dev_map_idx && lp->reserved == 0) {
5070f7c631bcSMatt Jacob 			lp->reserved = 1;
5071f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
5072427fa8f9SMatt Jacob 			lp->gone_timer = ISP_FC_PC(isp, bus)->gone_device_time;
5073a01f5aebSMatt Jacob 			if (fc->ready && !callout_active(&fc->gdt)) {
5074a6119ff6SMatt 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);
5075a01f5aebSMatt Jacob 				callout_reset(&fc->gdt, hz, isp_gdt, fc);
5076f7c631bcSMatt Jacob 			}
50772df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
50782df76c16SMatt 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);
5079f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
50802df76c16SMatt 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);
50814b9d588eSMatt Jacob 		}
508210365e5aSMatt Jacob 		break;
508310365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
508410365e5aSMatt Jacob 	{
508510365e5aSMatt Jacob 		char *msg;
50862df76c16SMatt Jacob 		int evt, nphdl, nlstate, reason;
50872df76c16SMatt Jacob 
50882df76c16SMatt Jacob 		va_start(ap, cmd);
50892df76c16SMatt Jacob 		bus = va_arg(ap, int);
50902df76c16SMatt Jacob 		evt = va_arg(ap, int);
50912df76c16SMatt Jacob 		if (IS_24XX(isp) && evt == ISPASYNC_CHANGE_PDB) {
50922df76c16SMatt Jacob 			nphdl = va_arg(ap, int);
50932df76c16SMatt Jacob 			nlstate = va_arg(ap, int);
50942df76c16SMatt Jacob 			reason = va_arg(ap, int);
509510365e5aSMatt Jacob 		} else {
50962df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
50972df76c16SMatt Jacob 			nlstate = reason = 0;
509810365e5aSMatt Jacob 		}
50992df76c16SMatt Jacob 		va_end(ap);
5100a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
51012df76c16SMatt Jacob 
51022df76c16SMatt Jacob 		if (evt == ISPASYNC_CHANGE_PDB) {
51032df76c16SMatt Jacob 			msg = "Chan %d Port Database Changed";
51042df76c16SMatt Jacob 		} else if (evt == ISPASYNC_CHANGE_SNS) {
51052df76c16SMatt Jacob 			msg = "Chan %d Name Server Database Changed";
51062df76c16SMatt Jacob 		} else {
51072df76c16SMatt Jacob 			msg = "Chan %d Other Change Notify";
51082df76c16SMatt Jacob 		}
51092df76c16SMatt Jacob 
5110f7c631bcSMatt Jacob 		/*
5111f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
5112f7c631bcSMatt Jacob 		 */
5113a01f5aebSMatt Jacob 		if (fc->ready && callout_active(&fc->ldt)) {
51142df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
5115a01f5aebSMatt Jacob 			callout_stop(&fc->ldt);
5116f7c631bcSMatt Jacob 		}
51172df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg, bus);
51184ecb1d4aSMatt Jacob 		if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
51192df76c16SMatt Jacob 			isp_freeze_loopdown(isp, bus, msg);
51202df76c16SMatt Jacob 		}
5121a01f5aebSMatt Jacob 		wakeup(fc);
512257c801f5SMatt Jacob 		break;
512302ab3379SMatt Jacob 	}
5124d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
5125e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
5126d81ba9d5SMatt Jacob 	{
51272df76c16SMatt Jacob 		isp_notify_t *notify;
51282df76c16SMatt Jacob 		va_start(ap, cmd);
51292df76c16SMatt Jacob 		notify = va_arg(ap, isp_notify_t *);
51302df76c16SMatt Jacob 		va_end(ap);
51312df76c16SMatt Jacob 		switch (notify->nt_ncode) {
51322df76c16SMatt Jacob 		case NT_ABORT_TASK:
51332df76c16SMatt Jacob 		case NT_ABORT_TASK_SET:
51342df76c16SMatt Jacob 		case NT_CLEAR_ACA:
51352df76c16SMatt Jacob 		case NT_CLEAR_TASK_SET:
51362df76c16SMatt Jacob 		case NT_LUN_RESET:
51372df76c16SMatt Jacob 		case NT_TARGET_RESET:
51382df76c16SMatt Jacob 			/*
51392df76c16SMatt Jacob 			 * These are task management functions.
51402df76c16SMatt Jacob 			 */
51412df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, notify);
51422df76c16SMatt Jacob 			break;
51432df76c16SMatt Jacob 		case NT_BUS_RESET:
51442df76c16SMatt Jacob 		case NT_LIP_RESET:
51452df76c16SMatt Jacob 		case NT_LINK_UP:
51462df76c16SMatt Jacob 		case NT_LINK_DOWN:
51472df76c16SMatt Jacob 			/*
51482df76c16SMatt Jacob 			 * No action need be taken here.
51492df76c16SMatt Jacob 			 */
51502df76c16SMatt Jacob 			break;
51512df76c16SMatt Jacob 		case NT_HBA_RESET:
51522df76c16SMatt Jacob 			isp_del_all_wwn_entries(isp, ISP_NOCHAN);
51532df76c16SMatt Jacob 			break;
51542df76c16SMatt Jacob 		case NT_LOGOUT:
51552df76c16SMatt Jacob 			/*
51562df76c16SMatt Jacob 			 * This is device arrival/departure notification
51572df76c16SMatt Jacob 			 */
51582df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
51592df76c16SMatt Jacob 			break;
51602df76c16SMatt Jacob 		case NT_ARRIVED:
51612df76c16SMatt Jacob 		{
51622df76c16SMatt Jacob 			struct ac_contract ac;
51632df76c16SMatt Jacob 			struct ac_device_changed *fc;
51642df76c16SMatt Jacob 
51652df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
51662df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
51672df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
51682df76c16SMatt Jacob 			fc->port = notify->nt_sid;
51692df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
51702df76c16SMatt Jacob 			fc->arrived = 1;
51712df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
51722df76c16SMatt Jacob 			break;
51732df76c16SMatt Jacob 		}
51742df76c16SMatt Jacob 		case NT_DEPARTED:
51752df76c16SMatt Jacob 		{
51762df76c16SMatt Jacob 			struct ac_contract ac;
51772df76c16SMatt Jacob 			struct ac_device_changed *fc;
51782df76c16SMatt Jacob 
51792df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
51802df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
51812df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
51822df76c16SMatt Jacob 			fc->port = notify->nt_sid;
51832df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
51842df76c16SMatt Jacob 			fc->arrived = 0;
51852df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
51862df76c16SMatt Jacob 			break;
51872df76c16SMatt Jacob 		}
51882df76c16SMatt Jacob 		default:
51892df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode);
51902df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
51912df76c16SMatt Jacob 			break;
51922df76c16SMatt Jacob 		}
5193d81ba9d5SMatt Jacob 		break;
5194d81ba9d5SMatt Jacob 	}
5195d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
51962df76c16SMatt Jacob 	{
51972df76c16SMatt Jacob 		isphdr_t *hp;
51982df76c16SMatt Jacob 
51992df76c16SMatt Jacob 		va_start(ap, cmd);
52002df76c16SMatt Jacob 		hp = va_arg(ap, isphdr_t *);
52012df76c16SMatt Jacob 		va_end(ap);
52022df76c16SMatt Jacob 		switch (hp->rqs_entry_type) {
5203cbf57b47SMatt Jacob 		default:
52042df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: unhandled target action 0x%x", __func__, hp->rqs_entry_type);
5205d81ba9d5SMatt Jacob 			break;
5206570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
5207570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
52082df76c16SMatt Jacob 				isp_handle_platform_notify_scsi(isp, (in_entry_t *) hp);
52092df76c16SMatt Jacob 			} else if (IS_24XX(isp)) {
52102df76c16SMatt Jacob 				isp_handle_platform_notify_24xx(isp, (in_fcentry_24xx_t *) hp);
5211570c7a3fSMatt Jacob 			} else {
52122df76c16SMatt Jacob 				isp_handle_platform_notify_fc(isp, (in_fcentry_t *) hp);
5213570c7a3fSMatt Jacob 			}
5214570c7a3fSMatt Jacob 			break;
5215d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
52162df76c16SMatt Jacob 			if (IS_24XX(isp)) {
52172df76c16SMatt Jacob 				isp_handle_platform_atio7(isp, (at7_entry_t *) hp);
52182df76c16SMatt Jacob 			} else {
52192df76c16SMatt Jacob 				isp_handle_platform_atio(isp, (at_entry_t *) hp);
52202df76c16SMatt Jacob 			}
5221d81ba9d5SMatt Jacob 			break;
5222d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
52232df76c16SMatt Jacob 			isp_handle_platform_atio2(isp, (at2_entry_t *) hp);
5224d81ba9d5SMatt Jacob 			break;
52252df76c16SMatt Jacob 		case RQSTYPE_CTIO7:
5226d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
5227d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
5228d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
52292df76c16SMatt Jacob 			isp_handle_platform_ctio(isp, hp);
5230d81ba9d5SMatt Jacob 			break;
52312df76c16SMatt Jacob 		case RQSTYPE_ABTS_RCVD:
52322df76c16SMatt Jacob 		{
52332df76c16SMatt Jacob 			abts_t *abts = (abts_t *)hp;
52342df76c16SMatt Jacob 			isp_notify_t notify, *nt = &notify;
52352df76c16SMatt Jacob 			tstate_t *tptr;
52362df76c16SMatt Jacob 			fcportdb_t *lp;
52372df76c16SMatt Jacob 			uint16_t chan;
52382df76c16SMatt Jacob 			uint32_t sid, did;
52392df76c16SMatt Jacob 
52402df76c16SMatt Jacob 			did = (abts->abts_did_hi << 16) | abts->abts_did_lo;
52412df76c16SMatt Jacob 			sid = (abts->abts_sid_hi << 16) | abts->abts_sid_lo;
52422df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
52432df76c16SMatt Jacob 
52442df76c16SMatt Jacob 			nt->nt_hba = isp;
52452df76c16SMatt Jacob 			nt->nt_did = did;
52462df76c16SMatt Jacob 			nt->nt_nphdl = abts->abts_nphdl;
52472df76c16SMatt Jacob 			nt->nt_sid = sid;
52482df76c16SMatt Jacob 			isp_find_chan_by_did(isp, did, &chan);
52492df76c16SMatt Jacob 			if (chan == ISP_NOCHAN) {
52502df76c16SMatt Jacob 				nt->nt_tgt = TGT_ANY;
52512df76c16SMatt Jacob 			} else {
52522df76c16SMatt Jacob 				nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
52532df76c16SMatt Jacob 				if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) {
52542df76c16SMatt Jacob 					nt->nt_wwn = lp->port_wwn;
52552df76c16SMatt Jacob 				} else {
52562df76c16SMatt Jacob 					nt->nt_wwn = INI_ANY;
52572df76c16SMatt Jacob 				}
52582df76c16SMatt Jacob 			}
52592df76c16SMatt Jacob 			/*
52602df76c16SMatt Jacob 			 * Try hard to find the lun for this command.
52612df76c16SMatt Jacob 			 */
52622df76c16SMatt Jacob 			tptr = get_lun_statep_from_tag(isp, chan, abts->abts_rxid_task);
52632df76c16SMatt Jacob 			if (tptr) {
52642df76c16SMatt Jacob 				nt->nt_lun = xpt_path_lun_id(tptr->owner);
52652df76c16SMatt Jacob 				rls_lun_statep(isp, tptr);
52662df76c16SMatt Jacob 			} else {
52672df76c16SMatt Jacob 				nt->nt_lun = LUN_ANY;
52682df76c16SMatt Jacob 			}
52692df76c16SMatt Jacob 			nt->nt_need_ack = 1;
52702df76c16SMatt Jacob 			nt->nt_tagval = abts->abts_rxid_task;
52712df76c16SMatt Jacob 			nt->nt_tagval |= (((uint64_t) abts->abts_rxid_abts) << 32);
52722df76c16SMatt Jacob 			if (abts->abts_rxid_task == ISP24XX_NO_TASK) {
52732df76c16SMatt 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)",
52742df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rx_id, abts->abts_ox_id);
52752df76c16SMatt Jacob 			} else {
52762df76c16SMatt 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)",
52772df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rxid_task, abts->abts_rx_id, abts->abts_ox_id);
52782df76c16SMatt Jacob 			}
52792df76c16SMatt Jacob 			nt->nt_channel = chan;
52802df76c16SMatt Jacob 			nt->nt_ncode = NT_ABORT_TASK;
52812df76c16SMatt Jacob 			nt->nt_lreserved = hp;
52822df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
52832df76c16SMatt Jacob 			break;
52842df76c16SMatt Jacob 		}
5285d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
5286d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
52872df76c16SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) hp);
5288d81ba9d5SMatt Jacob 			break;
5289d81ba9d5SMatt Jacob 		}
5290d81ba9d5SMatt Jacob 		break;
52912df76c16SMatt Jacob 	}
5292d81ba9d5SMatt Jacob #endif
5293ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
5294ab163f5fSMatt Jacob 	{
52951dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
5296ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
5297ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
5298ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
5299ab163f5fSMatt Jacob 		} else {
5300ab163f5fSMatt Jacob 			mbox6 = 0;
5301ab163f5fSMatt Jacob 		}
53022df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "Internal Firmware Error on bus %d @ RISC Address 0x%x", mbox6, mbox1);
53030a70657fSMatt Jacob 		mbox1 = isp->isp_osinfo.mbox_sleep_ok;
53040a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
53052df76c16SMatt Jacob 		isp_reinit(isp, 1);
53060a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = mbox1;
53070a70657fSMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
5308ab163f5fSMatt Jacob 		break;
5309ab163f5fSMatt Jacob 	}
5310d81ba9d5SMatt Jacob 	default:
5311b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
5312cbf57b47SMatt Jacob 		break;
5313cbf57b47SMatt Jacob 	}
5314cbf57b47SMatt Jacob }
5315cbf57b47SMatt Jacob 
531692718a7fSMatt Jacob 
531792718a7fSMatt Jacob /*
531892718a7fSMatt Jacob  * Locks are held before coming here.
531992718a7fSMatt Jacob  */
532092718a7fSMatt Jacob void
53219cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
532292718a7fSMatt Jacob {
532310365e5aSMatt Jacob 	if (IS_24XX(isp)) {
532410365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
532510365e5aSMatt Jacob 	} else {
5326ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
532710365e5aSMatt Jacob 	}
532810365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
532992718a7fSMatt Jacob }
5330b09b0095SMatt Jacob 
53312df76c16SMatt Jacob /*
53322df76c16SMatt Jacob  * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them
53332df76c16SMatt Jacob  * up from our platform default (defww{p|n}n) and morph them based upon
53342df76c16SMatt Jacob  * channel.
53352df76c16SMatt Jacob  *
53362df76c16SMatt Jacob  * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them
53372df76c16SMatt Jacob  * based upon channel.
53382df76c16SMatt Jacob  */
53392df76c16SMatt Jacob 
53402df76c16SMatt Jacob uint64_t
53412df76c16SMatt Jacob isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn)
53422df76c16SMatt Jacob {
53432df76c16SMatt Jacob 	uint64_t seed;
53442df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
53452df76c16SMatt Jacob 
53462df76c16SMatt Jacob 	/*
53472df76c16SMatt Jacob 	 * If we're asking for a active WWN, the default overrides get
53482df76c16SMatt Jacob 	 * returned, otherwise the NVRAM value is picked.
53492df76c16SMatt Jacob 	 *
53502df76c16SMatt Jacob 	 * If we're asking for a default WWN, we just pick the default override.
53512df76c16SMatt Jacob 	 */
53522df76c16SMatt Jacob 	if (isactive) {
53532df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
53542df76c16SMatt Jacob 		if (seed) {
53552df76c16SMatt Jacob 			return (seed);
53562df76c16SMatt Jacob 		}
53572df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram;
53585cc3786cSMatt Jacob 		if (seed) {
53595cc3786cSMatt Jacob 			return (seed);
53605cc3786cSMatt Jacob 		}
53615cc3786cSMatt Jacob 		return (0x400000007F000009ull);
53622df76c16SMatt Jacob 	} else {
53632df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
53642df76c16SMatt Jacob 	}
53652df76c16SMatt Jacob 
53662df76c16SMatt Jacob 
53672df76c16SMatt Jacob 	/*
5368b1ce21c6SRebecca Cran 	 * For channel zero just return what we have. For either ACTIVE or
53692df76c16SMatt Jacob 	 * DEFAULT cases, we depend on default override of NVRAM values for
53702df76c16SMatt Jacob 	 * channel zero.
53712df76c16SMatt Jacob 	 */
53722df76c16SMatt Jacob 	if (chan == 0) {
53732df76c16SMatt Jacob 		return (seed);
53742df76c16SMatt Jacob 	}
53752df76c16SMatt Jacob 
53762df76c16SMatt Jacob 	/*
53772df76c16SMatt Jacob 	 * For other channels, we are doing one of three things:
53782df76c16SMatt Jacob 	 *
53792df76c16SMatt Jacob 	 * 1. If what we have now is non-zero, return it. Otherwise we morph
53802df76c16SMatt Jacob 	 * values from channel 0. 2. If we're here for a WWPN we synthesize
53812df76c16SMatt Jacob 	 * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a
53822df76c16SMatt Jacob 	 * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA.
53832df76c16SMatt Jacob 	 */
53842df76c16SMatt Jacob 
53852df76c16SMatt Jacob 	if (seed) {
53862df76c16SMatt Jacob 		return (seed);
53872df76c16SMatt Jacob 	}
53882df76c16SMatt Jacob 	if (isactive) {
53892df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram;
53902df76c16SMatt Jacob 	} else {
53912df76c16SMatt Jacob 		seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn;
53922df76c16SMatt Jacob 	}
53932df76c16SMatt Jacob 
53942df76c16SMatt Jacob 	if (((seed >> 60) & 0xf) == 2) {
53952df76c16SMatt Jacob 		/*
53962df76c16SMatt Jacob 		 * The type 2 NAA fields for QLogic cards appear be laid out
53972df76c16SMatt Jacob 		 * thusly:
53982df76c16SMatt Jacob 		 *
53992df76c16SMatt Jacob 		 * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56
54002df76c16SMatt Jacob 		 * port (1) or node (0) WWN distinguishor bit 48
54012df76c16SMatt Jacob 		 * physical port on dual-port chips (23XX/24XX)
54022df76c16SMatt Jacob 		 *
54032df76c16SMatt Jacob 		 * This is somewhat nutty, particularly since bit 48 is
5404b1ce21c6SRebecca Cran 		 * irrelevant as they assign separate serial numbers to
54052df76c16SMatt Jacob 		 * different physical ports anyway.
54062df76c16SMatt Jacob 		 *
54072df76c16SMatt Jacob 		 * We'll stick our channel number plus one first into bits
54082df76c16SMatt Jacob 		 * 57..59 and thence into bits 52..55 which allows for 8 bits
54092df76c16SMatt Jacob 		 * of channel which is comfortably more than our maximum
54102df76c16SMatt Jacob 		 * (126) now.
54112df76c16SMatt Jacob 		 */
54122df76c16SMatt Jacob 		seed &= ~0x0FF0000000000000ULL;
54132df76c16SMatt Jacob 		if (iswwnn == 0) {
54142df76c16SMatt Jacob 			seed |= ((uint64_t) (chan + 1) & 0xf) << 56;
54152df76c16SMatt Jacob 			seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52;
54162df76c16SMatt Jacob 		}
54172df76c16SMatt Jacob 	} else {
54182df76c16SMatt Jacob 		seed = 0;
54192df76c16SMatt Jacob 	}
54202df76c16SMatt Jacob 	return (seed);
54212df76c16SMatt Jacob }
54222df76c16SMatt Jacob 
5423b09b0095SMatt Jacob void
54249cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
5425b09b0095SMatt Jacob {
5426b09b0095SMatt Jacob 	va_list ap;
5427b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
5428b09b0095SMatt Jacob 		return;
5429b09b0095SMatt Jacob 	}
54303c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
5431b09b0095SMatt Jacob 	va_start(ap, fmt);
5432b09b0095SMatt Jacob 	vprintf(fmt, ap);
5433b09b0095SMatt Jacob 	va_end(ap);
5434b09b0095SMatt Jacob 	printf("\n");
5435b09b0095SMatt Jacob }
5436f7c631bcSMatt Jacob 
5437670508b1SMatt Jacob void
5438670508b1SMatt Jacob isp_xs_prt(ispsoftc_t *isp, XS_T *xs, int level, const char *fmt, ...)
5439670508b1SMatt Jacob {
5440670508b1SMatt Jacob 	va_list ap;
5441670508b1SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
5442670508b1SMatt Jacob 		return;
5443670508b1SMatt Jacob 	}
5444670508b1SMatt Jacob 	xpt_print_path(xs->ccb_h.path);
5445670508b1SMatt Jacob 	va_start(ap, fmt);
5446670508b1SMatt Jacob 	vprintf(fmt, ap);
5447670508b1SMatt Jacob 	va_end(ap);
5448670508b1SMatt Jacob 	printf("\n");
5449670508b1SMatt Jacob }
5450670508b1SMatt Jacob 
5451f7c631bcSMatt Jacob uint64_t
5452f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
5453f7c631bcSMatt Jacob {
5454f7c631bcSMatt Jacob 	uint64_t elapsed;
5455f7c631bcSMatt Jacob 	struct timespec x = *b;
5456f7c631bcSMatt Jacob 	timespecsub(&x, a);
5457f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
5458f7c631bcSMatt Jacob 	if (elapsed == 0)
5459f7c631bcSMatt Jacob 		elapsed++;
5460f7c631bcSMatt Jacob 	return (elapsed);
5461f7c631bcSMatt Jacob }
5462f7c631bcSMatt Jacob 
5463f7c631bcSMatt Jacob int
5464f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
5465f7c631bcSMatt Jacob {
5466f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
5467f7c631bcSMatt Jacob 		return (1);
5468f7c631bcSMatt Jacob 	} else {
5469f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
5470f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
5471f7c631bcSMatt Jacob 		return (0);
5472f7c631bcSMatt Jacob 	}
5473f7c631bcSMatt Jacob }
5474f7c631bcSMatt Jacob 
5475f7c631bcSMatt Jacob void
5476f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
5477f7c631bcSMatt Jacob {
5478a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
5479a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
5480f7c631bcSMatt Jacob 
5481f7c631bcSMatt Jacob 	if (usecs == 0) {
5482f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
5483f7c631bcSMatt Jacob 	}
5484a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
5485a4f3a2beSMatt Jacob 
5486f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
5487a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
5488a4f3a2beSMatt Jacob 
5489f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
5490f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
5491a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
54922df76c16SMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, PRIBIO, "ispmbx_sleep", isp_mstohz(ms));
5493a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5494a4f3a2beSMatt Jacob 				break;
5495a4f3a2beSMatt Jacob 			}
5496a4f3a2beSMatt Jacob 		}
5497f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
5498f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
5499f7c631bcSMatt Jacob 	} else {
5500a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
5501a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
5502f7c631bcSMatt Jacob 				uint32_t isr;
5503f7c631bcSMatt Jacob 				uint16_t sema, mbox;
5504f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
5505f7c631bcSMatt Jacob 					break;
5506f7c631bcSMatt Jacob 				}
5507f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
5508f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
5509f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
5510f7c631bcSMatt Jacob 						break;
5511f7c631bcSMatt Jacob 					}
5512f7c631bcSMatt Jacob 				}
55132df76c16SMatt Jacob 				ISP_DELAY(100);
5514f7c631bcSMatt Jacob 			}
5515a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5516a4f3a2beSMatt Jacob 				break;
5517a4f3a2beSMatt Jacob 			}
5518a4f3a2beSMatt Jacob 		}
5519f7c631bcSMatt Jacob 	}
5520f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
55212df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s Mailbox Command (0x%x) Timeout (%uus) (started @ %s:%d)",
55222df76c16SMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", isp->isp_lastmbxcmd, usecs, mbp->func, mbp->lineno);
5523f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
5524f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
5525f7c631bcSMatt Jacob 	}
5526f7c631bcSMatt Jacob }
5527f7c631bcSMatt Jacob 
5528f7c631bcSMatt Jacob void
5529f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
5530f7c631bcSMatt Jacob {
5531f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
5532f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
5533f7c631bcSMatt Jacob 	}
5534f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
5535f7c631bcSMatt Jacob }
5536f7c631bcSMatt Jacob 
5537f7c631bcSMatt Jacob void
5538f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
5539f7c631bcSMatt Jacob {
5540f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
5541f7c631bcSMatt Jacob }
5542f7c631bcSMatt Jacob 
5543f7c631bcSMatt Jacob int
55442df76c16SMatt Jacob isp_fc_scratch_acquire(ispsoftc_t *isp, int chan)
55452df76c16SMatt Jacob {
55462df76c16SMatt Jacob 	int ret = 0;
55472df76c16SMatt Jacob 	if (isp->isp_osinfo.pc.fc[chan].fcbsy) {
55482df76c16SMatt Jacob 		ret = -1;
55492df76c16SMatt Jacob 	} else {
55502df76c16SMatt Jacob 		isp->isp_osinfo.pc.fc[chan].fcbsy = 1;
55512df76c16SMatt Jacob 	}
55522df76c16SMatt Jacob 	return (ret);
55532df76c16SMatt Jacob }
55542df76c16SMatt Jacob 
55552df76c16SMatt Jacob int
5556f7c631bcSMatt Jacob isp_mstohz(int ms)
5557f7c631bcSMatt Jacob {
5558a4f3a2beSMatt Jacob 	int hz;
5559f7c631bcSMatt Jacob 	struct timeval t;
5560f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
5561f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
5562a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
5563a4f3a2beSMatt Jacob 	if (hz < 0) {
5564a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
5565f7c631bcSMatt Jacob 	}
5566a4f3a2beSMatt Jacob 	if (hz == 0) {
5567a4f3a2beSMatt Jacob 		hz = 1;
5568a4f3a2beSMatt Jacob 	}
5569a4f3a2beSMatt Jacob 	return (hz);
5570f7c631bcSMatt Jacob }
55710a70657fSMatt Jacob 
55720a70657fSMatt Jacob void
55730a70657fSMatt Jacob isp_platform_intr(void *arg)
55740a70657fSMatt Jacob {
55750a70657fSMatt Jacob 	ispsoftc_t *isp = arg;
55760a70657fSMatt Jacob 	uint32_t isr;
55770a70657fSMatt Jacob 	uint16_t sema, mbox;
55780a70657fSMatt Jacob 
55790a70657fSMatt Jacob 	ISP_LOCK(isp);
55800a70657fSMatt Jacob 	isp->isp_intcnt++;
55810a70657fSMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
55820a70657fSMatt Jacob 		isp->isp_intbogus++;
55830a70657fSMatt Jacob 	} else {
55840a70657fSMatt Jacob 		isp_intr(isp, isr, sema, mbox);
55850a70657fSMatt Jacob 	}
55860a70657fSMatt Jacob 	ISP_UNLOCK(isp);
55870a70657fSMatt Jacob }
55880a70657fSMatt Jacob 
55890a70657fSMatt Jacob void
55900a70657fSMatt Jacob isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl)
55910a70657fSMatt Jacob {
55920a70657fSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
55932df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD);
55940a70657fSMatt Jacob 	} else {
55952df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE);
55960a70657fSMatt Jacob 	}
55970a70657fSMatt Jacob 	bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
55980a70657fSMatt Jacob }
55992df76c16SMatt Jacob 
56002df76c16SMatt Jacob void
56012df76c16SMatt Jacob isp_timer(void *arg)
56022df76c16SMatt Jacob {
56032df76c16SMatt Jacob 	ispsoftc_t *isp = arg;
56042df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
56052df76c16SMatt Jacob 	isp_tmcmd_restart(isp);
56062df76c16SMatt Jacob #endif
56072df76c16SMatt Jacob 	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
56082df76c16SMatt Jacob }
5609