xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision dd9fc7c3)
1098ca2bdSWarner Losh /*-
26054c3f6SMatt Jacob  *
3e5265237SMatt Jacob  * Copyright (c) 1997-2006 by Matthew Jacob
4e5265237SMatt Jacob  * All rights reserved.
56054c3f6SMatt Jacob  *
66054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
76054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
86054c3f6SMatt Jacob  * are met:
96054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
106054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
116054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
12aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
13aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
146054c3f6SMatt Jacob  *
156054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
196054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256054c3f6SMatt Jacob  * SUCH DAMAGE.
266054c3f6SMatt Jacob  */
27aad970f1SDavid E. O'Brien 
28799881e0SMatt Jacob /*
29799881e0SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
30799881e0SMatt Jacob  */
31aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
336054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
345d571944SMatt Jacob #include <sys/unistd.h>
355d571944SMatt Jacob #include <sys/kthread.h>
363ea883b4SMatt Jacob #include <machine/stdarg.h>	/* for use by isp_prt below */
375d571944SMatt Jacob #include <sys/conf.h>
384eb49427SMatt Jacob #include <sys/module.h>
395d571944SMatt Jacob #include <sys/ioccom.h>
405d571944SMatt Jacob #include <dev/isp/isp_ioctl.h>
419311717dSMatt Jacob #if	__FreeBSD_version >= 500000
429311717dSMatt Jacob #include <sys/sysctl.h>
439311717dSMatt Jacob #endif
44f7c631bcSMatt Jacob #include <cam/cam_periph.h>
456054c3f6SMatt Jacob 
46a1bc34c6SMatt Jacob 
474eb49427SMatt Jacob MODULE_VERSION(isp, 1);
4856c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1);
4973030e03SMatt Jacob int isp_announced = 0;
5010365e5aSMatt Jacob int isp_fabric_hysteresis = 5;
5110365e5aSMatt Jacob int isp_loop_down_limit = 300;	/* default loop down limit */
52f7c631bcSMatt Jacob int isp_change_is_bad = 0;	/* "changed" devices are bad */
53f7c631bcSMatt Jacob int isp_quickboot_time = 15;	/* don't wait more than N secs for loop up */
54f7c631bcSMatt Jacob int isp_gone_device_time = 30;	/* grace time before reporting device lost */
55f7c631bcSMatt Jacob static const char *roles[4] = {
56f7c631bcSMatt Jacob     "(none)", "Target", "Initiator", "Target/Initiator"
57f7c631bcSMatt Jacob };
58f7c631bcSMatt Jacob static const char prom3[] =
59f7c631bcSMatt Jacob     "PortID 0x%06x Departed from Target %u because of %s";
6073030e03SMatt Jacob 
61f7c631bcSMatt Jacob static void isp_freeze_loopdown(ispsoftc_t *, char *);
625d571944SMatt Jacob static d_ioctl_t ispioctl;
63f6e75de2SMatt Jacob static void isp_intr_enable(void *);
641dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
650470d791SMatt Jacob static void isp_poll(struct cam_sim *);
66b85389e1SMatt Jacob static timeout_t isp_watchdog;
67f7c631bcSMatt Jacob static timeout_t isp_ldt;
685d571944SMatt Jacob static void isp_kthread(void *);
69d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
700470d791SMatt Jacob 
71784ed707SMatt Jacob #if __FreeBSD_version < 700000
72784ed707SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
73784ed707SMatt Jacob #endif
74cc8df88bSMatt Jacob 
759cd7268eSMatt Jacob #if __FreeBSD_version < 500000
769cd7268eSMatt Jacob #define ISP_CDEV_MAJOR	248
779cd7268eSMatt Jacob static struct cdevsw isp_cdevsw = {
789cd7268eSMatt Jacob 	/* open */	nullopen,
799cd7268eSMatt Jacob 	/* close */	nullclose,
809cd7268eSMatt Jacob 	/* read */	noread,
819cd7268eSMatt Jacob 	/* write */	nowrite,
829cd7268eSMatt Jacob 	/* ioctl */	ispioctl,
839cd7268eSMatt Jacob 	/* poll */	nopoll,
849cd7268eSMatt Jacob 	/* mmap */	nommap,
859cd7268eSMatt Jacob 	/* strategy */	nostrategy,
869cd7268eSMatt Jacob 	/* name */	"isp",
879cd7268eSMatt Jacob 	/* maj */	ISP_CDEV_MAJOR,
889cd7268eSMatt Jacob 	/* dump */	nodump,
899cd7268eSMatt Jacob 	/* psize */	nopsize,
909cd7268eSMatt Jacob 	/* flags */	D_TAPE,
919cd7268eSMatt Jacob };
929311717dSMatt Jacob #define	isp_sysctl_update(x)	do { ; } while (0)
939cd7268eSMatt Jacob #else
945d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
95dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
96dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
977ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
987ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
995d571944SMatt Jacob };
1009311717dSMatt Jacob static void isp_sysctl_update(ispsoftc_t *);
1019cd7268eSMatt Jacob #endif
1025d571944SMatt Jacob 
1039cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL;
104478f8a96SJustin T. Gibbs 
105478f8a96SJustin T. Gibbs void
1069cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp)
107478f8a96SJustin T. Gibbs {
108ea6f23cdSMatt Jacob 	int primary, secondary;
109478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
110478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
111ea6f23cdSMatt Jacob 	struct cam_sim *sim;
112ea6f23cdSMatt Jacob 	struct cam_path *path;
113478f8a96SJustin T. Gibbs 
114478f8a96SJustin T. Gibbs 	/*
115ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
116ea6f23cdSMatt Jacob 	 */
117ea6f23cdSMatt Jacob 
118ea6f23cdSMatt Jacob 	primary = 0;
119ea6f23cdSMatt Jacob 	secondary = 1;
120ea6f23cdSMatt Jacob 
121ea6f23cdSMatt Jacob 	/*
122ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
123478f8a96SJustin T. Gibbs 	 */
124ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
125478f8a96SJustin T. Gibbs 	if (devq == NULL) {
126478f8a96SJustin T. Gibbs 		return;
127478f8a96SJustin T. Gibbs 	}
128478f8a96SJustin T. Gibbs 
129478f8a96SJustin T. Gibbs 	/*
130ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
131478f8a96SJustin T. Gibbs 	 */
13245c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
133ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
1343c75bb14SMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
135ea6f23cdSMatt Jacob 	if (sim == NULL) {
136478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
13745c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
138478f8a96SJustin T. Gibbs 		return;
139478f8a96SJustin T. Gibbs 	}
14045c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
141f6e75de2SMatt Jacob 
142f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
143f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
14445c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
145f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
14645c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
14745c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
148bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
149bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
150f6e75de2SMatt Jacob 		return;
151f6e75de2SMatt Jacob 	}
152f6e75de2SMatt Jacob 
153ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
154ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
15545c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
156478f8a96SJustin T. Gibbs 		return;
157478f8a96SJustin T. Gibbs 	}
158478f8a96SJustin T. Gibbs 
159ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
160478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
161ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
162ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1635d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
16445c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
165478f8a96SJustin T. Gibbs 		return;
166478f8a96SJustin T. Gibbs 	}
167478f8a96SJustin T. Gibbs 
168ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
169478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
170478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
171cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
172ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
173478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
17445c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
175ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
176ea6f23cdSMatt Jacob 	isp->isp_path = path;
1775d571944SMatt Jacob 	/*
1785d571944SMatt Jacob 	 * Create a kernel thread for fibre channel instances. We
1795d571944SMatt Jacob 	 * don't have dual channel FC cards.
1805d571944SMatt Jacob 	 */
1815d571944SMatt Jacob 	if (IS_FC(isp)) {
18245c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
1839cd7268eSMatt Jacob #if __FreeBSD_version >= 500000
1845d571944SMatt Jacob 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
1855d571944SMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
186316ec49aSScott Long 		    RFHIGHPID, 0, "%s: fc_thrd",
1879cd7268eSMatt Jacob 		    device_get_nameunit(isp->isp_dev)))
1889cd7268eSMatt Jacob #else
1899cd7268eSMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
1909cd7268eSMatt Jacob 		    "%s: fc_thrd", device_get_nameunit(isp->isp_dev)))
1919cd7268eSMatt Jacob #endif
1929cd7268eSMatt Jacob 		{
1935d571944SMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
1945d571944SMatt Jacob 			cam_sim_free(sim, TRUE);
1955d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
19645c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
19745c9a36aSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
1985d571944SMatt Jacob 			return;
1995d571944SMatt Jacob 		}
2008e6a12fcSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
201f7c631bcSMatt Jacob 		/*
202f7c631bcSMatt Jacob 		 * We start by being "loop down" if we have an initiator role
203f7c631bcSMatt Jacob 		 */
204f7c631bcSMatt Jacob 		if (isp->isp_role & ISP_ROLE_INITIATOR) {
205f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, "isp_attach");
206f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt =
207f7c631bcSMatt Jacob 			    timeout(isp_ldt, isp, isp_quickboot_time * hz);
208f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
209f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
210f7c631bcSMatt Jacob 			   "Starting Initial Loop Down Timer");
211f7c631bcSMatt Jacob 		}
2125d571944SMatt Jacob 	}
2135d571944SMatt Jacob 
214478f8a96SJustin T. Gibbs 
215ea6f23cdSMatt Jacob 	/*
216ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
217ea6f23cdSMatt Jacob 	 */
21822e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
21945c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
220ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
2213c75bb14SMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
222ea6f23cdSMatt Jacob 		if (sim == NULL) {
223ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
224ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
225ea6f23cdSMatt Jacob 			cam_simq_free(devq);
2265d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
227ea6f23cdSMatt Jacob 			return;
228ea6f23cdSMatt Jacob 		}
229ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
230ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
231ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
232ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2335d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
23445c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
235ea6f23cdSMatt Jacob 			return;
236ea6f23cdSMatt Jacob 		}
237ea6f23cdSMatt Jacob 
238ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
239ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
240ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
241ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
242ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
243ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2445d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
24545c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
246ea6f23cdSMatt Jacob 			return;
247ea6f23cdSMatt Jacob 		}
248ea6f23cdSMatt Jacob 
249ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
250ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
251ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
252ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
253ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
254ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
25545c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
256ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
257ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
258ea6f23cdSMatt Jacob 	}
2595d571944SMatt Jacob 
2605d571944SMatt Jacob 	/*
2615d571944SMatt Jacob 	 * Create device nodes
2625d571944SMatt Jacob 	 */
2635d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2645d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2655d571944SMatt Jacob 
266d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
267478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
26810365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
269d6e5500fSMatt Jacob 	}
270d81ba9d5SMatt Jacob 	if (isplist == NULL) {
271d81ba9d5SMatt Jacob 		isplist = isp;
272d81ba9d5SMatt Jacob 	} else {
2739cd7268eSMatt Jacob 		ispsoftc_t *tmp = isplist;
274d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
275d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
276d81ba9d5SMatt Jacob 		}
277d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
278478f8a96SJustin T. Gibbs 	}
2799311717dSMatt Jacob 	isp_sysctl_update(isp);
2805d571944SMatt Jacob }
2815d571944SMatt Jacob 
282f7c631bcSMatt Jacob static void
2839cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg)
284fdeb9f2fSMatt Jacob {
285fdeb9f2fSMatt Jacob 	if (isp->isp_osinfo.simqfrozen == 0) {
286fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg);
287fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
288fdeb9f2fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
289fdeb9f2fSMatt Jacob 		xpt_freeze_simq(isp->isp_sim, 1);
290fdeb9f2fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
291fdeb9f2fSMatt Jacob 	} else {
292fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg);
293fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
294fdeb9f2fSMatt Jacob 	}
295fdeb9f2fSMatt Jacob }
296fdeb9f2fSMatt Jacob 
2979cd7268eSMatt Jacob 
2989cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2999cd7268eSMatt Jacob #define	_DEV	dev_t
3009cd7268eSMatt Jacob #define	_IOP	struct proc
3019cd7268eSMatt Jacob #else
3029cd7268eSMatt Jacob #define	_IOP	struct thread
3039cd7268eSMatt Jacob #define	_DEV	struct cdev *
3049cd7268eSMatt Jacob #endif
3059cd7268eSMatt Jacob 
3065d571944SMatt Jacob static int
3079cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td)
3085d571944SMatt Jacob {
3099cd7268eSMatt Jacob 	ispsoftc_t *isp;
310746e9c85SMatt Jacob 	int nr, retval = ENOTTY;
3115d571944SMatt Jacob 
3125d571944SMatt Jacob 	isp = isplist;
3135d571944SMatt Jacob 	while (isp) {
3145d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
3155d571944SMatt Jacob 			break;
3165d571944SMatt Jacob 		}
3175d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
3185d571944SMatt Jacob 	}
3195d571944SMatt Jacob 	if (isp == NULL)
3205d571944SMatt Jacob 		return (ENXIO);
3215d571944SMatt Jacob 
322c1504bc0SMatt Jacob 	switch (c) {
323d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
324d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
32502e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
3261dae40ebSMatt Jacob 			uint16_t *ptr = FCPARAM(isp)->isp_dump_data;
327d134aa0bSMatt Jacob 			size_t sz;
328d134aa0bSMatt Jacob 
329d134aa0bSMatt Jacob 			retval = 0;
33002e2b2d9SMatt Jacob 			if (IS_2200(isp)) {
331d134aa0bSMatt Jacob 				sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
33202e2b2d9SMatt Jacob 			} else {
333d134aa0bSMatt Jacob 				sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
33402e2b2d9SMatt Jacob 			}
335d134aa0bSMatt Jacob 			ISP_LOCK(isp);
336d134aa0bSMatt Jacob 			if (ptr && *ptr) {
337d134aa0bSMatt Jacob 				void *uaddr = *((void **) addr);
338d134aa0bSMatt Jacob 				if (copyout(ptr, uaddr, sz)) {
339d134aa0bSMatt Jacob 					retval = EFAULT;
340d134aa0bSMatt Jacob 				} else {
341d134aa0bSMatt Jacob 					*ptr = 0;
342d134aa0bSMatt Jacob 				}
343d134aa0bSMatt Jacob 			} else {
344d134aa0bSMatt Jacob 				retval = ENXIO;
345d134aa0bSMatt Jacob 			}
346d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
347d134aa0bSMatt Jacob 		}
34802e2b2d9SMatt Jacob 		break;
349d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
35002e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
351d134aa0bSMatt Jacob 			ISP_LOCK(isp);
35202e2b2d9SMatt Jacob 			isp_freeze_loopdown(isp,
35302e2b2d9SMatt Jacob 			    "ispioctl(ISP_FORCE_CRASH_DUMP)");
354d134aa0bSMatt Jacob 			isp_fw_dump(isp);
355d134aa0bSMatt Jacob 			isp_reinit(isp);
356d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
357d134aa0bSMatt Jacob 			retval = 0;
35802e2b2d9SMatt Jacob 		}
359d134aa0bSMatt Jacob 		break;
360d134aa0bSMatt Jacob #endif
3615d571944SMatt Jacob 	case ISP_SDBLEV:
3625d571944SMatt Jacob 	{
3635d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3645d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3655d571944SMatt Jacob 		*(int *)addr = olddblev;
3665d571944SMatt Jacob 		retval = 0;
3675d571944SMatt Jacob 		break;
3685d571944SMatt Jacob 	}
369746e9c85SMatt Jacob 	case ISP_GETROLE:
370746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
371746e9c85SMatt Jacob 		retval = 0;
372746e9c85SMatt Jacob 		break;
373746e9c85SMatt Jacob 	case ISP_SETROLE:
374746e9c85SMatt Jacob 		nr = *(int *)addr;
375746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
376746e9c85SMatt Jacob 			retval = EINVAL;
377746e9c85SMatt Jacob 			break;
378746e9c85SMatt Jacob 		}
379746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
380746e9c85SMatt Jacob 		isp->isp_role = nr;
381746e9c85SMatt Jacob 		/* FALLTHROUGH */
3825d571944SMatt Jacob 	case ISP_RESETHBA:
3835d571944SMatt Jacob 		ISP_LOCK(isp);
3845d571944SMatt Jacob 		isp_reinit(isp);
3855d571944SMatt Jacob 		ISP_UNLOCK(isp);
3865d571944SMatt Jacob 		retval = 0;
3875d571944SMatt Jacob 		break;
388f553351eSMatt Jacob 	case ISP_RESCAN:
3895d571944SMatt Jacob 		if (IS_FC(isp)) {
3905d571944SMatt Jacob 			ISP_LOCK(isp);
3915d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
3925d571944SMatt Jacob 				retval = EIO;
3935d571944SMatt Jacob 			} else {
3945d571944SMatt Jacob 				retval = 0;
3955d571944SMatt Jacob 			}
3965d571944SMatt Jacob 			ISP_UNLOCK(isp);
3975d571944SMatt Jacob 		}
3985d571944SMatt Jacob 		break;
3995d571944SMatt Jacob 	case ISP_FC_LIP:
4005d571944SMatt Jacob 		if (IS_FC(isp)) {
4015d571944SMatt Jacob 			ISP_LOCK(isp);
4025d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
4035d571944SMatt Jacob 				retval = EIO;
4045d571944SMatt Jacob 			} else {
4055d571944SMatt Jacob 				retval = 0;
4065d571944SMatt Jacob 			}
4075d571944SMatt Jacob 			ISP_UNLOCK(isp);
4085d571944SMatt Jacob 		}
4095d571944SMatt Jacob 		break;
4105d571944SMatt Jacob 	case ISP_FC_GETDINFO:
4115d571944SMatt Jacob 	{
4125d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
41310365e5aSMatt Jacob 		fcportdb_t *lp;
4145d571944SMatt Jacob 
41502e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
41602e2b2d9SMatt Jacob 			break;
41702e2b2d9SMatt Jacob 		}
4185d571944SMatt Jacob 		if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
4195d571944SMatt Jacob 			retval = EINVAL;
4205d571944SMatt Jacob 			break;
4215d571944SMatt Jacob 		}
4225d571944SMatt Jacob 		ISP_LOCK(isp);
4235d571944SMatt Jacob 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
42410365e5aSMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID) {
425c6435ff3SMatt Jacob 			ifc->role = lp->roles;
42610365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4275d571944SMatt Jacob 			ifc->portid = lp->portid;
4285d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4295d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4305d571944SMatt Jacob 			retval = 0;
4315d571944SMatt Jacob 		} else {
4325d571944SMatt Jacob 			retval = ENODEV;
4335d571944SMatt Jacob 		}
4345d571944SMatt Jacob 		ISP_UNLOCK(isp);
4355d571944SMatt Jacob 		break;
4365d571944SMatt Jacob 	}
4372903b272SMatt Jacob 	case ISP_GET_STATS:
4382903b272SMatt Jacob 	{
4392903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4402903b272SMatt Jacob 
4412903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
4422903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4432903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
4442903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
4452903b272SMatt Jacob 		ISP_LOCK(isp);
4462903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
4472903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
4482903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
4492903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
4502903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
4512903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
4522903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
4532903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
4542903b272SMatt Jacob 		ISP_UNLOCK(isp);
4552903b272SMatt Jacob 		retval = 0;
4562903b272SMatt Jacob 		break;
4572903b272SMatt Jacob 	}
4582903b272SMatt Jacob 	case ISP_CLR_STATS:
4592903b272SMatt Jacob 		ISP_LOCK(isp);
4602903b272SMatt Jacob 		isp->isp_intcnt = 0;
4612903b272SMatt Jacob 		isp->isp_intbogus = 0;
4622903b272SMatt Jacob 		isp->isp_intmboxc = 0;
4632903b272SMatt Jacob 		isp->isp_intoasync = 0;
4642903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
4652903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
4662903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
4672903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
4682903b272SMatt Jacob 		ISP_UNLOCK(isp);
4692903b272SMatt Jacob 		retval = 0;
4702903b272SMatt Jacob 		break;
471570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
472570c7a3fSMatt Jacob 	{
473570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
474570c7a3fSMatt Jacob 		MEMZERO(hba, sizeof (*hba));
47502e2b2d9SMatt Jacob 
476a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
477a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
478a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
47902e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
480570c7a3fSMatt Jacob 			hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
481570c7a3fSMatt Jacob 			hba->fc_scsi_supported = 1;
482570c7a3fSMatt Jacob 			hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
483570c7a3fSMatt Jacob 			hba->fc_loopid = FCPARAM(isp)->isp_loopid;
484fd6eb9f7SMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp)->isp_nodewwn;
485fd6eb9f7SMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp)->isp_portwwn;
486fd6eb9f7SMatt Jacob 			hba->active_node_wwn = ISP_NODEWWN(isp);
487fd6eb9f7SMatt Jacob 			hba->active_port_wwn = ISP_PORTWWN(isp);
48802e2b2d9SMatt Jacob 		}
489570c7a3fSMatt Jacob 		retval = 0;
490570c7a3fSMatt Jacob 		break;
491570c7a3fSMatt Jacob 	}
492fdeb9f2fSMatt Jacob 	case ISP_GET_FC_PARAM:
493fdeb9f2fSMatt Jacob 	{
494fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
495fdeb9f2fSMatt Jacob 
49602e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
497fdeb9f2fSMatt Jacob 			break;
498fdeb9f2fSMatt Jacob 		}
499fdeb9f2fSMatt Jacob 		f->parameter = 0;
500fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
501fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_maxfrmlen;
502fdeb9f2fSMatt Jacob 			retval = 0;
503fdeb9f2fSMatt Jacob 			break;
504fdeb9f2fSMatt Jacob 		}
505fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
506fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_execthrottle;
507fdeb9f2fSMatt Jacob 			retval = 0;
508fdeb9f2fSMatt Jacob 			break;
509fdeb9f2fSMatt Jacob 		}
510fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
511fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX)
512fdeb9f2fSMatt Jacob 				f->parameter = 1;
513fdeb9f2fSMatt Jacob 			retval = 0;
514fdeb9f2fSMatt Jacob 			break;
515fdeb9f2fSMatt Jacob 		}
516fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
517fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_loopid;
518fdeb9f2fSMatt Jacob 			retval = 0;
519fdeb9f2fSMatt Jacob 			break;
520fdeb9f2fSMatt Jacob 		}
521fdeb9f2fSMatt Jacob 		retval = EINVAL;
522fdeb9f2fSMatt Jacob 		break;
523fdeb9f2fSMatt Jacob 	}
524fdeb9f2fSMatt Jacob 	case ISP_SET_FC_PARAM:
525fdeb9f2fSMatt Jacob 	{
526fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
5271dae40ebSMatt Jacob 		uint32_t param = f->parameter;
528fdeb9f2fSMatt Jacob 
52902e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
530fdeb9f2fSMatt Jacob 			break;
531fdeb9f2fSMatt Jacob 		}
532fdeb9f2fSMatt Jacob 		f->parameter = 0;
533fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
534fdeb9f2fSMatt Jacob 			if (param != 512 && param != 1024 && param != 1024) {
535fdeb9f2fSMatt Jacob 				retval = EINVAL;
536fdeb9f2fSMatt Jacob 				break;
537fdeb9f2fSMatt Jacob 			}
538fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_maxfrmlen = param;
539fdeb9f2fSMatt Jacob 			retval = 0;
540fdeb9f2fSMatt Jacob 			break;
541fdeb9f2fSMatt Jacob 		}
542fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
543fdeb9f2fSMatt Jacob 			if (param < 16 || param > 255) {
544fdeb9f2fSMatt Jacob 				retval = EINVAL;
545fdeb9f2fSMatt Jacob 				break;
546fdeb9f2fSMatt Jacob 			}
547fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_execthrottle = param;
548fdeb9f2fSMatt Jacob 			retval = 0;
549fdeb9f2fSMatt Jacob 			break;
550fdeb9f2fSMatt Jacob 		}
551fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
552fdeb9f2fSMatt Jacob 			if (param != 0 && param != 1) {
553fdeb9f2fSMatt Jacob 				retval = EINVAL;
554fdeb9f2fSMatt Jacob 				break;
555fdeb9f2fSMatt Jacob 			}
556fdeb9f2fSMatt Jacob 			if (param) {
557fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions |=
558fdeb9f2fSMatt Jacob 				    ICBOPT_FULL_DUPLEX;
559fdeb9f2fSMatt Jacob 			} else {
560fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions &=
561fdeb9f2fSMatt Jacob 				    ~ICBOPT_FULL_DUPLEX;
562fdeb9f2fSMatt Jacob 			}
563fdeb9f2fSMatt Jacob 			retval = 0;
564fdeb9f2fSMatt Jacob 			break;
565fdeb9f2fSMatt Jacob 		}
566fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
567fdeb9f2fSMatt Jacob 			if (param < 0 || param > 125) {
568fdeb9f2fSMatt Jacob 				retval = EINVAL;
569fdeb9f2fSMatt Jacob 				break;
570fdeb9f2fSMatt Jacob 			}
571fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_loopid = param;
572fdeb9f2fSMatt Jacob 			retval = 0;
573fdeb9f2fSMatt Jacob 			break;
574fdeb9f2fSMatt Jacob 		}
575fdeb9f2fSMatt Jacob 		retval = EINVAL;
576fdeb9f2fSMatt Jacob 		break;
577fdeb9f2fSMatt Jacob 	}
5788e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5798e62a8acSMatt Jacob 	{
5808e62a8acSMatt Jacob 		int needmarker;
5818e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5821dae40ebSMatt Jacob 		uint16_t loopid;
5838e62a8acSMatt Jacob 		mbreg_t mbs;
5848e62a8acSMatt Jacob 
5858e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5868e62a8acSMatt Jacob 			break;
5878e62a8acSMatt Jacob 		}
5888e62a8acSMatt Jacob 
5898e62a8acSMatt Jacob 		memset(&mbs, 0, sizeof (mbs));
5908e62a8acSMatt Jacob 		needmarker = retval = 0;
591e5265237SMatt Jacob 		loopid = fct->loopid;
59210365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin == 0) {
593e5265237SMatt Jacob 			loopid <<= 8;
594e5265237SMatt Jacob 		}
5958e62a8acSMatt Jacob 		switch (fct->action) {
596f0f536d1SMatt Jacob 		case IPT_CLEAR_ACA:
5978e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_ACA;
598e5265237SMatt Jacob 			mbs.param[1] = loopid;
5998e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6008e62a8acSMatt Jacob 			break;
601f0f536d1SMatt Jacob 		case IPT_TARGET_RESET:
6028e62a8acSMatt Jacob 			mbs.param[0] = MBOX_TARGET_RESET;
603e5265237SMatt Jacob 			mbs.param[1] = loopid;
6048e62a8acSMatt Jacob 			needmarker = 1;
6058e62a8acSMatt Jacob 			break;
606f0f536d1SMatt Jacob 		case IPT_LUN_RESET:
6078e62a8acSMatt Jacob 			mbs.param[0] = MBOX_LUN_RESET;
608e5265237SMatt Jacob 			mbs.param[1] = loopid;
6098e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6108e62a8acSMatt Jacob 			needmarker = 1;
6118e62a8acSMatt Jacob 			break;
612f0f536d1SMatt Jacob 		case IPT_CLEAR_TASK_SET:
6138e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_TASK_SET;
614e5265237SMatt Jacob 			mbs.param[1] = loopid;
6158e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6168e62a8acSMatt Jacob 			needmarker = 1;
6178e62a8acSMatt Jacob 			break;
618f0f536d1SMatt Jacob 		case IPT_ABORT_TASK_SET:
6198e62a8acSMatt Jacob 			mbs.param[0] = MBOX_ABORT_TASK_SET;
620e5265237SMatt Jacob 			mbs.param[1] = loopid;
6218e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6228e62a8acSMatt Jacob 			needmarker = 1;
6238e62a8acSMatt Jacob 			break;
6248e62a8acSMatt Jacob 		default:
6258e62a8acSMatt Jacob 			retval = EINVAL;
6268e62a8acSMatt Jacob 			break;
6278e62a8acSMatt Jacob 		}
6288e62a8acSMatt Jacob 		if (retval == 0) {
6298e62a8acSMatt Jacob 			ISP_LOCK(isp);
6308e62a8acSMatt Jacob 			if (needmarker) {
6318e62a8acSMatt Jacob 				isp->isp_sendmarker |= 1;
6328e62a8acSMatt Jacob 			}
6338e62a8acSMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6348e62a8acSMatt Jacob 			ISP_UNLOCK(isp);
6358e62a8acSMatt Jacob 			if (retval)
6368e62a8acSMatt Jacob 				retval = EIO;
6378e62a8acSMatt Jacob 		}
6388e62a8acSMatt Jacob 		break;
6398e62a8acSMatt Jacob 	}
6405d571944SMatt Jacob 	default:
6415d571944SMatt Jacob 		break;
6425d571944SMatt Jacob 	}
6435d571944SMatt Jacob 	return (retval);
6440470d791SMatt Jacob }
645478f8a96SJustin T. Gibbs 
6469311717dSMatt Jacob #if __FreeBSD_version >= 500000
6479311717dSMatt Jacob static void
6489311717dSMatt Jacob isp_sysctl_update(ispsoftc_t *isp)
6499311717dSMatt Jacob {
6509311717dSMatt Jacob 	struct sysctl_ctx_list *ctx =
6519311717dSMatt Jacob 	    device_get_sysctl_ctx(isp->isp_osinfo.dev);
6529311717dSMatt Jacob 	struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev);
6539311717dSMatt Jacob 
6549311717dSMatt Jacob 	if (IS_SCSI(isp)) {
6559311717dSMatt Jacob 		return;
6569311717dSMatt Jacob 	}
657f7c631bcSMatt Jacob 
6589311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn,
6599311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x",
6609311717dSMatt Jacob 	    (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp));
6619311717dSMatt Jacob 
6629311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn,
6639311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x",
6649311717dSMatt Jacob 	    (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp));
6659311717dSMatt Jacob 
6669311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6679311717dSMatt Jacob 	       "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0,
6689311717dSMatt Jacob 	       "World Wide Node Name");
669f7c631bcSMatt Jacob 
6709311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6719311717dSMatt Jacob 	       "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0,
6729311717dSMatt Jacob 	       "World Wide Port Name");
673f7c631bcSMatt Jacob 
674f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
675f7c631bcSMatt Jacob 	    "loop_down_limit",
676f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0,
677f7c631bcSMatt Jacob 	    "How long to wait for loop to come back up");
678f7c631bcSMatt Jacob 
679f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
680f7c631bcSMatt Jacob 	    "gone_device_time",
681f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0,
682f7c631bcSMatt Jacob 	    "How long to wait for a device to reappear");
6839311717dSMatt Jacob }
6849311717dSMatt Jacob #endif
6859311717dSMatt Jacob 
686f6e75de2SMatt Jacob static void
687f6e75de2SMatt Jacob isp_intr_enable(void *arg)
688f6e75de2SMatt Jacob {
6899cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
690d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
69110365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
692d6e5500fSMatt Jacob 	}
693f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
694f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
695f6e75de2SMatt Jacob }
696d81ba9d5SMatt Jacob 
697d81ba9d5SMatt Jacob /*
698d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
699d81ba9d5SMatt Jacob  */
700d81ba9d5SMatt Jacob 
701d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
702d81ba9d5SMatt Jacob 
7039cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7049cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int);
7059cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7069cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *);
7079cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int);
708d81ba9d5SMatt Jacob static cam_status
7099cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7109cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7119cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *);
7129cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
7139cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *);
714f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
715a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
716a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
7179cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
7189cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
7199cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
7209cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *);
7219cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
7229cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
723d81ba9d5SMatt Jacob 
72453af7d22SMatt Jacob static __inline int
7259cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
726d81ba9d5SMatt Jacob {
727d81ba9d5SMatt Jacob 	tstate_t *tptr;
728a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
729a1bc34c6SMatt Jacob 	if (tptr == NULL) {
730d81ba9d5SMatt Jacob 		return (0);
731d81ba9d5SMatt Jacob 	}
732d81ba9d5SMatt Jacob 	do {
733a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
734d81ba9d5SMatt Jacob 			return (1);
735d81ba9d5SMatt Jacob 		}
736d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
737d81ba9d5SMatt Jacob 	return (0);
738d81ba9d5SMatt Jacob }
739d81ba9d5SMatt Jacob 
74053af7d22SMatt Jacob static __inline int
7419cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port)
742d81ba9d5SMatt Jacob {
743a1bc34c6SMatt Jacob 	int lo, hi;
744a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
745a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
746a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
747a1bc34c6SMatt Jacob 	} else {
748a1bc34c6SMatt Jacob 		lo = 0;
749a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
750a1bc34c6SMatt Jacob 	}
751a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
752a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
753d81ba9d5SMatt Jacob 			return (1);
754d81ba9d5SMatt Jacob 		}
755d81ba9d5SMatt Jacob 	}
756d81ba9d5SMatt Jacob 	return (0);
757d81ba9d5SMatt Jacob }
758d81ba9d5SMatt Jacob 
75953af7d22SMatt Jacob static __inline tstate_t *
7609cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
761d81ba9d5SMatt Jacob {
76264edff94SMatt Jacob 	tstate_t *tptr = NULL;
763d81ba9d5SMatt Jacob 
764d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
76564edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
766a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
767d81ba9d5SMatt Jacob 			tptr->hold++;
768d81ba9d5SMatt Jacob 			return (tptr);
769d81ba9d5SMatt Jacob 		}
77067ff51f1SMatt Jacob 		return (NULL);
771126ec864SMatt Jacob 	} else {
772126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
77364edff94SMatt Jacob 		if (tptr == NULL) {
77464edff94SMatt Jacob 			return (NULL);
77564edff94SMatt Jacob 		}
776126ec864SMatt Jacob 	}
777d81ba9d5SMatt Jacob 
778d81ba9d5SMatt Jacob 	do {
779a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
780d81ba9d5SMatt Jacob 			tptr->hold++;
781d81ba9d5SMatt Jacob 			return (tptr);
782d81ba9d5SMatt Jacob 		}
783d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
784d81ba9d5SMatt Jacob 	return (tptr);
785d81ba9d5SMatt Jacob }
786d81ba9d5SMatt Jacob 
78753af7d22SMatt Jacob static __inline void
7889cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
789d81ba9d5SMatt Jacob {
790d81ba9d5SMatt Jacob 	if (tptr->hold)
791d81ba9d5SMatt Jacob 		tptr->hold--;
792d81ba9d5SMatt Jacob }
793d81ba9d5SMatt Jacob 
79453af7d22SMatt Jacob static __inline atio_private_data_t *
7959cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag)
79653036e92SMatt Jacob {
79753036e92SMatt Jacob 	atio_private_data_t *atp;
79853036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
79953036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
80053036e92SMatt Jacob 		if (atp->tag == tag)
80153036e92SMatt Jacob 			return (atp);
80253036e92SMatt Jacob 	}
80353036e92SMatt Jacob 	return (NULL);
80453036e92SMatt Jacob }
80553036e92SMatt Jacob 
806d81ba9d5SMatt Jacob static cam_status
8079cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus,
808a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
809d81ba9d5SMatt Jacob {
810d81ba9d5SMatt Jacob 	cam_status status;
811d81ba9d5SMatt Jacob 	lun_id_t lun;
812a1bc34c6SMatt Jacob 	int hfx;
813d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
814d81ba9d5SMatt Jacob 
815d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
816d81ba9d5SMatt Jacob 	if (lun < 0) {
817d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
818d81ba9d5SMatt Jacob 	}
819a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
820d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
821d81ba9d5SMatt Jacob 	}
822ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
823d81ba9d5SMatt Jacob 	if (new == NULL) {
824d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
825d81ba9d5SMatt Jacob 	}
826d81ba9d5SMatt Jacob 
827d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
828d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
829d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
830d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
831d81ba9d5SMatt Jacob 		return (status);
832d81ba9d5SMatt Jacob 	}
833a1bc34c6SMatt Jacob 	new->bus = bus;
834d81ba9d5SMatt Jacob 	new->lun = lun;
835d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
836d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
837d81ba9d5SMatt Jacob 	new->hold = 1;
838d81ba9d5SMatt Jacob 
839a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
840a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
841a1bc34c6SMatt Jacob 	if (tptr == NULL) {
842a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
843d81ba9d5SMatt Jacob 	} else {
844d81ba9d5SMatt Jacob 		while (tptr->next)
845d81ba9d5SMatt Jacob 			tptr = tptr->next;
846d81ba9d5SMatt Jacob 		tptr->next = new;
847d81ba9d5SMatt Jacob 	}
848d81ba9d5SMatt Jacob 	*rslt = new;
849d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
850d81ba9d5SMatt Jacob }
851d81ba9d5SMatt Jacob 
85253af7d22SMatt Jacob static __inline void
8539cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
854d81ba9d5SMatt Jacob {
855a1bc34c6SMatt Jacob 	int hfx;
856d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
857d81ba9d5SMatt Jacob 
858d81ba9d5SMatt Jacob 	if (tptr->hold) {
859d81ba9d5SMatt Jacob 		return;
860d81ba9d5SMatt Jacob 	}
86167ff51f1SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
862a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
863d81ba9d5SMatt Jacob 	if (pw == NULL) {
864d81ba9d5SMatt Jacob 		return;
865a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
866a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
867d81ba9d5SMatt Jacob 	} else {
868d81ba9d5SMatt Jacob 		lw = pw;
869d81ba9d5SMatt Jacob 		pw = lw->next;
870d81ba9d5SMatt Jacob 		while (pw) {
871a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
872d81ba9d5SMatt Jacob 				lw->next = pw->next;
873d81ba9d5SMatt Jacob 				break;
874d81ba9d5SMatt Jacob 			}
875d81ba9d5SMatt Jacob 			lw = pw;
876d81ba9d5SMatt Jacob 			pw = pw->next;
877d81ba9d5SMatt Jacob 		}
878d81ba9d5SMatt Jacob 		if (pw == NULL) {
879d81ba9d5SMatt Jacob 			return;
880d81ba9d5SMatt Jacob 		}
881d81ba9d5SMatt Jacob 	}
882d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
883d81ba9d5SMatt Jacob }
884d81ba9d5SMatt Jacob 
8855d571944SMatt Jacob /*
88667ff51f1SMatt Jacob  * Enable luns.
8875d571944SMatt Jacob  */
88867ff51f1SMatt Jacob static int
8899cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb)
890d81ba9d5SMatt Jacob {
891d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
892d81ba9d5SMatt Jacob 	tstate_t *tptr;
8931dae40ebSMatt Jacob 	uint32_t seq;
894746e9c85SMatt Jacob 	int bus, cmd, av, wildcard, tm_on;
895d81ba9d5SMatt Jacob 	lun_id_t lun;
896d81ba9d5SMatt Jacob 	target_id_t tgt;
897d81ba9d5SMatt Jacob 
89867ff51f1SMatt Jacob 	bus = XS_CHANNEL(ccb);
89967ff51f1SMatt Jacob 	if (bus > 1) {
900dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus);
90167ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_PATH_INVALID;
90267ff51f1SMatt Jacob 		return (-1);
90367ff51f1SMatt Jacob 	}
904d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
905d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
906d81ba9d5SMatt Jacob 
907dd9fc7c3SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
908dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n",
90967ff51f1SMatt Jacob 	    	    cel->enable? "en" : "dis", lun, bus);
910dd9fc7c3SMatt Jacob 	}
911d81ba9d5SMatt Jacob 
912d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
913d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
914d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
91567ff51f1SMatt Jacob 		return (-1);
916d81ba9d5SMatt Jacob 	}
91764edff94SMatt Jacob 
9182ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
919a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
920a1bc34c6SMatt Jacob 		sdp += bus;
921d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
922a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
923d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
92467ff51f1SMatt Jacob 			return (-1);
925d81ba9d5SMatt Jacob 		}
926d81ba9d5SMatt Jacob 	} else {
927746e9c85SMatt Jacob 		/*
928746e9c85SMatt Jacob 		 * There's really no point in doing this yet w/o multi-tid
929746e9c85SMatt Jacob 		 * capability. Even then, it's problematic.
930746e9c85SMatt Jacob 		 */
931746e9c85SMatt Jacob #if	0
932d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
933d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
934d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
93567ff51f1SMatt Jacob 			return (-1);
936d81ba9d5SMatt Jacob 		}
937746e9c85SMatt Jacob #endif
93864edff94SMatt Jacob 		/*
93964edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
94064edff94SMatt Jacob 		 */
94110365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_tmode == 0) {
942dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
943dd9fc7c3SMatt Jacob 			    "firmware does not support target mode\n");
94464edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
94567ff51f1SMatt Jacob 			return (-1);
94664edff94SMatt Jacob 		}
94764edff94SMatt Jacob 		/*
94864edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
949dd9fc7c3SMatt Jacob 		 * XXX: dork with our already fragile enable/disable code.
95064edff94SMatt Jacob 		 */
95110365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw == 0) {
952dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
953dd9fc7c3SMatt Jacob 			    "firmware not SCCLUN capable\n");
954746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
95567ff51f1SMatt Jacob 			return (-1);
95664edff94SMatt Jacob 		}
957d81ba9d5SMatt Jacob 	}
958d81ba9d5SMatt Jacob 
959d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
96064edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
96164edff94SMatt Jacob 			wildcard = 1;
96264edff94SMatt Jacob 		} else {
963d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
96467ff51f1SMatt Jacob 			return (-1);
965d6e5500fSMatt Jacob 		}
966126ec864SMatt Jacob 	} else {
967126ec864SMatt Jacob 		wildcard = 0;
968126ec864SMatt Jacob 	}
969b6b6ad2fSMatt Jacob 
970746e9c85SMatt Jacob 	tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0;
971746e9c85SMatt Jacob 
972b6b6ad2fSMatt Jacob 	/*
973b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
97464edff94SMatt Jacob 	 *
97564edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
97664edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
97764edff94SMatt Jacob 	 * handle them locally (if we see them at all).
978b6b6ad2fSMatt Jacob 	 */
979126ec864SMatt Jacob 
980126ec864SMatt Jacob 	if (wildcard) {
981a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
982b6b6ad2fSMatt Jacob 		if (cel->enable) {
98367ff51f1SMatt Jacob 			if (tm_on) {
984b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
98567ff51f1SMatt Jacob 				return (-1);
986b6b6ad2fSMatt Jacob 			}
987b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
988b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
989b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
990b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
991b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
992b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
99367ff51f1SMatt Jacob 				return (-1);
994b6b6ad2fSMatt Jacob 			}
995b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
996b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
99764edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
998126ec864SMatt Jacob 		} else {
99967ff51f1SMatt Jacob 			if (tm_on == 0) {
1000126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
100167ff51f1SMatt Jacob 				return (-1);
1002126ec864SMatt Jacob 			}
1003126ec864SMatt Jacob 			if (tptr->hold) {
1004126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
100567ff51f1SMatt Jacob 				return (-1);
1006126ec864SMatt Jacob 			}
1007126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
100864edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
1009126ec864SMatt Jacob 		}
1010126ec864SMatt Jacob 	}
1011126ec864SMatt Jacob 
1012126ec864SMatt Jacob 	/*
1013126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
1014126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
1015126ec864SMatt Jacob 	 */
1016126ec864SMatt Jacob 	av = bus << 31;
1017746e9c85SMatt Jacob 	if (cel->enable && tm_on == 0) {
1018a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
1019b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1020b6b6ad2fSMatt Jacob 		if (av) {
1021b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1022126ec864SMatt Jacob 			if (wildcard) {
102364edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
102464edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
1025b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
10265d571944SMatt Jacob 			}
102767ff51f1SMatt Jacob 			return (-1);
1028b6b6ad2fSMatt Jacob 		}
102964edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
1030dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n");
1031746e9c85SMatt Jacob 	} else if (cel->enable == 0 && tm_on && wildcard) {
1032a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
1033b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
103467ff51f1SMatt Jacob 			return (-1);
1035b6b6ad2fSMatt Jacob 		}
1036b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1037b6b6ad2fSMatt Jacob 		if (av) {
1038b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
103967ff51f1SMatt Jacob 			return (-1);
1040b6b6ad2fSMatt Jacob 		}
104164edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
1042dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n");
1043126ec864SMatt Jacob 	}
1044126ec864SMatt Jacob 
1045126ec864SMatt Jacob 	if (wildcard) {
104664edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
104767ff51f1SMatt Jacob 		return (-1);
1048b6b6ad2fSMatt Jacob 	}
1049b6b6ad2fSMatt Jacob 
105067ff51f1SMatt Jacob 	/*
105167ff51f1SMatt Jacob 	 * Find an empty slot
105267ff51f1SMatt Jacob 	 */
105367ff51f1SMatt Jacob 	for (seq = 0; seq < NLEACT; seq++) {
105467ff51f1SMatt Jacob 		if (isp->isp_osinfo.leact[seq] == 0) {
105567ff51f1SMatt Jacob 			break;
105667ff51f1SMatt Jacob 		}
105767ff51f1SMatt Jacob 	}
105867ff51f1SMatt Jacob 	if (seq >= NLEACT) {
105967ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
106067ff51f1SMatt Jacob 		return (-1);
106167ff51f1SMatt Jacob 
106267ff51f1SMatt Jacob 	}
106367ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = ccb;
106467ff51f1SMatt Jacob 
1065d81ba9d5SMatt Jacob 	if (cel->enable) {
1066d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
1067a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
1068d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
106967ff51f1SMatt Jacob 			isp->isp_osinfo.leact[seq] = 0;
107067ff51f1SMatt Jacob 			return (-1);
1071d81ba9d5SMatt Jacob 		}
1072d81ba9d5SMatt Jacob 	} else {
1073a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
1074d81ba9d5SMatt Jacob 		if (tptr == NULL) {
1075d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
107667ff51f1SMatt Jacob 			return (-1);
1077d81ba9d5SMatt Jacob 		}
1078d81ba9d5SMatt Jacob 	}
1079d81ba9d5SMatt Jacob 
1080d81ba9d5SMatt Jacob 	if (cel->enable) {
10815d571944SMatt Jacob 		int c, n, ulun = lun;
10825d571944SMatt Jacob 
10835d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
10845d571944SMatt Jacob 		c = DFLT_CMND_CNT;
10855d571944SMatt Jacob 		n = DFLT_INOT_CNT;
10865d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
10875d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
10885d571944SMatt Jacob 			n = 0;
10895d571944SMatt Jacob 			/*
10905d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
10915d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
10925d571944SMatt Jacob 			 */
10935d571944SMatt Jacob 			ulun = 0;
10945d571944SMatt Jacob 		}
109567ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
109667ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
109767ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
109867ff51f1SMatt Jacob 			return (seq);
1099d81ba9d5SMatt Jacob 		}
1100d81ba9d5SMatt Jacob 	} else {
11015d571944SMatt Jacob 		int c, n, ulun = lun;
1102d81ba9d5SMatt Jacob 
11035d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
11045d571944SMatt Jacob 		c = DFLT_CMND_CNT;
11055d571944SMatt Jacob 		n = DFLT_INOT_CNT;
11065d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
11075d571944SMatt Jacob 			n = 0;
11085d571944SMatt Jacob 			/*
11095d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
11105d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
11115d571944SMatt Jacob 			 */
11125d571944SMatt Jacob 			ulun = 0;
11135d571944SMatt Jacob 		}
111467ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
111567ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
111667ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
111767ff51f1SMatt Jacob 			return (seq);
1118d81ba9d5SMatt Jacob 		}
1119d81ba9d5SMatt Jacob 	}
112067ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
1121dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n");
112267ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
112367ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP_ERR;
112467ff51f1SMatt Jacob 	return (-1);
11255d571944SMatt Jacob }
11265d571944SMatt Jacob 
112767ff51f1SMatt Jacob static void
11289cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
112967ff51f1SMatt Jacob {
1130dd9fc7c3SMatt Jacob 	const char lfmt[] = "now %sabled for target mode";
113167ff51f1SMatt Jacob 	union ccb *ccb;
11321dae40ebSMatt Jacob 	uint32_t seq;
113367ff51f1SMatt Jacob 	tstate_t *tptr;
113467ff51f1SMatt Jacob 	int av;
113567ff51f1SMatt Jacob 	struct ccb_en_lun *cel;
1136d81ba9d5SMatt Jacob 
113767ff51f1SMatt Jacob 	seq = lep->le_reserved - 1;
113867ff51f1SMatt Jacob 	if (seq >= NLEACT) {
11393c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114067ff51f1SMatt Jacob 		    "seq out of range (%u) in isp_ledone", seq);
114167ff51f1SMatt Jacob 		return;
1142d81ba9d5SMatt Jacob 	}
114367ff51f1SMatt Jacob 	ccb = isp->isp_osinfo.leact[seq];
114467ff51f1SMatt Jacob 	if (ccb == 0) {
114567ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114667ff51f1SMatt Jacob 		    "no ccb for seq %u in isp_ledone", seq);
114767ff51f1SMatt Jacob 		return;
114867ff51f1SMatt Jacob 	}
114967ff51f1SMatt Jacob 	cel = &ccb->cel;
115067ff51f1SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
115167ff51f1SMatt Jacob 	if (tptr == NULL) {
1152dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n");
115367ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
115467ff51f1SMatt Jacob 		return;
1155d81ba9d5SMatt Jacob 	}
115667ff51f1SMatt Jacob 
115767ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
1158dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1159dd9fc7c3SMatt Jacob 		    "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status);
116067ff51f1SMatt Jacob err:
116167ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
116267ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
116367ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
116467ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
116567ff51f1SMatt Jacob 		xpt_done(ccb);
116667ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
116767ff51f1SMatt Jacob 		return;
116867ff51f1SMatt Jacob 	} else {
116967ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
117067ff51f1SMatt Jacob 		    "isp_ledone: ENABLE/MODIFY done okay");
117167ff51f1SMatt Jacob 	}
117267ff51f1SMatt Jacob 
117367ff51f1SMatt Jacob 
117467ff51f1SMatt Jacob 	if (cel->enable) {
117567ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1176dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, lfmt, "en");
117767ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
117867ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
117967ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
118067ff51f1SMatt Jacob 		xpt_done(ccb);
118167ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
118267ff51f1SMatt Jacob 		return;
118367ff51f1SMatt Jacob 	}
118467ff51f1SMatt Jacob 
118567ff51f1SMatt Jacob 	if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) {
118667ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb),
118767ff51f1SMatt Jacob 		    XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) {
1188dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1189dd9fc7c3SMatt Jacob 			    "isp_ledone: isp_lun_cmd failed\n");
119067ff51f1SMatt Jacob 			goto err;
119167ff51f1SMatt Jacob 		}
119267ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
119367ff51f1SMatt Jacob 		return;
119467ff51f1SMatt Jacob 	}
119567ff51f1SMatt Jacob 
1196dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, lfmt, "dis");
119767ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
119867ff51f1SMatt Jacob 	destroy_lun_state(isp, tptr);
119967ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
120067ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
120167ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
120267ff51f1SMatt Jacob 	xpt_done(ccb);
120367ff51f1SMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
120467ff51f1SMatt Jacob 	if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) {
120567ff51f1SMatt Jacob 		int bus = XS_CHANNEL(ccb);
120667ff51f1SMatt Jacob 		av = bus << 31;
1207126ec864SMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1208126ec864SMatt Jacob 		if (av) {
1209126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
121067ff51f1SMatt Jacob 			    "disable target mode on channel %d failed", bus);
1211126ec864SMatt Jacob 		}
121267ff51f1SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
121367ff51f1SMatt Jacob 	}
1214126ec864SMatt Jacob }
1215126ec864SMatt Jacob 
1216d81ba9d5SMatt Jacob 
1217d81ba9d5SMatt Jacob static cam_status
12189cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb)
1219d81ba9d5SMatt Jacob {
1220d81ba9d5SMatt Jacob 	tstate_t *tptr;
1221d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
1222d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
1223746e9c85SMatt Jacob 	int found, *ctr;
1224d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
1225d81ba9d5SMatt Jacob 
1226dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb);
1227d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1228746e9c85SMatt Jacob 		int badpath = 0;
1229d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
1230d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
1231746e9c85SMatt Jacob 			badpath = 1;
1232d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
1233d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
1234746e9c85SMatt Jacob 			badpath = 1;
1235746e9c85SMatt Jacob 		}
1236746e9c85SMatt Jacob 		if (badpath) {
1237746e9c85SMatt Jacob 			/*
1238746e9c85SMatt Jacob 			 * Being restrictive about target ids is really about
1239746e9c85SMatt Jacob 			 * making sure we're aborting for the right multi-tid
1240746e9c85SMatt Jacob 			 * path. This doesn't really make much sense at present.
1241746e9c85SMatt Jacob 			 */
1242746e9c85SMatt Jacob #if	0
1243d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1244746e9c85SMatt Jacob #endif
1245d81ba9d5SMatt Jacob 		}
1246d81ba9d5SMatt Jacob 	}
1247a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
1248d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1249dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "can't get statep\n");
1250d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
1251d81ba9d5SMatt Jacob 	}
1252d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1253d81ba9d5SMatt Jacob 		lp = &tptr->atios;
1254746e9c85SMatt Jacob 		ctr = &tptr->atio_count;
1255d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
1256d81ba9d5SMatt Jacob 		lp = &tptr->inots;
1257746e9c85SMatt Jacob 		ctr = &tptr->inot_count;
1258d81ba9d5SMatt Jacob 	} else {
1259d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1260dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "bad function code %d\n",
1261dd9fc7c3SMatt Jacob 		    accb->ccb_h.func_code);
1262d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
1263d81ba9d5SMatt Jacob 	}
1264d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
1265d81ba9d5SMatt Jacob 	found = 0;
1266d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
1267d81ba9d5SMatt Jacob 		found = 1;
1268d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
1269d81ba9d5SMatt Jacob 	} else {
1270d81ba9d5SMatt Jacob 		while(curelm != NULL) {
1271d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
1272d81ba9d5SMatt Jacob 
1273d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
1274d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
1275d81ba9d5SMatt Jacob 				found = 1;
1276d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
1277d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
1278d81ba9d5SMatt Jacob 				break;
1279d81ba9d5SMatt Jacob 			}
1280d81ba9d5SMatt Jacob 			curelm = nextelm;
1281d81ba9d5SMatt Jacob 		}
1282d81ba9d5SMatt Jacob 	}
1283d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1284d81ba9d5SMatt Jacob 	if (found) {
1285c1504bc0SMatt Jacob 		(*ctr)--;
1286d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
1287746e9c85SMatt Jacob 		xpt_done(accb);
1288d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
1289d81ba9d5SMatt Jacob 	}
1290dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb);
1291d81ba9d5SMatt Jacob 	return (CAM_PATH_INVALID);
1292d81ba9d5SMatt Jacob }
1293d81ba9d5SMatt Jacob 
12949cd7268eSMatt Jacob static void
12959cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1296d81ba9d5SMatt Jacob {
1297d81ba9d5SMatt Jacob 	void *qe;
129800a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
129910365e5aSMatt Jacob 	uint32_t nxti, optr, handle;
13001dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1301d81ba9d5SMatt Jacob 
1302f48ce188SMatt Jacob 
13034fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1304dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1305dd9fc7c3SMatt Jacob 		    "Request Queue Overflow in isp_target_start_ctio\n");
13069cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
13079cd7268eSMatt Jacob 		goto out;
1308d81ba9d5SMatt Jacob 	}
130929f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1310d81ba9d5SMatt Jacob 
1311d81ba9d5SMatt Jacob 	/*
1312d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1313d81ba9d5SMatt Jacob 	 */
1314d81ba9d5SMatt Jacob 
1315d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
131653036e92SMatt Jacob 		atio_private_data_t *atp;
13174fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
131800a8e174SMatt Jacob 
1319d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1320d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
132110365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin) {
132229f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
132329f76675SMatt Jacob 		} else {
132400a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
132510365e5aSMatt Jacob 			if (FCPARAM(isp)->isp_sccfw == 0) {
1326d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
13272ad50ca5SMatt Jacob 			}
132829f76675SMatt Jacob 		}
132953036e92SMatt Jacob 
133053036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
133153036e92SMatt Jacob 		if (atp == NULL) {
1332dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1333dd9fc7c3SMatt Jacob 			    "cannot find private data adjunct for tag %x\n",
133453036e92SMatt Jacob 			    cso->tag_id);
13359cd7268eSMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
13369cd7268eSMatt Jacob 			goto out;
133753036e92SMatt Jacob 		}
1338f48ce188SMatt Jacob 
133900a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
134000a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
134100a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1342f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
134300a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1344f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
134553036e92SMatt Jacob 				cto->ct_resid =
134653036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1347570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1348570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1349570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1350570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1351570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1352570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1353570c7a3fSMatt Jacob 				}
1354f48ce188SMatt Jacob 			}
135500a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
135600a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
135729f76675SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp,
135829f76675SMatt Jacob 				    &cso->sense_data, m);
135900a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
136000a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
136100a8e174SMatt Jacob 			}
136200a8e174SMatt Jacob 		} else {
136300a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
136400a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
136500a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
136600a8e174SMatt Jacob 			} else {
136700a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1368d81ba9d5SMatt Jacob 			}
1369570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
1370d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1371d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
137200a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
137353036e92SMatt Jacob 				cto->ct_resid =
137453036e92SMatt Jacob 				    atp->orig_datalen -
137553036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
1376570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1377570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1378570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1379570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1380570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1381570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1382570c7a3fSMatt Jacob 				}
138353036e92SMatt Jacob 			} else {
138453036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1385d81ba9d5SMatt Jacob 			}
1386f48ce188SMatt Jacob 			/*
1387f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1388f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1389f48ce188SMatt Jacob 			 */
139000a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
139100a8e174SMatt Jacob 		}
139253036e92SMatt Jacob 
1393290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
139464edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
139553036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
139653036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
139753036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1398a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1399570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
14009cd7268eSMatt Jacob 		} else {
1401570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
14029cd7268eSMatt Jacob 		}
1403a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1404d81ba9d5SMatt Jacob 	} else {
14054fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
140600a8e174SMatt Jacob 
1407d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1408d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
140900a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1410a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1411d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1412d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1413a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1414a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
14151dae40ebSMatt Jacob 			cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id);
1416f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1417f48ce188SMatt Jacob 		}
1418f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1419f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1420f48ce188SMatt Jacob 		}
1421f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1422d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
142300a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
142400a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
142500a8e174SMatt Jacob 		} else {
142600a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1427d81ba9d5SMatt Jacob 		}
1428f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
142953036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
143000a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
143100a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
143264edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1433a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1434a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1435a1bc34c6SMatt Jacob 			    cso->tag_id);
143692a1e549SMatt Jacob 		}
143764edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1438a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1439d81ba9d5SMatt Jacob 	}
1440d81ba9d5SMatt Jacob 
144110365e5aSMatt Jacob 	if (isp_save_xs_tgt(isp, ccb, &handle)) {
1442dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1443dd9fc7c3SMatt Jacob 		    "No XFLIST pointers for isp_target_start_ctio\n");
14449cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14459cd7268eSMatt Jacob 		goto out;
1446d81ba9d5SMatt Jacob 	}
1447d81ba9d5SMatt Jacob 
1448d81ba9d5SMatt Jacob 
1449d81ba9d5SMatt Jacob 	/*
1450d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1451d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1452b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1453d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1454d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1455d81ba9d5SMatt Jacob 	 * format.
1456d81ba9d5SMatt Jacob 	 */
1457d81ba9d5SMatt Jacob 
145810365e5aSMatt Jacob 	if (IS_FC(isp)) {
145910365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
146010365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146110365e5aSMatt Jacob 	} else {
146210365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
146310365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146410365e5aSMatt Jacob 	}
1465a1bc34c6SMatt Jacob 
14664fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1467d81ba9d5SMatt Jacob 	case CMD_QUEUED:
14684fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
14699cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
14709cd7268eSMatt Jacob 		return;
1471d81ba9d5SMatt Jacob 
1472d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
14739cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14749cd7268eSMatt Jacob 		break;
1475d81ba9d5SMatt Jacob 
1476d81ba9d5SMatt Jacob 	default:
14779cd7268eSMatt Jacob 		break;
1478d81ba9d5SMatt Jacob 	}
147910365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
14809cd7268eSMatt Jacob 
14819cd7268eSMatt Jacob out:
14829cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
14839cd7268eSMatt Jacob 	xpt_done(ccb);
14849cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1485d81ba9d5SMatt Jacob }
1486d81ba9d5SMatt Jacob 
1487a1bc34c6SMatt Jacob static void
1488a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1489f48ce188SMatt Jacob {
1490a1bc34c6SMatt Jacob 	int s = splcam();
1491a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1492a1bc34c6SMatt Jacob 	splx(s);
1493a1bc34c6SMatt Jacob }
1494a1bc34c6SMatt Jacob 
1495a1bc34c6SMatt Jacob static void
1496a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1497a1bc34c6SMatt Jacob {
14989cd7268eSMatt Jacob 	ispsoftc_t *isp;
1499a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
150010365e5aSMatt Jacob 	uint32_t nxti, optr;
1501a1bc34c6SMatt Jacob 	void *qe;
1502a1bc34c6SMatt Jacob 
1503a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1504f48ce188SMatt Jacob 
15054fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1506dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1507dd9fc7c3SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow\n");
1508a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1509a1bc34c6SMatt Jacob 		return;
1510f48ce188SMatt Jacob 	}
151129f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1512a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1513f48ce188SMatt Jacob 	if (IS_FC(isp)) {
15144fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
15154fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1516f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1517f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
151810365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw) {
1519a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1520f48ce188SMatt Jacob 		} else {
1521a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1522f48ce188SMatt Jacob 		}
1523f48ce188SMatt Jacob 		at->at_status = CT_OK;
1524a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1525570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
15264fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1527f48ce188SMatt Jacob 	} else {
15284fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
15294fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1530f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1531f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1532a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1533a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1534a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1535a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1536f48ce188SMatt Jacob 		at->at_status = CT_OK;
1537a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1538a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
15394fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1540f48ce188SMatt Jacob 	}
1541f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
15424fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1543a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1544f48ce188SMatt Jacob }
1545f48ce188SMatt Jacob 
1546f48ce188SMatt Jacob static void
1547a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1548f48ce188SMatt Jacob {
15499cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
1550a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1551a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1552f48ce188SMatt Jacob 	}
1553a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1554a1bc34c6SMatt Jacob 	xpt_done(ccb);
15559cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1556f48ce188SMatt Jacob }
1557f48ce188SMatt Jacob 
1558d81ba9d5SMatt Jacob /*
1559d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1560d81ba9d5SMatt Jacob  * This means handling CDBs.
1561d81ba9d5SMatt Jacob  */
1562d81ba9d5SMatt Jacob 
1563d81ba9d5SMatt Jacob static int
15649cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1565d81ba9d5SMatt Jacob {
1566d81ba9d5SMatt Jacob 	tstate_t *tptr;
156764edff94SMatt Jacob 	int status, bus, iswildcard;
1568d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1569d81ba9d5SMatt Jacob 
1570d81ba9d5SMatt Jacob 	/*
1571d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1572d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1573d81ba9d5SMatt Jacob 	 *
1574d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1575d81ba9d5SMatt Jacob 	 *
1576d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
15775d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1578d81ba9d5SMatt Jacob 	 */
1579d81ba9d5SMatt Jacob 	status = aep->at_status;
1580d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1581d81ba9d5SMatt Jacob 		/*
1582d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1583d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1584d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1585d81ba9d5SMatt Jacob 		 */
15863c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1587d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1588d81ba9d5SMatt Jacob 		return (0);
1589d81ba9d5SMatt Jacob 	}
1590d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
15915d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
15923c75bb14SMatt Jacob 		    status);
1593d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1594d81ba9d5SMatt Jacob 		return (0);
1595d81ba9d5SMatt Jacob 	}
1596d81ba9d5SMatt Jacob 
15975d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1598a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1599d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1600a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1601746e9c85SMatt Jacob 		if (tptr == NULL) {
1602d81ba9d5SMatt Jacob 			/*
1603d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1604d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1605d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1606d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1607d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1608d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1609d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1610d81ba9d5SMatt Jacob 			 */
1611d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1612d81ba9d5SMatt Jacob 			return (0);
1613d81ba9d5SMatt Jacob 		}
16148c4e89e2SMatt Jacob 		iswildcard = 1;
16158c4e89e2SMatt Jacob 	} else {
16168c4e89e2SMatt Jacob 		iswildcard = 0;
16178c4e89e2SMatt Jacob 	}
1618d81ba9d5SMatt Jacob 
1619d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1620d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1621d81ba9d5SMatt Jacob 		/*
1622d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1623d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1624d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1625d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1626d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1627d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1628d81ba9d5SMatt Jacob 		 */
1629dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1630dd9fc7c3SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d\n",
16315d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1632d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1633d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1634d81ba9d5SMatt Jacob 		else
1635d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
163664edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1637d81ba9d5SMatt Jacob 		return (0);
1638d81ba9d5SMatt Jacob 	}
1639d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1640746e9c85SMatt Jacob 	tptr->atio_count--;
1641746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1642746e9c85SMatt Jacob 	    aep->at_lun, tptr->atio_count);
164364edff94SMatt Jacob 	if (iswildcard) {
1644d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1645d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1646d81ba9d5SMatt Jacob 	}
1647d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1648f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1649f48ce188SMatt Jacob 	} else {
1650f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1651d81ba9d5SMatt Jacob 	}
1652d81ba9d5SMatt Jacob 
1653f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1654f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1655f48ce188SMatt Jacob 		atiop->sense_len = amt;
1656f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1657f48ce188SMatt Jacob 	} else {
1658f48ce188SMatt Jacob 		atiop->sense_len = 0;
1659f48ce188SMatt Jacob 	}
1660d81ba9d5SMatt Jacob 
16615d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1662d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1663d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1664d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1665a1bc34c6SMatt Jacob 	/*
1666a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1667a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1668a1bc34c6SMatt Jacob 	 */
16699f242f78SMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id,  device_get_unit(isp->isp_dev), aep);
1670a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1671a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1672d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1673d81ba9d5SMatt Jacob 	}
1674d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
167564edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
16765d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
16775d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
16785d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
16795d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
16805d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1681d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1682d81ba9d5SMatt Jacob 	return (0);
1683d81ba9d5SMatt Jacob }
1684d81ba9d5SMatt Jacob 
1685d81ba9d5SMatt Jacob static int
16869cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
1687d81ba9d5SMatt Jacob {
168892a1e549SMatt Jacob 	lun_id_t lun;
1689d81ba9d5SMatt Jacob 	tstate_t *tptr;
1690d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
169153036e92SMatt Jacob 	atio_private_data_t *atp;
1692d81ba9d5SMatt Jacob 
1693d81ba9d5SMatt Jacob 	/*
1694d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1695d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1696d81ba9d5SMatt Jacob 	 *
1697d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1698d81ba9d5SMatt Jacob 	 */
1699d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
17003c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
17013c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1702d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1703d81ba9d5SMatt Jacob 		return (0);
1704d81ba9d5SMatt Jacob 	}
1705d81ba9d5SMatt Jacob 
170610365e5aSMatt Jacob 	if (FCPARAM(isp)->isp_sccfw) {
170792a1e549SMatt Jacob 		lun = aep->at_scclun;
17082ad50ca5SMatt Jacob 	} else {
170992a1e549SMatt Jacob 		lun = aep->at_lun;
17102ad50ca5SMatt Jacob 	}
1711a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1712d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1713746e9c85SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
1714746e9c85SMatt Jacob 		    "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
1715a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1716746e9c85SMatt Jacob 		if (tptr == NULL) {
1717746e9c85SMatt Jacob 			isp_endcmd(isp, aep,
1718746e9c85SMatt Jacob 			    SCSI_STATUS_CHECK_COND | ECMD_SVALID |
1719746e9c85SMatt Jacob 			    (0x5 << 12) | (0x25 << 16), 0);
1720746e9c85SMatt Jacob 			return (0);
1721746e9c85SMatt Jacob 		}
1722d81ba9d5SMatt Jacob 	}
1723d81ba9d5SMatt Jacob 
172453036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1725d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
172653036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1727746e9c85SMatt Jacob 
1728d81ba9d5SMatt Jacob 		/*
1729d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1730d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1731d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1732d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1733d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1734d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1735d81ba9d5SMatt Jacob 		 */
1736dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1737dd9fc7c3SMatt Jacob 		    "no %s for lun %d from initiator %d\n",
1738570c7a3fSMatt Jacob 		    (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
1739570c7a3fSMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
1740d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1741d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1742d81ba9d5SMatt Jacob 		return (0);
1743d81ba9d5SMatt Jacob 	}
1744570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1745d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1746570c7a3fSMatt Jacob 	tptr->atio_count--;
1747746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1748570c7a3fSMatt Jacob 	    lun, tptr->atio_count);
1749f48ce188SMatt Jacob 
1750a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
175110365e5aSMatt Jacob 		atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid;
175292a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1753d81ba9d5SMatt Jacob 	}
1754b0a3ba7eSMatt Jacob 	/*
1755b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1756b0a3ba7eSMatt Jacob 	 */
1757f48ce188SMatt Jacob 	atiop->sense_len = 0;
1758f48ce188SMatt Jacob 
1759d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1760d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1761d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1762d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1763d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1764d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1765d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1766d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1767d81ba9d5SMatt Jacob 		break;
1768d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1769d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1770d81ba9d5SMatt Jacob 		break;
1771d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1772d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1773d81ba9d5SMatt Jacob 		break;
1774d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1775d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1776d81ba9d5SMatt Jacob 	default:
1777d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1778d81ba9d5SMatt Jacob 		break;
1779d81ba9d5SMatt Jacob 	}
1780570c7a3fSMatt Jacob 	atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
1781f48ce188SMatt Jacob 
178253036e92SMatt Jacob 	atp->tag = atiop->tag_id;
1783570c7a3fSMatt Jacob 	atp->lun = lun;
178453036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
178553036e92SMatt Jacob 	atp->last_xframt = 0;
178653036e92SMatt Jacob 	atp->bytes_xfered = 0;
1787570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
178867ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(siP);
1789d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
1790570c7a3fSMatt Jacob 
179164edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
17925f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
17935f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1794b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1795d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1796d81ba9d5SMatt Jacob 	return (0);
1797d81ba9d5SMatt Jacob }
1798d81ba9d5SMatt Jacob 
1799d81ba9d5SMatt Jacob static int
18009cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
1801d81ba9d5SMatt Jacob {
1802d81ba9d5SMatt Jacob 	union ccb *ccb;
1803a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
18041dae40ebSMatt Jacob 	uint16_t tval;
1805d81ba9d5SMatt Jacob 
1806d81ba9d5SMatt Jacob 	/*
1807d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1808d81ba9d5SMatt Jacob 	 */
1809d81ba9d5SMatt Jacob 
181051e23558SNate Lawson 	ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle);
1811d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
181251e23558SNate Lawson 	isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1813d81ba9d5SMatt Jacob 
1814d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1815d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1816570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
1817570c7a3fSMatt Jacob 		if (atp == NULL) {
1818570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1819570c7a3fSMatt Jacob 			    "cannot find adjunct for %x after I/O",
1820570c7a3fSMatt Jacob 			    ct->ct_rxid);
1821570c7a3fSMatt Jacob 			return (0);
1822570c7a3fSMatt Jacob 		}
1823d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1824d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1825a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
182600a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
182700a8e174SMatt Jacob 		}
1828a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
18295d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
1830a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
183153036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
183253036e92SMatt Jacob 			atp->last_xframt = 0;
1833570c7a3fSMatt Jacob 		}
1834570c7a3fSMatt Jacob 		if (sentstatus || !ok) {
183553036e92SMatt Jacob 			atp->tag = 0;
183653036e92SMatt Jacob 		}
1837570c7a3fSMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
183864edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
183964edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
184064edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
184164edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
184264edff94SMatt Jacob 		tval = ct->ct_rxid;
1843570c7a3fSMatt Jacob 
1844570c7a3fSMatt Jacob 		/* XXX: should really come after isp_complete_ctio */
1845570c7a3fSMatt Jacob 		atp->state = ATPD_STATE_PDON;
1846d81ba9d5SMatt Jacob 	} else {
1847d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1848d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1849d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1850d81ba9d5SMatt Jacob 		/*
1851a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1852a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1853a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1854a1bc34c6SMatt Jacob 		 * private data.
1855a1bc34c6SMatt Jacob 		 *
1856a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1857a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1858a1bc34c6SMatt Jacob 		 */
1859a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1860a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1861a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1862a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1863a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1864a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1865a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1866a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1867a1bc34c6SMatt Jacob 		}
18685d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1869a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1870a1bc34c6SMatt Jacob 		}
187164edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
187264edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
187364edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
187464edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
187564edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
187664edff94SMatt Jacob 		tval = ct->ct_fwhandle;
18775d571944SMatt Jacob 	}
1878a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1879a1bc34c6SMatt Jacob 
1880a1bc34c6SMatt Jacob 	/*
1881a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1882a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1883a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1884d81ba9d5SMatt Jacob 	 *
1885d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1886d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1887a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1888a1bc34c6SMatt Jacob 	 * freed.
1889d81ba9d5SMatt Jacob 	 */
1890f48ce188SMatt Jacob 	if (notify_cam == 0) {
189164edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1892f48ce188SMatt Jacob 		return (0);
1893f48ce188SMatt Jacob 	}
1894d81ba9d5SMatt Jacob 
189553036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
189653036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1897a1bc34c6SMatt Jacob 
1898a1bc34c6SMatt Jacob 	if (!ok) {
1899a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1900d81ba9d5SMatt Jacob 	} else {
1901a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1902a1bc34c6SMatt Jacob 
1903d81ba9d5SMatt Jacob 	}
1904a1bc34c6SMatt Jacob 	return (0);
1905d81ba9d5SMatt Jacob }
1906570c7a3fSMatt Jacob 
1907570c7a3fSMatt Jacob static int
19089cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp)
1909570c7a3fSMatt Jacob {
1910570c7a3fSMatt Jacob 	return (0);	/* XXXX */
1911570c7a3fSMatt Jacob }
1912570c7a3fSMatt Jacob 
1913570c7a3fSMatt Jacob static int
19149cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
1915570c7a3fSMatt Jacob {
1916570c7a3fSMatt Jacob 
1917570c7a3fSMatt Jacob 	switch (inp->in_status) {
1918570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
1919570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
1920570c7a3fSMatt Jacob 		   inp->in_iid);
1921570c7a3fSMatt Jacob 		break;
1922570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
1923570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
1924570c7a3fSMatt Jacob 		   inp->in_iid);
1925570c7a3fSMatt Jacob 		break;
1926570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
1927570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
1928570c7a3fSMatt Jacob 		break;
1929570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
1930570c7a3fSMatt Jacob 	{
1931570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
1932570c7a3fSMatt Jacob 		struct ccb_immed_notify *inot = NULL;
1933570c7a3fSMatt Jacob 
1934570c7a3fSMatt Jacob 		if (atp) {
1935570c7a3fSMatt Jacob 			tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
1936570c7a3fSMatt Jacob 			if (tptr) {
1937570c7a3fSMatt Jacob 				inot = (struct ccb_immed_notify *)
1938570c7a3fSMatt Jacob 				    SLIST_FIRST(&tptr->inots);
1939570c7a3fSMatt Jacob 				if (inot) {
1940746e9c85SMatt Jacob 					tptr->inot_count--;
1941570c7a3fSMatt Jacob 					SLIST_REMOVE_HEAD(&tptr->inots,
1942570c7a3fSMatt Jacob 					    sim_links.sle);
1943746e9c85SMatt Jacob 					isp_prt(isp, ISP_LOGTDEBUG0,
1944746e9c85SMatt Jacob 					    "Take FREE INOT count now %d",
1945746e9c85SMatt Jacob 					    tptr->inot_count);
1946570c7a3fSMatt Jacob 				}
1947570c7a3fSMatt Jacob 			}
1948570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1949570c7a3fSMatt Jacob 			   "abort task RX_ID %x IID %d state %d",
1950570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid, atp->state);
1951570c7a3fSMatt Jacob 		} else {
1952570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1953570c7a3fSMatt Jacob 			   "abort task RX_ID %x from iid %d, state unknown",
1954570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid);
1955570c7a3fSMatt Jacob 		}
1956570c7a3fSMatt Jacob 		if (inot) {
1957570c7a3fSMatt Jacob 			inot->initiator_id = inp->in_iid;
1958570c7a3fSMatt Jacob 			inot->sense_len = 0;
1959570c7a3fSMatt Jacob 			inot->message_args[0] = MSG_ABORT_TAG;
1960570c7a3fSMatt Jacob 			inot->message_args[1] = inp->in_seqid & 0xff;
1961570c7a3fSMatt Jacob 			inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
19626b5ec766SMatt Jacob 			inot->ccb_h.status = CAM_MESSAGE_RECV;
1963570c7a3fSMatt Jacob 			xpt_done((union ccb *)inot);
1964570c7a3fSMatt Jacob 		}
1965570c7a3fSMatt Jacob 		break;
1966570c7a3fSMatt Jacob 	}
1967570c7a3fSMatt Jacob 	default:
1968570c7a3fSMatt Jacob 		break;
1969570c7a3fSMatt Jacob 	}
1970570c7a3fSMatt Jacob 	return (0);
1971570c7a3fSMatt Jacob }
1972d81ba9d5SMatt Jacob #endif
1973d81ba9d5SMatt Jacob 
1974478f8a96SJustin T. Gibbs static void
19751dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
1976478f8a96SJustin T. Gibbs {
1977478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
19789cd7268eSMatt Jacob 	ispsoftc_t *isp;
1979478f8a96SJustin T. Gibbs 
1980478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
19819cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
1982478f8a96SJustin T. Gibbs 	switch (code) {
1983478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1984ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
19851dae40ebSMatt Jacob 			uint16_t oflags, nflags;
1986478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1987a1bc34c6SMatt Jacob 			int tgt;
1988478f8a96SJustin T. Gibbs 
1989f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
199041ed683eSMatt Jacob 			if (tgt >= 0) {
1991ea6f23cdSMatt Jacob 				sdp += cam_sim_bus(sim);
199241ed683eSMatt Jacob 				ISP_LOCK(isp);
19939ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
1994a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
19959ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
1996a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
1997478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
1998478f8a96SJustin T. Gibbs 				}
1999a1bc34c6SMatt Jacob #else
2000a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
2001a1bc34c6SMatt Jacob #endif
20029ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
20039ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
2004478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
2005a1bc34c6SMatt Jacob 				isp->isp_update |= (1 << cam_sim_bus(sim));
200641ed683eSMatt Jacob 				(void) isp_control(isp,
200741ed683eSMatt Jacob 				    ISPCTL_UPDATE_PARAMS, NULL);
20089ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
2009f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
2010478f8a96SJustin T. Gibbs 			}
201141ed683eSMatt Jacob 		}
2012478f8a96SJustin T. Gibbs 		break;
2013478f8a96SJustin T. Gibbs 	default:
20143c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
2015478f8a96SJustin T. Gibbs 		break;
2016478f8a96SJustin T. Gibbs 	}
2017478f8a96SJustin T. Gibbs }
2018478f8a96SJustin T. Gibbs 
2019478f8a96SJustin T. Gibbs static void
2020c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
2021478f8a96SJustin T. Gibbs {
20229cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
202310365e5aSMatt Jacob 	uint32_t isr;
202410365e5aSMatt Jacob 	uint16_t sema, mbox;
2025126ec864SMatt Jacob 
2026c40e096eSMatt Jacob 	ISP_LOCK(isp);
2027126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2028126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
2029126ec864SMatt Jacob 	}
2030c40e096eSMatt Jacob 	ISP_UNLOCK(isp);
2031478f8a96SJustin T. Gibbs }
2032478f8a96SJustin T. Gibbs 
2033ab6c4b31SMatt Jacob 
2034f7c631bcSMatt Jacob static int isp_watchdog_work(ispsoftc_t *, XS_T *);
2035f7c631bcSMatt Jacob 
2036f7c631bcSMatt Jacob static int
2037f7c631bcSMatt Jacob isp_watchdog_work(ispsoftc_t *isp, XS_T *xs)
2038cc8df88bSMatt Jacob {
20391dae40ebSMatt Jacob 	uint32_t handle;
2040b85389e1SMatt Jacob 
2041cc8df88bSMatt Jacob 	/*
2042b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
2043b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
2044b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
2045cc8df88bSMatt Jacob 	 */
2046f6e75de2SMatt Jacob 	ISP_LOCK(isp);
2047cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
2048cc8df88bSMatt Jacob 	if (handle) {
204910365e5aSMatt Jacob 		uint32_t isr;
205010365e5aSMatt Jacob 		uint16_t sema, mbox;
2051126ec864SMatt Jacob 
2052b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2053b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
2054b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
2055f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2056f7c631bcSMatt Jacob 			return (1);;
2057b85389e1SMatt Jacob 		}
2058b85389e1SMatt Jacob 
2059b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
2060b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2061b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
2062f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2063f7c631bcSMatt Jacob 			return (1);
2064b85389e1SMatt Jacob 		}
2065b85389e1SMatt Jacob 
2066b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
2067126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2068126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
2069126ec864SMatt Jacob 		}
2070126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2071b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2072126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
2073f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2074b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
2075f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2076b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
20771fcf5debSMatt Jacob 			/*
20781fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
20791fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
20801fcf5debSMatt Jacob 			 */
2081f7c631bcSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, xs);
20821fcf5debSMatt Jacob 
20831fcf5debSMatt Jacob 			/*
20841fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
20851fcf5debSMatt Jacob 			 */
2086f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
2087f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
2088f6e75de2SMatt Jacob                 	}
2089cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
2090dd9fc7c3SMatt Jacob 			xpt_print(xs->ccb_h.path,
2091dd9fc7c3SMatt Jacob 			    "watchdog timeout for handle 0x%x\n", handle);
2092cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
2093b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2094f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2095cc8df88bSMatt Jacob 			isp_done(xs);
2096f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2097b85389e1SMatt Jacob 		} else {
2098b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2099b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
2100b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
210110365e5aSMatt Jacob 			isp->isp_sendmarker |= 1 << XS_CHANNEL(xs);
2102b85389e1SMatt Jacob 		}
2103f7c631bcSMatt Jacob 		ISP_UNLOCK(isp);
2104f7c631bcSMatt Jacob 		return (1);
2105cc8df88bSMatt Jacob 	}
2106f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
2107f7c631bcSMatt Jacob 	return (0);
2108f7c631bcSMatt Jacob }
2109f7c631bcSMatt Jacob 
2110f7c631bcSMatt Jacob static void
2111f7c631bcSMatt Jacob isp_watchdog(void *arg)
2112f7c631bcSMatt Jacob {
2113f7c631bcSMatt Jacob 	ispsoftc_t *isp;
2114f7c631bcSMatt Jacob 	XS_T *xs = arg;
2115f7c631bcSMatt Jacob 	for (isp = isplist; isp != NULL; isp = isp->isp_osinfo.next) {
2116f7c631bcSMatt Jacob 		if (isp_watchdog_work(isp, xs)) {
2117f7c631bcSMatt Jacob 			break;
2118f7c631bcSMatt Jacob 		}
2119f7c631bcSMatt Jacob 	}
2120f7c631bcSMatt Jacob 	if (isp == NULL) {
2121f7c631bcSMatt Jacob 		printf("isp_watchdog: nobody had %p active\n", arg);
2122f7c631bcSMatt Jacob 	}
2123f7c631bcSMatt Jacob }
2124f7c631bcSMatt Jacob 
2125f7c631bcSMatt Jacob 
2126f7c631bcSMatt Jacob #if __FreeBSD_version >= 500000
2127f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	isp_announce(isp, tgt, AC_FOUND_DEVICE)
2128f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	isp_announce(isp, tgt, AC_LOST_DEVICE)
2129f7c631bcSMatt Jacob 
2130f7c631bcSMatt Jacob /*
2131f7c631bcSMatt Jacob  * Support function for Announcement
2132f7c631bcSMatt Jacob  */
2133f7c631bcSMatt Jacob static void
2134f7c631bcSMatt Jacob isp_announce(ispsoftc_t *isp, int tgt, int action)
2135f7c631bcSMatt Jacob {
2136f7c631bcSMatt Jacob 	struct cam_path *tmppath;
2137f7c631bcSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
2138f7c631bcSMatt Jacob 	if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), tgt,
2139f7c631bcSMatt Jacob 	    CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
2140f7c631bcSMatt Jacob 		xpt_async(action, tmppath, NULL);
2141f7c631bcSMatt Jacob 		xpt_free_path(tmppath);
2142f7c631bcSMatt Jacob 	}
2143f7c631bcSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
2144f7c631bcSMatt Jacob }
2145f7c631bcSMatt Jacob #else
2146f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	do { ; } while (0)
2147f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	do { ; } while (0)
2148f7c631bcSMatt Jacob #endif
2149f7c631bcSMatt Jacob 
2150f7c631bcSMatt Jacob 
2151f7c631bcSMatt Jacob /*
2152f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
2153f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
2154f7c631bcSMatt Jacob  * gone away.
2155f7c631bcSMatt Jacob  *
2156f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
2157f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
2158f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
2159f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
2160f7c631bcSMatt Jacob  */
2161f7c631bcSMatt Jacob static void
2162f7c631bcSMatt Jacob isp_gdt(void *arg)
2163f7c631bcSMatt Jacob {
2164f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2165f7c631bcSMatt Jacob 	fcportdb_t *lp;
2166f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
2167f7c631bcSMatt Jacob 
2168f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired");
2169f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2170f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2171f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2172f7c631bcSMatt Jacob 
2173f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
2174f7c631bcSMatt Jacob 			continue;
2175f7c631bcSMatt Jacob 		}
2176f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2177f7c631bcSMatt Jacob 			continue;
2178f7c631bcSMatt Jacob 		}
2179f7c631bcSMatt Jacob 		if (lp->new_reserved == 0) {
2180f7c631bcSMatt Jacob 			continue;
2181f7c631bcSMatt Jacob 		}
2182f7c631bcSMatt Jacob 		lp->new_reserved -= 1;
2183f7c631bcSMatt Jacob 		if (lp->new_reserved != 0) {
2184f7c631bcSMatt Jacob 			more_to_do++;
2185f7c631bcSMatt Jacob 			continue;
2186f7c631bcSMatt Jacob 		}
2187f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2188f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2189f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2190f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
2191f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2192f7c631bcSMatt Jacob 		    "Gone Device Timeout");
2193f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2194f7c631bcSMatt Jacob 	}
2195f7c631bcSMatt Jacob 	if (more_to_do) {
2196f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
2197f7c631bcSMatt Jacob 	} else {
2198f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2199f7c631bcSMatt Jacob 		    "stopping Gone Device Timer");
2200f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt_running = 0;
2201f7c631bcSMatt Jacob 	}
2202f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2203f7c631bcSMatt Jacob }
2204f7c631bcSMatt Jacob 
2205f7c631bcSMatt Jacob /*
2206f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
2207f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
2208f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
2209f7c631bcSMatt Jacob  *
2210f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
2211f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
2212f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
2213f7c631bcSMatt Jacob  */
2214f7c631bcSMatt Jacob static void
2215f7c631bcSMatt Jacob isp_ldt(void *arg)
2216f7c631bcSMatt Jacob {
2217f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2218f7c631bcSMatt Jacob 	fcportdb_t *lp;
2219f7c631bcSMatt Jacob 	int dbidx, tgt;
2220f7c631bcSMatt Jacob 
2221f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired");
2222f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2223f7c631bcSMatt Jacob 
2224f7c631bcSMatt Jacob 	/*
2225f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
2226f7c631bcSMatt Jacob 	 */
2227f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2228f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2229f7c631bcSMatt Jacob 
2230f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
2231f7c631bcSMatt Jacob 			continue;
2232f7c631bcSMatt Jacob 		}
2233f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2234f7c631bcSMatt Jacob 			continue;
2235f7c631bcSMatt Jacob 		}
2236f7c631bcSMatt Jacob 
2237f7c631bcSMatt Jacob 		/*
2238f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
2239f7c631bcSMatt Jacob 		 */
2240f7c631bcSMatt Jacob 
2241f7c631bcSMatt Jacob 		/*
2242f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
2243f7c631bcSMatt Jacob 		 */
2244f7c631bcSMatt Jacob 		lp->reserved = 1;
2245f7c631bcSMatt Jacob 
2246f7c631bcSMatt Jacob 		/*
2247f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
2248f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
2249f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
2250f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
2251f7c631bcSMatt Jacob 		 */
2252f7c631bcSMatt Jacob 
2253f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2254f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2255f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2256f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2257f7c631bcSMatt Jacob 		    "Loop Down Timeout");
2258f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2259f7c631bcSMatt Jacob 	}
2260f7c631bcSMatt Jacob 
2261f7c631bcSMatt Jacob 	/*
2262f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
2263f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
2264f7c631bcSMatt Jacob 	 */
2265f7c631bcSMatt Jacob 	isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1;
2266f7c631bcSMatt Jacob #if __FreeBSD_version < 500000
2267f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kproc);
2268f7c631bcSMatt Jacob #else
2269f7c631bcSMatt Jacob #ifdef	ISP_SMPLOCK
2270f7c631bcSMatt Jacob 	cv_signal(&isp->isp_osinfo.kthread_cv);
2271f7c631bcSMatt Jacob #else
2272f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kthread_cv);
2273f7c631bcSMatt Jacob #endif
2274f7c631bcSMatt Jacob #endif
2275f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2276cc8df88bSMatt Jacob }
2277cc8df88bSMatt Jacob 
22785d571944SMatt Jacob static void
22795d571944SMatt Jacob isp_kthread(void *arg)
22805d571944SMatt Jacob {
22819cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
2282f7c631bcSMatt Jacob 	int slp = 0;
22839cd7268eSMatt Jacob #if __FreeBSD_version < 500000
22849cd7268eSMatt Jacob         int s;
22859cd7268eSMatt Jacob 
22869cd7268eSMatt Jacob         s = splcam();
22879cd7268eSMatt Jacob #else
2288162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
22895d571944SMatt Jacob 	mtx_lock(&isp->isp_lock);
2290ee76282eSMatt Jacob #else
2291ee76282eSMatt Jacob 	mtx_lock(&Giant);
2292162e9893SMatt Jacob #endif
22939cd7268eSMatt Jacob #endif
2294fdeb9f2fSMatt Jacob 	/*
2295fdeb9f2fSMatt Jacob 	 * The first loop is for our usage where we have yet to have
2296fdeb9f2fSMatt Jacob 	 * gotten good fibre channel state.
2297fdeb9f2fSMatt Jacob 	 */
22985d571944SMatt Jacob 	for (;;) {
2299f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
2300fdeb9f2fSMatt Jacob 
2301f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2302f7c631bcSMatt Jacob 		    "isp_kthread: checking FC state");
2303f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
230410365e5aSMatt Jacob 		lb = isp_fc_runstate(isp, 250000);
2305f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
230610365e5aSMatt Jacob 		if (lb) {
2307f7c631bcSMatt Jacob 			/*
2308f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
2309f7c631bcSMatt Jacob 			 */
2310f7c631bcSMatt Jacob 			isp->isp_osinfo.loop_down_time += slp;
231110365e5aSMatt Jacob 
231210365e5aSMatt Jacob 			if (lb < 0) {
2313f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
231410365e5aSMatt Jacob 				    "kthread: FC loop not up (down count %d)",
231510365e5aSMatt Jacob 				    isp->isp_osinfo.loop_down_time);
231610365e5aSMatt Jacob 			} else {
2317f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
231810365e5aSMatt Jacob 				    "kthread: FC got to %d (down count %d)",
231910365e5aSMatt Jacob 				    lb, isp->isp_osinfo.loop_down_time);
2320f44257c2SMatt Jacob 			}
232110365e5aSMatt Jacob 
232210365e5aSMatt Jacob 
232310365e5aSMatt Jacob 			/*
232410365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
2325f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
2326f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
2327f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
232810365e5aSMatt Jacob 			 */
2329f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2330f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
233110365e5aSMatt Jacob 			} else {
2332f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2333f7c631bcSMatt Jacob 			}
2334f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2335f7c631bcSMatt Jacob 				isp_freeze_loopdown(isp, "loop limit hit");
2336f7c631bcSMatt Jacob 				slp = 0;
2337f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 10) {
233810365e5aSMatt Jacob 				slp = 1;
2339f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 30) {
2340f7c631bcSMatt Jacob 				slp = 5;
2341f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 60) {
2342f7c631bcSMatt Jacob 				slp = 10;
2343f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 120) {
2344f7c631bcSMatt Jacob 				slp = 20;
2345f7c631bcSMatt Jacob 			} else {
2346f7c631bcSMatt Jacob 				slp = 30;
2347f44257c2SMatt Jacob 			}
234810365e5aSMatt Jacob 
234910365e5aSMatt Jacob 		} else {
2350f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2351f7c631bcSMatt Jacob 			    "isp_kthread: FC state OK");
235210365e5aSMatt Jacob 			isp->isp_osinfo.loop_down_time = 0;
235310365e5aSMatt Jacob 			slp = 0;
23545d571944SMatt Jacob 		}
2355fdeb9f2fSMatt Jacob 
2356f44257c2SMatt Jacob 		/*
235710365e5aSMatt Jacob 		 * If we'd frozen the simq, unfreeze it now so that CAM
235810365e5aSMatt Jacob 		 * can start sending us commands. If the FC state isn't
235910365e5aSMatt Jacob 		 * okay yet, they'll hit that in isp_start which will
236010365e5aSMatt Jacob 		 * freeze the queue again.
2361f44257c2SMatt Jacob 		 */
23625d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
23635d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
23645d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
2365f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2366f7c631bcSMatt Jacob 			    "isp_kthread: releasing simq");
23675d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
23685d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
23695d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
23705d571944SMatt Jacob 		}
2371f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2372f7c631bcSMatt Jacob 		    "isp_kthread: sleep time %d", slp);
23739cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2374f7c631bcSMatt Jacob 		tsleep(&isp->isp_osinfo.kproc, PRIBIO, "ispf",
2375f7c631bcSMatt Jacob 		    slp * hz);
23769cd7268eSMatt Jacob #else
2377162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
2378f7c631bcSMatt Jacob 		cv_timed_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock,
2379f7c631bcSMatt Jacob 		    slp * hz);
2380162e9893SMatt Jacob #else
2381f7c631bcSMatt Jacob 		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "ispf",
2382f7c631bcSMatt Jacob 		    slp * hz);
2383162e9893SMatt Jacob #endif
23849cd7268eSMatt Jacob #endif
238510365e5aSMatt Jacob 		/*
238610365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
238710365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
238810365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
238910365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
239010365e5aSMatt Jacob 		 * to settle.
239110365e5aSMatt Jacob 		 */
239210365e5aSMatt Jacob 		if (slp == 0 && isp->isp_osinfo.hysteresis) {
2393f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2394f7c631bcSMatt Jacob 			    "isp_kthread: sleep hysteresis tick time %d",
2395f7c631bcSMatt Jacob 			    isp->isp_osinfo.hysteresis * hz);
239610365e5aSMatt Jacob 			(void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT",
239710365e5aSMatt Jacob 			    (isp->isp_osinfo.hysteresis * hz));
239810365e5aSMatt Jacob 		}
23995d571944SMatt Jacob 	}
24005d571944SMatt Jacob }
24015d571944SMatt Jacob 
2402cc8df88bSMatt Jacob static void
2403c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
2404478f8a96SJustin T. Gibbs {
2405f7c631bcSMatt Jacob 	int bus, tgt, error, lim;
24069cd7268eSMatt Jacob 	ispsoftc_t *isp;
24074663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
2408478f8a96SJustin T. Gibbs 
2409478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
2410478f8a96SJustin T. Gibbs 
24119cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
2412478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
2413478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
24140470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
24150470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
24165d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
241757c801f5SMatt Jacob 		isp_init(isp);
241857c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
2419f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
242057c801f5SMatt Jacob 			/*
242157c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
242257c801f5SMatt Jacob 			 */
2423b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
24240470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
242557c801f5SMatt Jacob 			xpt_done(ccb);
242657c801f5SMatt Jacob 			return;
242757c801f5SMatt Jacob 		}
242857c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
24295d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
243057c801f5SMatt Jacob 	}
2431b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
2432478f8a96SJustin T. Gibbs 
24335d571944SMatt Jacob 
2434478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
2435478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
2436478f8a96SJustin T. Gibbs 		/*
2437478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
2438478f8a96SJustin T. Gibbs 		 */
2439478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2440478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2441478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
2442478f8a96SJustin T. Gibbs 				xpt_done(ccb);
2443478f8a96SJustin T. Gibbs 				break;
2444478f8a96SJustin T. Gibbs 			}
2445478f8a96SJustin T. Gibbs 		}
24460470d791SMatt Jacob #ifdef	DIAGNOSTIC
24470470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
2448dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
2449478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
24500470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
2451dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
2452478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
2453478f8a96SJustin T. Gibbs 		}
2454478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
2455478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2456478f8a96SJustin T. Gibbs 			break;
2457478f8a96SJustin T. Gibbs 		}
24580470d791SMatt Jacob #endif
24590470d791SMatt Jacob 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
24605d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2461b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
24620470d791SMatt Jacob 		switch (error) {
2463478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
2464f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
2465f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2466478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2467cc8df88bSMatt Jacob 			if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
2468f7c631bcSMatt Jacob 				int ms = ccb->ccb_h.timeout;
2469f7c631bcSMatt Jacob 				if (ms == CAM_TIME_DEFAULT) {
2470f7c631bcSMatt Jacob 					ms = 60*1000;
2471d69a5f7dSMatt Jacob 				}
2472f7c631bcSMatt Jacob 				ccb->ccb_h.timeout_ch =
2473f7c631bcSMatt Jacob 				    timeout(isp_watchdog, ccb, isp_mstohz(ms));
2474b85389e1SMatt Jacob 			} else {
2475b85389e1SMatt Jacob 				callout_handle_init(&ccb->ccb_h.timeout_ch);
2476cc8df88bSMatt Jacob 			}
2477478f8a96SJustin T. Gibbs 			break;
24780470d791SMatt Jacob 		case CMD_RQLATER:
2479f44257c2SMatt Jacob 			/*
2480f44257c2SMatt Jacob 			 * This can only happen for Fibre Channel
2481f44257c2SMatt Jacob 			 */
2482f44257c2SMatt Jacob 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
2483f7c631bcSMatt Jacob 
248410365e5aSMatt Jacob 			/*
2485f7c631bcSMatt Jacob 			 * Handle initial and subsequent loop down cases
248610365e5aSMatt Jacob 			 */
2487f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2488f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
2489f7c631bcSMatt Jacob 			} else {
2490f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2491f7c631bcSMatt Jacob 			}
2492f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2493f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
2494f7c631bcSMatt Jacob 				    "%d.%d downtime (%d) > lim (%d)",
2495f7c631bcSMatt Jacob 				    XS_TGT(ccb), XS_LUN(ccb),
2496f7c631bcSMatt Jacob 				    isp->isp_osinfo.loop_down_time, lim);
2497f7c631bcSMatt Jacob 				ccb->ccb_h.status =
2498f7c631bcSMatt Jacob 				    CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
2499f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
2500f44257c2SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2501f44257c2SMatt Jacob 				xpt_done(ccb);
2502f44257c2SMatt Jacob 				break;
2503f44257c2SMatt Jacob 			}
2504f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2505f7c631bcSMatt Jacob 			    "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
2506f7c631bcSMatt Jacob 			/*
2507f7c631bcSMatt Jacob 			 * Otherwise, retry in a while.
2508f7c631bcSMatt Jacob 			 */
2509fdeb9f2fSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2510f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2511f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2512f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
2513f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
2514478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2515478f8a96SJustin T. Gibbs 			break;
25160470d791SMatt Jacob 		case CMD_EAGAIN:
25175d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2518f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2519f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2520f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
2521478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2522478f8a96SJustin T. Gibbs 			break;
25230470d791SMatt Jacob 		case CMD_COMPLETE:
25240470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
25255d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
25260470d791SMatt Jacob 			break;
25270470d791SMatt Jacob 		default:
2528f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2529bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2530bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
253191f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
2532b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
25330470d791SMatt Jacob 			xpt_done(ccb);
2534478f8a96SJustin T. Gibbs 		}
2535478f8a96SJustin T. Gibbs 		break;
2536478f8a96SJustin T. Gibbs 
2537d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2538478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
253964edff94SMatt Jacob 	{
254010365e5aSMatt Jacob 		int seq, i;
25415d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
254267ff51f1SMatt Jacob 		seq = isp_en_lun(isp, ccb);
254367ff51f1SMatt Jacob 		if (seq < 0) {
25445d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2545478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2546478f8a96SJustin T. Gibbs 			break;
254764edff94SMatt Jacob 		}
254867ff51f1SMatt Jacob 		for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) {
254910365e5aSMatt Jacob 			uint32_t isr;
255010365e5aSMatt Jacob 			uint16_t sema, mbox;
255167ff51f1SMatt Jacob 			if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
255267ff51f1SMatt Jacob 				isp_intr(isp, isr, sema, mbox);
255367ff51f1SMatt Jacob 			}
255467ff51f1SMatt Jacob 			DELAY(1000);
255567ff51f1SMatt Jacob 		}
255667ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
255767ff51f1SMatt Jacob 		break;
255867ff51f1SMatt Jacob 	}
2559d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
2560d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
2561d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
2562d81ba9d5SMatt Jacob 	{
2563a1bc34c6SMatt Jacob 		tstate_t *tptr =
2564a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
2565d81ba9d5SMatt Jacob 		if (tptr == NULL) {
2566d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
2567d81ba9d5SMatt Jacob 			xpt_done(ccb);
2568d81ba9d5SMatt Jacob 			break;
2569d81ba9d5SMatt Jacob 		}
2570f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2571f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
2572570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
2573570c7a3fSMatt Jacob 
25745d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2575d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
2576570c7a3fSMatt Jacob 			/*
2577570c7a3fSMatt Jacob 			 * Note that the command itself may not be done-
2578570c7a3fSMatt Jacob 			 * it may not even have had the first CTIO sent.
2579570c7a3fSMatt Jacob 			 */
2580570c7a3fSMatt Jacob 			tptr->atio_count++;
2581570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2582746e9c85SMatt Jacob 			    "Put FREE ATIO, lun %d, count now %d",
2583570c7a3fSMatt Jacob 			    ccb->ccb_h.target_lun, tptr->atio_count);
2584570c7a3fSMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
2585570c7a3fSMatt Jacob 			    sim_links.sle);
2586570c7a3fSMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
2587746e9c85SMatt Jacob 			tptr->inot_count++;
2588746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2589746e9c85SMatt Jacob 			    "Put FREE INOT, lun %d, count now %d",
2590746e9c85SMatt Jacob 			    ccb->ccb_h.target_lun, tptr->inot_count);
2591d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
2592d81ba9d5SMatt Jacob 			    sim_links.sle);
2593570c7a3fSMatt Jacob 		} else {
2594746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");;
2595d81ba9d5SMatt Jacob 		}
2596d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
2597d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
25985d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2599d81ba9d5SMatt Jacob 		break;
2600d81ba9d5SMatt Jacob 	}
2601d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
2602d81ba9d5SMatt Jacob 	{
26035d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
26049cd7268eSMatt Jacob 		isp_target_start_ctio(isp, ccb);
26055d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2606d81ba9d5SMatt Jacob 		break;
2607d81ba9d5SMatt Jacob 	}
2608d81ba9d5SMatt Jacob #endif
2609478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2610d81ba9d5SMatt Jacob 
2611d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2612d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2613d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2614d81ba9d5SMatt Jacob 
26155d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2616ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
26175d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2618478f8a96SJustin T. Gibbs 		if (error) {
2619478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2620478f8a96SJustin T. Gibbs 		} else {
2621478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2622478f8a96SJustin T. Gibbs 		}
2623478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2624478f8a96SJustin T. Gibbs 		break;
2625478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2626d81ba9d5SMatt Jacob 	{
2627d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
26285d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2629d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2630d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2631d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2632d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2633d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2634d81ba9d5SMatt Jacob 			break;
2635d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2636b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2637d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2638d81ba9d5SMatt Jacob 			break;
2639d81ba9d5SMatt Jacob #endif
2640d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2641478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2642478f8a96SJustin T. Gibbs 			if (error) {
2643d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2644478f8a96SJustin T. Gibbs 			} else {
2645478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2646478f8a96SJustin T. Gibbs 			}
2647d81ba9d5SMatt Jacob 			break;
2648d81ba9d5SMatt Jacob 		default:
2649d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2650d81ba9d5SMatt Jacob 			break;
2651d81ba9d5SMatt Jacob 		}
26525d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2653478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2654478f8a96SJustin T. Gibbs 		break;
2655d81ba9d5SMatt Jacob 	}
2656ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2657478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2658478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
26599ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
26609ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
26619ce9bdafSMatt Jacob 			xpt_done(ccb);
26629ce9bdafSMatt Jacob 			break;
26639ce9bdafSMatt Jacob 		}
2664478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
26655d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2666ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2667ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2668ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2669ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2670ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2671ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
26721dae40ebSMatt Jacob 			uint16_t *dptr;
2673ab163f5fSMatt Jacob 
2674b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
2675b61386a4SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2676b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
2677b61386a4SMatt Jacob 				xpt_done(ccb);
2678b61386a4SMatt Jacob 				break;
2679b61386a4SMatt Jacob 			}
2680b61386a4SMatt Jacob 
2681ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2682ab163f5fSMatt Jacob 			sdp += bus;
2683ab163f5fSMatt Jacob 			/*
26849ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2685ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2686ab163f5fSMatt Jacob 			 * vectored to that location.
2687ab163f5fSMatt Jacob 			 */
26889ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2689ab163f5fSMatt Jacob 
2690ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2691ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2692ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2693ab163f5fSMatt Jacob 				else
2694ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2695ab163f5fSMatt Jacob 			}
2696ab163f5fSMatt Jacob 
2697ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2698ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2699ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2700ab163f5fSMatt Jacob 				else
2701ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2702ab163f5fSMatt Jacob 			}
2703ab163f5fSMatt Jacob 
2704ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2705ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2706ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2707ab163f5fSMatt Jacob 				else
2708ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2709ab163f5fSMatt Jacob 			}
2710ab163f5fSMatt Jacob 
2711ab163f5fSMatt Jacob 			/*
2712ab163f5fSMatt Jacob 			 * XXX: FIX ME
2713ab163f5fSMatt Jacob 			 */
2714ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
27159ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
27169ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2717ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
27189ce9bdafSMatt Jacob 				/*
27199ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
27209ce9bdafSMatt Jacob 				 */
27219ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
27229ce9bdafSMatt Jacob 				    spi->sync_period;
27239ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
27249ce9bdafSMatt Jacob 				    spi->sync_offset;
2725ab163f5fSMatt Jacob 			} else {
2726ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2727ab163f5fSMatt Jacob 			}
2728bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2729b61386a4SMatt Jacob 			    "SET (%d.%d.%d) to flags %x off %x per %x",
2730b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun,
2731b61386a4SMatt Jacob 			    sdp->isp_devparam[tgt].goal_flags,
27329ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
27339ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2734478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2735ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2736478f8a96SJustin T. Gibbs 		}
27375d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2738478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2739478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2740478f8a96SJustin T. Gibbs 		break;
2741478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2742478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2743478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2744ab163f5fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2745ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2746ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
2747ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2748ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2749478f8a96SJustin T. Gibbs 
2750ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2751ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2752ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2753ab163f5fSMatt Jacob 			cts->transport_version = 0;
2754ab163f5fSMatt Jacob 
2755ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
275653036e92SMatt Jacob 			if (fcp->isp_gbspeed == 2)
275753036e92SMatt Jacob 				fc->bitrate = 200000;
275853036e92SMatt Jacob 			else
2759ab163f5fSMatt Jacob 				fc->bitrate = 100000;
2760ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
276110365e5aSMatt Jacob 				fcportdb_t *lp = &fcp->portdb[tgt];
2762ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2763ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2764ab163f5fSMatt Jacob 				fc->port = lp->portid;
2765ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2766ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2767ab163f5fSMatt Jacob 			}
2768ab163f5fSMatt Jacob 		} else {
2769ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2770ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2771ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2772ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2773ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2774ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
27751dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
2776ab163f5fSMatt Jacob 
2777ea6f23cdSMatt Jacob 			sdp += bus;
2778ab163f5fSMatt Jacob 
2779ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
278083ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
278183ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
278283ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
278383ae4407SMatt Jacob 				    NULL);
27849ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
27859ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
27869ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
27874394c92fSMatt Jacob 			} else {
27889ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
27899ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
27909ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
27914394c92fSMatt Jacob 			}
2792478f8a96SJustin T. Gibbs 
2793ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2794ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2795ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2796ab163f5fSMatt Jacob 			cts->transport_version = 2;
2797ab163f5fSMatt Jacob 
2798b61386a4SMatt Jacob 			spi->valid = 0;
2799b61386a4SMatt Jacob 			scsi->valid = 0;
2800b61386a4SMatt Jacob 			spi->flags = 0;
2801b61386a4SMatt Jacob 			scsi->flags = 0;
2802ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2803ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2804ab163f5fSMatt Jacob 			}
28059ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2806ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2807ab163f5fSMatt Jacob 				spi->sync_period = pval;
2808b61386a4SMatt Jacob 			} else {
2809b61386a4SMatt Jacob 				spi->sync_offset = 0;
2810b61386a4SMatt Jacob 				spi->sync_period = 0;
2811b61386a4SMatt Jacob 			}
2812ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2813ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2814ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2815ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2816ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2817ab163f5fSMatt Jacob 			} else {
2818ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2819ab163f5fSMatt Jacob 			}
2820ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2821ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2822b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
2823b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2824b61386a4SMatt Jacob 				}
2825ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2826ab163f5fSMatt Jacob 			}
2827bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2828b61386a4SMatt Jacob 			    "GET %s (%d.%d.%d) to flags %x off %x per %x",
28299ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
2830b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
2831478f8a96SJustin T. Gibbs 		}
2832ab163f5fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2833478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2834478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2835478f8a96SJustin T. Gibbs 		break;
2836478f8a96SJustin T. Gibbs 
2837478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
28389cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2839478f8a96SJustin T. Gibbs 	{
2840478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
28419cd7268eSMatt Jacob 		u_int32_t secs_per_cylinder;
28429cd7268eSMatt Jacob 		u_int32_t size_mb;
2843478f8a96SJustin T. Gibbs 
2844478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2845478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2846478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2847478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2848478f8a96SJustin T. Gibbs 			break;
2849478f8a96SJustin T. Gibbs 		}
28509cd7268eSMatt Jacob 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
28519cd7268eSMatt Jacob 		if (size_mb > 1024) {
28529cd7268eSMatt Jacob 			ccg->heads = 255;
28539cd7268eSMatt Jacob 			ccg->secs_per_track = 63;
28549cd7268eSMatt Jacob 		} else {
28559cd7268eSMatt Jacob 			ccg->heads = 64;
28569cd7268eSMatt Jacob 			ccg->secs_per_track = 32;
28579cd7268eSMatt Jacob 		}
28589cd7268eSMatt Jacob 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
28599cd7268eSMatt Jacob 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
28609cd7268eSMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
2861478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2862478f8a96SJustin T. Gibbs 		break;
2863478f8a96SJustin T. Gibbs 	}
28649cd7268eSMatt Jacob #else
28659cd7268eSMatt Jacob 	{
28669cd7268eSMatt Jacob 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
28679cd7268eSMatt Jacob 		xpt_done(ccb);
28689cd7268eSMatt Jacob 		break;
28699cd7268eSMatt Jacob 	}
28709cd7268eSMatt Jacob #endif
2871478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
2872ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
28735d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2874ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
28755d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2876478f8a96SJustin T. Gibbs 		if (error)
2877478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
28782b052931SMatt Jacob 		else {
2879ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
2880ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
2881ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
28822b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
2883478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
28842b052931SMatt Jacob 		}
2885478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2886478f8a96SJustin T. Gibbs 		break;
2887478f8a96SJustin T. Gibbs 
2888478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
2889478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2890478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2891478f8a96SJustin T. Gibbs 		break;
2892478f8a96SJustin T. Gibbs 
2893478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
2894478f8a96SJustin T. Gibbs 	{
2895478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
2896478f8a96SJustin T. Gibbs 
2897478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
2898d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2899a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
2900d81ba9d5SMatt Jacob #else
2901478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
2902d81ba9d5SMatt Jacob #endif
2903478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
29040470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
29050470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
29060470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
29074394c92fSMatt Jacob 		if (IS_FC(isp)) {
29084394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
29090470d791SMatt Jacob 			/*
29100470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
29110470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
29120470d791SMatt Jacob 			 */
29130470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
29140470d791SMatt Jacob 
29159deea857SKenneth D. Merry 			/*
29169deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
29179deea857SKenneth D. Merry 			 * Technically not correct because we don't know
29189deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
29199deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
29209deea857SKenneth D. Merry 			 */
292153036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
292253036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
292353036e92SMatt Jacob 			else
29249deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
29250470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
2926ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
2927ab163f5fSMatt Jacob 			cpi->transport_version = 0;	/* WHAT'S THIS FOR? */
2928478f8a96SJustin T. Gibbs 		} else {
2929ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
2930ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
29310470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
29324394c92fSMatt Jacob 			cpi->hba_misc = 0;
2933ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
29349deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
2935ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
2936ab163f5fSMatt Jacob 			cpi->transport_version = 2;	/* WHAT'S THIS FOR? */
2937478f8a96SJustin T. Gibbs 		}
2938ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
2939ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
2940478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2941478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
2942478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2943478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
2944478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
2945478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2946478f8a96SJustin T. Gibbs 		break;
2947478f8a96SJustin T. Gibbs 	}
2948478f8a96SJustin T. Gibbs 	default:
2949478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2950478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2951478f8a96SJustin T. Gibbs 		break;
2952478f8a96SJustin T. Gibbs 	}
2953478f8a96SJustin T. Gibbs }
2954d3a9eb2eSMatt Jacob 
2955d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
2956f7c631bcSMatt Jacob 
2957d3a9eb2eSMatt Jacob void
2958c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
2959d3a9eb2eSMatt Jacob {
29609cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
2961d3a9eb2eSMatt Jacob 
2962d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
2963d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
2964b85389e1SMatt Jacob 
2965d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
2966d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
2967d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
296892a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
296992a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
297092a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
297192a1e549SMatt Jacob 		} else {
2972d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
2973d3a9eb2eSMatt Jacob 		}
297492a1e549SMatt Jacob 	}
2975b85389e1SMatt Jacob 
29760470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
2977d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2978f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0,
2979f7c631bcSMatt Jacob 		    "target %d lun %d CAM status 0x%x SCSI status 0x%x",
2980f7c631bcSMatt Jacob 		    XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status,
2981f7c631bcSMatt Jacob 		    sccb->scsi_status);
2982d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2983d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
29840470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
2985d3a9eb2eSMatt Jacob 		}
2986d3a9eb2eSMatt Jacob 	}
2987b85389e1SMatt Jacob 
2988b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
2989d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2990dd9fc7c3SMatt Jacob 		xpt_print(sccb->ccb_h.path,
2991dd9fc7c3SMatt Jacob 		    "cam completion status 0x%x\n", sccb->ccb_h.status);
2992d3a9eb2eSMatt Jacob 	}
2993b85389e1SMatt Jacob 
2994b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
2995b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
2996f7c631bcSMatt Jacob 		untimeout(isp_watchdog, sccb, sccb->ccb_h.timeout_ch);
2997b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
2998b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2999b09b0095SMatt Jacob 			    "finished command on borrowed time");
3000b85389e1SMatt Jacob 		}
3001b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
30025d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3003d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
30045d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3005d3a9eb2eSMatt Jacob 	}
3006b85389e1SMatt Jacob }
3007d3a9eb2eSMatt Jacob 
3008cbf57b47SMatt Jacob int
30099cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg)
3010cbf57b47SMatt Jacob {
3011ea6f23cdSMatt Jacob 	int bus, rv = 0;
301210365e5aSMatt Jacob 	static const char prom[] =
301310365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s\n"
301410365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
301510365e5aSMatt Jacob 	static const char prom2[] =
301610365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s tgt %u\n"
301710365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
3018f7c631bcSMatt Jacob 	char *msg = NULL;
301910365e5aSMatt Jacob 	target_id_t tgt;
302010365e5aSMatt Jacob 	fcportdb_t *lp;
302110365e5aSMatt Jacob 	struct cam_path *tmppath;
302210365e5aSMatt Jacob 
3023cbf57b47SMatt Jacob 	switch (cmd) {
3024cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
30250470d791SMatt Jacob 	{
3026ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
3027ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
3028cbf57b47SMatt Jacob 		int flags, tgt;
3029cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
3030ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
3031cbf57b47SMatt Jacob 
303229f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
3033ab163f5fSMatt Jacob 
3034cbf57b47SMatt Jacob 		tgt = *((int *)arg);
3035ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
3036ea6f23cdSMatt Jacob 		tgt &= 0xffff;
3037ea6f23cdSMatt Jacob 		sdp += bus;
303845c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3039cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
3040ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
3041ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
304245c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3043bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3044bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
3045bfbab170SMatt Jacob 			    tgt, bus);
3046cbf57b47SMatt Jacob 			rv = -1;
3047cbf57b47SMatt Jacob 			break;
3048cbf57b47SMatt Jacob 		}
304945c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
30509ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
3051ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
3052ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
3053ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
3054ab163f5fSMatt Jacob 
3055ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
3056ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
3057ab163f5fSMatt Jacob 
3058ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
3059ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
3060ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3061ab163f5fSMatt Jacob 		}
3062ab163f5fSMatt Jacob 
3063cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
3064ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
3065ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3066ab163f5fSMatt Jacob 		}
3067ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
3068ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
3069ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
3070ab163f5fSMatt Jacob 		} else {
3071ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
3072ab163f5fSMatt Jacob 		}
3073ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
3074ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3075ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
30769ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
30779ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
3078ab163f5fSMatt Jacob 		}
3079b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
3080b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
30819ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
30829ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
3083ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
30845d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3085ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
3086cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
3087f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3088cbf57b47SMatt Jacob 		break;
30890470d791SMatt Jacob 	}
309057c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
3091ea6f23cdSMatt Jacob 		bus = *((int *)arg);
3092b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
3093b09b0095SMatt Jacob 		    bus);
3094ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
30955d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
3096ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
30975d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3098ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
30995d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
310057c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
31015d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
310257c801f5SMatt Jacob 		}
310357c801f5SMatt Jacob 		break;
31045d571944SMatt Jacob 	case ISPASYNC_LIP:
3105f7c631bcSMatt Jacob 		if (msg == NULL) {
3106f7c631bcSMatt Jacob 			msg = "LIP Received";
31075d571944SMatt Jacob 		}
3108f7c631bcSMatt Jacob 		/* FALLTHROUGH */
31095d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
3110f7c631bcSMatt Jacob 		if (msg == NULL) {
3111f7c631bcSMatt Jacob 			msg = "LOOP Reset";
31125d571944SMatt Jacob 		}
3113f7c631bcSMatt Jacob 		/* FALLTHROUGH */
311457c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
3115f7c631bcSMatt Jacob 		if (msg == NULL) {
3116f7c631bcSMatt Jacob 			msg = "LOOP Down";
311757c801f5SMatt Jacob 		}
3118f7c631bcSMatt Jacob 		if (isp->isp_path) {
3119f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, msg);
3120f7c631bcSMatt Jacob 		}
3121f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running == 0) {
3122f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt = timeout(isp_ldt, isp,
3123f7c631bcSMatt Jacob 			    isp->isp_osinfo.loop_down_limit * hz);
3124f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
3125f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3126f7c631bcSMatt Jacob 			   "starting Loop Down Timer");
3127f7c631bcSMatt Jacob 		}
3128f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
312957c801f5SMatt Jacob 		break;
313057c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
31315d571944SMatt Jacob 		/*
31325d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
31335d571944SMatt Jacob 		 * actually do anything because we're waiting for a
31345d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
31355d571944SMatt Jacob 		 * thread to look at the state of the loop again.
31365d571944SMatt Jacob 		 */
3137b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
313857c801f5SMatt Jacob 		break;
313910365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
314010365e5aSMatt Jacob 		lp = arg;
3141f7c631bcSMatt Jacob 		lp->reserved = 0;
3142f7c631bcSMatt Jacob 		if ((isp->isp_role & ISP_ROLE_INITIATOR) &&
3143f7c631bcSMatt Jacob 		    (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
3144f7c631bcSMatt Jacob 			int dbidx = lp - FCPARAM(isp)->portdb;
3145f7c631bcSMatt Jacob 			int i;
314602ab3379SMatt Jacob 
3147f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
3148f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
3149f7c631bcSMatt Jacob 					continue;
3150f7c631bcSMatt Jacob 				}
3151f7c631bcSMatt Jacob 				if (FCPARAM(isp)->isp_ini_map[i] == 0) {
3152f7c631bcSMatt Jacob 					break;
3153f7c631bcSMatt Jacob 				}
3154f7c631bcSMatt Jacob 			}
3155f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
3156f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[i] = dbidx + 1;
3157f7c631bcSMatt Jacob 				lp->ini_map_idx = i + 1;
3158f7c631bcSMatt Jacob 			} else {
3159f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
3160f7c631bcSMatt Jacob 				isp_dump_portdb(isp);
3161f7c631bcSMatt Jacob 			}
3162f7c631bcSMatt Jacob 		}
316310365e5aSMatt Jacob 		if (lp->ini_map_idx) {
316410365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
316510365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
316610365e5aSMatt Jacob 			    lp->portid, lp->handle,
3167f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived at", tgt,
31681dae40ebSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
316910365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
317010365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
317110365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3172f7c631bcSMatt Jacob 			isp_make_here(isp, tgt);
317310365e5aSMatt Jacob 		} else {
317410365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
317510365e5aSMatt Jacob 			    lp->portid, lp->handle,
3176f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived",
317710365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
317810365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
317910365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
318010365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
318110365e5aSMatt Jacob 		}
318210365e5aSMatt Jacob 		break;
318310365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
318410365e5aSMatt Jacob 		lp = arg;
3185f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
3186f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
318710365e5aSMatt Jacob 			if (lp->ini_map_idx) {
318810365e5aSMatt Jacob 				tgt = lp->ini_map_idx - 1;
3189f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[tgt] = 0;
3190f7c631bcSMatt Jacob 				lp->ini_map_idx = 0;
3191f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3,
3192f7c631bcSMatt Jacob 				    lp->portid, tgt, "change is bad");
3193f7c631bcSMatt Jacob 				isp_make_gone(isp, tgt);
3194f7c631bcSMatt Jacob 			} else {
3195f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
3196f7c631bcSMatt Jacob 				    lp->portid, lp->handle,
3197f7c631bcSMatt Jacob 				    roles[lp->roles],
3198f7c631bcSMatt Jacob 				    "changed and departed",
3199f7c631bcSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
3200f7c631bcSMatt Jacob 				    (uint32_t) lp->node_wwn,
3201f7c631bcSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
3202f7c631bcSMatt Jacob 				    (uint32_t) lp->port_wwn);
3203f7c631bcSMatt Jacob 			}
3204f7c631bcSMatt Jacob 		} else {
3205f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
3206f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
3207f7c631bcSMatt Jacob 			if (lp->ini_map_idx) {
3208f7c631bcSMatt Jacob 				int t = lp->ini_map_idx - 1;
3209f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[t] =
3210f7c631bcSMatt Jacob 				    (lp - FCPARAM(isp)->portdb) + 1;
3211f7c631bcSMatt Jacob 				tgt = lp->ini_map_idx - 1;
321210365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2,
321310365e5aSMatt Jacob 				    lp->portid, lp->handle,
3214f7c631bcSMatt Jacob 				    roles[lp->roles], "changed at", tgt,
321510365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
321610365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
321710365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
321810365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
321910365e5aSMatt Jacob 			} else {
322010365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
322110365e5aSMatt Jacob 				    lp->portid, lp->handle,
3222f7c631bcSMatt Jacob 				    roles[lp->roles], "changed",
322310365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
322410365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
322510365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
322610365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
322710365e5aSMatt Jacob 			}
3228f7c631bcSMatt Jacob 		}
322910365e5aSMatt Jacob 		break;
323010365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
323110365e5aSMatt Jacob 		lp = arg;
323210365e5aSMatt Jacob 		if (lp->ini_map_idx) {
323310365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
323410365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
323510365e5aSMatt Jacob 			    lp->portid, lp->handle,
3236f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed at", tgt,
323710365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
323810365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
323910365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
324010365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
324110365e5aSMatt Jacob 		} else {
324210365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
324310365e5aSMatt Jacob 			    lp->portid, lp->handle,
3244f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed",
324510365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
324610365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
324710365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
324810365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
324910365e5aSMatt Jacob 		}
325010365e5aSMatt Jacob 		break;
325110365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
325210365e5aSMatt Jacob 		lp = arg;
3253f7c631bcSMatt Jacob 		/*
3254f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
3255f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
3256f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
3257f7c631bcSMatt Jacob 		 *
3258f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
3259f7c631bcSMatt Jacob 		 * announce that it's gone.
3260f7c631bcSMatt Jacob 		 */
3261f7c631bcSMatt Jacob 		if (lp->ini_map_idx && lp->reserved == 0) {
3262f7c631bcSMatt Jacob 			lp->reserved = 1;
3263f7c631bcSMatt Jacob 			lp->new_reserved = isp->isp_osinfo.gone_device_time;
3264f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
3265f7c631bcSMatt Jacob 			if (isp->isp_osinfo.gdt_running == 0) {
3266f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3267f7c631bcSMatt Jacob 				    "starting Gone Device Timer");
3268f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
3269f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt_running = 1;
3270f7c631bcSMatt Jacob 			}
327110365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
327210365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
327310365e5aSMatt Jacob 			    lp->portid, lp->handle,
3274f7c631bcSMatt Jacob 		            roles[lp->roles], "gone zombie at", tgt,
327510365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
327610365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
327710365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
327810365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3279f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
328010365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
328110365e5aSMatt Jacob 			    lp->portid, lp->handle,
3282f7c631bcSMatt Jacob 			    roles[lp->roles], "departed",
328310365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
328410365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
328510365e5aSMatt Jacob 			    (uint32_t) (lp->port_wwn >> 32),
328610365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
32874b9d588eSMatt Jacob 		}
328810365e5aSMatt Jacob 		break;
328910365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
329010365e5aSMatt Jacob 	{
329110365e5aSMatt Jacob 		char *msg;
329210365e5aSMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
329310365e5aSMatt Jacob 			msg = "Port Database Changed";
329410365e5aSMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
329510365e5aSMatt Jacob 			msg = "Name Server Database Changed";
329610365e5aSMatt Jacob 		} else {
329710365e5aSMatt Jacob 			msg = "Other Change Notify";
329810365e5aSMatt Jacob 		}
3299f7c631bcSMatt Jacob 		/*
3300f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
3301f7c631bcSMatt Jacob 		 */
3302f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running) {
3303f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3304f7c631bcSMatt Jacob 			   "Stopping Loop Down Timer");
3305f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 0;
3306f7c631bcSMatt Jacob 			untimeout(isp_ldt, isp, isp->isp_osinfo.ldt);
3307f7c631bcSMatt Jacob 			callout_handle_init(&isp->isp_osinfo.ldt);
3308f7c631bcSMatt Jacob 		}
330910365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
331010365e5aSMatt Jacob 		isp_freeze_loopdown(isp, msg);
33119cd7268eSMatt Jacob #if __FreeBSD_version < 500000
33129cd7268eSMatt Jacob 		wakeup(&isp->isp_osinfo.kproc);
33139cd7268eSMatt Jacob #else
3314162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
33155d571944SMatt Jacob 		cv_signal(&isp->isp_osinfo.kthread_cv);
3316162e9893SMatt Jacob #else
3317162e9893SMatt Jacob 		wakeup(&isp->isp_osinfo.kthread_cv);
3318162e9893SMatt Jacob #endif
33199cd7268eSMatt Jacob #endif
332057c801f5SMatt Jacob 		break;
332102ab3379SMatt Jacob 	}
3322d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3323e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
3324d81ba9d5SMatt Jacob 	{
3325e5265237SMatt Jacob 		tmd_notify_t *nt = arg;
332664edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3327e5265237SMatt Jacob 		    "target notify code 0x%x", nt->nt_ncode);
3328d81ba9d5SMatt Jacob 		break;
3329d81ba9d5SMatt Jacob 	}
3330d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
3331d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
3332cbf57b47SMatt Jacob 		default:
3333bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3334bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
3335bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
3336d81ba9d5SMatt Jacob 			break;
3337570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
3338570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
3339570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_scsi(isp,
3340570c7a3fSMatt Jacob 				    (in_entry_t *) arg);
3341570c7a3fSMatt Jacob 			} else {
3342570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_fc(isp,
3343570c7a3fSMatt Jacob 				    (in_fcentry_t *) arg);
3344570c7a3fSMatt Jacob 			}
3345570c7a3fSMatt Jacob 			break;
3346d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
3347d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
3348d81ba9d5SMatt Jacob 			break;
3349d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
3350d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
3351d81ba9d5SMatt Jacob 			break;
3352d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
3353d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
3354d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
3355d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
3356d81ba9d5SMatt Jacob 			break;
3357d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
3358d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
335967ff51f1SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) arg);
3360d81ba9d5SMatt Jacob 			break;
3361d81ba9d5SMatt Jacob 		}
3362d81ba9d5SMatt Jacob 		break;
3363d81ba9d5SMatt Jacob #endif
3364ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
3365ab163f5fSMatt Jacob 	{
33661dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
3367ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
3368ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
3369ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
3370ab163f5fSMatt Jacob 		} else {
3371ab163f5fSMatt Jacob 			mbox6 = 0;
3372ab163f5fSMatt Jacob 		}
3373ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
3374570c7a3fSMatt Jacob                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
3375ab163f5fSMatt Jacob                     mbox6, mbox1);
33768a5f89b9SMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
33778a5f89b9SMatt Jacob 		/*
33788a5f89b9SMatt Jacob 		 * XXX: really need a thread to do this right.
33798a5f89b9SMatt Jacob 		 */
33808a5f89b9SMatt Jacob 		if (IS_FC(isp)) {
33818a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
33828a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_loopstate = LOOP_NIL;
33838a5f89b9SMatt Jacob 			isp_freeze_loopdown(isp, "f/w crash");
33848a5f89b9SMatt Jacob 			isp_fw_dump(isp);
33858a5f89b9SMatt Jacob 		}
3386ab163f5fSMatt Jacob 		isp_reinit(isp);
33878a5f89b9SMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
33888a5f89b9SMatt Jacob #endif
3389ab163f5fSMatt Jacob 		break;
3390ab163f5fSMatt Jacob 	}
3391be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
3392be534d5fSMatt Jacob 		break;
3393d81ba9d5SMatt Jacob 	default:
3394b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
3395cbf57b47SMatt Jacob 		break;
3396cbf57b47SMatt Jacob 	}
3397cbf57b47SMatt Jacob 	return (rv);
3398cbf57b47SMatt Jacob }
3399cbf57b47SMatt Jacob 
340092718a7fSMatt Jacob 
340192718a7fSMatt Jacob /*
340292718a7fSMatt Jacob  * Locks are held before coming here.
340392718a7fSMatt Jacob  */
340492718a7fSMatt Jacob void
34059cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
340692718a7fSMatt Jacob {
340710365e5aSMatt Jacob 	if (IS_24XX(isp)) {
340810365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
340910365e5aSMatt Jacob 	} else {
3410ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
341110365e5aSMatt Jacob 	}
341210365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
341392718a7fSMatt Jacob }
3414b09b0095SMatt Jacob 
3415b09b0095SMatt Jacob void
34169cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
3417b09b0095SMatt Jacob {
3418b09b0095SMatt Jacob 	va_list ap;
3419b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
3420b09b0095SMatt Jacob 		return;
3421b09b0095SMatt Jacob 	}
34223c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
3423b09b0095SMatt Jacob 	va_start(ap, fmt);
3424b09b0095SMatt Jacob 	vprintf(fmt, ap);
3425b09b0095SMatt Jacob 	va_end(ap);
3426b09b0095SMatt Jacob 	printf("\n");
3427b09b0095SMatt Jacob }
3428f7c631bcSMatt Jacob 
3429f7c631bcSMatt Jacob uint64_t
3430f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
3431f7c631bcSMatt Jacob {
3432f7c631bcSMatt Jacob 	uint64_t elapsed;
3433f7c631bcSMatt Jacob 	struct timespec x = *b;
3434f7c631bcSMatt Jacob 	timespecsub(&x, a);
3435f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
3436f7c631bcSMatt Jacob 	if (elapsed == 0)
3437f7c631bcSMatt Jacob 		elapsed++;
3438f7c631bcSMatt Jacob 	return (elapsed);
3439f7c631bcSMatt Jacob }
3440f7c631bcSMatt Jacob 
3441f7c631bcSMatt Jacob int
3442f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
3443f7c631bcSMatt Jacob {
3444f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
3445f7c631bcSMatt Jacob 		return (1);
3446f7c631bcSMatt Jacob 	} else {
3447f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
3448f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
3449f7c631bcSMatt Jacob 		return (0);
3450f7c631bcSMatt Jacob 	}
3451f7c631bcSMatt Jacob }
3452f7c631bcSMatt Jacob 
3453f7c631bcSMatt Jacob void
3454f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
3455f7c631bcSMatt Jacob {
3456f7c631bcSMatt Jacob 	int usecs = mbp->timeout;
3457f7c631bcSMatt Jacob 	int j;
3458f7c631bcSMatt Jacob 
3459f7c631bcSMatt Jacob 	if (usecs == 0) {
3460f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
3461f7c631bcSMatt Jacob 	}
3462f7c631bcSMatt Jacob 	if (isp->isp_mbxwrk0) {
3463f7c631bcSMatt Jacob 		usecs *= isp->isp_mbxwrk0;
3464f7c631bcSMatt Jacob 	}
3465f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
3466f7c631bcSMatt Jacob 		int ms = usecs / 1000;
3467f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
3468f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
3469f7c631bcSMatt Jacob #if __FreeBSD_version < 500000  || !defined(ISP_SMPLOCK)
3470f7c631bcSMatt Jacob 		tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep",
3471f7c631bcSMatt Jacob 		    isp_mstohz(ms));
3472f7c631bcSMatt Jacob #else
3473f7c631bcSMatt Jacob 		msleep(&isp->isp_mbxworkp, &isp->isp_mtx, PRIBIO,
3474f7c631bcSMatt Jacob 		    "ispmbx_sleep", isp_mstohz(ms));
3475f7c631bcSMatt Jacob #endif
3476f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
3477f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
3478f7c631bcSMatt Jacob 	} else {
3479f7c631bcSMatt Jacob 		for (j = 0; j < usecs; j += 100) {
3480f7c631bcSMatt Jacob 			uint32_t isr;
3481f7c631bcSMatt Jacob 			uint16_t sema, mbox;
3482f7c631bcSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3483f7c631bcSMatt Jacob 				break;
3484f7c631bcSMatt Jacob 			}
3485f7c631bcSMatt Jacob 			if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3486f7c631bcSMatt Jacob 				isp_intr(isp, isr, sema, mbox);
3487f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
3488f7c631bcSMatt Jacob 					break;
3489f7c631bcSMatt Jacob 				}
3490f7c631bcSMatt Jacob 			}
3491f7c631bcSMatt Jacob 			USEC_DELAY(100);
3492f7c631bcSMatt Jacob 		}
3493f7c631bcSMatt Jacob 	}
3494f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
3495f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
3496f7c631bcSMatt Jacob 		    "%s Mailbox Command (0x%x) Timeout",
3497f7c631bcSMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled",
3498f7c631bcSMatt Jacob 		    isp->isp_lastmbxcmd);
3499f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
3500f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
3501f7c631bcSMatt Jacob 	}
3502f7c631bcSMatt Jacob }
3503f7c631bcSMatt Jacob 
3504f7c631bcSMatt Jacob void
3505f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
3506f7c631bcSMatt Jacob {
3507f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
3508f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
3509f7c631bcSMatt Jacob 	}
3510f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
3511f7c631bcSMatt Jacob }
3512f7c631bcSMatt Jacob 
3513f7c631bcSMatt Jacob void
3514f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
3515f7c631bcSMatt Jacob {
3516f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
3517f7c631bcSMatt Jacob }
3518f7c631bcSMatt Jacob 
3519f7c631bcSMatt Jacob int
3520f7c631bcSMatt Jacob isp_mstohz(int ms)
3521f7c631bcSMatt Jacob {
3522f7c631bcSMatt Jacob 	struct timeval t;
3523f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
3524f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
3525f7c631bcSMatt Jacob 	ms = tvtohz(&t);
3526f7c631bcSMatt Jacob 	if (ms < 0) {
3527f7c631bcSMatt Jacob 		ms = 0x7fffffff;
3528f7c631bcSMatt Jacob 	}
3529f7c631bcSMatt Jacob 	return (ms);
3530f7c631bcSMatt Jacob }
3531