xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 443e752d97bd51b3e124436734ffba7be0eb0682)
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;
522df76c16SMatt Jacob int isp_fabric_hysteresis = 3;
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 
1452df76c16SMatt Jacob 		callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
1462df76c16SMatt Jacob 		callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
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 	}
2842df76c16SMatt 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);
6072df76c16SMatt Jacob 			MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN);
6082df76c16SMatt Jacob 			sp = (isp24xx_statusreq_t *) local;
6092df76c16SMatt Jacob 			sp->req_completion_status = 1;
6102df76c16SMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6112df76c16SMatt Jacob 			MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN);
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 	 *
1790d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware 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;
19102df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
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 	 *
1917d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware 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 	if (atp) {
20642df76c16SMatt Jacob 		isp_put_atpd(isp, tptr, atp);
20652df76c16SMatt Jacob 	}
20662df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
20672df76c16SMatt Jacob 	if (ntp == NULL) {
20682df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
20692df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, 0, SCSI_STATUS_BUSY, 0);
20702df76c16SMatt Jacob 		return;
20712df76c16SMatt Jacob 	}
20722df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
20732df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
20742df76c16SMatt Jacob 	tptr->restart_queue = ntp;
20752df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
2076d81ba9d5SMatt Jacob }
2077d81ba9d5SMatt Jacob 
20782df76c16SMatt Jacob static void
20792df76c16SMatt Jacob isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep)
20802df76c16SMatt Jacob {
20812df76c16SMatt Jacob 	int cdbxlen;
20822df76c16SMatt Jacob 	uint16_t lun, chan, nphdl = NIL_HANDLE;
20832df76c16SMatt Jacob 	uint32_t did, sid;
20842df76c16SMatt Jacob 	uint64_t wwn = INI_NONE;
20852df76c16SMatt Jacob 	fcportdb_t *lp;
20862df76c16SMatt Jacob 	tstate_t *tptr;
20872df76c16SMatt Jacob 	struct ccb_accept_tio *atiop;
20882df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
20892df76c16SMatt Jacob 	inot_private_data_t *ntp;
20902df76c16SMatt Jacob 
20912df76c16SMatt Jacob 	did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2];
20922df76c16SMatt Jacob 	sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
20932df76c16SMatt Jacob 	lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | aep->at_cmnd.fcp_cmnd_lun[1];
20942df76c16SMatt Jacob 
20952df76c16SMatt Jacob 	/*
20962df76c16SMatt Jacob 	 * Find the N-port handle, and Virtual Port Index for this command.
20972df76c16SMatt Jacob 	 *
20982df76c16SMatt Jacob 	 * If we can't, we're somewhat in trouble because we can't actually respond w/o that information.
20992df76c16SMatt Jacob 	 * We also, as a matter of course, need to know the WWN of the initiator too.
21002df76c16SMatt Jacob 	 */
21012df76c16SMatt Jacob 	if (ISP_CAP_MULTI_ID(isp)) {
21022df76c16SMatt Jacob 		/*
21032df76c16SMatt Jacob 		 * Find the right channel based upon D_ID
21042df76c16SMatt Jacob 		 */
21052df76c16SMatt Jacob 		isp_find_chan_by_did(isp, did, &chan);
21062df76c16SMatt Jacob 
21072df76c16SMatt Jacob 		if (chan == ISP_NOCHAN) {
21082df76c16SMatt Jacob 			NANOTIME_T now;
21092df76c16SMatt Jacob 
21102df76c16SMatt Jacob 			/*
21112df76c16SMatt Jacob 			 * If we don't recognizer our own D_DID, terminate the exchange, unless we're within 2 seconds of startup
21122df76c16SMatt Jacob 			 * It's a bit tricky here as we need to stash this command *somewhere*.
21132df76c16SMatt Jacob 			 */
21142df76c16SMatt Jacob 			GET_NANOTIME(&now);
21152df76c16SMatt Jacob 			if (NANOTIME_SUB(&isp->isp_init_time, &now) > 2000000000ULL) {
21162df76c16SMatt 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);
21172df76c16SMatt Jacob 				isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
21182df76c16SMatt Jacob 				return;
21192df76c16SMatt Jacob 			}
21202df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, 0);
21212df76c16SMatt Jacob 			if (tptr == NULL) {
21222df76c16SMatt Jacob 				tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
21232df76c16SMatt Jacob 				if (tptr == NULL) {
21242df76c16SMatt 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);
21252df76c16SMatt Jacob 					isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0);
21262df76c16SMatt Jacob 					return;
21272df76c16SMatt Jacob 				}
21282df76c16SMatt Jacob 			}
21292df76c16SMatt 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);
21302df76c16SMatt Jacob 			goto noresrc;
21312df76c16SMatt Jacob 		}
21322df76c16SMatt 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);
21332df76c16SMatt Jacob 	} else {
21342df76c16SMatt Jacob 		chan = 0;
21352df76c16SMatt Jacob 	}
21362df76c16SMatt Jacob 
21372df76c16SMatt Jacob 	/*
21382df76c16SMatt Jacob 	 * Find the PDB entry for this initiator
21392df76c16SMatt Jacob 	 */
21402df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, chan, sid, &lp) == 0) {
21412df76c16SMatt Jacob 		/*
21422df76c16SMatt Jacob 		 * If we're not in the port database terminate the exchange.
21432df76c16SMatt Jacob 		 */
21442df76c16SMatt 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",
21452df76c16SMatt Jacob 		    __func__, aep->at_rxid, did, chan, sid);
21462df76c16SMatt Jacob 		isp_endcmd(isp, aep, NIL_HANDLE, chan, ECMD_TERMINATE, 0);
21472df76c16SMatt Jacob 		return;
21482df76c16SMatt Jacob 	}
21492df76c16SMatt Jacob 	nphdl = lp->handle;
21502df76c16SMatt Jacob 	wwn = lp->port_wwn;
21512df76c16SMatt Jacob 
21522df76c16SMatt Jacob 	/*
21532df76c16SMatt Jacob 	 * Get the tstate pointer
21542df76c16SMatt Jacob 	 */
21552df76c16SMatt Jacob 	tptr = get_lun_statep(isp, chan, lun);
21562df76c16SMatt Jacob 	if (tptr == NULL) {
21572df76c16SMatt Jacob 		tptr = get_lun_statep(isp, chan, CAM_LUN_WILDCARD);
21582df76c16SMatt Jacob 		if (tptr == NULL) {
21592df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] no state pointer for lun %d or wildcard", aep->at_rxid, lun);
21602df76c16SMatt Jacob 			isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_CHECK_COND | ECMD_SVALID | (0x5 << 12) | (0x25 << 16), 0);
21612df76c16SMatt Jacob 			return;
21622df76c16SMatt Jacob 		}
21632df76c16SMatt Jacob 	}
21642df76c16SMatt Jacob 
21652df76c16SMatt Jacob 	/*
21662df76c16SMatt Jacob 	 * Start any commands pending resources first.
21672df76c16SMatt Jacob 	 */
21682df76c16SMatt Jacob 	if (tptr->restart_queue) {
21692df76c16SMatt Jacob 		inot_private_data_t *restart_queue = tptr->restart_queue;
21702df76c16SMatt Jacob 		tptr->restart_queue = NULL;
21712df76c16SMatt Jacob 		while (restart_queue) {
21722df76c16SMatt Jacob 			ntp = restart_queue;
21732df76c16SMatt Jacob 			restart_queue = ntp->rd.nt.nt_hba;
21742df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: restarting resrc deprived %x", __func__, ((at7_entry_t *)ntp->rd.data)->at_rxid);
21752df76c16SMatt Jacob 			isp_handle_platform_atio7(isp, (at7_entry_t *) ntp->rd.data);
21762df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
21772df76c16SMatt Jacob 			/*
21782df76c16SMatt Jacob 			 * If a recursion caused the restart queue to start to fill again,
21792df76c16SMatt Jacob 			 * stop and splice the new list on top of the old list and restore
21802df76c16SMatt Jacob 			 * it and go to noresrc.
21812df76c16SMatt Jacob 			 */
21822df76c16SMatt Jacob 			if (tptr->restart_queue) {
21832df76c16SMatt Jacob 				if (restart_queue) {
21842df76c16SMatt Jacob 					ntp = tptr->restart_queue;
21852df76c16SMatt Jacob 					tptr->restart_queue = restart_queue;
21862df76c16SMatt Jacob 					while (restart_queue->rd.nt.nt_hba) {
21872df76c16SMatt Jacob 						restart_queue = restart_queue->rd.nt.nt_hba;
21882df76c16SMatt Jacob 					}
21892df76c16SMatt Jacob 					restart_queue->rd.nt.nt_hba = ntp;
21902df76c16SMatt Jacob 				}
21912df76c16SMatt Jacob 				goto noresrc;
21922df76c16SMatt Jacob 			}
21932df76c16SMatt Jacob 		}
21942df76c16SMatt Jacob 	}
21952df76c16SMatt Jacob 
21962df76c16SMatt Jacob 	/*
21972df76c16SMatt Jacob 	 * If the f/w is out of resources, just send a BUSY status back.
21982df76c16SMatt Jacob 	 */
21992df76c16SMatt Jacob 	if (aep->at_rxid == AT7_NORESRC_RXID) {
22002df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
22012df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0);
22022df76c16SMatt Jacob 		return;
22032df76c16SMatt Jacob 	}
22042df76c16SMatt Jacob 
22052df76c16SMatt Jacob 	/*
22062df76c16SMatt Jacob 	 * If we're out of resources, just send a BUSY status back.
22072df76c16SMatt Jacob 	 */
22082df76c16SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
22092df76c16SMatt Jacob 	if (atiop == NULL) {
22102df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atios", aep->at_rxid);
22112df76c16SMatt Jacob 		goto noresrc;
22122df76c16SMatt Jacob 	}
22132df76c16SMatt Jacob 
22142df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, 0);
22152df76c16SMatt Jacob 	if (atp == NULL) {
22162df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] out of atps", aep->at_rxid);
22172df76c16SMatt Jacob 		goto noresrc;
22182df76c16SMatt Jacob 	}
22192df76c16SMatt Jacob 	if (isp_get_atpd(isp, tptr, aep->at_rxid)) {
22202df76c16SMatt 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",
22212df76c16SMatt Jacob 		    aep->at_rxid, nphdl, sid, aep->at_hdr.ox_id);
22222df76c16SMatt Jacob 		/*
22232df76c16SMatt Jacob 		 * It's not a "no resource" condition- but we can treat it like one
22242df76c16SMatt Jacob 		 */
22252df76c16SMatt Jacob 		goto noresrc;
22262df76c16SMatt Jacob 	}
22272df76c16SMatt Jacob 
22282df76c16SMatt Jacob 	atp->tag = aep->at_rxid;
22292df76c16SMatt Jacob 	atp->state = ATPD_STATE_ATIO;
22302df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
22312df76c16SMatt Jacob 	tptr->atio_count--;
22322df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, atiop->ccb_h.path, "Take FREE ATIO count now %d\n", tptr->atio_count);
22332df76c16SMatt Jacob 	atiop->init_id = nphdl;
22342df76c16SMatt Jacob 	atiop->ccb_h.target_id = FCPARAM(isp, chan)->isp_loopid;
22352df76c16SMatt Jacob 	atiop->ccb_h.target_lun = lun;
22362df76c16SMatt Jacob 	atiop->sense_len = 0;
22372df76c16SMatt Jacob 	cdbxlen = aep->at_cmnd.fcp_cmnd_alen_datadir >> FCP_CMND_ADDTL_CDBLEN_SHIFT;
22382df76c16SMatt Jacob 	if (cdbxlen) {
22392df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "additional CDBLEN ignored");
22402df76c16SMatt Jacob 	}
22412df76c16SMatt Jacob 	cdbxlen = sizeof (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb);
22422df76c16SMatt Jacob 	ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb, cdbxlen);
22432df76c16SMatt Jacob 	atiop->cdb_len = cdbxlen;
22442df76c16SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
22452df76c16SMatt Jacob 	atiop->tag_id = atp->tag;
22462df76c16SMatt Jacob 	switch (aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK) {
22472df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_SIMPLE:
22482df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22492df76c16SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
22502df76c16SMatt Jacob 		break;
22512df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_HEAD:
22522df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22532df76c16SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
22542df76c16SMatt Jacob 		break;
22552df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ORDERED:
22562df76c16SMatt Jacob 		atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
22572df76c16SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
22582df76c16SMatt Jacob 		break;
22592df76c16SMatt Jacob 	default:
22602df76c16SMatt Jacob 		/* FALLTHROUGH */
22612df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_ACA:
22622df76c16SMatt Jacob 	case FCP_CMND_TASK_ATTR_UNTAGGED:
22632df76c16SMatt Jacob 		atiop->tag_action = 0;
22642df76c16SMatt Jacob 		break;
22652df76c16SMatt Jacob 	}
22662df76c16SMatt Jacob 	atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl;
22672df76c16SMatt Jacob 	atp->bytes_xfered = 0;
22682df76c16SMatt Jacob 	atp->last_xframt = 0;
22692df76c16SMatt Jacob 	atp->lun = lun;
22702df76c16SMatt Jacob 	atp->nphdl = nphdl;
22712df76c16SMatt Jacob 	atp->portid = sid;
22722df76c16SMatt Jacob 	atp->oxid = aep->at_hdr.ox_id;
22732df76c16SMatt Jacob 	atp->cdb0 = atiop->cdb_io.cdb_bytes[0];
22742df76c16SMatt Jacob 	atp->tattr = aep->at_cmnd.fcp_cmnd_task_attribute & FCP_CMND_TASK_ATTR_MASK;
22752df76c16SMatt Jacob 	atp->state = ATPD_STATE_CAM;
22762df76c16SMatt 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);
22772df76c16SMatt Jacob 	xpt_done((union ccb *)atiop);
22782df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
22792df76c16SMatt Jacob 	return;
22802df76c16SMatt Jacob noresrc:
22812df76c16SMatt Jacob 	if (atp) {
22822df76c16SMatt Jacob 		isp_put_atpd(isp, tptr, atp);
22832df76c16SMatt Jacob 	}
22842df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
22852df76c16SMatt Jacob 	if (ntp == NULL) {
22862df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
22872df76c16SMatt Jacob 		isp_endcmd(isp, aep, nphdl, chan, SCSI_STATUS_BUSY, 0);
22882df76c16SMatt Jacob 		return;
22892df76c16SMatt Jacob 	}
22902df76c16SMatt Jacob 	memcpy(ntp->rd.data, aep, QENTRY_LEN);
22912df76c16SMatt Jacob 	ntp->rd.nt.nt_hba = tptr->restart_queue;
22922df76c16SMatt Jacob 	tptr->restart_queue = ntp;
22932df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
22942df76c16SMatt Jacob }
22952df76c16SMatt Jacob 
22962df76c16SMatt Jacob static void
22979cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
2298d81ba9d5SMatt Jacob {
2299d81ba9d5SMatt Jacob 	union ccb *ccb;
2300a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
23012df76c16SMatt Jacob 	tstate_t *tptr = NULL;
23022df76c16SMatt Jacob 	atio_private_data_t *atp = NULL;
23032df76c16SMatt Jacob 	int bus;
23042df76c16SMatt Jacob 	uint32_t tval, handle;
2305d81ba9d5SMatt Jacob 
2306d81ba9d5SMatt Jacob 	/*
2307443e752dSMatt Jacob 	 * CTIO handles are 16 bits.
2308443e752dSMatt Jacob 	 * CTIO2 and CTIO7 are 32 bits.
2309d81ba9d5SMatt Jacob 	 */
2310d81ba9d5SMatt Jacob 
23112df76c16SMatt Jacob 	if (IS_SCSI(isp)) {
23122df76c16SMatt Jacob 		handle = ((ct_entry_t *)arg)->ct_syshandle;
23132df76c16SMatt Jacob 	} else {
23142df76c16SMatt Jacob 		handle = ((ct2_entry_t *)arg)->ct_syshandle;
23152df76c16SMatt Jacob 	}
23162df76c16SMatt Jacob 	ccb = isp_find_xs_tgt(isp, handle);
23172df76c16SMatt Jacob 	if (ccb == NULL) {
23182df76c16SMatt Jacob 		isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg);
23192df76c16SMatt Jacob 		return;
23202df76c16SMatt Jacob 	}
23212df76c16SMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
23222df76c16SMatt Jacob 	bus = XS_CHANNEL(ccb);
23232df76c16SMatt Jacob 	tptr = get_lun_statep(isp, bus, XS_LUN(ccb));
23242df76c16SMatt Jacob 	if (tptr == NULL) {
23252df76c16SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
23262df76c16SMatt Jacob 	}
23272df76c16SMatt Jacob 	KASSERT((tptr != NULL), ("cannot get state pointer"));
23282df76c16SMatt Jacob 	if (isp->isp_nactive) {
23292df76c16SMatt Jacob 		isp->isp_nactive++;
23302df76c16SMatt Jacob 	}
23312df76c16SMatt Jacob 	if (IS_24XX(isp)) {
23322df76c16SMatt Jacob 		ct7_entry_t *ct = arg;
2333d81ba9d5SMatt Jacob 
23342df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
2335570c7a3fSMatt Jacob 		if (atp == NULL) {
23362df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
23372df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
23382df76c16SMatt Jacob 			return;
23392df76c16SMatt Jacob 		}
23402df76c16SMatt Jacob 
23412df76c16SMatt Jacob 		sentstatus = ct->ct_flags & CT7_SENDSTATUS;
23422df76c16SMatt Jacob 		ok = (ct->ct_nphdl == CT7_OK);
23432df76c16SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
23442df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
23452df76c16SMatt Jacob 		}
23462df76c16SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
23472df76c16SMatt Jacob 		if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) {
23482df76c16SMatt Jacob 			resid = ct->ct_resid;
23492df76c16SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
23502df76c16SMatt Jacob 			atp->last_xframt = 0;
23512df76c16SMatt Jacob 		}
23522df76c16SMatt Jacob 		if (ct->ct_nphdl == CT_HBA_RESET) {
23532df76c16SMatt Jacob 			ok = 0;
23542df76c16SMatt Jacob 			notify_cam = 1;
23552df76c16SMatt Jacob 			sentstatus = 1;
23562df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
23572df76c16SMatt Jacob 		} else if (!ok) {
23582df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
23592df76c16SMatt Jacob 		}
23602df76c16SMatt Jacob 		tval = atp->tag;
23612df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
23622df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
23632df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
23642df76c16SMatt Jacob 	} else if (IS_FC(isp)) {
23652df76c16SMatt Jacob 		ct2_entry_t *ct = arg;
23662df76c16SMatt Jacob 
23672df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, ct->ct_rxid);
23682df76c16SMatt Jacob 		if (atp == NULL) {
23692df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
23702df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: cannot find adjunct for %x after I/O", __func__, ct->ct_rxid);
23712df76c16SMatt Jacob 			return;
2372570c7a3fSMatt Jacob 		}
2373d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
2374d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
2375a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
237600a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
237700a8e174SMatt Jacob 		}
2378a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
23795d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
2380a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
238153036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
238253036e92SMatt Jacob 			atp->last_xframt = 0;
2383570c7a3fSMatt Jacob 		}
23842df76c16SMatt Jacob 		if (ct->ct_status == CT_HBA_RESET) {
23852df76c16SMatt Jacob 			ok = 0;
23862df76c16SMatt Jacob 			notify_cam = 1;
23872df76c16SMatt Jacob 			sentstatus = 1;
23882df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
23892df76c16SMatt Jacob 		} else if (!ok) {
23902df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
239153036e92SMatt Jacob 		}
23922df76c16SMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
23932df76c16SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
23942df76c16SMatt Jacob 		tval = atp->tag;
23952df76c16SMatt Jacob 		atp->state = ATPD_STATE_PDON; /* XXX: should really come after isp_complete_ctio */
2396d81ba9d5SMatt Jacob 	} else {
2397d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
2398d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
2399d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
2400d81ba9d5SMatt Jacob 		/*
2401a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
2402a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
2403a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
2404a1bc34c6SMatt Jacob 		 * private data.
2405a1bc34c6SMatt Jacob 		 *
2406a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
2407a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
2408a1bc34c6SMatt Jacob 		 */
2409a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
24102df76c16SMatt Jacob 		if (ct->ct_status == (CT_HBA_RESET & 0xff)) {
24112df76c16SMatt Jacob 			ok = 0;
24122df76c16SMatt Jacob 			notify_cam = 1;
24132df76c16SMatt Jacob 			sentstatus = 1;
24142df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
24152df76c16SMatt Jacob 		} else if (!ok) {
24162df76c16SMatt Jacob 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
24172df76c16SMatt Jacob 		} else if (ct->ct_status & QLTM_SVALID) {
2418a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
2419a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
24202df76c16SMatt Jacob 			ccb->csio.sense_len = min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
24212df76c16SMatt Jacob 			ISP_MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
2422a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2423a1bc34c6SMatt Jacob 		}
24245d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
2425a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
2426a1bc34c6SMatt Jacob 		}
24272df76c16SMatt 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__,
24282df76c16SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID");
242964edff94SMatt Jacob 		tval = ct->ct_fwhandle;
24305d571944SMatt Jacob 	}
2431a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
2432a1bc34c6SMatt Jacob 
2433a1bc34c6SMatt Jacob 	/*
2434a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
2435a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
2436a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
2437d81ba9d5SMatt Jacob 	 *
2438d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
2439d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
2440a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
2441a1bc34c6SMatt Jacob 	 * freed.
2442d81ba9d5SMatt Jacob 	 */
2443f48ce188SMatt Jacob 	if (notify_cam == 0) {
244464edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
24452df76c16SMatt Jacob 		return;
2446f48ce188SMatt Jacob 	}
24472df76c16SMatt Jacob 	if (tptr) {
24482df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
24492df76c16SMatt Jacob 	}
24502df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done", (sentstatus)? "  FINAL " : "MIDTERM ", tval);
2451d81ba9d5SMatt Jacob 
24522df76c16SMatt Jacob 	if (!ok && !IS_24XX(isp)) {
2453a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
2454d81ba9d5SMatt Jacob 	} else {
2455a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
2456d81ba9d5SMatt Jacob 	}
2457d81ba9d5SMatt Jacob }
2458570c7a3fSMatt Jacob 
24592df76c16SMatt Jacob static void
24602df76c16SMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inot)
2461570c7a3fSMatt Jacob {
24622df76c16SMatt Jacob 	(void) isp_notify_ack(isp, inot);
2463570c7a3fSMatt Jacob }
2464570c7a3fSMatt Jacob 
24652df76c16SMatt Jacob static void
24669cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
2467570c7a3fSMatt Jacob {
24682df76c16SMatt Jacob 	int needack = 1;
2469570c7a3fSMatt Jacob 	switch (inp->in_status) {
2470570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
24712df76c16SMatt Jacob 		/*
24722df76c16SMatt Jacob 		 * XXX: Need to delete this initiator's WWN from the database
24732df76c16SMatt Jacob 		 * XXX: Need to send this LOGOUT upstream
24742df76c16SMatt Jacob 		 */
24752df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of S_ID 0x%x", inp->in_iid);
2476570c7a3fSMatt Jacob 		break;
2477570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
24782df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for S_ID 0x%x", inp->in_iid);
2479570c7a3fSMatt Jacob 		break;
2480570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
24812df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, 0);
2482570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
2483570c7a3fSMatt Jacob 		break;
2484570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
2485570c7a3fSMatt Jacob 	{
24862df76c16SMatt Jacob 		tstate_t *tptr;
24872df76c16SMatt Jacob 		uint16_t lun;
24882df76c16SMatt Jacob 		uint32_t loopid;
24892df76c16SMatt Jacob 		uint64_t wwn;
24902df76c16SMatt Jacob 		atio_private_data_t *atp;
24912df76c16SMatt Jacob 		fcportdb_t *lp;
24922df76c16SMatt Jacob 		struct ccb_immediate_notify *inot = NULL;
24932df76c16SMatt Jacob 
24942df76c16SMatt Jacob 		if (ISP_CAP_SCCFW(isp)) {
24952df76c16SMatt Jacob 			lun = inp->in_scclun;
24962df76c16SMatt Jacob 		} else {
24972df76c16SMatt Jacob 			lun = inp->in_lun;
24982df76c16SMatt Jacob 		}
24992df76c16SMatt Jacob 		if (ISP_CAP_2KLOGIN(isp)) {
25002df76c16SMatt Jacob 			loopid = ((in_fcentry_e_t *)inot)->in_iid;
25012df76c16SMatt Jacob 		} else {
25022df76c16SMatt Jacob 			loopid = inp->in_iid;
25032df76c16SMatt Jacob 		}
25042df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, 0, loopid, &lp)) {
25052df76c16SMatt Jacob 			wwn = lp->port_wwn;
25062df76c16SMatt Jacob 		} else {
25072df76c16SMatt Jacob 			wwn = INI_ANY;
25082df76c16SMatt Jacob 		}
25092df76c16SMatt Jacob 		tptr = get_lun_statep(isp, 0, lun);
25102df76c16SMatt Jacob 		if (tptr == NULL) {
25112df76c16SMatt Jacob 			tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
25122df76c16SMatt Jacob 			if (tptr == NULL) {
25132df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "ABORT TASK for lun %u- but no tstate", lun);
25142df76c16SMatt Jacob 				return;
25152df76c16SMatt Jacob 			}
25162df76c16SMatt Jacob 		}
25172df76c16SMatt Jacob 		atp = isp_get_atpd(isp, tptr, inp->in_seqid);
2518570c7a3fSMatt Jacob 
2519570c7a3fSMatt Jacob 		if (atp) {
25202df76c16SMatt Jacob 			inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
25212df76c16SMatt 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);
2522570c7a3fSMatt Jacob 			if (inot) {
2523746e9c85SMatt Jacob 				tptr->inot_count--;
25242df76c16SMatt Jacob 				SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
25252df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
2526570c7a3fSMatt Jacob 			} else {
25272df76c16SMatt Jacob 				ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, tptr->owner, "out of INOT structures\n");
25282df76c16SMatt Jacob 			}
25292df76c16SMatt Jacob 		} else {
25302df76c16SMatt 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);
2531570c7a3fSMatt Jacob 		}
2532570c7a3fSMatt Jacob 		if (inot) {
25332df76c16SMatt Jacob 			isp_notify_t tmp, *nt = &tmp;
25342df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
25352df76c16SMatt Jacob     			nt->nt_hba = isp;
25362df76c16SMatt Jacob 			nt->nt_tgt = FCPARAM(isp, 0)->isp_wwpn;
25372df76c16SMatt Jacob 			nt->nt_wwn = wwn;
25382df76c16SMatt Jacob 			nt->nt_nphdl = loopid;
25392df76c16SMatt Jacob 			nt->nt_sid = PORT_ANY;
25402df76c16SMatt Jacob 			nt->nt_did = PORT_ANY;
25412df76c16SMatt Jacob     			nt->nt_lun = lun;
25422df76c16SMatt Jacob             		nt->nt_need_ack = 1;
25432df76c16SMatt Jacob     			nt->nt_channel = 0;
25442df76c16SMatt Jacob     			nt->nt_ncode = NT_ABORT_TASK;
25452df76c16SMatt Jacob     			nt->nt_lreserved = inot;
25462df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
25472df76c16SMatt Jacob 			needack = 0;
2548570c7a3fSMatt Jacob 		}
25492df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
2550570c7a3fSMatt Jacob 		break;
2551570c7a3fSMatt Jacob 	}
2552570c7a3fSMatt Jacob 	default:
2553570c7a3fSMatt Jacob 		break;
2554570c7a3fSMatt Jacob 	}
25552df76c16SMatt Jacob 	if (needack) {
25562df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inp);
25572df76c16SMatt Jacob 	}
25582df76c16SMatt Jacob }
25592df76c16SMatt Jacob 
25602df76c16SMatt Jacob static void
25612df76c16SMatt Jacob isp_handle_platform_notify_24xx(ispsoftc_t *isp, in_fcentry_24xx_t *inot)
25622df76c16SMatt Jacob {
25632df76c16SMatt Jacob 	uint16_t nphdl;
25642df76c16SMatt Jacob 	uint32_t portid;
25652df76c16SMatt Jacob 	fcportdb_t *lp;
25662df76c16SMatt Jacob 	uint8_t *ptr = NULL;
25672df76c16SMatt Jacob 	uint64_t wwn;
25682df76c16SMatt Jacob 
25692df76c16SMatt Jacob 	nphdl = inot->in_nphdl;
25702df76c16SMatt Jacob 	if (nphdl != NIL_HANDLE) {
25712df76c16SMatt Jacob 		portid = inot->in_portid_hi << 16 | inot->in_portid_lo;
25722df76c16SMatt Jacob 	} else {
25732df76c16SMatt Jacob 		portid = PORT_ANY;
25742df76c16SMatt Jacob 	}
25752df76c16SMatt Jacob 
25762df76c16SMatt Jacob 	switch (inot->in_status) {
25772df76c16SMatt Jacob 	case IN24XX_ELS_RCVD:
25782df76c16SMatt Jacob 	{
25792df76c16SMatt Jacob 		char buf[16], *msg;
25802df76c16SMatt Jacob 		int chan = ISP_GET_VPIDX(isp, inot->in_vpidx);
25812df76c16SMatt Jacob 
25822df76c16SMatt Jacob 		/*
25832df76c16SMatt Jacob 		 * Note that we're just getting notification that an ELS was received
25842df76c16SMatt Jacob 		 * (possibly with some associcated information sent upstream). This is
25852df76c16SMatt Jacob 		 * *not* the same as being given the ELS frame to accept or reject.
25862df76c16SMatt Jacob 		 */
25872df76c16SMatt Jacob 		switch (inot->in_status_subcode) {
25882df76c16SMatt Jacob 		case LOGO:
25892df76c16SMatt Jacob 			msg = "LOGO";
25902df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
25912df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
25922df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF])   << 56) |
25932df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+1]) << 48) |
25942df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+2]) << 40) |
25952df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+3]) << 32) |
25962df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+4]) << 24) |
25972df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+5]) << 16) |
25982df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+6]) <<  8) |
25992df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_LOGO_WWPN_OFF+7]));
26002df76c16SMatt Jacob 			} else {
26012df76c16SMatt Jacob 				wwn = INI_ANY;
26022df76c16SMatt Jacob 			}
26032df76c16SMatt Jacob 			isp_del_wwn_entry(isp, chan, wwn, nphdl, portid);
26042df76c16SMatt Jacob 			break;
26052df76c16SMatt Jacob 		case PRLO:
26062df76c16SMatt Jacob 			msg = "PRLO";
26072df76c16SMatt Jacob 			break;
26082df76c16SMatt Jacob 		case PLOGI:
26092df76c16SMatt Jacob 			msg = "PLOGI";
26102df76c16SMatt Jacob 			if (ISP_FW_NEWER_THAN(isp, 4, 0, 25)) {
26112df76c16SMatt Jacob 				ptr = (uint8_t *)inot;  /* point to unswizzled entry! */
26122df76c16SMatt Jacob 				wwn =	(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF])   << 56) |
26132df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+1]) << 48) |
26142df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+2]) << 40) |
26152df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+3]) << 32) |
26162df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+4]) << 24) |
26172df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+5]) << 16) |
26182df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+6]) <<  8) |
26192df76c16SMatt Jacob 					(((uint64_t) ptr[IN24XX_PLOGI_WWPN_OFF+7]));
26202df76c16SMatt Jacob 			} else {
26212df76c16SMatt Jacob 				wwn = INI_NONE;
26222df76c16SMatt Jacob 			}
26232df76c16SMatt Jacob 			isp_add_wwn_entry(isp, chan, wwn, nphdl, portid);
26242df76c16SMatt Jacob 			break;
26252df76c16SMatt Jacob 		case PRLI:
26262df76c16SMatt Jacob 			msg = "PRLI";
26272df76c16SMatt Jacob 			break;
26282df76c16SMatt Jacob 		case PDISC:
26292df76c16SMatt Jacob 			msg = "PDISC";
26302df76c16SMatt Jacob 			break;
26312df76c16SMatt Jacob 		case ADISC:
26322df76c16SMatt Jacob 			msg = "ADISC";
26332df76c16SMatt Jacob 			break;
26342df76c16SMatt Jacob 		default:
26352df76c16SMatt Jacob 			ISP_SNPRINTF(buf, sizeof (buf), "ELS 0x%x", inot->in_status_subcode);
26362df76c16SMatt Jacob 			msg = buf;
26372df76c16SMatt Jacob 			break;
26382df76c16SMatt Jacob 		}
26392df76c16SMatt Jacob 		if (inot->in_flags & IN24XX_FLAG_PUREX_IOCB) {
26402df76c16SMatt 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);
26412df76c16SMatt Jacob 			break;
26422df76c16SMatt Jacob 		}
26432df76c16SMatt 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,
26442df76c16SMatt Jacob 		    inot->in_rxid, inot->in_oxid);
26452df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26462df76c16SMatt Jacob 		break;
26472df76c16SMatt Jacob 	}
26482df76c16SMatt Jacob 
26492df76c16SMatt Jacob 	case IN24XX_PORT_LOGOUT:
26502df76c16SMatt Jacob 		ptr = "PORT LOGOUT";
26512df76c16SMatt Jacob 		if (isp_find_pdb_by_loopid(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), nphdl, &lp)) {
26522df76c16SMatt Jacob 			isp_del_wwn_entry(isp, ISP_GET_VPIDX(isp, inot->in_vpidx), lp->port_wwn, nphdl, lp->portid);
26532df76c16SMatt Jacob 		}
26542df76c16SMatt Jacob 		/* FALLTHROUGH */
26552df76c16SMatt Jacob 	case IN24XX_PORT_CHANGED:
26562df76c16SMatt Jacob 		if (ptr == NULL) {
26572df76c16SMatt Jacob 			ptr = "PORT CHANGED";
26582df76c16SMatt Jacob 		}
26592df76c16SMatt Jacob 		/* FALLTHROUGH */
26602df76c16SMatt Jacob 	case IN24XX_LIP_RESET:
26612df76c16SMatt Jacob 		if (ptr == NULL) {
26622df76c16SMatt Jacob 			ptr = "LIP RESET";
26632df76c16SMatt Jacob 		}
26642df76c16SMatt 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);
26652df76c16SMatt Jacob 
26662df76c16SMatt Jacob 		/*
26672df76c16SMatt Jacob 		 * All subcodes here are irrelevant. What is relevant
26682df76c16SMatt Jacob 		 * is that we need to terminate all active commands from
26692df76c16SMatt Jacob 		 * this initiator (known by N-port handle).
26702df76c16SMatt Jacob 		 */
26712df76c16SMatt Jacob 		/* XXX IMPLEMENT XXX */
26722df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26732df76c16SMatt Jacob 		break;
26742df76c16SMatt Jacob 
26752df76c16SMatt Jacob 	case IN24XX_LINK_RESET:
26762df76c16SMatt Jacob 	case IN24XX_LINK_FAILED:
26772df76c16SMatt Jacob 	case IN24XX_SRR_RCVD:
26782df76c16SMatt Jacob 	default:
26792df76c16SMatt Jacob 		(void) isp_notify_ack(isp, inot);
26802df76c16SMatt Jacob 		break;
26812df76c16SMatt Jacob 	}
26822df76c16SMatt Jacob }
26832df76c16SMatt Jacob 
26842df76c16SMatt Jacob static int
26852df76c16SMatt Jacob isp_handle_platform_target_notify_ack(ispsoftc_t *isp, isp_notify_t *mp)
26862df76c16SMatt Jacob {
26872df76c16SMatt Jacob 
26882df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
26892df76c16SMatt 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);
2690570c7a3fSMatt Jacob 		return (0);
2691570c7a3fSMatt Jacob 	}
26922df76c16SMatt Jacob 
26932df76c16SMatt Jacob 	/*
26942df76c16SMatt Jacob 	 * This case is for a Task Management Function, which shows up as an ATIO7 entry.
26952df76c16SMatt Jacob 	 */
26962df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ATIO) {
26972df76c16SMatt Jacob 		ct7_entry_t local, *cto = &local;
26982df76c16SMatt Jacob 		at7_entry_t *aep = (at7_entry_t *)mp->nt_lreserved;
26992df76c16SMatt Jacob 		fcportdb_t *lp;
27002df76c16SMatt Jacob 		uint32_t sid;
27012df76c16SMatt Jacob 		uint16_t nphdl;
27022df76c16SMatt Jacob 
27032df76c16SMatt Jacob 		sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2];
27042df76c16SMatt Jacob 		if (isp_find_pdb_by_sid(isp, mp->nt_channel, sid, &lp)) {
27052df76c16SMatt Jacob 			nphdl = lp->handle;
27062df76c16SMatt Jacob 		} else {
27072df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
27082df76c16SMatt Jacob 		}
27092df76c16SMatt Jacob 		ISP_MEMZERO(&local, sizeof (local));
27102df76c16SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
27112df76c16SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
27122df76c16SMatt Jacob 		cto->ct_nphdl = nphdl;
27132df76c16SMatt Jacob 		cto->ct_rxid = aep->at_rxid;
27142df76c16SMatt Jacob 		cto->ct_vpidx = mp->nt_channel;
27152df76c16SMatt Jacob 		cto->ct_iid_lo = sid;
27162df76c16SMatt Jacob 		cto->ct_iid_hi = sid >> 16;
27172df76c16SMatt Jacob 		cto->ct_oxid = aep->at_hdr.ox_id;
27182df76c16SMatt Jacob 		cto->ct_flags = CT7_SENDSTATUS|CT7_NOACK|CT7_NO_DATA|CT7_FLAG_MODE1;
27192df76c16SMatt Jacob 		cto->ct_flags |= (aep->at_ta_len >> 12) << CT7_TASK_ATTR_SHIFT;
27202df76c16SMatt Jacob 		return (isp_target_put_entry(isp, &local));
27212df76c16SMatt Jacob 	}
27222df76c16SMatt Jacob 
27232df76c16SMatt Jacob 	/*
27242df76c16SMatt Jacob 	 * This case is for a responding to an ABTS frame
27252df76c16SMatt Jacob 	 */
27262df76c16SMatt Jacob 	if (IS_24XX(isp) && mp->nt_lreserved && ((isphdr_t *)mp->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
27272df76c16SMatt Jacob 
27282df76c16SMatt Jacob 		/*
27292df76c16SMatt Jacob 		 * Overload nt_need_ack here to mark whether we've terminated the associated command.
27302df76c16SMatt Jacob 		 */
27312df76c16SMatt Jacob 		if (mp->nt_need_ack) {
27322df76c16SMatt Jacob 			uint8_t storage[QENTRY_LEN];
27332df76c16SMatt Jacob 			ct7_entry_t *cto = (ct7_entry_t *) storage;
27342df76c16SMatt Jacob 			abts_t *abts = (abts_t *)mp->nt_lreserved;
27352df76c16SMatt Jacob 
27362df76c16SMatt Jacob 			ISP_MEMZERO(cto, sizeof (ct7_entry_t));
27372df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0, "%s: [%x] terminating after ABTS received", __func__, abts->abts_rxid_task);
27382df76c16SMatt Jacob 			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
27392df76c16SMatt Jacob 			cto->ct_header.rqs_entry_count = 1;
27402df76c16SMatt Jacob 			cto->ct_nphdl = mp->nt_nphdl;
27412df76c16SMatt Jacob 			cto->ct_rxid = abts->abts_rxid_task;
27422df76c16SMatt Jacob 			cto->ct_iid_lo = mp->nt_sid;
27432df76c16SMatt Jacob 			cto->ct_iid_hi = mp->nt_sid >> 16;
27442df76c16SMatt Jacob 			cto->ct_oxid = abts->abts_ox_id;
27452df76c16SMatt Jacob 			cto->ct_vpidx = mp->nt_channel;
27462df76c16SMatt Jacob 			cto->ct_flags = CT7_NOACK|CT7_TERMINATE;
27472df76c16SMatt Jacob 			if (isp_target_put_entry(isp, cto)) {
27482df76c16SMatt Jacob 				return (ENOMEM);
27492df76c16SMatt Jacob 			}
27502df76c16SMatt Jacob 			mp->nt_need_ack = 0;
27512df76c16SMatt Jacob 		}
27522df76c16SMatt Jacob 		if (isp_acknak_abts(isp, mp->nt_lreserved, 0) == ENOMEM) {
27532df76c16SMatt Jacob 			return (ENOMEM);
27542df76c16SMatt Jacob 		} else {
27552df76c16SMatt Jacob 			return (0);
27562df76c16SMatt Jacob 		}
27572df76c16SMatt Jacob 	}
27582df76c16SMatt Jacob 
27592df76c16SMatt Jacob 	/*
27602df76c16SMatt Jacob 	 * Handle logout cases here
27612df76c16SMatt Jacob 	 */
27622df76c16SMatt Jacob 	if (mp->nt_ncode == NT_GLOBAL_LOGOUT) {
27632df76c16SMatt Jacob 		isp_del_all_wwn_entries(isp, mp->nt_channel);
27642df76c16SMatt Jacob 	}
27652df76c16SMatt Jacob 
27662df76c16SMatt Jacob 	if (mp->nt_ncode == NT_LOGOUT) {
27672df76c16SMatt Jacob 		if (!IS_2100(isp) && IS_FC(isp)) {
27682df76c16SMatt Jacob 			isp_del_wwn_entries(isp, mp);
27692df76c16SMatt Jacob 		}
27702df76c16SMatt Jacob 	}
27712df76c16SMatt Jacob 
27722df76c16SMatt Jacob 	/*
27732df76c16SMatt Jacob 	 * General purpose acknowledgement
27742df76c16SMatt Jacob 	 */
27752df76c16SMatt Jacob 	if (mp->nt_need_ack) {
27762df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGTINFO, "Notify Code 0x%x (qevalid=%d) being acked", mp->nt_ncode, mp->nt_lreserved != NULL);
27772df76c16SMatt Jacob 		return (isp_notify_ack(isp, mp->nt_lreserved));
27782df76c16SMatt Jacob 	}
27792df76c16SMatt Jacob 	return (0);
27802df76c16SMatt Jacob }
27812df76c16SMatt Jacob 
27822df76c16SMatt Jacob /*
27832df76c16SMatt Jacob  * Handle task managment functions.
27842df76c16SMatt Jacob  *
27852df76c16SMatt Jacob  * We show up here with a notify structure filled out.
27862df76c16SMatt Jacob  *
27872df76c16SMatt Jacob  * The nt_lreserved tag points to the original queue entry
27882df76c16SMatt Jacob  */
27892df76c16SMatt Jacob static void
27902df76c16SMatt Jacob isp_handle_platform_target_tmf(ispsoftc_t *isp, isp_notify_t *notify)
27912df76c16SMatt Jacob {
27922df76c16SMatt Jacob 	tstate_t *tptr;
27932df76c16SMatt Jacob 	fcportdb_t *lp;
27942df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
27952df76c16SMatt Jacob 	inot_private_data_t *ntp = NULL;
27962df76c16SMatt Jacob 	lun_id_t lun;
27972df76c16SMatt Jacob 
27982df76c16SMatt 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,
27992df76c16SMatt Jacob 	    notify->nt_sid, (unsigned long long) notify->nt_tagval, notify->nt_channel, notify->nt_lun);
28002df76c16SMatt Jacob 	/*
28012df76c16SMatt Jacob 	 * NB: This assignment is necessary because of tricky type conversion.
28022df76c16SMatt Jacob 	 * XXX: This is tricky and I need to check this. If the lun isn't known
28032df76c16SMatt Jacob 	 * XXX: for the task management function, it does not of necessity follow
28042df76c16SMatt Jacob 	 * XXX: that it should go up stream to the wildcard listener.
28052df76c16SMatt Jacob 	 */
28062df76c16SMatt Jacob 	if (notify->nt_lun == LUN_ANY) {
28072df76c16SMatt Jacob 		lun = CAM_LUN_WILDCARD;
28082df76c16SMatt Jacob 	} else {
28092df76c16SMatt Jacob 		lun = notify->nt_lun;
28102df76c16SMatt Jacob 	}
28112df76c16SMatt Jacob 	tptr = get_lun_statep(isp, notify->nt_channel, lun);
28122df76c16SMatt Jacob 	if (tptr == NULL) {
28132df76c16SMatt Jacob 		tptr = get_lun_statep(isp, notify->nt_channel, CAM_LUN_WILDCARD);
28142df76c16SMatt Jacob 		if (tptr == NULL) {
28152df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: no state pointer found for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
28162df76c16SMatt Jacob 			goto bad;
28172df76c16SMatt Jacob 		}
28182df76c16SMatt Jacob 	}
28192df76c16SMatt Jacob 	inot = (struct ccb_immediate_notify *) SLIST_FIRST(&tptr->inots);
28202df76c16SMatt Jacob 	if (inot == NULL) {
28212df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of immediate notify structures for chan %d lun 0x%x", __func__, notify->nt_channel, lun);
28222df76c16SMatt Jacob 		goto bad;
28232df76c16SMatt Jacob 	}
28242df76c16SMatt Jacob 
28252df76c16SMatt Jacob 	if (isp_find_pdb_by_sid(isp, notify->nt_channel, notify->nt_sid, &lp) == 0) {
28262df76c16SMatt Jacob 		inot->initiator_id = CAM_TARGET_WILDCARD;
28272df76c16SMatt Jacob 	} else {
28282df76c16SMatt Jacob 		inot->initiator_id = lp->handle;
28292df76c16SMatt Jacob 	}
28302df76c16SMatt Jacob 	inot->seq_id = notify->nt_tagval;
28312df76c16SMatt Jacob 	inot->tag_id = notify->nt_tagval >> 32;
28322df76c16SMatt Jacob 
28332df76c16SMatt Jacob 	switch (notify->nt_ncode) {
28342df76c16SMatt Jacob 	case NT_ABORT_TASK:
28352df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, inot->tag_id);
28362df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK;
28372df76c16SMatt Jacob 		break;
28382df76c16SMatt Jacob 	case NT_ABORT_TASK_SET:
28392df76c16SMatt Jacob 		isp_target_mark_aborted_early(isp, tptr, TAG_ANY);
28402df76c16SMatt Jacob 		inot->arg = MSG_ABORT_TASK_SET;
28412df76c16SMatt Jacob 		break;
28422df76c16SMatt Jacob 	case NT_CLEAR_ACA:
28432df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_ACA;
28442df76c16SMatt Jacob 		break;
28452df76c16SMatt Jacob 	case NT_CLEAR_TASK_SET:
28462df76c16SMatt Jacob 		inot->arg = MSG_CLEAR_TASK_SET;
28472df76c16SMatt Jacob 		break;
28482df76c16SMatt Jacob 	case NT_LUN_RESET:
28492df76c16SMatt Jacob 		inot->arg = MSG_LOGICAL_UNIT_RESET;
28502df76c16SMatt Jacob 		break;
28512df76c16SMatt Jacob 	case NT_TARGET_RESET:
28522df76c16SMatt Jacob 		inot->arg = MSG_TARGET_RESET;
28532df76c16SMatt Jacob 		break;
28542df76c16SMatt Jacob 	default:
28552df76c16SMatt 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);
28562df76c16SMatt Jacob 		goto bad;
28572df76c16SMatt Jacob 	}
28582df76c16SMatt Jacob 
28592df76c16SMatt Jacob 	ntp = isp_get_ntpd(isp, tptr);
28602df76c16SMatt Jacob 	if (ntp == NULL) {
28612df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s: out of inotify private structures", __func__);
28622df76c16SMatt Jacob 		goto bad;
28632df76c16SMatt Jacob 	}
28642df76c16SMatt Jacob 	ISP_MEMCPY(&ntp->rd.nt, notify, sizeof (isp_notify_t));
28652df76c16SMatt Jacob 	if (notify->nt_lreserved) {
28662df76c16SMatt Jacob 		ISP_MEMCPY(&ntp->rd.data, notify->nt_lreserved, QENTRY_LEN);
28672df76c16SMatt Jacob 		ntp->rd.nt.nt_lreserved = &ntp->rd.data;
28682df76c16SMatt Jacob 	}
28692df76c16SMatt Jacob 	ntp->rd.seq_id = notify->nt_tagval;
28702df76c16SMatt Jacob 	ntp->rd.tag_id = notify->nt_tagval >> 32;
28712df76c16SMatt Jacob 
28722df76c16SMatt Jacob 	tptr->inot_count--;
28732df76c16SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->inots, sim_links.sle);
28742df76c16SMatt Jacob 	rls_lun_statep(isp, tptr);
28752df76c16SMatt Jacob 	ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, inot->ccb_h.path, "%s: Take FREE INOT count now %d\n", __func__, tptr->inot_count);
28762df76c16SMatt Jacob 	inot->ccb_h.status = CAM_MESSAGE_RECV;
28772df76c16SMatt Jacob 	xpt_done((union ccb *)inot);
28782df76c16SMatt Jacob 	return;
28792df76c16SMatt Jacob bad:
28802df76c16SMatt Jacob 	if (tptr) {
28812df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
28822df76c16SMatt Jacob 	}
28832df76c16SMatt Jacob 	if (notify->nt_need_ack && notify->nt_lreserved) {
28842df76c16SMatt Jacob 		if (((isphdr_t *)notify->nt_lreserved)->rqs_entry_type == RQSTYPE_ABTS_RCVD) {
28852df76c16SMatt Jacob 			(void) isp_acknak_abts(isp, notify->nt_lreserved, ENOMEM);
28862df76c16SMatt Jacob 		} else {
28872df76c16SMatt Jacob 			(void) isp_notify_ack(isp, notify->nt_lreserved);
28882df76c16SMatt Jacob 		}
28892df76c16SMatt Jacob 	}
28902df76c16SMatt Jacob }
28912df76c16SMatt Jacob 
28922df76c16SMatt Jacob /*
28932df76c16SMatt Jacob  * Find the associated private data and makr it as dead so
28942df76c16SMatt Jacob  * we don't try to work on it any further.
28952df76c16SMatt Jacob  */
28962df76c16SMatt Jacob static void
28972df76c16SMatt Jacob isp_target_mark_aborted(ispsoftc_t *isp, union ccb *ccb)
28982df76c16SMatt Jacob {
28992df76c16SMatt Jacob 	tstate_t *tptr;
29002df76c16SMatt Jacob 	atio_private_data_t *atp;
29012df76c16SMatt Jacob 
29022df76c16SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
29032df76c16SMatt Jacob 	if (tptr == NULL) {
29042df76c16SMatt Jacob 		tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
29052df76c16SMatt Jacob 		if (tptr == NULL) {
29062df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
29072df76c16SMatt Jacob 			return;
29082df76c16SMatt Jacob 		}
29092df76c16SMatt Jacob 	}
29102df76c16SMatt Jacob 
29112df76c16SMatt Jacob 	atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id);
29122df76c16SMatt Jacob 	if (atp == NULL) {
29132df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INVALID;
29142df76c16SMatt Jacob 		return;
29152df76c16SMatt Jacob 	}
29162df76c16SMatt Jacob 	atp->dead = 1;
29172df76c16SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
29182df76c16SMatt Jacob }
29192df76c16SMatt Jacob 
29202df76c16SMatt Jacob static void
29212df76c16SMatt Jacob isp_target_mark_aborted_early(ispsoftc_t *isp, tstate_t *tptr, uint32_t tag_id)
29222df76c16SMatt Jacob {
29232df76c16SMatt Jacob 	atio_private_data_t *atp;
29242df76c16SMatt Jacob 	inot_private_data_t *restart_queue = tptr->restart_queue;
29252df76c16SMatt Jacob 
29262df76c16SMatt Jacob 	/*
29272df76c16SMatt Jacob 	 * First, clean any commands pending restart
29282df76c16SMatt Jacob 	 */
29292df76c16SMatt Jacob 	tptr->restart_queue = NULL;
29302df76c16SMatt Jacob 	while (restart_queue) {
29312df76c16SMatt Jacob 		uint32_t this_tag_id;
29322df76c16SMatt Jacob 		inot_private_data_t *ntp = restart_queue;
29332df76c16SMatt Jacob 
29342df76c16SMatt Jacob 		restart_queue = ntp->rd.nt.nt_hba;
29352df76c16SMatt Jacob 
29362df76c16SMatt Jacob 		if (IS_24XX(isp)) {
29372df76c16SMatt Jacob 			this_tag_id = ((at7_entry_t *)ntp->rd.data)->at_rxid;
29382df76c16SMatt Jacob 		} else {
29392df76c16SMatt Jacob 			this_tag_id = ((at2_entry_t *)ntp->rd.data)->at_rxid;
29402df76c16SMatt Jacob 		}
29412df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || tag_id == this_tag_id) {
29422df76c16SMatt Jacob 			isp_put_ntpd(isp, tptr, ntp);
29432df76c16SMatt Jacob 		} else {
29442df76c16SMatt Jacob 			ntp->rd.nt.nt_hba = tptr->restart_queue;
29452df76c16SMatt Jacob 			tptr->restart_queue = ntp;
29462df76c16SMatt Jacob 		}
29472df76c16SMatt Jacob 	}
29482df76c16SMatt Jacob 
29492df76c16SMatt Jacob 	/*
29502df76c16SMatt Jacob 	 * Now mark other ones dead as well.
29512df76c16SMatt Jacob 	 */
29522df76c16SMatt Jacob 	for (atp = tptr->atpool; atp < &tptr->atpool[ATPDPSIZE]; atp++) {
29532df76c16SMatt Jacob 		if ((uint64_t)tag_id == TAG_ANY || atp->tag == tag_id) {
29542df76c16SMatt Jacob 			atp->dead = 1;
29552df76c16SMatt Jacob 		}
29562df76c16SMatt Jacob 	}
29572df76c16SMatt Jacob }
29582df76c16SMatt Jacob 
29592df76c16SMatt Jacob 
29602df76c16SMatt Jacob #ifdef	ISP_INTERNAL_TARGET
29612df76c16SMatt Jacob // #define	ISP_FORCE_TIMEOUT		1
2962ae5db118SMatt Jacob // #define	ISP_TEST_WWNS			1
2963ae5db118SMatt Jacob // #define	ISP_TEST_SEPARATE_STATUS	1
29642df76c16SMatt Jacob 
29652df76c16SMatt Jacob #define	ccb_data_offset		ppriv_field0
29662df76c16SMatt Jacob #define	ccb_atio		ppriv_ptr1
29672df76c16SMatt Jacob #define	ccb_inot		ppriv_ptr1
29682df76c16SMatt Jacob 
29692df76c16SMatt Jacob #define	MAX_ISP_TARG_TRANSFER	(2 << 20)
29702df76c16SMatt Jacob #define	NISP_TARG_CMDS		1024
29712df76c16SMatt Jacob #define	NISP_TARG_NOTIFIES	1024
29722df76c16SMatt Jacob #define	DISK_SHIFT		9
29732df76c16SMatt Jacob #define	JUNK_SIZE		256
29742df76c16SMatt Jacob 
29752df76c16SMatt Jacob #ifndef	VERIFY_10
29762df76c16SMatt Jacob #define	VERIFY_10	0x2f
29772df76c16SMatt Jacob #endif
29782df76c16SMatt Jacob 
29792df76c16SMatt Jacob TAILQ_HEAD(ccb_queue, ccb_hdr);
29802df76c16SMatt Jacob extern u_int vm_kmem_size;
29812df76c16SMatt Jacob static int ca;
29822df76c16SMatt Jacob static uint32_t disk_size;
29832df76c16SMatt Jacob static uint8_t *disk_data = NULL;
29842df76c16SMatt Jacob static uint8_t *junk_data;
29852df76c16SMatt Jacob static MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data");
29862df76c16SMatt Jacob struct isptarg_softc {
29872df76c16SMatt Jacob 	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
29882df76c16SMatt Jacob 	struct ccb_queue	work_queue;
29892df76c16SMatt Jacob 	struct ccb_queue	rework_queue;
29902df76c16SMatt Jacob 	struct ccb_queue	running_queue;
29912df76c16SMatt Jacob 	struct ccb_queue	inot_queue;
29922df76c16SMatt Jacob 	struct cam_periph       *periph;
29932df76c16SMatt Jacob 	struct cam_path	 	*path;
29942df76c16SMatt Jacob 	ispsoftc_t		*isp;
29952df76c16SMatt Jacob };
29962df76c16SMatt Jacob static periph_ctor_t	isptargctor;
29972df76c16SMatt Jacob static periph_dtor_t	isptargdtor;
29982df76c16SMatt Jacob static periph_start_t	isptargstart;
29992df76c16SMatt Jacob static periph_init_t	isptarginit;
30002df76c16SMatt Jacob static void		isptarg_done(struct cam_periph *, union ccb *);
30012df76c16SMatt Jacob static void		isptargasync(void *, u_int32_t, struct cam_path *, void *);
30022df76c16SMatt Jacob 
30032df76c16SMatt Jacob 
30042df76c16SMatt Jacob static int isptarg_rwparm(uint8_t *, uint8_t *, uint64_t, uint32_t, uint8_t **, uint32_t *, int *);
30052df76c16SMatt Jacob 
30062df76c16SMatt Jacob static struct periph_driver isptargdriver =
30072df76c16SMatt Jacob {
30082df76c16SMatt Jacob 	isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), /* generation */ 0
30092df76c16SMatt Jacob };
30102df76c16SMatt Jacob 
30112df76c16SMatt Jacob static void
30122df76c16SMatt Jacob isptarginit(void)
30132df76c16SMatt Jacob {
30142df76c16SMatt Jacob }
30152df76c16SMatt Jacob 
30162df76c16SMatt Jacob static void
30172df76c16SMatt Jacob isptargnotify(ispsoftc_t *isp, union ccb *iccb, struct ccb_immediate_notify *inot)
30182df76c16SMatt Jacob {
30192df76c16SMatt Jacob 	struct ccb_notify_acknowledge *ack = &iccb->cna2;
30202df76c16SMatt Jacob 
30212df76c16SMatt 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__,
30222df76c16SMatt Jacob 	    inot->tag_id, inot->initiator_id, inot->seq_id, inot->ccb_h.status, inot->arg);
30232df76c16SMatt Jacob 	ack->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE;
30242df76c16SMatt Jacob 	ack->ccb_h.flags = 0;
30252df76c16SMatt Jacob 	ack->ccb_h.retry_count = 0;
30262df76c16SMatt Jacob 	ack->ccb_h.cbfcnp = isptarg_done;
30272df76c16SMatt Jacob 	ack->ccb_h.timeout = 0;
30282df76c16SMatt Jacob 	ack->ccb_h.ccb_inot = inot;
30292df76c16SMatt Jacob 	ack->tag_id = inot->tag_id;
30302df76c16SMatt Jacob 	ack->seq_id = inot->seq_id;
30312df76c16SMatt Jacob 	ack->initiator_id = inot->initiator_id;
30322df76c16SMatt Jacob 	xpt_action(iccb);
30332df76c16SMatt Jacob }
30342df76c16SMatt Jacob 
30352df76c16SMatt Jacob static void
30362df76c16SMatt Jacob isptargstart(struct cam_periph *periph, union ccb *iccb)
30372df76c16SMatt Jacob {
30382df76c16SMatt Jacob 	const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = { 0x7f };
30392df76c16SMatt Jacob 	const uint8_t iqd[SHORT_INQUIRY_LENGTH] = {
30402df76c16SMatt Jacob 		0, 0x0, 0x2, 0x2, 32, 0, 0, 0x32,
30412df76c16SMatt Jacob 		'F', 'R', 'E', 'E', 'B', 'S', 'D', ' ',
30422df76c16SMatt Jacob 		'S', 'C', 'S', 'I', ' ', 'M', 'E', 'M',
30432df76c16SMatt Jacob 		'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
30442df76c16SMatt Jacob 		'0', '0', '0', '1'
30452df76c16SMatt Jacob 	};
30462df76c16SMatt Jacob 	int i, more = 0, last;
30472df76c16SMatt Jacob 	struct isptarg_softc *softc = periph->softc;
30482df76c16SMatt Jacob 	struct ccb_scsiio *csio;
30492df76c16SMatt Jacob 	lun_id_t return_lun;
30502df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
30512df76c16SMatt Jacob 	uint8_t *cdb, *ptr, status;
30522df76c16SMatt Jacob 	uint8_t *data_ptr;
30532df76c16SMatt Jacob 	uint32_t data_len, flags;
30542df76c16SMatt Jacob 	struct ccb_hdr *ccbh;
30552df76c16SMatt Jacob 
30562df76c16SMatt Jacob 	mtx_assert(periph->sim->mtx, MA_OWNED);
30572df76c16SMatt 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,
30582df76c16SMatt Jacob 	    TAILQ_FIRST(&softc->inot_queue)? 'y' : 'n', TAILQ_FIRST(&softc->work_queue)? 'y' : 'n', TAILQ_FIRST(&softc->rework_queue)? 'y' : 'n');
30592df76c16SMatt Jacob 	/*
30602df76c16SMatt Jacob 	 * Check for immediate notifies first
30612df76c16SMatt Jacob 	 */
30622df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->inot_queue);
30632df76c16SMatt Jacob 	if (ccbh) {
30642df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->inot_queue, ccbh, periph_links.tqe);
30652df76c16SMatt Jacob 		if (TAILQ_FIRST(&softc->inot_queue) || TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue)) {
30662df76c16SMatt Jacob 			xpt_schedule(periph, 1);
30672df76c16SMatt Jacob 		}
30682df76c16SMatt Jacob 		isptargnotify(softc->isp, iccb, (struct ccb_immediate_notify *)ccbh);
30692df76c16SMatt Jacob 		return;
30702df76c16SMatt Jacob 	}
30712df76c16SMatt Jacob 
30722df76c16SMatt Jacob 	/*
30732df76c16SMatt Jacob 	 * Check the rework (continuation) work queue first.
30742df76c16SMatt Jacob 	 */
30752df76c16SMatt Jacob 	ccbh = TAILQ_FIRST(&softc->rework_queue);
30762df76c16SMatt Jacob 	if (ccbh) {
30772df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
30782df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe);
30792df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue);
30802df76c16SMatt Jacob 	} else {
30812df76c16SMatt Jacob 		ccbh = TAILQ_FIRST(&softc->work_queue);
30822df76c16SMatt Jacob 		if (ccbh == NULL) {
30832df76c16SMatt Jacob 			ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, iccb->ccb_h.path, "%s: woken up but no work?\n", __func__);
30842df76c16SMatt Jacob 			xpt_release_ccb(iccb);
30852df76c16SMatt Jacob 			return;
30862df76c16SMatt Jacob 		}
30872df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *)ccbh;
30882df76c16SMatt Jacob 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
30892df76c16SMatt Jacob 		more = TAILQ_FIRST(&softc->work_queue) != NULL;
30902df76c16SMatt Jacob 		atio->ccb_h.ccb_data_offset = 0;
30912df76c16SMatt Jacob 	}
30922df76c16SMatt Jacob 
30932df76c16SMatt Jacob 	if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) {
30942df76c16SMatt Jacob 		panic("BAD ATIO");
30952df76c16SMatt Jacob 	}
30962df76c16SMatt Jacob 
30972df76c16SMatt Jacob 	data_ptr = NULL;
30982df76c16SMatt Jacob 	data_len = 0;
30992df76c16SMatt Jacob 	csio = &iccb->csio;
31002df76c16SMatt Jacob 	status = SCSI_STATUS_OK;
31012df76c16SMatt Jacob 	flags = CAM_SEND_STATUS;
31022df76c16SMatt Jacob 	memset(&atio->sense_data, 0, sizeof (atio->sense_data));
31032df76c16SMatt Jacob 	cdb = atio->cdb_io.cdb_bytes;
31042df76c16SMatt 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,
31052df76c16SMatt Jacob 	    cdb[0], atio->ccb_h.ccb_data_offset);
31062df76c16SMatt Jacob 
31072df76c16SMatt Jacob 	return_lun = XS_LUN(atio);
31082df76c16SMatt Jacob 	if (return_lun != 0) {
31092df76c16SMatt Jacob 		xpt_print(atio->ccb_h.path, "[0x%x] Non-Zero Lun %d: cdb0=0x%x\n", atio->tag_id, return_lun, cdb[0]);
31102df76c16SMatt Jacob 		if (cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
31112df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31122df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_ILLEGAL_REQUEST;
31132df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x25;
31142df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x0;
31152df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31162df76c16SMatt Jacob 		}
31172df76c16SMatt Jacob 		return_lun = CAM_LUN_WILDCARD;
31182df76c16SMatt Jacob 	}
31192df76c16SMatt Jacob 
31202df76c16SMatt Jacob 	switch (cdb[0]) {
31212df76c16SMatt Jacob 	case REQUEST_SENSE:
31222df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
31232df76c16SMatt Jacob 		data_len = sizeof (atio->sense_data);
31242df76c16SMatt Jacob 		junk_data[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_NO_SENSE;
31252df76c16SMatt Jacob 		memset(junk_data+1, 0, data_len-1);
31262df76c16SMatt Jacob 		if (data_len > cdb[4]) {
31272df76c16SMatt Jacob 			data_len = cdb[4];
31282df76c16SMatt Jacob 		}
31292df76c16SMatt Jacob 		if (data_len) {
31302df76c16SMatt Jacob 			data_ptr = junk_data;
31312df76c16SMatt Jacob 		}
31322df76c16SMatt Jacob 		break;
31332df76c16SMatt Jacob 	case READ_6:
31342df76c16SMatt Jacob 	case READ_10:
31352df76c16SMatt Jacob 	case READ_12:
31362df76c16SMatt Jacob 	case READ_16:
31372df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
31382df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31392df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
31402df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
31412df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
31422df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31432df76c16SMatt Jacob 		} else {
31442df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
31452df76c16SMatt Jacob 			{
31462df76c16SMatt Jacob 				static int foo;
31472df76c16SMatt Jacob 				if (foo++ == 500) {
31482df76c16SMatt Jacob 					if (more) {
31492df76c16SMatt Jacob 						xpt_schedule(periph, 1);
31502df76c16SMatt Jacob 					}
31512df76c16SMatt Jacob 					foo = 0;
31522df76c16SMatt Jacob 					return;
31532df76c16SMatt Jacob 				}
31542df76c16SMatt Jacob 			}
31552df76c16SMatt Jacob #endif
31562df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
31572df76c16SMatt Jacob 			if (last && data_len) {
31582df76c16SMatt Jacob 				last = 0;
31592df76c16SMatt Jacob 			}
31602df76c16SMatt Jacob #endif
31612df76c16SMatt Jacob 			if (last == 0) {
31622df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
31632df76c16SMatt Jacob 			}
31642df76c16SMatt Jacob 			if (data_len) {
31652df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
31662df76c16SMatt Jacob 				flags |= CAM_DIR_IN;
31672df76c16SMatt Jacob 			} else {
31682df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
31692df76c16SMatt Jacob 			}
31702df76c16SMatt Jacob 		}
31712df76c16SMatt Jacob 		break;
31722df76c16SMatt Jacob 	case WRITE_6:
31732df76c16SMatt Jacob 	case WRITE_10:
31742df76c16SMatt Jacob 	case WRITE_12:
31752df76c16SMatt Jacob 	case WRITE_16:
31762df76c16SMatt Jacob 		if (isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last)) {
31772df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
31782df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
31792df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
31802df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
31812df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
31822df76c16SMatt Jacob 		} else {
31832df76c16SMatt Jacob #ifdef	ISP_FORCE_TIMEOUT
31842df76c16SMatt Jacob 			{
31852df76c16SMatt Jacob 				static int foo;
31862df76c16SMatt Jacob 				if (foo++ == 500) {
31872df76c16SMatt Jacob 					if (more) {
31882df76c16SMatt Jacob 						xpt_schedule(periph, 1);
31892df76c16SMatt Jacob 					}
31902df76c16SMatt Jacob 					foo = 0;
31912df76c16SMatt Jacob 					return;
31922df76c16SMatt Jacob 				}
31932df76c16SMatt Jacob 			}
31942df76c16SMatt Jacob #endif
31952df76c16SMatt Jacob #ifdef	ISP_TEST_SEPARATE_STATUS
31962df76c16SMatt Jacob 			if (last && data_len) {
31972df76c16SMatt Jacob 				last = 0;
31982df76c16SMatt Jacob 			}
31992df76c16SMatt Jacob #endif
32002df76c16SMatt Jacob 			if (last == 0) {
32012df76c16SMatt Jacob 				flags &= ~CAM_SEND_STATUS;
32022df76c16SMatt Jacob 			}
32032df76c16SMatt Jacob 			if (data_len) {
32042df76c16SMatt Jacob 				atio->ccb_h.ccb_data_offset += data_len;
32052df76c16SMatt Jacob 				flags |= CAM_DIR_OUT;
32062df76c16SMatt Jacob 			} else {
32072df76c16SMatt Jacob 				flags |= CAM_DIR_NONE;
32082df76c16SMatt Jacob 			}
32092df76c16SMatt Jacob 		}
32102df76c16SMatt Jacob 		break;
32112df76c16SMatt Jacob 	case INQUIRY:
32122df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32132df76c16SMatt Jacob 		if (cdb[1] || cdb[2] || cdb[3]) {
32142df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32152df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32162df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
32172df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x20;
32182df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32192df76c16SMatt Jacob 			break;
32202df76c16SMatt Jacob 		}
32212df76c16SMatt Jacob 		data_len = sizeof (iqd);
32222df76c16SMatt Jacob 		if (data_len > cdb[4]) {
32232df76c16SMatt Jacob 			data_len = cdb[4];
32242df76c16SMatt Jacob 		}
32252df76c16SMatt Jacob 		if (data_len) {
32262df76c16SMatt Jacob 			if (XS_LUN(iccb) != 0) {
32272df76c16SMatt Jacob 				memcpy(junk_data, niliqd, sizeof (iqd));
32282df76c16SMatt Jacob 			} else {
32292df76c16SMatt Jacob 				memcpy(junk_data, iqd, sizeof (iqd));
32302df76c16SMatt Jacob 			}
32312df76c16SMatt Jacob 			data_ptr = junk_data;
32322df76c16SMatt Jacob 		}
32332df76c16SMatt Jacob 		break;
32342df76c16SMatt Jacob 	case TEST_UNIT_READY:
32352df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
32362df76c16SMatt Jacob 		if (ca) {
32372df76c16SMatt Jacob 			ca = 0;
32382df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32392df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32402df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x28;
32412df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x0;
32422df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32432df76c16SMatt Jacob 		}
32442df76c16SMatt Jacob 		break;
32452df76c16SMatt Jacob 	case SYNCHRONIZE_CACHE:
32462df76c16SMatt Jacob 	case START_STOP:
32472df76c16SMatt Jacob 	case RESERVE:
32482df76c16SMatt Jacob 	case RELEASE:
32492df76c16SMatt Jacob 	case VERIFY_10:
32502df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
32512df76c16SMatt Jacob 		break;
32522df76c16SMatt Jacob 
32532df76c16SMatt Jacob 	case READ_CAPACITY:
32542df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32552df76c16SMatt Jacob 		if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
32562df76c16SMatt Jacob 			status = SCSI_STATUS_CHECK_COND;
32572df76c16SMatt Jacob 			atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
32582df76c16SMatt Jacob 			atio->sense_data.add_sense_code = 0x5;
32592df76c16SMatt Jacob 			atio->sense_data.add_sense_code_qual = 0x24;
32602df76c16SMatt Jacob 			atio->sense_len = sizeof (atio->sense_data);
32612df76c16SMatt Jacob 			break;
32622df76c16SMatt Jacob 		}
32632df76c16SMatt Jacob 		if (cdb[8] & 0x1) { /* PMI */
32642df76c16SMatt Jacob 			junk_data[0] = 0xff;
32652df76c16SMatt Jacob 			junk_data[1] = 0xff;
32662df76c16SMatt Jacob 			junk_data[2] = 0xff;
32672df76c16SMatt Jacob 			junk_data[3] = 0xff;
32682df76c16SMatt Jacob 		} else {
32692df76c16SMatt Jacob 			uint64_t last_blk = (disk_size >> DISK_SHIFT) - 1;
32702df76c16SMatt Jacob 			if (last_blk < 0xffffffffULL) {
32712df76c16SMatt Jacob 			    junk_data[0] = (last_blk >> 24) & 0xff;
32722df76c16SMatt Jacob 			    junk_data[1] = (last_blk >> 16) & 0xff;
32732df76c16SMatt Jacob 			    junk_data[2] = (last_blk >>  8) & 0xff;
32742df76c16SMatt Jacob 			    junk_data[3] = (last_blk) & 0xff;
32752df76c16SMatt Jacob 			} else {
32762df76c16SMatt Jacob 			    junk_data[0] = 0xff;
32772df76c16SMatt Jacob 			    junk_data[1] = 0xff;
32782df76c16SMatt Jacob 			    junk_data[2] = 0xff;
32792df76c16SMatt Jacob 			    junk_data[3] = 0xff;
32802df76c16SMatt Jacob 			}
32812df76c16SMatt Jacob 		}
32822df76c16SMatt Jacob 		junk_data[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
32832df76c16SMatt Jacob 		junk_data[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
32842df76c16SMatt Jacob 		junk_data[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
32852df76c16SMatt Jacob 		junk_data[7] = ((1 << DISK_SHIFT)) & 0xff;
32862df76c16SMatt Jacob 		data_ptr = junk_data;
32872df76c16SMatt Jacob 		data_len = 8;
32882df76c16SMatt Jacob 		break;
32892df76c16SMatt Jacob 	case REPORT_LUNS:
32902df76c16SMatt Jacob 		flags |= CAM_DIR_IN;
32912df76c16SMatt Jacob 		memset(junk_data, 0, JUNK_SIZE);
32922df76c16SMatt Jacob 		junk_data[0] = (1 << 3) >> 24;
32932df76c16SMatt Jacob 		junk_data[1] = (1 << 3) >> 16;
32942df76c16SMatt Jacob 		junk_data[2] = (1 << 3) >> 8;
32952df76c16SMatt Jacob 		junk_data[3] = (1 << 3);
32962df76c16SMatt Jacob 		ptr = NULL;
32972df76c16SMatt Jacob 		for (i = 0; i < 1; i++) {
32982df76c16SMatt Jacob 			ptr = &junk_data[8 + (1 << 3)];
32992df76c16SMatt Jacob 			if (i >= 256) {
33002df76c16SMatt Jacob 				ptr[0] = 0x40 | ((i >> 8) & 0x3f);
33012df76c16SMatt Jacob 			}
33022df76c16SMatt Jacob 			ptr[1] = i;
33032df76c16SMatt Jacob 		}
33042df76c16SMatt Jacob 		data_ptr = junk_data;
33052df76c16SMatt Jacob 		data_len = (ptr + 8) - junk_data;
33062df76c16SMatt Jacob 		break;
33072df76c16SMatt Jacob 
33082df76c16SMatt Jacob 	default:
33092df76c16SMatt Jacob 		flags |= CAM_DIR_NONE;
33102df76c16SMatt Jacob 		status = SCSI_STATUS_CHECK_COND;
33112df76c16SMatt Jacob 		atio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR|SSD_KEY_UNIT_ATTENTION;
33122df76c16SMatt Jacob 		atio->sense_data.add_sense_code = 0x5;
33132df76c16SMatt Jacob 		atio->sense_data.add_sense_code_qual = 0x20;
33142df76c16SMatt Jacob 		atio->sense_len = sizeof (atio->sense_data);
33152df76c16SMatt Jacob 		break;
33162df76c16SMatt Jacob 	}
33172df76c16SMatt Jacob 
33182df76c16SMatt Jacob 	/*
33192df76c16SMatt Jacob 	 * If we are done with the transaction, tell the
33202df76c16SMatt Jacob 	 * controller to send status and perform a CMD_CMPLT.
33212df76c16SMatt Jacob 	 * If we have associated sense data, see if we can
33222df76c16SMatt Jacob 	 * send that too.
33232df76c16SMatt Jacob 	 */
33242df76c16SMatt Jacob 	if (status == SCSI_STATUS_CHECK_COND) {
33252df76c16SMatt Jacob 		flags |= CAM_SEND_SENSE;
33262df76c16SMatt Jacob 		csio->sense_len = atio->sense_len;
33272df76c16SMatt Jacob 		csio->sense_data = atio->sense_data;
33282df76c16SMatt Jacob 		flags &= ~CAM_DIR_MASK;
33292df76c16SMatt Jacob 		data_len = 0;
33302df76c16SMatt Jacob 		data_ptr = NULL;
33312df76c16SMatt Jacob 	}
33322df76c16SMatt 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);
33332df76c16SMatt Jacob 	iccb->ccb_h.target_id = atio->ccb_h.target_id;
33342df76c16SMatt Jacob 	iccb->ccb_h.target_lun = return_lun;
33352df76c16SMatt Jacob 	iccb->ccb_h.ccb_atio = atio;
33362df76c16SMatt Jacob 	xpt_action(iccb);
33372df76c16SMatt Jacob 
33382df76c16SMatt Jacob 	if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
33392df76c16SMatt Jacob 		cam_release_devq(periph->path, 0, 0, 0, 0);
33402df76c16SMatt Jacob 		atio->ccb_h.status &= ~CAM_DEV_QFRZN;
33412df76c16SMatt Jacob 	}
33422df76c16SMatt Jacob 	if (more) {
33432df76c16SMatt Jacob 		xpt_schedule(periph, 1);
33442df76c16SMatt Jacob 	}
33452df76c16SMatt Jacob }
33462df76c16SMatt Jacob 
33472df76c16SMatt Jacob static cam_status
33482df76c16SMatt Jacob isptargctor(struct cam_periph *periph, void *arg)
33492df76c16SMatt Jacob {
33502df76c16SMatt Jacob 	struct isptarg_softc *softc;
33512df76c16SMatt Jacob 
33522df76c16SMatt Jacob 	softc = (struct isptarg_softc *)arg;
33532df76c16SMatt Jacob 	periph->softc = softc;
33542df76c16SMatt Jacob 	softc->periph = periph;
33552df76c16SMatt Jacob 	softc->path = periph->path;
33562df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
33572df76c16SMatt Jacob 	return (CAM_REQ_CMP);
33582df76c16SMatt Jacob }
33592df76c16SMatt Jacob 
33602df76c16SMatt Jacob static void
33612df76c16SMatt Jacob isptargdtor(struct cam_periph *periph)
33622df76c16SMatt Jacob {
33632df76c16SMatt Jacob 	struct isptarg_softc *softc;
33642df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
33652df76c16SMatt Jacob 	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, periph->path, "%s called\n", __func__);
33662df76c16SMatt Jacob 	softc->periph = NULL;
33672df76c16SMatt Jacob 	softc->path = NULL;
33682df76c16SMatt Jacob 	periph->softc = NULL;
33692df76c16SMatt Jacob }
33702df76c16SMatt Jacob 
33712df76c16SMatt Jacob static void
33722df76c16SMatt Jacob isptarg_done(struct cam_periph *periph, union ccb *ccb)
33732df76c16SMatt Jacob {
33742df76c16SMatt Jacob 	struct isptarg_softc *softc;
33752df76c16SMatt Jacob 	ispsoftc_t *isp;
33762df76c16SMatt Jacob 	struct ccb_accept_tio *atio;
33772df76c16SMatt Jacob 	struct ccb_immediate_notify *inot;
33782df76c16SMatt Jacob 	cam_status status;
33792df76c16SMatt Jacob 
33802df76c16SMatt Jacob 	softc = (struct isptarg_softc *)periph->softc;
33812df76c16SMatt Jacob 	isp = softc->isp;
33822df76c16SMatt Jacob 	status = ccb->ccb_h.status & CAM_STATUS_MASK;
33832df76c16SMatt Jacob 
33842df76c16SMatt Jacob 	switch (ccb->ccb_h.func_code) {
33852df76c16SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:
33862df76c16SMatt Jacob 		atio = (struct ccb_accept_tio *) ccb;
33872df76c16SMatt Jacob 		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__);
33882df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe);
33892df76c16SMatt Jacob 		xpt_schedule(periph, 1);
33902df76c16SMatt Jacob 		break;
33912df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:
33922df76c16SMatt Jacob 		inot = (struct ccb_immediate_notify *) ccb;
33932df76c16SMatt 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__);
33942df76c16SMatt Jacob 		TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe);
33952df76c16SMatt Jacob 		xpt_schedule(periph, 1);
33962df76c16SMatt Jacob 		break;
33972df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
33982df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
33992df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
34002df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
34012df76c16SMatt Jacob 		}
34022df76c16SMatt Jacob 		atio = ccb->ccb_h.ccb_atio;
34032df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
34042df76c16SMatt Jacob 			cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
34052df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
34062df76c16SMatt Jacob 		} else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
34072df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO seen in %s\n", atio->tag_id, __func__);
34082df76c16SMatt Jacob 			TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe);
34092df76c16SMatt Jacob 			xpt_schedule(periph, 1);
34102df76c16SMatt Jacob 		} else {
34112df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO seen in %s\n", atio->tag_id, __func__);
34122df76c16SMatt Jacob 			xpt_action((union ccb *)atio);
34132df76c16SMatt Jacob 		}
34142df76c16SMatt Jacob 		xpt_release_ccb(ccb);
34152df76c16SMatt Jacob 		break;
34162df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:
34172df76c16SMatt Jacob 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
34182df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
34192df76c16SMatt Jacob 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
34202df76c16SMatt Jacob 		}
34212df76c16SMatt Jacob 		inot = ccb->ccb_h.ccb_inot;
34222df76c16SMatt 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);
34232df76c16SMatt Jacob 		xpt_release_ccb(ccb);
34242df76c16SMatt Jacob 		xpt_action((union ccb *)inot);
34252df76c16SMatt Jacob 		break;
34262df76c16SMatt Jacob 	default:
34272df76c16SMatt Jacob 		xpt_print(ccb->ccb_h.path, "unexpected code 0x%x\n", ccb->ccb_h.func_code);
34282df76c16SMatt Jacob 		break;
34292df76c16SMatt Jacob 	}
34302df76c16SMatt Jacob }
34312df76c16SMatt Jacob 
34322df76c16SMatt Jacob static void
34332df76c16SMatt Jacob isptargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
34342df76c16SMatt Jacob {
34352df76c16SMatt Jacob 	struct ac_contract *acp = arg;
34362df76c16SMatt Jacob 	struct ac_device_changed *fc = (struct ac_device_changed *) acp->contract_data;
34372df76c16SMatt Jacob 
34382df76c16SMatt Jacob 	if (code != AC_CONTRACT) {
34392df76c16SMatt Jacob 		return;
34402df76c16SMatt Jacob 	}
34412df76c16SMatt Jacob 	xpt_print(path, "0x%016llx Port ID 0x%06x %s\n", (unsigned long long) fc->wwpn, fc->port, fc->arrived? "arrived" : "departed");
34422df76c16SMatt Jacob }
34432df76c16SMatt Jacob 
34442df76c16SMatt Jacob static void
34452df76c16SMatt Jacob isp_target_thread(ispsoftc_t *isp, int chan)
34462df76c16SMatt Jacob {
34472df76c16SMatt Jacob 	union ccb *ccb = NULL;
34482df76c16SMatt Jacob 	int i;
34492df76c16SMatt Jacob 	void *wchan;
34502df76c16SMatt Jacob 	cam_status status;
34512df76c16SMatt Jacob 	struct isptarg_softc *softc = NULL;
34522df76c16SMatt Jacob 	struct cam_periph *periph = NULL, *wperiph = NULL;
34532df76c16SMatt Jacob 	struct cam_path *path, *wpath;
34542df76c16SMatt Jacob 	struct cam_sim *sim;
34552df76c16SMatt Jacob 
34562df76c16SMatt Jacob 	if (disk_data == NULL) {
34572df76c16SMatt Jacob 		disk_size = roundup2(vm_kmem_size >> 1, (1ULL << 20));
34582df76c16SMatt Jacob 		if (disk_size < (50 << 20)) {
34592df76c16SMatt Jacob 			disk_size = 50 << 20;
34602df76c16SMatt Jacob 		}
34612df76c16SMatt Jacob 		disk_data = malloc(disk_size, M_ISPTARG, M_WAITOK | M_ZERO);
34622df76c16SMatt Jacob 		if (disk_data == NULL) {
34632df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "%s: could not allocate disk data", __func__);
34642df76c16SMatt Jacob 			goto out;
34652df76c16SMatt Jacob 		}
34662df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "allocated a %ju MiB disk", (uintmax_t) (disk_size >> 20));
34672df76c16SMatt Jacob 	}
34682df76c16SMatt Jacob 	junk_data = malloc(JUNK_SIZE, M_ISPTARG, M_WAITOK | M_ZERO);
34692df76c16SMatt Jacob 	if (junk_data == NULL) {
34702df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate junk", __func__);
34712df76c16SMatt Jacob 		goto out;
34722df76c16SMatt Jacob 	}
34732df76c16SMatt Jacob 
34742df76c16SMatt Jacob 
34752df76c16SMatt Jacob 	softc = malloc(sizeof (*softc), M_ISPTARG, M_WAITOK | M_ZERO);
34762df76c16SMatt Jacob 	if (softc == NULL) {
34772df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate softc", __func__);
34782df76c16SMatt Jacob 		goto out;
34792df76c16SMatt Jacob 	}
34802df76c16SMatt Jacob 	TAILQ_INIT(&softc->work_queue);
34812df76c16SMatt Jacob 	TAILQ_INIT(&softc->rework_queue);
34822df76c16SMatt Jacob 	TAILQ_INIT(&softc->running_queue);
34832df76c16SMatt Jacob 	TAILQ_INIT(&softc->inot_queue);
34842df76c16SMatt Jacob 	softc->isp = isp;
34852df76c16SMatt Jacob 
34862df76c16SMatt Jacob 	periphdriver_register(&isptargdriver);
34872df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, sim, sim);
34882df76c16SMatt Jacob 	ISP_GET_PC(isp, chan, path,  path);
34892df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&wpath, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
34902df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
34912df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate wildcard path", __func__);
34922df76c16SMatt Jacob 		return;
34932df76c16SMatt Jacob 	}
34942df76c16SMatt Jacob 	status = xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), 0, 0);
34952df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
34962df76c16SMatt Jacob 		xpt_free_path(wpath);
34972df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: could not allocate path", __func__);
34982df76c16SMatt Jacob 		return;
34992df76c16SMatt Jacob 	}
35002df76c16SMatt Jacob 
35012df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
35022df76c16SMatt Jacob 
35032df76c16SMatt Jacob 	ISP_LOCK(isp);
35042df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, wpath, NULL, 0, softc);
35052df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35062df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35072df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc for wildcard failed", __func__);
35082df76c16SMatt Jacob 		goto out;
35092df76c16SMatt Jacob 	}
35102df76c16SMatt Jacob 	wperiph = cam_periph_find(wpath, "isptarg");
35112df76c16SMatt Jacob 	if (wperiph == NULL) {
35122df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35132df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: wildcard periph already allocated but doesn't exist", __func__);
35142df76c16SMatt Jacob 		goto out;
35152df76c16SMatt Jacob 	}
35162df76c16SMatt Jacob 
35172df76c16SMatt Jacob 	status = cam_periph_alloc(isptargctor, NULL, isptargdtor, isptargstart, "isptarg", CAM_PERIPH_BIO, path, NULL, 0, softc);
35182df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35192df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35202df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: cam_periph_alloc failed", __func__);
35212df76c16SMatt Jacob 		goto out;
35222df76c16SMatt Jacob 	}
35232df76c16SMatt Jacob 
35242df76c16SMatt Jacob 	periph = cam_periph_find(path, "isptarg");
35252df76c16SMatt Jacob 	if (periph == NULL) {
35262df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35272df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: periph already allocated but doesn't exist", __func__);
35282df76c16SMatt Jacob 		goto out;
35292df76c16SMatt Jacob 	}
35302df76c16SMatt Jacob 
35312df76c16SMatt Jacob 	status = xpt_register_async(AC_CONTRACT, isptargasync, isp, wpath);
35322df76c16SMatt Jacob 	if (status != CAM_REQ_CMP) {
35332df76c16SMatt Jacob 		ISP_UNLOCK(isp);
35342df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: xpt_register_async failed", __func__);
35352df76c16SMatt Jacob 		goto out;
35362df76c16SMatt Jacob 	}
35372df76c16SMatt Jacob 
35382df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35392df76c16SMatt Jacob 
35402df76c16SMatt Jacob 	ccb = xpt_alloc_ccb();
35412df76c16SMatt Jacob 
35422df76c16SMatt Jacob 	/*
35432df76c16SMatt Jacob 	 * Make sure role is none.
35442df76c16SMatt Jacob 	 */
35452df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
35462df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
35472df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE;
35482df76c16SMatt Jacob #ifdef	ISP_TEST_WWNS
35492df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE | KNOB_VALID_ADDRESS;
35502df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwnn = 0x508004d000000000ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
35512df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.wwpn = 0x508004d000000001ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
35522df76c16SMatt Jacob #else
35532df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
35542df76c16SMatt Jacob #endif
35552df76c16SMatt Jacob 
35562df76c16SMatt Jacob 	ISP_LOCK(isp);
35572df76c16SMatt Jacob 	xpt_action(ccb);
35582df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35592df76c16SMatt Jacob 
35602df76c16SMatt Jacob 	/*
35612df76c16SMatt Jacob 	 * Now enable luns
35622df76c16SMatt Jacob 	 */
35632df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
35642df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
35652df76c16SMatt Jacob 	ccb->cel.enable = 1;
35662df76c16SMatt Jacob 	ISP_LOCK(isp);
35672df76c16SMatt Jacob 	xpt_action(ccb);
35682df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35692df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
35702df76c16SMatt Jacob 		xpt_free_ccb(ccb);
35712df76c16SMatt Jacob 		xpt_print(periph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
35722df76c16SMatt Jacob 		goto out;
35732df76c16SMatt Jacob 	}
35742df76c16SMatt Jacob 
35752df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 10);
35762df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_EN_LUN;
35772df76c16SMatt Jacob 	ccb->cel.enable = 1;
35782df76c16SMatt Jacob 	ISP_LOCK(isp);
35792df76c16SMatt Jacob 	xpt_action(ccb);
35802df76c16SMatt Jacob 	ISP_UNLOCK(isp);
35812df76c16SMatt Jacob 	if (ccb->ccb_h.status != CAM_REQ_CMP) {
35822df76c16SMatt Jacob 		xpt_free_ccb(ccb);
35832df76c16SMatt Jacob 		xpt_print(wperiph->path, "failed to enable lun (0x%x)\n", ccb->ccb_h.status);
35842df76c16SMatt Jacob 		goto out;
35852df76c16SMatt Jacob 	}
35862df76c16SMatt Jacob 	xpt_free_ccb(ccb);
35872df76c16SMatt Jacob 
35882df76c16SMatt Jacob 	/*
35892df76c16SMatt Jacob 	 * Add resources
35902df76c16SMatt Jacob 	 */
35912df76c16SMatt Jacob 	ISP_GET_PC_ADDR(isp, chan, target_proc, wchan);
35922df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
35932df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
35942df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
35952df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
35962df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
35972df76c16SMatt Jacob 		ISP_LOCK(isp);
35982df76c16SMatt Jacob 		xpt_action(ccb);
35992df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36002df76c16SMatt Jacob 	}
36012df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_CMDS; i++) {
36022df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36032df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
36042df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
36052df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36062df76c16SMatt Jacob 		ISP_LOCK(isp);
36072df76c16SMatt Jacob 		xpt_action(ccb);
36082df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36092df76c16SMatt Jacob 	}
36102df76c16SMatt Jacob 	for (i = 0; i < 4; i++) {
36112df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36122df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
36132df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
36142df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36152df76c16SMatt Jacob 		ISP_LOCK(isp);
36162df76c16SMatt Jacob 		xpt_action(ccb);
36172df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36182df76c16SMatt Jacob 	}
36192df76c16SMatt Jacob 	for (i = 0; i < NISP_TARG_NOTIFIES; i++) {
36202df76c16SMatt Jacob 		ccb = malloc(sizeof (*ccb), M_ISPTARG, M_WAITOK | M_ZERO);
36212df76c16SMatt Jacob 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
36222df76c16SMatt Jacob 		ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
36232df76c16SMatt Jacob 		ccb->ccb_h.cbfcnp = isptarg_done;
36242df76c16SMatt Jacob 		ISP_LOCK(isp);
36252df76c16SMatt Jacob 		xpt_action(ccb);
36262df76c16SMatt Jacob 		ISP_UNLOCK(isp);
36272df76c16SMatt Jacob 	}
36282df76c16SMatt Jacob 
36292df76c16SMatt Jacob 	/*
36302df76c16SMatt Jacob 	 * Now turn it all back on
36312df76c16SMatt Jacob 	 */
36322df76c16SMatt Jacob 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
36332df76c16SMatt Jacob 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
36342df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
36352df76c16SMatt Jacob 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_TARGET;
36362df76c16SMatt Jacob 	ISP_LOCK(isp);
36372df76c16SMatt Jacob 	xpt_action(ccb);
36382df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36392df76c16SMatt Jacob 
36402df76c16SMatt Jacob 	/*
36412df76c16SMatt Jacob 	 * Okay, while things are still active, sleep...
36422df76c16SMatt Jacob 	 */
36432df76c16SMatt Jacob 	ISP_LOCK(isp);
36442df76c16SMatt Jacob 	for (;;) {
36452df76c16SMatt Jacob 		ISP_GET_PC(isp, chan, proc_active, i);
36462df76c16SMatt Jacob 		if (i == 0) {
36472df76c16SMatt Jacob 			break;
36482df76c16SMatt Jacob 		}
36492df76c16SMatt Jacob 		msleep(wchan, &isp->isp_lock, PUSER, "tsnooze", 0);
36502df76c16SMatt Jacob 	}
36512df76c16SMatt Jacob 	ISP_UNLOCK(isp);
36522df76c16SMatt Jacob 
36532df76c16SMatt Jacob out:
36542df76c16SMatt Jacob 	if (wperiph) {
36552df76c16SMatt Jacob 		cam_periph_invalidate(wperiph);
36562df76c16SMatt Jacob 	}
36572df76c16SMatt Jacob 	if (periph) {
36582df76c16SMatt Jacob 		cam_periph_invalidate(periph);
36592df76c16SMatt Jacob 	}
36602df76c16SMatt Jacob 	if (junk_data) {
36612df76c16SMatt Jacob 		free(junk_data, M_ISPTARG);
36622df76c16SMatt Jacob 	}
36632df76c16SMatt Jacob 	if (disk_data) {
36642df76c16SMatt Jacob 		free(disk_data, M_ISPTARG);
36652df76c16SMatt Jacob 	}
36662df76c16SMatt Jacob 	if (softc) {
36672df76c16SMatt Jacob 		free(softc, M_ISPTARG);
36682df76c16SMatt Jacob 	}
36692df76c16SMatt Jacob 	xpt_free_path(path);
36702df76c16SMatt Jacob 	xpt_free_path(wpath);
36712df76c16SMatt Jacob }
36722df76c16SMatt Jacob 
36732df76c16SMatt Jacob static void
36742df76c16SMatt Jacob isp_target_thread_pi(void *arg)
36752df76c16SMatt Jacob {
36762df76c16SMatt Jacob 	struct isp_spi *pi = arg;
36772df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(pi->sim), cam_sim_bus(pi->sim));
36782df76c16SMatt Jacob }
36792df76c16SMatt Jacob 
36802df76c16SMatt Jacob static void
36812df76c16SMatt Jacob isp_target_thread_fc(void *arg)
36822df76c16SMatt Jacob {
36832df76c16SMatt Jacob 	struct isp_fc *fc = arg;
36842df76c16SMatt Jacob 	isp_target_thread(cam_sim_softc(fc->sim), cam_sim_bus(fc->sim));
36852df76c16SMatt Jacob }
36862df76c16SMatt Jacob 
36872df76c16SMatt Jacob static int
36882df76c16SMatt Jacob isptarg_rwparm(uint8_t *cdb, uint8_t *dp, uint64_t dl, uint32_t offset, uint8_t **kp, uint32_t *tl, int *lp)
36892df76c16SMatt Jacob {
36902df76c16SMatt Jacob 	uint32_t cnt, curcnt;
36912df76c16SMatt Jacob 	uint64_t lba;
36922df76c16SMatt Jacob 
36932df76c16SMatt Jacob 	switch (cdb[0]) {
36942df76c16SMatt Jacob 	case WRITE_16:
36952df76c16SMatt Jacob 	case READ_16:
36962df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[10]) <<  24) |
36972df76c16SMatt Jacob 			(((uint32_t)cdb[11]) <<  16) |
36982df76c16SMatt Jacob 			(((uint32_t)cdb[12]) <<   8) |
36992df76c16SMatt Jacob 			((uint32_t)cdb[13]);
37002df76c16SMatt Jacob 
37012df76c16SMatt Jacob 		lba =	(((uint64_t)cdb[2]) << 56) |
37022df76c16SMatt Jacob 			(((uint64_t)cdb[3]) << 48) |
37032df76c16SMatt Jacob 			(((uint64_t)cdb[4]) << 40) |
37042df76c16SMatt Jacob 			(((uint64_t)cdb[5]) << 32) |
37052df76c16SMatt Jacob 			(((uint64_t)cdb[6]) << 24) |
37062df76c16SMatt Jacob 			(((uint64_t)cdb[7]) << 16) |
37072df76c16SMatt Jacob 			(((uint64_t)cdb[8]) <<  8) |
37082df76c16SMatt Jacob 			((uint64_t)cdb[9]);
37092df76c16SMatt Jacob 		break;
37102df76c16SMatt Jacob 	case WRITE_12:
37112df76c16SMatt Jacob 	case READ_12:
37122df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[6]) <<  16) |
37132df76c16SMatt Jacob 			(((uint32_t)cdb[7]) <<   8) |
37142df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
37152df76c16SMatt Jacob 
37162df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
37172df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
37182df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
37192df76c16SMatt Jacob 			((uint32_t)cdb[5]);
37202df76c16SMatt Jacob 		break;
37212df76c16SMatt Jacob 	case WRITE_10:
37222df76c16SMatt Jacob 	case READ_10:
37232df76c16SMatt Jacob 		cnt =	(((uint32_t)cdb[7]) <<  8) |
37242df76c16SMatt Jacob 			((u_int32_t)cdb[8]);
37252df76c16SMatt Jacob 
37262df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[2]) << 24) |
37272df76c16SMatt Jacob 			(((uint32_t)cdb[3]) << 16) |
37282df76c16SMatt Jacob 			(((uint32_t)cdb[4]) <<  8) |
37292df76c16SMatt Jacob 			((uint32_t)cdb[5]);
37302df76c16SMatt Jacob 		break;
37312df76c16SMatt Jacob 	case WRITE_6:
37322df76c16SMatt Jacob 	case READ_6:
37332df76c16SMatt Jacob 		cnt = cdb[4];
37342df76c16SMatt Jacob 		if (cnt == 0) {
37352df76c16SMatt Jacob 			cnt = 256;
37362df76c16SMatt Jacob 		}
37372df76c16SMatt Jacob 		lba =	(((uint32_t)cdb[1] & 0x1f) << 16) |
37382df76c16SMatt Jacob 			(((uint32_t)cdb[2]) << 8) |
37392df76c16SMatt Jacob 			((uint32_t)cdb[3]);
37402df76c16SMatt Jacob 		break;
37412df76c16SMatt Jacob 	default:
37422df76c16SMatt Jacob 		return (-1);
37432df76c16SMatt Jacob 	}
37442df76c16SMatt Jacob 
37452df76c16SMatt Jacob 	cnt <<= DISK_SHIFT;
37462df76c16SMatt Jacob 	lba <<= DISK_SHIFT;
37472df76c16SMatt Jacob 
37482df76c16SMatt Jacob 	if (offset == cnt) {
37492df76c16SMatt Jacob 		*lp = 1;
37502df76c16SMatt Jacob 		return (0);
37512df76c16SMatt Jacob 	}
37522df76c16SMatt Jacob 
37532df76c16SMatt Jacob 	if (lba + cnt > dl) {
37542df76c16SMatt Jacob 		return (-1);
37552df76c16SMatt Jacob 	}
37562df76c16SMatt Jacob 
37572df76c16SMatt Jacob 
37582df76c16SMatt Jacob 	curcnt = MAX_ISP_TARG_TRANSFER;
37592df76c16SMatt Jacob 	if (offset + curcnt >= cnt) {
37602df76c16SMatt Jacob 		curcnt = cnt - offset;
37612df76c16SMatt Jacob 		*lp = 1;
37622df76c16SMatt Jacob 	} else {
37632df76c16SMatt Jacob 		*lp = 0;
37642df76c16SMatt Jacob 	}
37652df76c16SMatt Jacob 	*tl = curcnt;
37662df76c16SMatt Jacob 	*kp = &dp[lba + offset];
37672df76c16SMatt Jacob 	return (0);
37682df76c16SMatt Jacob }
37692df76c16SMatt Jacob 
37702df76c16SMatt Jacob #endif
3771d81ba9d5SMatt Jacob #endif
3772d81ba9d5SMatt Jacob 
3773478f8a96SJustin T. Gibbs static void
37741dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
3775478f8a96SJustin T. Gibbs {
3776478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
37779cd7268eSMatt Jacob 	ispsoftc_t *isp;
3778478f8a96SJustin T. Gibbs 
3779478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
37809cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
3781478f8a96SJustin T. Gibbs 	switch (code) {
3782478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
3783ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
37841dae40ebSMatt Jacob 			uint16_t oflags, nflags;
37852df76c16SMatt Jacob 			int bus = cam_sim_bus(sim);
37862df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
3787a1bc34c6SMatt Jacob 			int tgt;
3788478f8a96SJustin T. Gibbs 
3789f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
379041ed683eSMatt Jacob 			if (tgt >= 0) {
37919ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
3792a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
37939ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
3794a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
3795478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
3796478f8a96SJustin T. Gibbs 				}
3797a1bc34c6SMatt Jacob #else
3798a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
3799a1bc34c6SMatt Jacob #endif
38009ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
38019ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
3802478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
38032df76c16SMatt Jacob 				sdp->update = 1;
38042df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
38059ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
3806478f8a96SJustin T. Gibbs 			}
380741ed683eSMatt Jacob 		}
3808478f8a96SJustin T. Gibbs 		break;
3809478f8a96SJustin T. Gibbs 	default:
38103c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
3811478f8a96SJustin T. Gibbs 		break;
3812478f8a96SJustin T. Gibbs 	}
3813478f8a96SJustin T. Gibbs }
3814478f8a96SJustin T. Gibbs 
3815478f8a96SJustin T. Gibbs static void
3816c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
3817478f8a96SJustin T. Gibbs {
38189cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
381910365e5aSMatt Jacob 	uint32_t isr;
382010365e5aSMatt Jacob 	uint16_t sema, mbox;
3821126ec864SMatt Jacob 
3822126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3823126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
3824126ec864SMatt Jacob 	}
3825478f8a96SJustin T. Gibbs }
3826478f8a96SJustin T. Gibbs 
3827ab6c4b31SMatt Jacob 
38282df76c16SMatt Jacob static void
38292df76c16SMatt Jacob isp_watchdog(void *arg)
3830cc8df88bSMatt Jacob {
38312df76c16SMatt Jacob 	struct ccb_scsiio *xs = arg;
38322df76c16SMatt Jacob 	ispsoftc_t *isp;
38331dae40ebSMatt Jacob 	uint32_t handle;
3834b85389e1SMatt Jacob 
38352df76c16SMatt Jacob 	isp = XS_ISP(xs);
38362df76c16SMatt Jacob 
3837cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
3838c8b8a2c4SMatt Jacob 	if (handle != ISP_HANDLE_FREE) {
38391fcf5debSMatt Jacob 		/*
3840c8b8a2c4SMatt Jacob 		 * Try and make sure the command is really dead before
3841c8b8a2c4SMatt Jacob 		 * we release the handle (and DMA resources) for reuse.
3842c8b8a2c4SMatt Jacob 		 *
3843c8b8a2c4SMatt Jacob 		 * If we are successful in aborting the command then
3844c8b8a2c4SMatt Jacob 		 * we're done here because we'll get the command returned
3845c8b8a2c4SMatt Jacob 		 * back separately.
38461fcf5debSMatt Jacob 		 */
3847c8b8a2c4SMatt Jacob 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) {
3848c8b8a2c4SMatt Jacob 			return;
3849c8b8a2c4SMatt Jacob 		}
38501fcf5debSMatt Jacob 
38511fcf5debSMatt Jacob 		/*
3852c8b8a2c4SMatt Jacob 		 * Note that after calling the above, the command may in
3853c8b8a2c4SMatt Jacob 		 * fact have been completed.
3854c8b8a2c4SMatt Jacob 		 */
3855c8b8a2c4SMatt Jacob 		xs = isp_find_xs(isp, handle);
3856c8b8a2c4SMatt Jacob 
3857c8b8a2c4SMatt Jacob 		/*
3858c8b8a2c4SMatt Jacob 		 * If the command no longer exists, then we won't
3859c8b8a2c4SMatt Jacob 		 * be able to find the xs again with this handle.
3860c8b8a2c4SMatt Jacob 		 */
3861c8b8a2c4SMatt Jacob 		if (xs == NULL) {
3862c8b8a2c4SMatt Jacob 			return;
3863c8b8a2c4SMatt Jacob 		}
3864c8b8a2c4SMatt Jacob 
3865c8b8a2c4SMatt Jacob 		/*
3866c8b8a2c4SMatt Jacob 		 * After this point, the command is really dead.
38671fcf5debSMatt Jacob 		 */
3868f6e75de2SMatt Jacob 		if (XS_XFRLEN(xs)) {
3869f6e75de2SMatt Jacob 			ISP_DMAFREE(isp, xs, handle);
3870f6e75de2SMatt Jacob 		}
3871cc8df88bSMatt Jacob 		isp_destroy_handle(isp, handle);
3872c8b8a2c4SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle);
3873cc8df88bSMatt Jacob 		XS_SETERR(xs, CAM_CMD_TIMEOUT);
3874cc8df88bSMatt Jacob 		isp_done(xs);
3875b85389e1SMatt Jacob 	}
3876f7c631bcSMatt Jacob }
3877f7c631bcSMatt Jacob 
3878f7c631bcSMatt Jacob static void
38792df76c16SMatt Jacob isp_make_here(ispsoftc_t *isp, int chan, int tgt)
3880f7c631bcSMatt Jacob {
3881ffcf6651SMatt Jacob 	union ccb *ccb;
38822df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
38832df76c16SMatt Jacob 
38842df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
38852df76c16SMatt Jacob 		return;
38862df76c16SMatt Jacob 	}
38872df76c16SMatt Jacob 
3888ffcf6651SMatt Jacob 	/*
38892df76c16SMatt Jacob 	 * Allocate a CCB, create a wildcard path for this bus/target and schedule a rescan.
3890ffcf6651SMatt Jacob 	 */
38918008a935SScott Long 	ccb = xpt_alloc_ccb_nowait();
3892ffcf6651SMatt Jacob 	if (ccb == NULL) {
38932df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "Chan %d unable to alloc CCB for rescan", chan);
3894ffcf6651SMatt Jacob 		return;
3895ffcf6651SMatt Jacob 	}
389694090790SMatt Jacob 	/*
389794090790SMatt Jacob 	 * xpt_rescan only honors wildcard in the target field.
389894090790SMatt Jacob 	 * Scan the whole bus instead of target, which will then
389994090790SMatt Jacob 	 * force a scan of all luns.
390094090790SMatt Jacob 	 */
390194090790SMatt Jacob 	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fc->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
3902ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
3903ffcf6651SMatt Jacob 		xpt_free_ccb(ccb);
3904ffcf6651SMatt Jacob 		return;
3905ffcf6651SMatt Jacob 	}
3906ffcf6651SMatt Jacob 	xpt_rescan(ccb);
3907ffcf6651SMatt Jacob }
3908ffcf6651SMatt Jacob 
3909ffcf6651SMatt Jacob static void
39102df76c16SMatt Jacob isp_make_gone(ispsoftc_t *isp, int chan, int tgt)
3911ffcf6651SMatt Jacob {
3912ffcf6651SMatt Jacob 	struct cam_path *tp;
39132df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
39142df76c16SMatt Jacob 
39152df76c16SMatt Jacob 	if (isp_autoconfig == 0) {
39162df76c16SMatt Jacob 		return;
39172df76c16SMatt Jacob 	}
39182df76c16SMatt Jacob 	if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
3919ffcf6651SMatt Jacob 		xpt_async(AC_LOST_DEVICE, tp, NULL);
3920ffcf6651SMatt Jacob 		xpt_free_path(tp);
3921f7c631bcSMatt Jacob 	}
3922f7c631bcSMatt Jacob }
3923f7c631bcSMatt Jacob 
3924f7c631bcSMatt Jacob /*
3925f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
3926f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
3927f7c631bcSMatt Jacob  * gone away.
3928f7c631bcSMatt Jacob  *
3929f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
3930f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
3931f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
3932f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
3933f7c631bcSMatt Jacob  */
3934f7c631bcSMatt Jacob static void
3935f7c631bcSMatt Jacob isp_gdt(void *arg)
3936f7c631bcSMatt Jacob {
39372df76c16SMatt Jacob 	struct isp_fc *fc = arg;
39382df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
39392df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
3940f7c631bcSMatt Jacob 	fcportdb_t *lp;
3941f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
3942f7c631bcSMatt Jacob 
39432df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan);
3944f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
39452df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
3946f7c631bcSMatt Jacob 
3947f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
3948f7c631bcSMatt Jacob 			continue;
3949f7c631bcSMatt Jacob 		}
39502df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
3951f7c631bcSMatt Jacob 			continue;
3952f7c631bcSMatt Jacob 		}
3953f7c631bcSMatt Jacob 		if (lp->new_reserved == 0) {
3954f7c631bcSMatt Jacob 			continue;
3955f7c631bcSMatt Jacob 		}
3956f7c631bcSMatt Jacob 		lp->new_reserved -= 1;
3957f7c631bcSMatt Jacob 		if (lp->new_reserved != 0) {
3958f7c631bcSMatt Jacob 			more_to_do++;
3959f7c631bcSMatt Jacob 			continue;
3960f7c631bcSMatt Jacob 		}
39612df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
39622df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
39632df76c16SMatt Jacob 		lp->dev_map_idx = 0;
3964f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
39652df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout");
39662df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
3967f7c631bcSMatt Jacob 	}
3968a01f5aebSMatt Jacob 	if (fc->ready) {
3969f7c631bcSMatt Jacob 		if (more_to_do) {
39702df76c16SMatt Jacob 			callout_reset(&fc->gdt, hz, isp_gdt, fc);
3971f7c631bcSMatt Jacob 		} else {
39722df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan);
3973a01f5aebSMatt Jacob 		}
3974f7c631bcSMatt Jacob 	}
3975f7c631bcSMatt Jacob }
3976f7c631bcSMatt Jacob 
3977f7c631bcSMatt Jacob /*
3978f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
3979f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
3980f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
3981f7c631bcSMatt Jacob  *
3982f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
3983f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
3984f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
3985f7c631bcSMatt Jacob  */
3986f7c631bcSMatt Jacob static void
3987f7c631bcSMatt Jacob isp_ldt(void *arg)
3988f7c631bcSMatt Jacob {
39892df76c16SMatt Jacob 	struct isp_fc *fc = arg;
39902df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
39912df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
3992f7c631bcSMatt Jacob 	fcportdb_t *lp;
3993f7c631bcSMatt Jacob 	int dbidx, tgt;
3994f7c631bcSMatt Jacob 
39952df76c16SMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime);
39960a70657fSMatt Jacob 
3997f7c631bcSMatt Jacob 	/*
3998f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
3999f7c631bcSMatt Jacob 	 */
4000f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
40012df76c16SMatt Jacob 		lp = &FCPARAM(isp, chan)->portdb[dbidx];
4002f7c631bcSMatt Jacob 
4003f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
4004f7c631bcSMatt Jacob 			continue;
4005f7c631bcSMatt Jacob 		}
40062df76c16SMatt Jacob 		if (lp->dev_map_idx == 0 || lp->target_mode) {
4007f7c631bcSMatt Jacob 			continue;
4008f7c631bcSMatt Jacob 		}
4009f7c631bcSMatt Jacob 
4010f7c631bcSMatt Jacob 		/*
4011f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
4012f7c631bcSMatt Jacob 		 */
4013f7c631bcSMatt Jacob 
4014f7c631bcSMatt Jacob 		/*
4015f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
4016f7c631bcSMatt Jacob 		 */
4017f7c631bcSMatt Jacob 		lp->reserved = 1;
4018f7c631bcSMatt Jacob 
4019f7c631bcSMatt Jacob 		/*
4020f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
4021f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
4022f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
4023f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
4024f7c631bcSMatt Jacob 		 */
4025f7c631bcSMatt Jacob 
40262df76c16SMatt Jacob 		tgt = lp->dev_map_idx - 1;
40272df76c16SMatt Jacob 		FCPARAM(isp, chan)->isp_dev_map[tgt] = 0;
40282df76c16SMatt Jacob 		lp->dev_map_idx = 0;
40292df76c16SMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
40302df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout");
40312df76c16SMatt Jacob 		isp_make_gone(isp, chan, tgt);
4032f7c631bcSMatt Jacob 	}
4033f7c631bcSMatt Jacob 
4034f7c631bcSMatt Jacob 	/*
4035f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
4036f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
4037f7c631bcSMatt Jacob 	 */
40382df76c16SMatt Jacob 	fc->loop_dead = 1;
40392df76c16SMatt Jacob 	fc->loop_down_time = fc->loop_down_limit+1;
40402df76c16SMatt Jacob 	wakeup(fc);
4041cc8df88bSMatt Jacob }
4042cc8df88bSMatt Jacob 
40435d571944SMatt Jacob static void
40445d571944SMatt Jacob isp_kthread(void *arg)
40455d571944SMatt Jacob {
40462df76c16SMatt Jacob 	struct isp_fc *fc = arg;
40472df76c16SMatt Jacob 	ispsoftc_t *isp = fc->isp;
40482df76c16SMatt Jacob 	int chan = fc - isp->isp_osinfo.pc.fc;
4049f7c631bcSMatt Jacob 	int slp = 0;
4050a01f5aebSMatt Jacob 
40510a70657fSMatt Jacob 	mtx_lock(&isp->isp_osinfo.lock);
40522df76c16SMatt Jacob 
40535d571944SMatt Jacob 	for (;;) {
4054f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
4055fdeb9f2fSMatt Jacob 
40562df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan);
40572df76c16SMatt Jacob 		lb = isp_fc_runstate(isp, chan, 250000);
40582df76c16SMatt Jacob 
40592df76c16SMatt Jacob 		/*
40602df76c16SMatt Jacob 		 * Our action is different based upon whether we're supporting
40612df76c16SMatt Jacob 		 * Initiator mode or not. If we are, we might freeze the simq
40622df76c16SMatt Jacob 		 * when loop is down and set all sorts of different delays to
40632df76c16SMatt Jacob 		 * check again.
40642df76c16SMatt Jacob 		 *
40652df76c16SMatt Jacob 		 * If not, we simply just wait for loop to come up.
40662df76c16SMatt Jacob 		 */
40672df76c16SMatt Jacob 		if (lb && (fc->role & ISP_ROLE_INITIATOR)) {
4068f7c631bcSMatt Jacob 			/*
4069f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
4070f7c631bcSMatt Jacob 			 */
40712df76c16SMatt Jacob 			fc->loop_down_time += slp;
407210365e5aSMatt Jacob 
407310365e5aSMatt Jacob 			if (lb < 0) {
40742df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time);
407510365e5aSMatt Jacob 			} else {
40762df76c16SMatt 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);
4077f44257c2SMatt Jacob 			}
407810365e5aSMatt Jacob 
407910365e5aSMatt Jacob 			/*
408010365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
4081f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
4082f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
4083f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
408410365e5aSMatt Jacob 			 */
40852df76c16SMatt Jacob 			if (FCPARAM(isp, chan)->loop_seen_once == 0) {
4086f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
408710365e5aSMatt Jacob 			} else {
40882df76c16SMatt Jacob 				lim = fc->loop_down_limit;
4089f7c631bcSMatt Jacob 			}
40902df76c16SMatt Jacob 			if (fc->loop_down_time >= lim) {
40912df76c16SMatt Jacob 				isp_freeze_loopdown(isp, chan, "loop limit hit");
4092f7c631bcSMatt Jacob 				slp = 0;
40932df76c16SMatt Jacob 			} else if (fc->loop_down_time < 10) {
409410365e5aSMatt Jacob 				slp = 1;
40952df76c16SMatt Jacob 			} else if (fc->loop_down_time < 30) {
4096f7c631bcSMatt Jacob 				slp = 5;
40972df76c16SMatt Jacob 			} else if (fc->loop_down_time < 60) {
4098f7c631bcSMatt Jacob 				slp = 10;
40992df76c16SMatt Jacob 			} else if (fc->loop_down_time < 120) {
4100f7c631bcSMatt Jacob 				slp = 20;
4101f7c631bcSMatt Jacob 			} else {
4102f7c631bcSMatt Jacob 				slp = 30;
4103f44257c2SMatt Jacob 			}
410410365e5aSMatt Jacob 
41052df76c16SMatt Jacob 		} else if (lb) {
41062df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan);
41072df76c16SMatt Jacob 			fc->loop_down_time += slp;
41082df76c16SMatt Jacob 			slp = 60;
410910365e5aSMatt Jacob 		} else {
41102df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan);
41112df76c16SMatt Jacob 			fc->loop_down_time = 0;
411210365e5aSMatt Jacob 			slp = 0;
41135d571944SMatt Jacob 		}
4114fdeb9f2fSMatt Jacob 
41152df76c16SMatt Jacob 
4116f44257c2SMatt Jacob 		/*
41172df76c16SMatt Jacob 		 * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it
41182df76c16SMatt Jacob 		 * now so that CAM can start sending us commands.
41192df76c16SMatt Jacob 		 *
41202df76c16SMatt Jacob 		 * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again
41212df76c16SMatt Jacob 		 * or kill the commands, as appropriate.
4122f44257c2SMatt Jacob 		 */
41232df76c16SMatt Jacob 
41242df76c16SMatt Jacob 		if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) {
41252df76c16SMatt Jacob 			wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
41262df76c16SMatt Jacob 			fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
41272df76c16SMatt Jacob 			if (wasfrozen && fc->simqfrozen == 0) {
41282df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
41292df76c16SMatt Jacob 				xpt_release_simq(fc->sim, 1);
41305d571944SMatt Jacob 			}
41312df76c16SMatt Jacob 		}
41322df76c16SMatt Jacob 
41332df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp);
41342df76c16SMatt Jacob 
41352df76c16SMatt Jacob 		msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz);
41362df76c16SMatt Jacob 
413710365e5aSMatt Jacob 		/*
413810365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
413910365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
414010365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
414110365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
414210365e5aSMatt Jacob 		 * to settle.
414310365e5aSMatt Jacob 		 */
41442df76c16SMatt Jacob 		if (slp == 0 && fc->hysteresis) {
41452df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz);
41462df76c16SMatt Jacob 			(void) msleep(&isp_fabric_hysteresis, &isp->isp_osinfo.lock, PRIBIO, "ispT", (fc->hysteresis * hz));
414710365e5aSMatt Jacob 		}
41485d571944SMatt Jacob 	}
41490a70657fSMatt Jacob 	mtx_unlock(&isp->isp_osinfo.lock);
41505d571944SMatt Jacob }
41515d571944SMatt Jacob 
4152cc8df88bSMatt Jacob static void
4153c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
4154478f8a96SJustin T. Gibbs {
41550a70657fSMatt Jacob 	int bus, tgt, ts, error, lim;
41569cd7268eSMatt Jacob 	ispsoftc_t *isp;
41574663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
4158478f8a96SJustin T. Gibbs 
4159478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
4160478f8a96SJustin T. Gibbs 
41619cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
41622df76c16SMatt Jacob 	mtx_assert(&isp->isp_lock, MA_OWNED);
41632df76c16SMatt Jacob 
41642df76c16SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE && ccb->ccb_h.func_code == XPT_SCSI_IO) {
416557c801f5SMatt Jacob 		isp_init(isp);
416657c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
416757c801f5SMatt Jacob 			/*
416857c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
416957c801f5SMatt Jacob 			 */
4170b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
41710470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
417257c801f5SMatt Jacob 			xpt_done(ccb);
417357c801f5SMatt Jacob 			return;
417457c801f5SMatt Jacob 		}
417557c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
417657c801f5SMatt Jacob 	}
4177b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
41780a70657fSMatt Jacob 	ISP_PCMD(ccb) = NULL;
41795d571944SMatt Jacob 
4180478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
4181478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
41822df76c16SMatt Jacob 		bus = XS_CHANNEL(ccb);
4183478f8a96SJustin T. Gibbs 		/*
4184478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
4185478f8a96SJustin T. Gibbs 		 */
4186478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
4187478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
4188478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
4189478f8a96SJustin T. Gibbs 				xpt_done(ccb);
4190478f8a96SJustin T. Gibbs 				break;
4191478f8a96SJustin T. Gibbs 			}
4192478f8a96SJustin T. Gibbs 		}
41930470d791SMatt Jacob #ifdef	DIAGNOSTIC
41940470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
4195dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
4196478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
41970470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
4198dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
4199478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
4200478f8a96SJustin T. Gibbs 		}
4201478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
4202478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4203478f8a96SJustin T. Gibbs 			break;
4204478f8a96SJustin T. Gibbs 		}
42050470d791SMatt Jacob #endif
42060a70657fSMatt Jacob 		ccb->csio.scsi_status = SCSI_STATUS_OK;
42070a70657fSMatt Jacob 		if (isp_get_pcmd(isp, ccb)) {
42080a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "out of PCMDs");
42090a70657fSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42102df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
42110a70657fSMatt Jacob 			xpt_done(ccb);
42120a70657fSMatt Jacob 			break;
42130a70657fSMatt Jacob 		}
4214b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
42150470d791SMatt Jacob 		switch (error) {
4216478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
4217f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
4218478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
42190a70657fSMatt Jacob 			if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) {
42200a70657fSMatt Jacob 				break;
4221d69a5f7dSMatt Jacob 			}
42220a70657fSMatt Jacob 			ts = ccb->ccb_h.timeout;
42230a70657fSMatt Jacob 			if (ts == CAM_TIME_DEFAULT) {
42240a70657fSMatt Jacob 				ts = 60*1000;
4225cc8df88bSMatt Jacob 			}
42260a70657fSMatt Jacob 			ts = isp_mstohz(ts);
42272df76c16SMatt Jacob 			callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb);
4228478f8a96SJustin T. Gibbs 			break;
42290470d791SMatt Jacob 		case CMD_RQLATER:
4230f44257c2SMatt Jacob 			/*
42312df76c16SMatt Jacob 			 * We get this result for FC devices if the loop state isn't ready yet
42322df76c16SMatt Jacob 			 * or if the device in question has gone zombie on us.
42332df76c16SMatt Jacob 			 *
42342df76c16SMatt Jacob 			 * If we've never seen Loop UP at all, we requeue this request and wait
42352df76c16SMatt Jacob 			 * for the initial loop up delay to expire.
423610365e5aSMatt Jacob 			 */
42372df76c16SMatt Jacob 			lim = ISP_FC_PC(isp, bus)->loop_down_limit;
42382df76c16SMatt Jacob 			if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) {
42392df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->loop_seen_once == 0) {
42402df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGDEBUG0, "%d.%d loop not seen yet @ %lu", XS_TGT(ccb), XS_LUN(ccb), (unsigned long) time_uptime);
4241f7c631bcSMatt Jacob 				} else {
42422df76c16SMatt 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);
4243f7c631bcSMatt Jacob 				}
42442df76c16SMatt Jacob 				ccb->ccb_h.status = CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
4245f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
42460a70657fSMatt Jacob 				isp_free_pcmd(isp, ccb);
4247f44257c2SMatt Jacob 				xpt_done(ccb);
4248f44257c2SMatt Jacob 				break;
4249f44257c2SMatt Jacob 			}
42502df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
4251f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42522df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
4253f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
42540a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
4255478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4256478f8a96SJustin T. Gibbs 			break;
42570470d791SMatt Jacob 		case CMD_EAGAIN:
42580a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
42592df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
42602df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0);
42612df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
4262478f8a96SJustin T. Gibbs 			xpt_done(ccb);
4263478f8a96SJustin T. Gibbs 			break;
42640470d791SMatt Jacob 		case CMD_COMPLETE:
42650470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
42660470d791SMatt Jacob 			break;
42670470d791SMatt Jacob 		default:
42682df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "What's this? 0x%x at %d in file %s", error, __LINE__, __FILE__);
4269b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
42700a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
42710470d791SMatt Jacob 			xpt_done(ccb);
4272478f8a96SJustin T. Gibbs 		}
4273478f8a96SJustin T. Gibbs 		break;
4274478f8a96SJustin T. Gibbs 
4275d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
42762df76c16SMatt Jacob 	case XPT_EN_LUN:		/* Enable/Disable LUN as a target */
42772df76c16SMatt Jacob 		if (ccb->cel.enable) {
42782df76c16SMatt Jacob 			isp_enable_lun(isp, ccb);
42792df76c16SMatt Jacob 		} else {
42802df76c16SMatt Jacob 			isp_disable_lun(isp, ccb);
428167ff51f1SMatt Jacob 		}
428267ff51f1SMatt Jacob 		break;
4283ae5db118SMatt Jacob 	case XPT_IMMED_NOTIFY:
42842df76c16SMatt Jacob 	case XPT_IMMEDIATE_NOTIFY:	/* Add Immediate Notify Resource */
4285d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
4286d81ba9d5SMatt Jacob 	{
42872df76c16SMatt Jacob 		tstate_t *tptr = get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
4288d81ba9d5SMatt Jacob 		if (tptr == NULL) {
42892df76c16SMatt Jacob 			tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
42902df76c16SMatt Jacob 		}
42912df76c16SMatt Jacob 		if (tptr == NULL) {
42922df76c16SMatt Jacob 			const char *str;
42932df76c16SMatt Jacob 			uint32_t tag;
42942df76c16SMatt Jacob 
42952df76c16SMatt Jacob 			if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
42962df76c16SMatt Jacob 				str = "XPT_IMMEDIATE_NOTIFY";
42972df76c16SMatt Jacob 				tag = ccb->cin1.seq_id;
42982df76c16SMatt Jacob 			} else {
42992df76c16SMatt Jacob 				tag = ccb->atio.tag_id;
43002df76c16SMatt Jacob 				str = "XPT_ACCEPT_TARGET_IO";
43012df76c16SMatt Jacob 			}
43022df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "%s: [0x%x] no state pointer found for %s\n", __func__, tag, str);
43032df76c16SMatt Jacob 			dump_tstates(isp, XS_CHANNEL(ccb));
43042df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
4305d81ba9d5SMatt Jacob 			break;
4306d81ba9d5SMatt Jacob 		}
4307f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
4308f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
4309570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
4310570c7a3fSMatt Jacob 
4311d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
43122df76c16SMatt Jacob 			if (ccb->atio.tag_id) {
43132df76c16SMatt Jacob 				atio_private_data_t *atp = isp_get_atpd(isp, tptr, ccb->atio.tag_id);
43142df76c16SMatt Jacob 				if (atp) {
43152df76c16SMatt Jacob 					isp_put_atpd(isp, tptr, atp);
43162df76c16SMatt Jacob 				}
43172df76c16SMatt Jacob 			}
4318570c7a3fSMatt Jacob 			tptr->atio_count++;
43192df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle);
43202df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n",
43212df76c16SMatt Jacob 			    ((struct ccb_accept_tio *)ccb)->tag_id, tptr->atio_count);
43222df76c16SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
43232df76c16SMatt Jacob 			if (ccb->cin1.tag_id) {
43242df76c16SMatt Jacob 				inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id);
43252df76c16SMatt Jacob 				if (ntp) {
43262df76c16SMatt Jacob 					isp_put_ntpd(isp, tptr, ntp);
43272df76c16SMatt Jacob 				}
43282df76c16SMatt Jacob 			}
4329746e9c85SMatt Jacob 			tptr->inot_count++;
43302df76c16SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
43312df76c16SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
43322df76c16SMatt Jacob 			    ((struct ccb_immediate_notify *)ccb)->seq_id, tptr->inot_count);
4333ae5db118SMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
4334ae5db118SMatt Jacob 			tptr->inot_count++;
4335ae5db118SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
4336ae5db118SMatt Jacob 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
4337ae5db118SMatt Jacob 			    ((struct ccb_immediate_notify *)ccb)->seq_id, tptr->inot_count);
4338d81ba9d5SMatt Jacob 		}
4339d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
4340d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
4341d81ba9d5SMatt Jacob 		break;
4342d81ba9d5SMatt Jacob 	}
4343ae5db118SMatt Jacob 	case XPT_NOTIFY_ACK:
4344ae5db118SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4345ae5db118SMatt Jacob 		break;
43462df76c16SMatt Jacob 	case XPT_NOTIFY_ACKNOWLEDGE:		/* notify ack */
4347d81ba9d5SMatt Jacob 	{
43482df76c16SMatt Jacob 		tstate_t *tptr;
43492df76c16SMatt Jacob 		inot_private_data_t *ntp;
43502df76c16SMatt Jacob 
43512df76c16SMatt Jacob 		/*
43522df76c16SMatt Jacob 		 * XXX: Because we cannot guarantee that the path information in the notify acknowledge ccb
43532df76c16SMatt Jacob 		 * XXX: matches that for the immediate notify, we have to *search* for the notify structure
43542df76c16SMatt Jacob 		 */
43552df76c16SMatt Jacob 		/*
43562df76c16SMatt Jacob 		 * All the relevant path information is in the associated immediate notify
43572df76c16SMatt Jacob 		 */
43582df76c16SMatt 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);
43592df76c16SMatt Jacob 		ntp = get_ntp_from_tagdata(isp, ccb->cna2.tag_id, ccb->cna2.seq_id, &tptr);
43602df76c16SMatt Jacob 		if (ntp == NULL) {
43612df76c16SMatt 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__,
43622df76c16SMatt Jacob 			     ccb->cna2.tag_id, ccb->cna2.seq_id);
43632df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
43642df76c16SMatt Jacob 			xpt_done(ccb);
4365d81ba9d5SMatt Jacob 			break;
4366d81ba9d5SMatt Jacob 		}
43672df76c16SMatt Jacob 		if (isp_handle_platform_target_notify_ack(isp, &ntp->rd.nt)) {
43682df76c16SMatt Jacob 			rls_lun_statep(isp, tptr);
43692df76c16SMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
43702df76c16SMatt Jacob 			cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
43712df76c16SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
43722df76c16SMatt Jacob 			break;
43732df76c16SMatt Jacob 		}
43742df76c16SMatt Jacob 		isp_put_ntpd(isp, tptr, ntp);
43752df76c16SMatt Jacob 		rls_lun_statep(isp, tptr);
43762df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
43772df76c16SMatt 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);
43782df76c16SMatt Jacob 		xpt_done(ccb);
43792df76c16SMatt Jacob 		break;
43802df76c16SMatt Jacob 	}
43812df76c16SMatt Jacob 	case XPT_CONT_TARGET_IO:
43822df76c16SMatt Jacob 		isp_target_start_ctio(isp, ccb);
43832df76c16SMatt Jacob 		break;
4384d81ba9d5SMatt Jacob #endif
4385478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
4386d81ba9d5SMatt Jacob 
4387d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
4388d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
4389d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
4390d81ba9d5SMatt Jacob 
43912df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt);
4392478f8a96SJustin T. Gibbs 		if (error) {
4393478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
4394478f8a96SJustin T. Gibbs 		} else {
4395478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
4396478f8a96SJustin T. Gibbs 		}
4397478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4398478f8a96SJustin T. Gibbs 		break;
4399478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
4400d81ba9d5SMatt Jacob 	{
4401d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
4402d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
4403d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4404d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
44052df76c16SMatt Jacob 			isp_target_mark_aborted(isp, accb);
4406d81ba9d5SMatt Jacob 			break;
4407d81ba9d5SMatt Jacob #endif
4408d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
4409478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
4410478f8a96SJustin T. Gibbs 			if (error) {
4411d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
4412478f8a96SJustin T. Gibbs 			} else {
4413478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
4414478f8a96SJustin T. Gibbs 			}
4415d81ba9d5SMatt Jacob 			break;
4416d81ba9d5SMatt Jacob 		default:
4417d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
4418d81ba9d5SMatt Jacob 			break;
4419d81ba9d5SMatt Jacob 		}
4420478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4421478f8a96SJustin T. Gibbs 		break;
4422d81ba9d5SMatt Jacob 	}
4423ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
4424478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
4425478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
44269ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
44279ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
44289ce9bdafSMatt Jacob 			xpt_done(ccb);
44299ce9bdafSMatt Jacob 			break;
44309ce9bdafSMatt Jacob 		}
4431478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
4432805e1f82SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
44332df76c16SMatt Jacob 		if (IS_SCSI(isp)) {
44342df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
44352df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
44362df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
44371dae40ebSMatt Jacob 			uint16_t *dptr;
4438ab163f5fSMatt Jacob 
4439b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
4440b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
4441b61386a4SMatt Jacob 				xpt_done(ccb);
4442b61386a4SMatt Jacob 				break;
4443b61386a4SMatt Jacob 			}
4444b61386a4SMatt Jacob 
4445ab163f5fSMatt Jacob 			/*
44469ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
4447ab163f5fSMatt Jacob 			 * so any request to change settings just gets
4448ab163f5fSMatt Jacob 			 * vectored to that location.
4449ab163f5fSMatt Jacob 			 */
44509ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
4451ab163f5fSMatt Jacob 
4452ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
4453ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
4454ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
4455ab163f5fSMatt Jacob 				else
4456ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
4457ab163f5fSMatt Jacob 			}
4458ab163f5fSMatt Jacob 
4459ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
4460ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
4461ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
4462ab163f5fSMatt Jacob 				else
4463ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
4464ab163f5fSMatt Jacob 			}
4465ab163f5fSMatt Jacob 
4466ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
4467ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
4468ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
4469ab163f5fSMatt Jacob 				else
4470ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
4471ab163f5fSMatt Jacob 			}
4472ab163f5fSMatt Jacob 
4473ab163f5fSMatt Jacob 			/*
4474ab163f5fSMatt Jacob 			 * XXX: FIX ME
4475ab163f5fSMatt Jacob 			 */
44762df76c16SMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && (spi->valid & CTS_SPI_VALID_SYNC_RATE) && (spi->sync_period && spi->sync_offset)) {
4477ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
44789ce9bdafSMatt Jacob 				/*
44799ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
44809ce9bdafSMatt Jacob 				 */
44812df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_period = spi->sync_period;
44822df76c16SMatt Jacob 				sdp->isp_devparam[tgt].goal_offset = spi->sync_offset;
4483ab163f5fSMatt Jacob 			} else {
4484ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
4485ab163f5fSMatt Jacob 			}
44862df76c16SMatt 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,
44872df76c16SMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset, sdp->isp_devparam[tgt].goal_period);
4488478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
44892df76c16SMatt Jacob 			sdp->update = 1;
4490478f8a96SJustin T. Gibbs 		}
4491478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4492478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4493478f8a96SJustin T. Gibbs 		break;
4494478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
4495478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
4496478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
44972df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
4498ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
44992df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
45002df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
45012df76c16SMatt Jacob 			struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc;
4502478f8a96SJustin T. Gibbs 
4503ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4504ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4505ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
4506ab163f5fSMatt Jacob 			cts->transport_version = 0;
4507ab163f5fSMatt Jacob 
45089b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
45099b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
4510ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
4511ab163f5fSMatt Jacob 			fc->bitrate = 100000;
4512fada2376SJung-uk Kim 			fc->bitrate *= fcp->isp_gbspeed;
4513ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
451410365e5aSMatt Jacob 				fcportdb_t *lp = &fcp->portdb[tgt];
4515ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
4516ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
4517ab163f5fSMatt Jacob 				fc->port = lp->portid;
45182df76c16SMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
4519ab163f5fSMatt Jacob 			}
4520ab163f5fSMatt Jacob 		} else {
45212df76c16SMatt Jacob 			struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
45222df76c16SMatt Jacob 			struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
45232df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
45241dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
4525ab163f5fSMatt Jacob 
4526ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
452783ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
45282df76c16SMatt Jacob 				sdp->update = 1;
45292df76c16SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, bus);
45309ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
45319ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
45329ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
45334394c92fSMatt Jacob 			} else {
45349ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
45359ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
45369ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
45374394c92fSMatt Jacob 			}
4538478f8a96SJustin T. Gibbs 
4539ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
4540ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
4541ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
4542ab163f5fSMatt Jacob 			cts->transport_version = 2;
4543ab163f5fSMatt Jacob 
4544b61386a4SMatt Jacob 			spi->valid = 0;
4545b61386a4SMatt Jacob 			scsi->valid = 0;
4546b61386a4SMatt Jacob 			spi->flags = 0;
4547b61386a4SMatt Jacob 			scsi->flags = 0;
4548ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
4549ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
4550ab163f5fSMatt Jacob 			}
45519ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
4552ab163f5fSMatt Jacob 				spi->sync_offset = oval;
4553ab163f5fSMatt Jacob 				spi->sync_period = pval;
4554b61386a4SMatt Jacob 			} else {
4555b61386a4SMatt Jacob 				spi->sync_offset = 0;
4556b61386a4SMatt Jacob 				spi->sync_period = 0;
4557b61386a4SMatt Jacob 			}
4558ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
4559ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
4560ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
4561ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
4562ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
4563ab163f5fSMatt Jacob 			} else {
4564ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
4565ab163f5fSMatt Jacob 			}
4566ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
4567ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
4568b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
4569b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
4570b61386a4SMatt Jacob 				}
4571ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
4572ab163f5fSMatt Jacob 			}
45732df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "GET %s (%d.%d.%d) to flags %x off %x per %x", IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
4574b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
4575478f8a96SJustin T. Gibbs 		}
4576478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4577478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4578478f8a96SJustin T. Gibbs 		break;
4579478f8a96SJustin T. Gibbs 
4580478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
45812df76c16SMatt Jacob 		cam_calc_geometry(&ccb->ccg, 1);
45822df76c16SMatt Jacob 		xpt_done(ccb);
45832df76c16SMatt Jacob 		break;
4584478f8a96SJustin T. Gibbs 
4585478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
4586ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
45872df76c16SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, bus);
45882df76c16SMatt Jacob 		if (error) {
4589478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
45902df76c16SMatt Jacob 			xpt_done(ccb);
45912df76c16SMatt Jacob 			break;
45922df76c16SMatt Jacob 		}
45930a70657fSMatt Jacob 		if (bootverbose) {
45942df76c16SMatt Jacob 			xpt_print(ccb->ccb_h.path, "reset bus on channel %d\n", bus);
45950a70657fSMatt Jacob 		}
45962df76c16SMatt Jacob 		if (IS_FC(isp)) {
45972df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, 0);
45982df76c16SMatt Jacob 		} else {
45992df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, 0);
46002df76c16SMatt Jacob 		}
4601478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
4602478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4603478f8a96SJustin T. Gibbs 		break;
4604478f8a96SJustin T. Gibbs 
4605478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
4606478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4607478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4608478f8a96SJustin T. Gibbs 		break;
4609478f8a96SJustin T. Gibbs 
46102df76c16SMatt Jacob 	case XPT_SET_SIM_KNOB:		/* Set SIM knobs */
46112df76c16SMatt Jacob 	{
46122df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
46132df76c16SMatt Jacob 		fcparam *fcp;
46142df76c16SMatt Jacob 
46152df76c16SMatt Jacob 
46162df76c16SMatt Jacob 		if (!IS_FC(isp)) {
46172df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
46182df76c16SMatt Jacob 			xpt_done(ccb);
46192df76c16SMatt Jacob 			break;
46202df76c16SMatt Jacob 		}
46212df76c16SMatt Jacob 
46222df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
46232df76c16SMatt Jacob 		fcp = FCPARAM(isp, bus);
46242df76c16SMatt Jacob 
46252df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) {
46262df76c16SMatt Jacob 			fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn;
46272df76c16SMatt Jacob 			fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn;
46282df76c16SMatt Jacob isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn);
46292df76c16SMatt Jacob 		}
46302df76c16SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
46312df76c16SMatt Jacob 		if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) {
46322df76c16SMatt Jacob 			int rchange = 0;
46332df76c16SMatt Jacob 			int newrole = 0;
46342df76c16SMatt Jacob 
46352df76c16SMatt Jacob 			switch (kp->xport_specific.fc.role) {
46362df76c16SMatt Jacob 			case KNOB_ROLE_NONE:
46372df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_NONE) {
46382df76c16SMatt Jacob 					rchange = 1;
46392df76c16SMatt Jacob 					newrole = ISP_ROLE_NONE;
46402df76c16SMatt Jacob 				}
46412df76c16SMatt Jacob 				break;
46422df76c16SMatt Jacob 			case KNOB_ROLE_TARGET:
46432df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_TARGET) {
46442df76c16SMatt Jacob 					rchange = 1;
46452df76c16SMatt Jacob 					newrole = ISP_ROLE_TARGET;
46462df76c16SMatt Jacob 				}
46472df76c16SMatt Jacob 				break;
46482df76c16SMatt Jacob 			case KNOB_ROLE_INITIATOR:
46492df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_INITIATOR) {
46502df76c16SMatt Jacob 					rchange = 1;
46512df76c16SMatt Jacob 					newrole = ISP_ROLE_INITIATOR;
46522df76c16SMatt Jacob 				}
46532df76c16SMatt Jacob 				break;
46542df76c16SMatt Jacob 			case KNOB_ROLE_BOTH:
4655ae5db118SMatt Jacob #if 0
46562df76c16SMatt Jacob 				if (fcp->role != ISP_ROLE_BOTH) {
46572df76c16SMatt Jacob 					rchange = 1;
46582df76c16SMatt Jacob 					newrole = ISP_ROLE_BOTH;
46592df76c16SMatt Jacob 				}
4660ae5db118SMatt Jacob #else
4661ae5db118SMatt Jacob 				/*
4662ae5db118SMatt Jacob 				 * We don't really support dual role at present on FC cards.
4663ae5db118SMatt Jacob 				 *
4664ae5db118SMatt Jacob 				 * We should, but a bunch of things are currently broken,
4665ae5db118SMatt Jacob 				 * so don't allow it.
4666ae5db118SMatt Jacob 				 */
4667ae5db118SMatt Jacob 				isp_prt(isp, ISP_LOGERR, "cannot support dual role at present");
4668ae5db118SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_INVALID;
4669ae5db118SMatt Jacob #endif
46702df76c16SMatt Jacob 				break;
46712df76c16SMatt Jacob 			}
46722df76c16SMatt Jacob 			if (rchange) {
46732df76c16SMatt Jacob 				if (isp_fc_change_role(isp, bus, newrole) != 0) {
46742df76c16SMatt Jacob 					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
46752df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
46762df76c16SMatt Jacob 				} else if (newrole == ISP_ROLE_TARGET || newrole == ISP_ROLE_BOTH) {
46772df76c16SMatt Jacob 					isp_enable_deferred_luns(isp, bus);
46782df76c16SMatt Jacob #endif
46792df76c16SMatt Jacob 				}
46802df76c16SMatt Jacob 			}
46812df76c16SMatt Jacob 		}
46822df76c16SMatt Jacob 		xpt_done(ccb);
46832df76c16SMatt Jacob 		break;
46842df76c16SMatt Jacob 	}
46852df76c16SMatt Jacob 	case XPT_GET_SIM_KNOB:		/* Set SIM knobs */
46862df76c16SMatt Jacob 	{
46872df76c16SMatt Jacob 		struct ccb_sim_knob *kp = &ccb->knob;
46882df76c16SMatt Jacob 
46892df76c16SMatt Jacob 		if (IS_FC(isp)) {
46902df76c16SMatt Jacob 			fcparam *fcp;
46912df76c16SMatt Jacob 
46922df76c16SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(kp->ccb_h.path));
46932df76c16SMatt Jacob 			fcp = FCPARAM(isp, bus);
46942df76c16SMatt Jacob 
46952df76c16SMatt Jacob 			kp->xport_specific.fc.wwnn = fcp->isp_wwnn;
46962df76c16SMatt Jacob 			kp->xport_specific.fc.wwpn = fcp->isp_wwpn;
46972df76c16SMatt Jacob 			switch (fcp->role) {
46982df76c16SMatt Jacob 			case ISP_ROLE_NONE:
46992df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_NONE;
47002df76c16SMatt Jacob 				break;
47012df76c16SMatt Jacob 			case ISP_ROLE_TARGET:
47022df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_TARGET;
47032df76c16SMatt Jacob 				break;
47042df76c16SMatt Jacob 			case ISP_ROLE_INITIATOR:
47052df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_INITIATOR;
47062df76c16SMatt Jacob 				break;
47072df76c16SMatt Jacob 			case ISP_ROLE_BOTH:
47082df76c16SMatt Jacob 				kp->xport_specific.fc.role = KNOB_ROLE_BOTH;
47092df76c16SMatt Jacob 				break;
47102df76c16SMatt Jacob 			}
47112df76c16SMatt Jacob 			kp->xport_specific.fc.valid = KNOB_VALID_ADDRESS | KNOB_VALID_ROLE;
47122df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_CMP;
47132df76c16SMatt Jacob 		} else {
47142df76c16SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
47152df76c16SMatt Jacob 		}
47162df76c16SMatt Jacob 		xpt_done(ccb);
47172df76c16SMatt Jacob 		break;
47182df76c16SMatt Jacob 	}
4719478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
4720478f8a96SJustin T. Gibbs 	{
4721478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
4722478f8a96SJustin T. Gibbs 
4723478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
4724d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
4725a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
4726d81ba9d5SMatt Jacob #else
4727478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
4728d81ba9d5SMatt Jacob #endif
4729478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
47300470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
47310470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
47320470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
47332df76c16SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
47344394c92fSMatt Jacob 		if (IS_FC(isp)) {
47352df76c16SMatt Jacob 			fcparam *fcp = FCPARAM(isp, bus);
47362df76c16SMatt Jacob 
47374394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
47382df76c16SMatt Jacob 
47390470d791SMatt Jacob 			/*
47400470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
47410470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
47420470d791SMatt Jacob 			 */
47430470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
47440470d791SMatt Jacob 
47459deea857SKenneth D. Merry 			/*
47462df76c16SMatt Jacob 			 * Set base transfer capabilities for Fibre Channel, for this HBA.
47479deea857SKenneth D. Merry 			 */
47482df76c16SMatt Jacob 			if (IS_24XX(isp)) {
47492df76c16SMatt Jacob 				cpi->base_transfer_speed = 4000000;
47502df76c16SMatt Jacob 			} else if (IS_23XX(isp)) {
47512df76c16SMatt Jacob 				cpi->base_transfer_speed = 2000000;
47522df76c16SMatt Jacob 			} else {
47532df76c16SMatt Jacob 				cpi->base_transfer_speed = 1000000;
47542df76c16SMatt Jacob 			}
47550470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
4756ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
4757805e1f82SMatt Jacob 			cpi->transport_version = 0;
47582df76c16SMatt Jacob 			cpi->xport_specific.fc.wwnn = fcp->isp_wwnn;
47592df76c16SMatt Jacob 			cpi->xport_specific.fc.wwpn = fcp->isp_wwpn;
47602df76c16SMatt Jacob 			cpi->xport_specific.fc.port = fcp->isp_portid;
47612df76c16SMatt Jacob 			cpi->xport_specific.fc.bitrate = fcp->isp_gbspeed * 1000;
4762478f8a96SJustin T. Gibbs 		} else {
47632df76c16SMatt Jacob 			sdparam *sdp = SDPARAM(isp, bus);
47640470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
47654394c92fSMatt Jacob 			cpi->hba_misc = 0;
4766ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
47679deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
4768ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
4769805e1f82SMatt Jacob 			cpi->transport_version = 2;
4770478f8a96SJustin T. Gibbs 		}
4771ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
4772ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
4773478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
4774478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
4775478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
4776478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
4777478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
4778478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4779478f8a96SJustin T. Gibbs 		break;
4780478f8a96SJustin T. Gibbs 	}
4781478f8a96SJustin T. Gibbs 	default:
4782478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
4783478f8a96SJustin T. Gibbs 		xpt_done(ccb);
4784478f8a96SJustin T. Gibbs 		break;
4785478f8a96SJustin T. Gibbs 	}
4786478f8a96SJustin T. Gibbs }
4787d3a9eb2eSMatt Jacob 
4788d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
4789f7c631bcSMatt Jacob 
4790d3a9eb2eSMatt Jacob void
47912df76c16SMatt Jacob isp_done(XS_T *sccb)
4792d3a9eb2eSMatt Jacob {
47939cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
4794d3a9eb2eSMatt Jacob 
4795d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
4796d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
4797b85389e1SMatt Jacob 
47982df76c16SMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && (sccb->scsi_status != SCSI_STATUS_OK)) {
4799d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
48002df76c16SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) && (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
480192a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
480292a1e549SMatt Jacob 		} else {
4803d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
4804d3a9eb2eSMatt Jacob 		}
480592a1e549SMatt Jacob 	}
4806b85389e1SMatt Jacob 
48070470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
4808d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48092df76c16SMatt 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);
4810d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
4811d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
48120470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
4813d3a9eb2eSMatt Jacob 		}
4814d3a9eb2eSMatt Jacob 	}
4815b85389e1SMatt Jacob 
48162df76c16SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) && (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48172df76c16SMatt Jacob 		xpt_print(sccb->ccb_h.path, "cam completion status 0x%x\n", sccb->ccb_h.status);
4818d3a9eb2eSMatt Jacob 	}
4819b85389e1SMatt Jacob 
4820b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
48210ec60713SMarius Strobl 	callout_stop(&PISP_PCMD(sccb)->wdog);
4822b85389e1SMatt Jacob 	XS_CMD_S_CLEAR(sccb);
48230a70657fSMatt Jacob 	isp_free_pcmd(isp, (union ccb *) sccb);
4824d3a9eb2eSMatt Jacob 	xpt_done((union ccb *) sccb);
4825d3a9eb2eSMatt Jacob }
4826d3a9eb2eSMatt Jacob 
48272df76c16SMatt Jacob void
48282df76c16SMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
4829cbf57b47SMatt Jacob {
48302df76c16SMatt Jacob 	int bus;
48312df76c16SMatt Jacob 	static const char prom[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s WWPN 0x%08x%08x";
48322df76c16SMatt Jacob 	static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x role %s %s tgt %u WWPN 0x%08x%08x";
4833f7c631bcSMatt Jacob 	char *msg = NULL;
483410365e5aSMatt Jacob 	target_id_t tgt;
483510365e5aSMatt Jacob 	fcportdb_t *lp;
4836a01f5aebSMatt Jacob 	struct isp_fc *fc;
483710365e5aSMatt Jacob 	struct cam_path *tmppath;
48382df76c16SMatt Jacob 	va_list ap;
483910365e5aSMatt Jacob 
4840cbf57b47SMatt Jacob 	switch (cmd) {
4841cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
48420470d791SMatt Jacob 	{
4843ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
4844ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
4845cbf57b47SMatt Jacob 		int flags, tgt;
48462df76c16SMatt Jacob 		sdparam *sdp;
4847ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
4848cbf57b47SMatt Jacob 
484929f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
4850ab163f5fSMatt Jacob 
48512df76c16SMatt Jacob 		va_start(ap, cmd);
48522df76c16SMatt Jacob 		bus = va_arg(ap, int);
48532df76c16SMatt Jacob 		tgt = va_arg(ap, int);
48542df76c16SMatt Jacob 		va_end(ap);
48552df76c16SMatt Jacob 		sdp = SDPARAM(isp, bus);
48562df76c16SMatt Jacob 
48572df76c16SMatt Jacob 		if (xpt_create_path(&tmppath, NULL, cam_sim_path(ISP_SPI_PC(isp, bus)->sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
48582df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "isp_async cannot make temp path for %d.%d", tgt, bus);
4859cbf57b47SMatt Jacob 			break;
4860cbf57b47SMatt Jacob 		}
48619ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
4862ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
4863ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
4864ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
4865ab163f5fSMatt Jacob 
4866ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
4867ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
4868ab163f5fSMatt Jacob 
4869ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
4870ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
4871ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
4872ab163f5fSMatt Jacob 		}
4873ab163f5fSMatt Jacob 
4874cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
4875ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
4876ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
4877ab163f5fSMatt Jacob 		}
4878ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
4879ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
4880ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
4881ab163f5fSMatt Jacob 		} else {
4882ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
4883ab163f5fSMatt Jacob 		}
4884ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
4885ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
4886ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
48879ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
48889ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
4889ab163f5fSMatt Jacob 		}
48902df76c16SMatt 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);
4891ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
4892ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
4893cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
4894cbf57b47SMatt Jacob 		break;
48950470d791SMatt Jacob 	}
489657c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
48972df76c16SMatt Jacob 	{
48982df76c16SMatt Jacob 		va_start(ap, cmd);
48992df76c16SMatt Jacob 		bus = va_arg(ap, int);
49002df76c16SMatt Jacob 		va_end(ap);
49012df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected", bus);
49022df76c16SMatt Jacob 		if (IS_FC(isp)) {
49032df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_FC_PC(isp, bus)->path, NULL);
49042df76c16SMatt Jacob 		} else {
49052df76c16SMatt Jacob 			xpt_async(AC_BUS_RESET, ISP_SPI_PC(isp, bus)->path, NULL);
490657c801f5SMatt Jacob 		}
490757c801f5SMatt Jacob 		break;
49082df76c16SMatt Jacob 	}
49095d571944SMatt Jacob 	case ISPASYNC_LIP:
4910f7c631bcSMatt Jacob 		if (msg == NULL) {
4911f7c631bcSMatt Jacob 			msg = "LIP Received";
49125d571944SMatt Jacob 		}
4913f7c631bcSMatt Jacob 		/* FALLTHROUGH */
49145d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
4915f7c631bcSMatt Jacob 		if (msg == NULL) {
4916f7c631bcSMatt Jacob 			msg = "LOOP Reset";
49175d571944SMatt Jacob 		}
4918f7c631bcSMatt Jacob 		/* FALLTHROUGH */
491957c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
49202df76c16SMatt Jacob 	{
4921f7c631bcSMatt Jacob 		if (msg == NULL) {
4922f7c631bcSMatt Jacob 			msg = "LOOP Down";
492357c801f5SMatt Jacob 		}
49242df76c16SMatt Jacob 		va_start(ap, cmd);
49252df76c16SMatt Jacob 		bus = va_arg(ap, int);
49262df76c16SMatt Jacob 		va_end(ap);
49272df76c16SMatt Jacob 
4928a01f5aebSMatt Jacob 		FCPARAM(isp, bus)->link_active = 0;
49292df76c16SMatt Jacob 
49302df76c16SMatt Jacob 		fc = ISP_FC_PC(isp, bus);
4931a01f5aebSMatt Jacob 		if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
49322df76c16SMatt Jacob 			/*
49332df76c16SMatt Jacob 			 * We don't do any simq freezing if we are only in target mode
49342df76c16SMatt Jacob 			 */
49352df76c16SMatt Jacob 			if (fc->role & ISP_ROLE_INITIATOR) {
49362df76c16SMatt Jacob 				if (fc->path) {
49372df76c16SMatt Jacob 					isp_freeze_loopdown(isp, bus, msg);
4938f7c631bcSMatt Jacob 				}
4939a01f5aebSMatt Jacob 				if (!callout_active(&fc->ldt)) {
49402df76c16SMatt Jacob 					callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
49412df76c16SMatt Jacob 					isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
4942f7c631bcSMatt Jacob 				}
49432df76c16SMatt Jacob 			}
4944a01f5aebSMatt Jacob 		}
49452df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
494657c801f5SMatt Jacob 		break;
49472df76c16SMatt Jacob 	}
494857c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
49492df76c16SMatt Jacob 		va_start(ap, cmd);
49502df76c16SMatt Jacob 		bus = va_arg(ap, int);
49512df76c16SMatt Jacob 		va_end(ap);
4952a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
49535d571944SMatt Jacob 		/*
49545d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
49555d571944SMatt Jacob 		 * actually do anything because we're waiting for a
49565d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
49575d571944SMatt Jacob 		 * thread to look at the state of the loop again.
49585d571944SMatt Jacob 		 */
49592df76c16SMatt Jacob 		FCPARAM(isp, bus)->link_active = 1;
4960a01f5aebSMatt Jacob 		fc->loop_dead = 0;
4961a01f5aebSMatt Jacob 		fc->loop_down_time = 0;
49622df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
496357c801f5SMatt Jacob 		break;
496410365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
49652df76c16SMatt Jacob 		va_start(ap, cmd);
49662df76c16SMatt Jacob 		bus = va_arg(ap, int);
49672df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
49682df76c16SMatt Jacob 		va_end(ap);
4969a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
4970f7c631bcSMatt Jacob 		lp->reserved = 0;
4971a01f5aebSMatt Jacob 		if ((fc->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
49722df76c16SMatt Jacob 			int dbidx = lp - FCPARAM(isp, bus)->portdb;
4973f7c631bcSMatt Jacob 			int i;
497402ab3379SMatt Jacob 
4975f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
4976f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
4977f7c631bcSMatt Jacob 					continue;
4978f7c631bcSMatt Jacob 				}
49792df76c16SMatt Jacob 				if (FCPARAM(isp, bus)->isp_dev_map[i] == 0) {
4980f7c631bcSMatt Jacob 					break;
4981f7c631bcSMatt Jacob 				}
4982f7c631bcSMatt Jacob 			}
4983f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
49842df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[i] = dbidx + 1;
49852df76c16SMatt Jacob 				lp->dev_map_idx = i + 1;
4986f7c631bcSMatt Jacob 			} else {
4987f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
49882df76c16SMatt Jacob 				isp_dump_portdb(isp, bus);
4989f7c631bcSMatt Jacob 			}
4990f7c631bcSMatt Jacob 		}
49912df76c16SMatt Jacob 		if (lp->dev_map_idx) {
49922df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
49932df76c16SMatt 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);
49942df76c16SMatt Jacob 			isp_make_here(isp, bus, tgt);
499510365e5aSMatt Jacob 		} else {
49962df76c16SMatt 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);
499710365e5aSMatt Jacob 		}
499810365e5aSMatt Jacob 		break;
499910365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
50002df76c16SMatt Jacob 		va_start(ap, cmd);
50012df76c16SMatt Jacob 		bus = va_arg(ap, int);
50022df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50032df76c16SMatt Jacob 		va_end(ap);
5004a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
50052df76c16SMatt Jacob 		lp->reserved = 0;
5006f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
5007f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
50082df76c16SMatt Jacob 			if (lp->dev_map_idx) {
50092df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
50102df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[tgt] = 0;
50112df76c16SMatt Jacob 				lp->dev_map_idx = 0;
50122df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad");
50132df76c16SMatt Jacob 				isp_make_gone(isp, bus, tgt);
5014f7c631bcSMatt Jacob 			} else {
50152df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "changed and departed",
50162df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
5017f7c631bcSMatt Jacob 			}
5018f7c631bcSMatt Jacob 		} else {
5019f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
5020f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
50212df76c16SMatt Jacob 			if (lp->dev_map_idx) {
50222df76c16SMatt Jacob 				int t = lp->dev_map_idx - 1;
50232df76c16SMatt Jacob 				FCPARAM(isp, bus)->isp_dev_map[t] = (lp - FCPARAM(isp, bus)->portdb) + 1;
50242df76c16SMatt Jacob 				tgt = lp->dev_map_idx - 1;
50252df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "changed at", tgt,
50262df76c16SMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
502710365e5aSMatt Jacob 			} else {
50282df76c16SMatt 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);
502910365e5aSMatt Jacob 			}
5030f7c631bcSMatt Jacob 		}
503110365e5aSMatt Jacob 		break;
503210365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
50332df76c16SMatt Jacob 		va_start(ap, cmd);
50342df76c16SMatt Jacob 		bus = va_arg(ap, int);
50352df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50362df76c16SMatt Jacob 		va_end(ap);
50372df76c16SMatt Jacob 		if (lp->dev_map_idx) {
50382df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
50392df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "stayed at", tgt,
50402df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
504110365e5aSMatt Jacob 		} else {
50422df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom, bus, lp->portid, lp->handle, roles[lp->roles], "stayed",
50432df76c16SMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
504410365e5aSMatt Jacob 		}
504510365e5aSMatt Jacob 		break;
504610365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
50472df76c16SMatt Jacob 		va_start(ap, cmd);
50482df76c16SMatt Jacob 		bus = va_arg(ap, int);
50492df76c16SMatt Jacob 		lp = va_arg(ap, fcportdb_t *);
50502df76c16SMatt Jacob 		va_end(ap);
5051a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
5052f7c631bcSMatt Jacob 		/*
5053f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
5054f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
5055f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
5056f7c631bcSMatt Jacob 		 *
5057f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
5058f7c631bcSMatt Jacob 		 * announce that it's gone.
5059f7c631bcSMatt Jacob 		 */
50602df76c16SMatt Jacob 		if (lp->dev_map_idx && lp->reserved == 0) {
5061f7c631bcSMatt Jacob 			lp->reserved = 1;
50622df76c16SMatt Jacob 			lp->new_reserved = ISP_FC_PC(isp, bus)->gone_device_time;
5063f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
5064a01f5aebSMatt Jacob 			if (fc->ready && !callout_active(&fc->gdt)) {
50652df76c16SMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d starting Gone Device Timer", bus);
5066a01f5aebSMatt Jacob 				callout_reset(&fc->gdt, hz, isp_gdt, fc);
5067f7c631bcSMatt Jacob 			}
50682df76c16SMatt Jacob 			tgt = lp->dev_map_idx - 1;
50692df76c16SMatt 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);
5070f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
50712df76c16SMatt 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);
50724b9d588eSMatt Jacob 		}
507310365e5aSMatt Jacob 		break;
507410365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
507510365e5aSMatt Jacob 	{
507610365e5aSMatt Jacob 		char *msg;
50772df76c16SMatt Jacob 		int evt, nphdl, nlstate, reason;
50782df76c16SMatt Jacob 
50792df76c16SMatt Jacob 		va_start(ap, cmd);
50802df76c16SMatt Jacob 		bus = va_arg(ap, int);
50812df76c16SMatt Jacob 		evt = va_arg(ap, int);
50822df76c16SMatt Jacob 		if (IS_24XX(isp) && evt == ISPASYNC_CHANGE_PDB) {
50832df76c16SMatt Jacob 			nphdl = va_arg(ap, int);
50842df76c16SMatt Jacob 			nlstate = va_arg(ap, int);
50852df76c16SMatt Jacob 			reason = va_arg(ap, int);
508610365e5aSMatt Jacob 		} else {
50872df76c16SMatt Jacob 			nphdl = NIL_HANDLE;
50882df76c16SMatt Jacob 			nlstate = reason = 0;
508910365e5aSMatt Jacob 		}
50902df76c16SMatt Jacob 		va_end(ap);
5091a01f5aebSMatt Jacob 		fc = ISP_FC_PC(isp, bus);
50922df76c16SMatt Jacob 
50932df76c16SMatt Jacob 		if (evt == ISPASYNC_CHANGE_PDB) {
50942df76c16SMatt Jacob 			msg = "Chan %d Port Database Changed";
50952df76c16SMatt Jacob 		} else if (evt == ISPASYNC_CHANGE_SNS) {
50962df76c16SMatt Jacob 			msg = "Chan %d Name Server Database Changed";
50972df76c16SMatt Jacob 		} else {
50982df76c16SMatt Jacob 			msg = "Chan %d Other Change Notify";
50992df76c16SMatt Jacob 		}
51002df76c16SMatt Jacob 
5101f7c631bcSMatt Jacob 		/*
5102f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
5103f7c631bcSMatt Jacob 		 */
5104a01f5aebSMatt Jacob 		if (fc->ready && callout_active(&fc->ldt)) {
51052df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
5106a01f5aebSMatt Jacob 			callout_stop(&fc->ldt);
5107f7c631bcSMatt Jacob 		}
51082df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg, bus);
5109a01f5aebSMatt Jacob 		if (fc->role & ISP_ROLE_INITIATOR) {
51102df76c16SMatt Jacob 			isp_freeze_loopdown(isp, bus, msg);
51112df76c16SMatt Jacob 		}
5112a01f5aebSMatt Jacob 		wakeup(fc);
511357c801f5SMatt Jacob 		break;
511402ab3379SMatt Jacob 	}
5115d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
5116e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
5117d81ba9d5SMatt Jacob 	{
51182df76c16SMatt Jacob 		isp_notify_t *notify;
51192df76c16SMatt Jacob 		va_start(ap, cmd);
51202df76c16SMatt Jacob 		notify = va_arg(ap, isp_notify_t *);
51212df76c16SMatt Jacob 		va_end(ap);
51222df76c16SMatt Jacob 		switch (notify->nt_ncode) {
51232df76c16SMatt Jacob 		case NT_ABORT_TASK:
51242df76c16SMatt Jacob 		case NT_ABORT_TASK_SET:
51252df76c16SMatt Jacob 		case NT_CLEAR_ACA:
51262df76c16SMatt Jacob 		case NT_CLEAR_TASK_SET:
51272df76c16SMatt Jacob 		case NT_LUN_RESET:
51282df76c16SMatt Jacob 		case NT_TARGET_RESET:
51292df76c16SMatt Jacob 			/*
51302df76c16SMatt Jacob 			 * These are task management functions.
51312df76c16SMatt Jacob 			 */
51322df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, notify);
51332df76c16SMatt Jacob 			break;
51342df76c16SMatt Jacob 		case NT_BUS_RESET:
51352df76c16SMatt Jacob 		case NT_LIP_RESET:
51362df76c16SMatt Jacob 		case NT_LINK_UP:
51372df76c16SMatt Jacob 		case NT_LINK_DOWN:
51382df76c16SMatt Jacob 			/*
51392df76c16SMatt Jacob 			 * No action need be taken here.
51402df76c16SMatt Jacob 			 */
51412df76c16SMatt Jacob 			break;
51422df76c16SMatt Jacob 		case NT_HBA_RESET:
51432df76c16SMatt Jacob 			isp_del_all_wwn_entries(isp, ISP_NOCHAN);
51442df76c16SMatt Jacob 			break;
51452df76c16SMatt Jacob 		case NT_LOGOUT:
51462df76c16SMatt Jacob 			/*
51472df76c16SMatt Jacob 			 * This is device arrival/departure notification
51482df76c16SMatt Jacob 			 */
51492df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
51502df76c16SMatt Jacob 			break;
51512df76c16SMatt Jacob 		case NT_ARRIVED:
51522df76c16SMatt Jacob 		{
51532df76c16SMatt Jacob 			struct ac_contract ac;
51542df76c16SMatt Jacob 			struct ac_device_changed *fc;
51552df76c16SMatt Jacob 
51562df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
51572df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
51582df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
51592df76c16SMatt Jacob 			fc->port = notify->nt_sid;
51602df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
51612df76c16SMatt Jacob 			fc->arrived = 1;
51622df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
51632df76c16SMatt Jacob 			break;
51642df76c16SMatt Jacob 		}
51652df76c16SMatt Jacob 		case NT_DEPARTED:
51662df76c16SMatt Jacob 		{
51672df76c16SMatt Jacob 			struct ac_contract ac;
51682df76c16SMatt Jacob 			struct ac_device_changed *fc;
51692df76c16SMatt Jacob 
51702df76c16SMatt Jacob 			ac.contract_number = AC_CONTRACT_DEV_CHG;
51712df76c16SMatt Jacob 			fc = (struct ac_device_changed *) ac.contract_data;
51722df76c16SMatt Jacob 			fc->wwpn = notify->nt_wwn;
51732df76c16SMatt Jacob 			fc->port = notify->nt_sid;
51742df76c16SMatt Jacob 			fc->target = notify->nt_nphdl;
51752df76c16SMatt Jacob 			fc->arrived = 0;
51762df76c16SMatt Jacob 			xpt_async(AC_CONTRACT, ISP_FC_PC(isp, notify->nt_channel)->path, &ac);
51772df76c16SMatt Jacob 			break;
51782df76c16SMatt Jacob 		}
51792df76c16SMatt Jacob 		default:
51802df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGALL, "target notify code 0x%x", notify->nt_ncode);
51812df76c16SMatt Jacob 			isp_handle_platform_target_notify_ack(isp, notify);
51822df76c16SMatt Jacob 			break;
51832df76c16SMatt Jacob 		}
5184d81ba9d5SMatt Jacob 		break;
5185d81ba9d5SMatt Jacob 	}
5186d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
51872df76c16SMatt Jacob 	{
51882df76c16SMatt Jacob 		isphdr_t *hp;
51892df76c16SMatt Jacob 
51902df76c16SMatt Jacob 		va_start(ap, cmd);
51912df76c16SMatt Jacob 		hp = va_arg(ap, isphdr_t *);
51922df76c16SMatt Jacob 		va_end(ap);
51932df76c16SMatt Jacob 		switch (hp->rqs_entry_type) {
5194cbf57b47SMatt Jacob 		default:
51952df76c16SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "%s: unhandled target action 0x%x", __func__, hp->rqs_entry_type);
5196d81ba9d5SMatt Jacob 			break;
5197570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
5198570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
51992df76c16SMatt Jacob 				isp_handle_platform_notify_scsi(isp, (in_entry_t *) hp);
52002df76c16SMatt Jacob 			} else if (IS_24XX(isp)) {
52012df76c16SMatt Jacob 				isp_handle_platform_notify_24xx(isp, (in_fcentry_24xx_t *) hp);
5202570c7a3fSMatt Jacob 			} else {
52032df76c16SMatt Jacob 				isp_handle_platform_notify_fc(isp, (in_fcentry_t *) hp);
5204570c7a3fSMatt Jacob 			}
5205570c7a3fSMatt Jacob 			break;
5206d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
52072df76c16SMatt Jacob 			if (IS_24XX(isp)) {
52082df76c16SMatt Jacob 				isp_handle_platform_atio7(isp, (at7_entry_t *) hp);
52092df76c16SMatt Jacob 			} else {
52102df76c16SMatt Jacob 				isp_handle_platform_atio(isp, (at_entry_t *) hp);
52112df76c16SMatt Jacob 			}
5212d81ba9d5SMatt Jacob 			break;
5213d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
52142df76c16SMatt Jacob 			isp_handle_platform_atio2(isp, (at2_entry_t *) hp);
5215d81ba9d5SMatt Jacob 			break;
52162df76c16SMatt Jacob 		case RQSTYPE_CTIO7:
5217d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
5218d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
5219d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
52202df76c16SMatt Jacob 			isp_handle_platform_ctio(isp, hp);
5221d81ba9d5SMatt Jacob 			break;
52222df76c16SMatt Jacob 		case RQSTYPE_ABTS_RCVD:
52232df76c16SMatt Jacob 		{
52242df76c16SMatt Jacob 			abts_t *abts = (abts_t *)hp;
52252df76c16SMatt Jacob 			isp_notify_t notify, *nt = &notify;
52262df76c16SMatt Jacob 			tstate_t *tptr;
52272df76c16SMatt Jacob 			fcportdb_t *lp;
52282df76c16SMatt Jacob 			uint16_t chan;
52292df76c16SMatt Jacob 			uint32_t sid, did;
52302df76c16SMatt Jacob 
52312df76c16SMatt Jacob 			did = (abts->abts_did_hi << 16) | abts->abts_did_lo;
52322df76c16SMatt Jacob 			sid = (abts->abts_sid_hi << 16) | abts->abts_sid_lo;
52332df76c16SMatt Jacob 			ISP_MEMZERO(nt, sizeof (isp_notify_t));
52342df76c16SMatt Jacob 
52352df76c16SMatt Jacob 			nt->nt_hba = isp;
52362df76c16SMatt Jacob 			nt->nt_did = did;
52372df76c16SMatt Jacob 			nt->nt_nphdl = abts->abts_nphdl;
52382df76c16SMatt Jacob 			nt->nt_sid = sid;
52392df76c16SMatt Jacob 			isp_find_chan_by_did(isp, did, &chan);
52402df76c16SMatt Jacob 			if (chan == ISP_NOCHAN) {
52412df76c16SMatt Jacob 				nt->nt_tgt = TGT_ANY;
52422df76c16SMatt Jacob 			} else {
52432df76c16SMatt Jacob 				nt->nt_tgt = FCPARAM(isp, chan)->isp_wwpn;
52442df76c16SMatt Jacob 				if (isp_find_pdb_by_loopid(isp, chan, abts->abts_nphdl, &lp)) {
52452df76c16SMatt Jacob 					nt->nt_wwn = lp->port_wwn;
52462df76c16SMatt Jacob 				} else {
52472df76c16SMatt Jacob 					nt->nt_wwn = INI_ANY;
52482df76c16SMatt Jacob 				}
52492df76c16SMatt Jacob 			}
52502df76c16SMatt Jacob 			/*
52512df76c16SMatt Jacob 			 * Try hard to find the lun for this command.
52522df76c16SMatt Jacob 			 */
52532df76c16SMatt Jacob 			tptr = get_lun_statep_from_tag(isp, chan, abts->abts_rxid_task);
52542df76c16SMatt Jacob 			if (tptr) {
52552df76c16SMatt Jacob 				nt->nt_lun = xpt_path_lun_id(tptr->owner);
52562df76c16SMatt Jacob 				rls_lun_statep(isp, tptr);
52572df76c16SMatt Jacob 			} else {
52582df76c16SMatt Jacob 				nt->nt_lun = LUN_ANY;
52592df76c16SMatt Jacob 			}
52602df76c16SMatt Jacob 			nt->nt_need_ack = 1;
52612df76c16SMatt Jacob 			nt->nt_tagval = abts->abts_rxid_task;
52622df76c16SMatt Jacob 			nt->nt_tagval |= (((uint64_t) abts->abts_rxid_abts) << 32);
52632df76c16SMatt Jacob 			if (abts->abts_rxid_task == ISP24XX_NO_TASK) {
52642df76c16SMatt 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)",
52652df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rx_id, abts->abts_ox_id);
52662df76c16SMatt Jacob 			} else {
52672df76c16SMatt 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)",
52682df76c16SMatt Jacob 				    abts->abts_rxid_abts, abts->abts_nphdl, sid, abts->abts_rxid_task, abts->abts_rx_id, abts->abts_ox_id);
52692df76c16SMatt Jacob 			}
52702df76c16SMatt Jacob 			nt->nt_channel = chan;
52712df76c16SMatt Jacob 			nt->nt_ncode = NT_ABORT_TASK;
52722df76c16SMatt Jacob 			nt->nt_lreserved = hp;
52732df76c16SMatt Jacob 			isp_handle_platform_target_tmf(isp, nt);
52742df76c16SMatt Jacob 			break;
52752df76c16SMatt Jacob 		}
5276d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
5277d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
52782df76c16SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) hp);
5279d81ba9d5SMatt Jacob 			break;
5280d81ba9d5SMatt Jacob 		}
5281d81ba9d5SMatt Jacob 		break;
52822df76c16SMatt Jacob 	}
5283d81ba9d5SMatt Jacob #endif
5284ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
5285ab163f5fSMatt Jacob 	{
52861dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
5287ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
5288ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
5289ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
5290ab163f5fSMatt Jacob 		} else {
5291ab163f5fSMatt Jacob 			mbox6 = 0;
5292ab163f5fSMatt Jacob 		}
52932df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "Internal Firmware Error on bus %d @ RISC Address 0x%x", mbox6, mbox1);
52940a70657fSMatt Jacob 		mbox1 = isp->isp_osinfo.mbox_sleep_ok;
52950a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
52962df76c16SMatt Jacob 		isp_reinit(isp, 1);
52970a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = mbox1;
52980a70657fSMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
5299ab163f5fSMatt Jacob 		break;
5300ab163f5fSMatt Jacob 	}
5301d81ba9d5SMatt Jacob 	default:
5302b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
5303cbf57b47SMatt Jacob 		break;
5304cbf57b47SMatt Jacob 	}
5305cbf57b47SMatt Jacob }
5306cbf57b47SMatt Jacob 
530792718a7fSMatt Jacob 
530892718a7fSMatt Jacob /*
530992718a7fSMatt Jacob  * Locks are held before coming here.
531092718a7fSMatt Jacob  */
531192718a7fSMatt Jacob void
53129cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
531392718a7fSMatt Jacob {
531410365e5aSMatt Jacob 	if (IS_24XX(isp)) {
531510365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
531610365e5aSMatt Jacob 	} else {
5317ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
531810365e5aSMatt Jacob 	}
531910365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
532092718a7fSMatt Jacob }
5321b09b0095SMatt Jacob 
53222df76c16SMatt Jacob /*
53232df76c16SMatt Jacob  * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them
53242df76c16SMatt Jacob  * up from our platform default (defww{p|n}n) and morph them based upon
53252df76c16SMatt Jacob  * channel.
53262df76c16SMatt Jacob  *
53272df76c16SMatt Jacob  * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them
53282df76c16SMatt Jacob  * based upon channel.
53292df76c16SMatt Jacob  */
53302df76c16SMatt Jacob 
53312df76c16SMatt Jacob uint64_t
53322df76c16SMatt Jacob isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn)
53332df76c16SMatt Jacob {
53342df76c16SMatt Jacob 	uint64_t seed;
53352df76c16SMatt Jacob 	struct isp_fc *fc = ISP_FC_PC(isp, chan);
53362df76c16SMatt Jacob 
53372df76c16SMatt Jacob 	/*
53382df76c16SMatt Jacob 	 * If we're asking for a active WWN, the default overrides get
53392df76c16SMatt Jacob 	 * returned, otherwise the NVRAM value is picked.
53402df76c16SMatt Jacob 	 *
53412df76c16SMatt Jacob 	 * If we're asking for a default WWN, we just pick the default override.
53422df76c16SMatt Jacob 	 */
53432df76c16SMatt Jacob 	if (isactive) {
53442df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
53452df76c16SMatt Jacob 		if (seed) {
53462df76c16SMatt Jacob 			return (seed);
53472df76c16SMatt Jacob 		}
53482df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram;
53495cc3786cSMatt Jacob 		if (seed) {
53505cc3786cSMatt Jacob 			return (seed);
53515cc3786cSMatt Jacob 		}
53525cc3786cSMatt Jacob 		return (0x400000007F000009ull);
53532df76c16SMatt Jacob 	} else {
53542df76c16SMatt Jacob 		seed = iswwnn ? fc->def_wwnn : fc->def_wwpn;
53552df76c16SMatt Jacob 	}
53562df76c16SMatt Jacob 
53572df76c16SMatt Jacob 
53582df76c16SMatt Jacob 	/*
53592df76c16SMatt Jacob 	 * For channel zero just return what we have. For either ACIIVE or
53602df76c16SMatt Jacob 	 * DEFAULT cases, we depend on default override of NVRAM values for
53612df76c16SMatt Jacob 	 * channel zero.
53622df76c16SMatt Jacob 	 */
53632df76c16SMatt Jacob 	if (chan == 0) {
53642df76c16SMatt Jacob 		return (seed);
53652df76c16SMatt Jacob 	}
53662df76c16SMatt Jacob 
53672df76c16SMatt Jacob 	/*
53682df76c16SMatt Jacob 	 * For other channels, we are doing one of three things:
53692df76c16SMatt Jacob 	 *
53702df76c16SMatt Jacob 	 * 1. If what we have now is non-zero, return it. Otherwise we morph
53712df76c16SMatt Jacob 	 * values from channel 0. 2. If we're here for a WWPN we synthesize
53722df76c16SMatt Jacob 	 * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a
53732df76c16SMatt Jacob 	 * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA.
53742df76c16SMatt Jacob 	 */
53752df76c16SMatt Jacob 
53762df76c16SMatt Jacob 	if (seed) {
53772df76c16SMatt Jacob 		return (seed);
53782df76c16SMatt Jacob 	}
53792df76c16SMatt Jacob 	if (isactive) {
53802df76c16SMatt Jacob 		seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram;
53812df76c16SMatt Jacob 	} else {
53822df76c16SMatt Jacob 		seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn;
53832df76c16SMatt Jacob 	}
53842df76c16SMatt Jacob 
53852df76c16SMatt Jacob 	if (((seed >> 60) & 0xf) == 2) {
53862df76c16SMatt Jacob 		/*
53872df76c16SMatt Jacob 		 * The type 2 NAA fields for QLogic cards appear be laid out
53882df76c16SMatt Jacob 		 * thusly:
53892df76c16SMatt Jacob 		 *
53902df76c16SMatt Jacob 		 * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56
53912df76c16SMatt Jacob 		 * port (1) or node (0) WWN distinguishor bit 48
53922df76c16SMatt Jacob 		 * physical port on dual-port chips (23XX/24XX)
53932df76c16SMatt Jacob 		 *
53942df76c16SMatt Jacob 		 * This is somewhat nutty, particularly since bit 48 is
53952df76c16SMatt Jacob 		 * irrelevant as they assign seperate serial numbers to
53962df76c16SMatt Jacob 		 * different physical ports anyway.
53972df76c16SMatt Jacob 		 *
53982df76c16SMatt Jacob 		 * We'll stick our channel number plus one first into bits
53992df76c16SMatt Jacob 		 * 57..59 and thence into bits 52..55 which allows for 8 bits
54002df76c16SMatt Jacob 		 * of channel which is comfortably more than our maximum
54012df76c16SMatt Jacob 		 * (126) now.
54022df76c16SMatt Jacob 		 */
54032df76c16SMatt Jacob 		seed &= ~0x0FF0000000000000ULL;
54042df76c16SMatt Jacob 		if (iswwnn == 0) {
54052df76c16SMatt Jacob 			seed |= ((uint64_t) (chan + 1) & 0xf) << 56;
54062df76c16SMatt Jacob 			seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52;
54072df76c16SMatt Jacob 		}
54082df76c16SMatt Jacob 	} else {
54092df76c16SMatt Jacob 		seed = 0;
54102df76c16SMatt Jacob 	}
54112df76c16SMatt Jacob 	return (seed);
54122df76c16SMatt Jacob }
54132df76c16SMatt Jacob 
5414b09b0095SMatt Jacob void
54159cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
5416b09b0095SMatt Jacob {
5417b09b0095SMatt Jacob 	va_list ap;
5418b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
5419b09b0095SMatt Jacob 		return;
5420b09b0095SMatt Jacob 	}
54213c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
5422b09b0095SMatt Jacob 	va_start(ap, fmt);
5423b09b0095SMatt Jacob 	vprintf(fmt, ap);
5424b09b0095SMatt Jacob 	va_end(ap);
5425b09b0095SMatt Jacob 	printf("\n");
5426b09b0095SMatt Jacob }
5427f7c631bcSMatt Jacob 
5428f7c631bcSMatt Jacob uint64_t
5429f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
5430f7c631bcSMatt Jacob {
5431f7c631bcSMatt Jacob 	uint64_t elapsed;
5432f7c631bcSMatt Jacob 	struct timespec x = *b;
5433f7c631bcSMatt Jacob 	timespecsub(&x, a);
5434f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
5435f7c631bcSMatt Jacob 	if (elapsed == 0)
5436f7c631bcSMatt Jacob 		elapsed++;
5437f7c631bcSMatt Jacob 	return (elapsed);
5438f7c631bcSMatt Jacob }
5439f7c631bcSMatt Jacob 
5440f7c631bcSMatt Jacob int
5441f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
5442f7c631bcSMatt Jacob {
5443f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
5444f7c631bcSMatt Jacob 		return (1);
5445f7c631bcSMatt Jacob 	} else {
5446f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
5447f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
5448f7c631bcSMatt Jacob 		return (0);
5449f7c631bcSMatt Jacob 	}
5450f7c631bcSMatt Jacob }
5451f7c631bcSMatt Jacob 
5452f7c631bcSMatt Jacob void
5453f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
5454f7c631bcSMatt Jacob {
5455a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
5456a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
5457f7c631bcSMatt Jacob 
5458f7c631bcSMatt Jacob 	if (usecs == 0) {
5459f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
5460f7c631bcSMatt Jacob 	}
5461a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
5462a4f3a2beSMatt Jacob 
5463f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
5464a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
5465a4f3a2beSMatt Jacob 
5466f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
5467f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
5468a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
54692df76c16SMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock, PRIBIO, "ispmbx_sleep", isp_mstohz(ms));
5470a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5471a4f3a2beSMatt Jacob 				break;
5472a4f3a2beSMatt Jacob 			}
5473a4f3a2beSMatt Jacob 		}
5474f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
5475f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
5476f7c631bcSMatt Jacob 	} else {
5477a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
5478a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
5479f7c631bcSMatt Jacob 				uint32_t isr;
5480f7c631bcSMatt Jacob 				uint16_t sema, mbox;
5481f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
5482f7c631bcSMatt Jacob 					break;
5483f7c631bcSMatt Jacob 				}
5484f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
5485f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
5486f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
5487f7c631bcSMatt Jacob 						break;
5488f7c631bcSMatt Jacob 					}
5489f7c631bcSMatt Jacob 				}
54902df76c16SMatt Jacob 				ISP_DELAY(100);
5491f7c631bcSMatt Jacob 			}
5492a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
5493a4f3a2beSMatt Jacob 				break;
5494a4f3a2beSMatt Jacob 			}
5495a4f3a2beSMatt Jacob 		}
5496f7c631bcSMatt Jacob 	}
5497f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
54982df76c16SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "%s Mailbox Command (0x%x) Timeout (%uus) (started @ %s:%d)",
54992df76c16SMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled", isp->isp_lastmbxcmd, usecs, mbp->func, mbp->lineno);
5500f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
5501f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
5502f7c631bcSMatt Jacob 	}
5503f7c631bcSMatt Jacob }
5504f7c631bcSMatt Jacob 
5505f7c631bcSMatt Jacob void
5506f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
5507f7c631bcSMatt Jacob {
5508f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
5509f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
5510f7c631bcSMatt Jacob 	}
5511f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
5512f7c631bcSMatt Jacob }
5513f7c631bcSMatt Jacob 
5514f7c631bcSMatt Jacob void
5515f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
5516f7c631bcSMatt Jacob {
5517f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
5518f7c631bcSMatt Jacob }
5519f7c631bcSMatt Jacob 
5520f7c631bcSMatt Jacob int
55212df76c16SMatt Jacob isp_fc_scratch_acquire(ispsoftc_t *isp, int chan)
55222df76c16SMatt Jacob {
55232df76c16SMatt Jacob 	int ret = 0;
55242df76c16SMatt Jacob 	if (isp->isp_osinfo.pc.fc[chan].fcbsy) {
55252df76c16SMatt Jacob 		ret = -1;
55262df76c16SMatt Jacob 	} else {
55272df76c16SMatt Jacob 		isp->isp_osinfo.pc.fc[chan].fcbsy = 1;
55282df76c16SMatt Jacob 	}
55292df76c16SMatt Jacob 	return (ret);
55302df76c16SMatt Jacob }
55312df76c16SMatt Jacob 
55322df76c16SMatt Jacob int
5533f7c631bcSMatt Jacob isp_mstohz(int ms)
5534f7c631bcSMatt Jacob {
5535a4f3a2beSMatt Jacob 	int hz;
5536f7c631bcSMatt Jacob 	struct timeval t;
5537f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
5538f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
5539a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
5540a4f3a2beSMatt Jacob 	if (hz < 0) {
5541a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
5542f7c631bcSMatt Jacob 	}
5543a4f3a2beSMatt Jacob 	if (hz == 0) {
5544a4f3a2beSMatt Jacob 		hz = 1;
5545a4f3a2beSMatt Jacob 	}
5546a4f3a2beSMatt Jacob 	return (hz);
5547f7c631bcSMatt Jacob }
55480a70657fSMatt Jacob 
55490a70657fSMatt Jacob void
55500a70657fSMatt Jacob isp_platform_intr(void *arg)
55510a70657fSMatt Jacob {
55520a70657fSMatt Jacob 	ispsoftc_t *isp = arg;
55530a70657fSMatt Jacob 	uint32_t isr;
55540a70657fSMatt Jacob 	uint16_t sema, mbox;
55550a70657fSMatt Jacob 
55560a70657fSMatt Jacob 	ISP_LOCK(isp);
55570a70657fSMatt Jacob 	isp->isp_intcnt++;
55580a70657fSMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
55590a70657fSMatt Jacob 		isp->isp_intbogus++;
55600a70657fSMatt Jacob 	} else {
55610a70657fSMatt Jacob 		isp_intr(isp, isr, sema, mbox);
55620a70657fSMatt Jacob 	}
55630a70657fSMatt Jacob 	ISP_UNLOCK(isp);
55640a70657fSMatt Jacob }
55650a70657fSMatt Jacob 
55660a70657fSMatt Jacob void
55670a70657fSMatt Jacob isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl)
55680a70657fSMatt Jacob {
55690a70657fSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
55702df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD);
55710a70657fSMatt Jacob 	} else {
55722df76c16SMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE);
55730a70657fSMatt Jacob 	}
55740a70657fSMatt Jacob 	bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
55750a70657fSMatt Jacob }
55762df76c16SMatt Jacob 
55772df76c16SMatt Jacob void
55782df76c16SMatt Jacob isp_timer(void *arg)
55792df76c16SMatt Jacob {
55802df76c16SMatt Jacob 	ispsoftc_t *isp = arg;
55812df76c16SMatt Jacob #ifdef	ISP_TARGET_MODE
55822df76c16SMatt Jacob 	isp_tmcmd_restart(isp);
55832df76c16SMatt Jacob #endif
55842df76c16SMatt Jacob 	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
55852df76c16SMatt Jacob }
5586