xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 6c81a0ae)
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>
456c81a0aeSMatt Jacob #include <cam/cam_xpt_periph.h>
466054c3f6SMatt Jacob 
47805e1f82SMatt Jacob #if !defined(CAM_NEW_TRAN_CODE) && __FreeBSD_version >= 700025
48805e1f82SMatt Jacob #define	CAM_NEW_TRAN_CODE	1
49805e1f82SMatt Jacob #endif
50805e1f82SMatt Jacob 
51a1bc34c6SMatt Jacob 
524eb49427SMatt Jacob MODULE_VERSION(isp, 1);
5356c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1);
5473030e03SMatt Jacob int isp_announced = 0;
5510365e5aSMatt Jacob int isp_fabric_hysteresis = 5;
5610365e5aSMatt Jacob int isp_loop_down_limit = 300;	/* default loop down limit */
57f7c631bcSMatt Jacob int isp_change_is_bad = 0;	/* "changed" devices are bad */
58f7c631bcSMatt Jacob int isp_quickboot_time = 15;	/* don't wait more than N secs for loop up */
59f7c631bcSMatt Jacob int isp_gone_device_time = 30;	/* grace time before reporting device lost */
60f7c631bcSMatt Jacob static const char *roles[4] = {
61f7c631bcSMatt Jacob     "(none)", "Target", "Initiator", "Target/Initiator"
62f7c631bcSMatt Jacob };
63f7c631bcSMatt Jacob static const char prom3[] =
64f7c631bcSMatt Jacob     "PortID 0x%06x Departed from Target %u because of %s";
6573030e03SMatt Jacob 
66f7c631bcSMatt Jacob static void isp_freeze_loopdown(ispsoftc_t *, char *);
675d571944SMatt Jacob static d_ioctl_t ispioctl;
68f6e75de2SMatt Jacob static void isp_intr_enable(void *);
691dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
700470d791SMatt Jacob static void isp_poll(struct cam_sim *);
71b85389e1SMatt Jacob static timeout_t isp_watchdog;
72f7c631bcSMatt Jacob static timeout_t isp_ldt;
735d571944SMatt Jacob static void isp_kthread(void *);
74d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
750470d791SMatt Jacob 
76784ed707SMatt Jacob #if __FreeBSD_version < 700000
77784ed707SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
78784ed707SMatt Jacob #endif
79cc8df88bSMatt Jacob 
809cd7268eSMatt Jacob #if __FreeBSD_version < 500000
819cd7268eSMatt Jacob #define ISP_CDEV_MAJOR	248
829cd7268eSMatt Jacob static struct cdevsw isp_cdevsw = {
839cd7268eSMatt Jacob 	/* open */	nullopen,
849cd7268eSMatt Jacob 	/* close */	nullclose,
859cd7268eSMatt Jacob 	/* read */	noread,
869cd7268eSMatt Jacob 	/* write */	nowrite,
879cd7268eSMatt Jacob 	/* ioctl */	ispioctl,
889cd7268eSMatt Jacob 	/* poll */	nopoll,
899cd7268eSMatt Jacob 	/* mmap */	nommap,
909cd7268eSMatt Jacob 	/* strategy */	nostrategy,
919cd7268eSMatt Jacob 	/* name */	"isp",
929cd7268eSMatt Jacob 	/* maj */	ISP_CDEV_MAJOR,
939cd7268eSMatt Jacob 	/* dump */	nodump,
949cd7268eSMatt Jacob 	/* psize */	nopsize,
959cd7268eSMatt Jacob 	/* flags */	D_TAPE,
969cd7268eSMatt Jacob };
979311717dSMatt Jacob #define	isp_sysctl_update(x)	do { ; } while (0)
989cd7268eSMatt Jacob #else
995d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
100dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
101dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1027ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
1037ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
1045d571944SMatt Jacob };
1059311717dSMatt Jacob static void isp_sysctl_update(ispsoftc_t *);
1069cd7268eSMatt Jacob #endif
1075d571944SMatt Jacob 
1089cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL;
109478f8a96SJustin T. Gibbs 
110478f8a96SJustin T. Gibbs void
1119cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp)
112478f8a96SJustin T. Gibbs {
113ea6f23cdSMatt Jacob 	int primary, secondary;
114478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
115478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
116ea6f23cdSMatt Jacob 	struct cam_sim *sim;
117ea6f23cdSMatt Jacob 	struct cam_path *path;
118478f8a96SJustin T. Gibbs 
119478f8a96SJustin T. Gibbs 	/*
120ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
121ea6f23cdSMatt Jacob 	 */
122ea6f23cdSMatt Jacob 
123ea6f23cdSMatt Jacob 	primary = 0;
124ea6f23cdSMatt Jacob 	secondary = 1;
125ea6f23cdSMatt Jacob 
126ea6f23cdSMatt Jacob 	/*
127ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
128478f8a96SJustin T. Gibbs 	 */
129ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
130478f8a96SJustin T. Gibbs 	if (devq == NULL) {
131478f8a96SJustin T. Gibbs 		return;
132478f8a96SJustin T. Gibbs 	}
133478f8a96SJustin T. Gibbs 
134478f8a96SJustin T. Gibbs 	/*
135ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
136478f8a96SJustin T. Gibbs 	 */
13745c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
138ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
1393c75bb14SMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
140ea6f23cdSMatt Jacob 	if (sim == NULL) {
141478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
14245c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
143478f8a96SJustin T. Gibbs 		return;
144478f8a96SJustin T. Gibbs 	}
14545c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
146f6e75de2SMatt Jacob 
147f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
148f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
14945c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
150f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
15145c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
15245c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
153bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
154bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
155f6e75de2SMatt Jacob 		return;
156f6e75de2SMatt Jacob 	}
157f6e75de2SMatt Jacob 
158ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
159ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
16045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
161478f8a96SJustin T. Gibbs 		return;
162478f8a96SJustin T. Gibbs 	}
163478f8a96SJustin T. Gibbs 
164ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
165478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
166ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
167ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1685d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
16945c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
170478f8a96SJustin T. Gibbs 		return;
171478f8a96SJustin T. Gibbs 	}
172478f8a96SJustin T. Gibbs 
173ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
174478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
175478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
176cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
177ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
178478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
17945c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
180ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
181ea6f23cdSMatt Jacob 	isp->isp_path = path;
1825d571944SMatt Jacob 	/*
1835d571944SMatt Jacob 	 * Create a kernel thread for fibre channel instances. We
1845d571944SMatt Jacob 	 * don't have dual channel FC cards.
1855d571944SMatt Jacob 	 */
1865d571944SMatt Jacob 	if (IS_FC(isp)) {
18745c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
1889cd7268eSMatt Jacob #if __FreeBSD_version >= 500000
1895d571944SMatt Jacob 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
1905d571944SMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
191316ec49aSScott Long 		    RFHIGHPID, 0, "%s: fc_thrd",
1929cd7268eSMatt Jacob 		    device_get_nameunit(isp->isp_dev)))
1939cd7268eSMatt Jacob #else
1949cd7268eSMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
1959cd7268eSMatt Jacob 		    "%s: fc_thrd", device_get_nameunit(isp->isp_dev)))
1969cd7268eSMatt Jacob #endif
1979cd7268eSMatt Jacob 		{
1985d571944SMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
1995d571944SMatt Jacob 			cam_sim_free(sim, TRUE);
2005d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
20145c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
20245c9a36aSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
2035d571944SMatt Jacob 			return;
2045d571944SMatt Jacob 		}
2058e6a12fcSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
206f7c631bcSMatt Jacob 		/*
207f7c631bcSMatt Jacob 		 * We start by being "loop down" if we have an initiator role
208f7c631bcSMatt Jacob 		 */
209f7c631bcSMatt Jacob 		if (isp->isp_role & ISP_ROLE_INITIATOR) {
210f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, "isp_attach");
211f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt =
212f7c631bcSMatt Jacob 			    timeout(isp_ldt, isp, isp_quickboot_time * hz);
213f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
214f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
215f7c631bcSMatt Jacob 			   "Starting Initial Loop Down Timer");
216f7c631bcSMatt Jacob 		}
2175d571944SMatt Jacob 	}
2185d571944SMatt Jacob 
219478f8a96SJustin T. Gibbs 
220ea6f23cdSMatt Jacob 	/*
221ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
222ea6f23cdSMatt Jacob 	 */
22322e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
22445c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
225ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
2263c75bb14SMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
227ea6f23cdSMatt Jacob 		if (sim == NULL) {
228ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
229ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
230ea6f23cdSMatt Jacob 			cam_simq_free(devq);
2315d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
232ea6f23cdSMatt Jacob 			return;
233ea6f23cdSMatt Jacob 		}
234ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
235ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
236ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
237ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2385d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
23945c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
240ea6f23cdSMatt Jacob 			return;
241ea6f23cdSMatt Jacob 		}
242ea6f23cdSMatt Jacob 
243ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
244ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
245ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
246ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
247ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
248ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2495d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
25045c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
251ea6f23cdSMatt Jacob 			return;
252ea6f23cdSMatt Jacob 		}
253ea6f23cdSMatt Jacob 
254ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
255ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
256ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
257ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
258ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
259ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
26045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
261ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
262ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
263ea6f23cdSMatt Jacob 	}
2645d571944SMatt Jacob 
2655d571944SMatt Jacob 	/*
2665d571944SMatt Jacob 	 * Create device nodes
2675d571944SMatt Jacob 	 */
2685d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2695d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2705d571944SMatt Jacob 
271d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
272478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
27310365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
274d6e5500fSMatt Jacob 	}
275d81ba9d5SMatt Jacob 	if (isplist == NULL) {
276d81ba9d5SMatt Jacob 		isplist = isp;
277d81ba9d5SMatt Jacob 	} else {
2789cd7268eSMatt Jacob 		ispsoftc_t *tmp = isplist;
279d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
280d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
281d81ba9d5SMatt Jacob 		}
282d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
283478f8a96SJustin T. Gibbs 	}
2849311717dSMatt Jacob 	isp_sysctl_update(isp);
2855d571944SMatt Jacob }
2865d571944SMatt Jacob 
287f7c631bcSMatt Jacob static void
2889cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg)
289fdeb9f2fSMatt Jacob {
290fdeb9f2fSMatt Jacob 	if (isp->isp_osinfo.simqfrozen == 0) {
291fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg);
292fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
293fdeb9f2fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
294fdeb9f2fSMatt Jacob 		xpt_freeze_simq(isp->isp_sim, 1);
295fdeb9f2fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
296fdeb9f2fSMatt Jacob 	} else {
297fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg);
298fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
299fdeb9f2fSMatt Jacob 	}
300fdeb9f2fSMatt Jacob }
301fdeb9f2fSMatt Jacob 
3029cd7268eSMatt Jacob 
3039cd7268eSMatt Jacob #if __FreeBSD_version < 500000
3049cd7268eSMatt Jacob #define	_DEV	dev_t
3059cd7268eSMatt Jacob #define	_IOP	struct proc
3069cd7268eSMatt Jacob #else
3079cd7268eSMatt Jacob #define	_IOP	struct thread
3089cd7268eSMatt Jacob #define	_DEV	struct cdev *
3099cd7268eSMatt Jacob #endif
3109cd7268eSMatt Jacob 
3115d571944SMatt Jacob static int
3129cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td)
3135d571944SMatt Jacob {
3149cd7268eSMatt Jacob 	ispsoftc_t *isp;
315746e9c85SMatt Jacob 	int nr, retval = ENOTTY;
3165d571944SMatt Jacob 
3175d571944SMatt Jacob 	isp = isplist;
3185d571944SMatt Jacob 	while (isp) {
3195d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
3205d571944SMatt Jacob 			break;
3215d571944SMatt Jacob 		}
3225d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
3235d571944SMatt Jacob 	}
3245d571944SMatt Jacob 	if (isp == NULL)
3255d571944SMatt Jacob 		return (ENXIO);
3265d571944SMatt Jacob 
327c1504bc0SMatt Jacob 	switch (c) {
328d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
329d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
33002e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
3311dae40ebSMatt Jacob 			uint16_t *ptr = FCPARAM(isp)->isp_dump_data;
332d134aa0bSMatt Jacob 			size_t sz;
333d134aa0bSMatt Jacob 
334d134aa0bSMatt Jacob 			retval = 0;
33502e2b2d9SMatt Jacob 			if (IS_2200(isp)) {
336d134aa0bSMatt Jacob 				sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
33702e2b2d9SMatt Jacob 			} else {
338d134aa0bSMatt Jacob 				sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
33902e2b2d9SMatt Jacob 			}
340d134aa0bSMatt Jacob 			ISP_LOCK(isp);
341d134aa0bSMatt Jacob 			if (ptr && *ptr) {
342d134aa0bSMatt Jacob 				void *uaddr = *((void **) addr);
343d134aa0bSMatt Jacob 				if (copyout(ptr, uaddr, sz)) {
344d134aa0bSMatt Jacob 					retval = EFAULT;
345d134aa0bSMatt Jacob 				} else {
346d134aa0bSMatt Jacob 					*ptr = 0;
347d134aa0bSMatt Jacob 				}
348d134aa0bSMatt Jacob 			} else {
349d134aa0bSMatt Jacob 				retval = ENXIO;
350d134aa0bSMatt Jacob 			}
351d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
352d134aa0bSMatt Jacob 		}
35302e2b2d9SMatt Jacob 		break;
354d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
35502e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
356d134aa0bSMatt Jacob 			ISP_LOCK(isp);
35702e2b2d9SMatt Jacob 			isp_freeze_loopdown(isp,
35802e2b2d9SMatt Jacob 			    "ispioctl(ISP_FORCE_CRASH_DUMP)");
359d134aa0bSMatt Jacob 			isp_fw_dump(isp);
360d134aa0bSMatt Jacob 			isp_reinit(isp);
361d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
362d134aa0bSMatt Jacob 			retval = 0;
36302e2b2d9SMatt Jacob 		}
364d134aa0bSMatt Jacob 		break;
365d134aa0bSMatt Jacob #endif
3665d571944SMatt Jacob 	case ISP_SDBLEV:
3675d571944SMatt Jacob 	{
3685d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3695d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3705d571944SMatt Jacob 		*(int *)addr = olddblev;
3715d571944SMatt Jacob 		retval = 0;
3725d571944SMatt Jacob 		break;
3735d571944SMatt Jacob 	}
374746e9c85SMatt Jacob 	case ISP_GETROLE:
375746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
376746e9c85SMatt Jacob 		retval = 0;
377746e9c85SMatt Jacob 		break;
378746e9c85SMatt Jacob 	case ISP_SETROLE:
379746e9c85SMatt Jacob 		nr = *(int *)addr;
380746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
381746e9c85SMatt Jacob 			retval = EINVAL;
382746e9c85SMatt Jacob 			break;
383746e9c85SMatt Jacob 		}
384746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
385746e9c85SMatt Jacob 		isp->isp_role = nr;
386746e9c85SMatt Jacob 		/* FALLTHROUGH */
3875d571944SMatt Jacob 	case ISP_RESETHBA:
3885d571944SMatt Jacob 		ISP_LOCK(isp);
3895d571944SMatt Jacob 		isp_reinit(isp);
3905d571944SMatt Jacob 		ISP_UNLOCK(isp);
3915d571944SMatt Jacob 		retval = 0;
3925d571944SMatt Jacob 		break;
393f553351eSMatt Jacob 	case ISP_RESCAN:
3945d571944SMatt Jacob 		if (IS_FC(isp)) {
3955d571944SMatt Jacob 			ISP_LOCK(isp);
3965d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
3975d571944SMatt Jacob 				retval = EIO;
3985d571944SMatt Jacob 			} else {
3995d571944SMatt Jacob 				retval = 0;
4005d571944SMatt Jacob 			}
4015d571944SMatt Jacob 			ISP_UNLOCK(isp);
4025d571944SMatt Jacob 		}
4035d571944SMatt Jacob 		break;
4045d571944SMatt Jacob 	case ISP_FC_LIP:
4055d571944SMatt Jacob 		if (IS_FC(isp)) {
4065d571944SMatt Jacob 			ISP_LOCK(isp);
4075d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
4085d571944SMatt Jacob 				retval = EIO;
4095d571944SMatt Jacob 			} else {
4105d571944SMatt Jacob 				retval = 0;
4115d571944SMatt Jacob 			}
4125d571944SMatt Jacob 			ISP_UNLOCK(isp);
4135d571944SMatt Jacob 		}
4145d571944SMatt Jacob 		break;
4155d571944SMatt Jacob 	case ISP_FC_GETDINFO:
4165d571944SMatt Jacob 	{
4175d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
41810365e5aSMatt Jacob 		fcportdb_t *lp;
4195d571944SMatt Jacob 
42002e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
42102e2b2d9SMatt Jacob 			break;
42202e2b2d9SMatt Jacob 		}
4235d571944SMatt Jacob 		if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
4245d571944SMatt Jacob 			retval = EINVAL;
4255d571944SMatt Jacob 			break;
4265d571944SMatt Jacob 		}
4275d571944SMatt Jacob 		ISP_LOCK(isp);
4285d571944SMatt Jacob 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
42910365e5aSMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID) {
430c6435ff3SMatt Jacob 			ifc->role = lp->roles;
43110365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4325d571944SMatt Jacob 			ifc->portid = lp->portid;
4335d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4345d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4355d571944SMatt Jacob 			retval = 0;
4365d571944SMatt Jacob 		} else {
4375d571944SMatt Jacob 			retval = ENODEV;
4385d571944SMatt Jacob 		}
4395d571944SMatt Jacob 		ISP_UNLOCK(isp);
4405d571944SMatt Jacob 		break;
4415d571944SMatt Jacob 	}
4422903b272SMatt Jacob 	case ISP_GET_STATS:
4432903b272SMatt Jacob 	{
4442903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4452903b272SMatt Jacob 
4462903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
4472903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4482903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
4492903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
4502903b272SMatt Jacob 		ISP_LOCK(isp);
4512903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
4522903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
4532903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
4542903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
4552903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
4562903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
4572903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
4582903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
4592903b272SMatt Jacob 		ISP_UNLOCK(isp);
4602903b272SMatt Jacob 		retval = 0;
4612903b272SMatt Jacob 		break;
4622903b272SMatt Jacob 	}
4632903b272SMatt Jacob 	case ISP_CLR_STATS:
4642903b272SMatt Jacob 		ISP_LOCK(isp);
4652903b272SMatt Jacob 		isp->isp_intcnt = 0;
4662903b272SMatt Jacob 		isp->isp_intbogus = 0;
4672903b272SMatt Jacob 		isp->isp_intmboxc = 0;
4682903b272SMatt Jacob 		isp->isp_intoasync = 0;
4692903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
4702903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
4712903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
4722903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
4732903b272SMatt Jacob 		ISP_UNLOCK(isp);
4742903b272SMatt Jacob 		retval = 0;
4752903b272SMatt Jacob 		break;
476570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
477570c7a3fSMatt Jacob 	{
478570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
479570c7a3fSMatt Jacob 		MEMZERO(hba, sizeof (*hba));
48002e2b2d9SMatt Jacob 
481a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
482a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
483a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
48402e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
485570c7a3fSMatt Jacob 			hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
486570c7a3fSMatt Jacob 			hba->fc_scsi_supported = 1;
487570c7a3fSMatt Jacob 			hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
488570c7a3fSMatt Jacob 			hba->fc_loopid = FCPARAM(isp)->isp_loopid;
4896c81a0aeSMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp)->isp_wwnn_nvram;
4906c81a0aeSMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp)->isp_wwpn_nvram;
491fd6eb9f7SMatt Jacob 			hba->active_node_wwn = ISP_NODEWWN(isp);
492fd6eb9f7SMatt Jacob 			hba->active_port_wwn = ISP_PORTWWN(isp);
49302e2b2d9SMatt Jacob 		}
494570c7a3fSMatt Jacob 		retval = 0;
495570c7a3fSMatt Jacob 		break;
496570c7a3fSMatt Jacob 	}
497fdeb9f2fSMatt Jacob 	case ISP_GET_FC_PARAM:
498fdeb9f2fSMatt Jacob 	{
499fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
500fdeb9f2fSMatt Jacob 
50102e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
502fdeb9f2fSMatt Jacob 			break;
503fdeb9f2fSMatt Jacob 		}
504fdeb9f2fSMatt Jacob 		f->parameter = 0;
505fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
506fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_maxfrmlen;
507fdeb9f2fSMatt Jacob 			retval = 0;
508fdeb9f2fSMatt Jacob 			break;
509fdeb9f2fSMatt Jacob 		}
510fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
511fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_execthrottle;
512fdeb9f2fSMatt Jacob 			retval = 0;
513fdeb9f2fSMatt Jacob 			break;
514fdeb9f2fSMatt Jacob 		}
515fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
516fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX)
517fdeb9f2fSMatt Jacob 				f->parameter = 1;
518fdeb9f2fSMatt Jacob 			retval = 0;
519fdeb9f2fSMatt Jacob 			break;
520fdeb9f2fSMatt Jacob 		}
521fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
522fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_loopid;
523fdeb9f2fSMatt Jacob 			retval = 0;
524fdeb9f2fSMatt Jacob 			break;
525fdeb9f2fSMatt Jacob 		}
526fdeb9f2fSMatt Jacob 		retval = EINVAL;
527fdeb9f2fSMatt Jacob 		break;
528fdeb9f2fSMatt Jacob 	}
529fdeb9f2fSMatt Jacob 	case ISP_SET_FC_PARAM:
530fdeb9f2fSMatt Jacob 	{
531fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
5321dae40ebSMatt Jacob 		uint32_t param = f->parameter;
533fdeb9f2fSMatt Jacob 
53402e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
535fdeb9f2fSMatt Jacob 			break;
536fdeb9f2fSMatt Jacob 		}
537fdeb9f2fSMatt Jacob 		f->parameter = 0;
538fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
539fdeb9f2fSMatt Jacob 			if (param != 512 && param != 1024 && param != 1024) {
540fdeb9f2fSMatt Jacob 				retval = EINVAL;
541fdeb9f2fSMatt Jacob 				break;
542fdeb9f2fSMatt Jacob 			}
543fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_maxfrmlen = param;
544fdeb9f2fSMatt Jacob 			retval = 0;
545fdeb9f2fSMatt Jacob 			break;
546fdeb9f2fSMatt Jacob 		}
547fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
548fdeb9f2fSMatt Jacob 			if (param < 16 || param > 255) {
549fdeb9f2fSMatt Jacob 				retval = EINVAL;
550fdeb9f2fSMatt Jacob 				break;
551fdeb9f2fSMatt Jacob 			}
552fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_execthrottle = param;
553fdeb9f2fSMatt Jacob 			retval = 0;
554fdeb9f2fSMatt Jacob 			break;
555fdeb9f2fSMatt Jacob 		}
556fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
557fdeb9f2fSMatt Jacob 			if (param != 0 && param != 1) {
558fdeb9f2fSMatt Jacob 				retval = EINVAL;
559fdeb9f2fSMatt Jacob 				break;
560fdeb9f2fSMatt Jacob 			}
561fdeb9f2fSMatt Jacob 			if (param) {
562fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions |=
563fdeb9f2fSMatt Jacob 				    ICBOPT_FULL_DUPLEX;
564fdeb9f2fSMatt Jacob 			} else {
565fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions &=
566fdeb9f2fSMatt Jacob 				    ~ICBOPT_FULL_DUPLEX;
567fdeb9f2fSMatt Jacob 			}
568fdeb9f2fSMatt Jacob 			retval = 0;
569fdeb9f2fSMatt Jacob 			break;
570fdeb9f2fSMatt Jacob 		}
571fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
572fdeb9f2fSMatt Jacob 			if (param < 0 || param > 125) {
573fdeb9f2fSMatt Jacob 				retval = EINVAL;
574fdeb9f2fSMatt Jacob 				break;
575fdeb9f2fSMatt Jacob 			}
576fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_loopid = param;
577fdeb9f2fSMatt Jacob 			retval = 0;
578fdeb9f2fSMatt Jacob 			break;
579fdeb9f2fSMatt Jacob 		}
580fdeb9f2fSMatt Jacob 		retval = EINVAL;
581fdeb9f2fSMatt Jacob 		break;
582fdeb9f2fSMatt Jacob 	}
5838e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5848e62a8acSMatt Jacob 	{
5858e62a8acSMatt Jacob 		int needmarker;
5868e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5871dae40ebSMatt Jacob 		uint16_t loopid;
5888e62a8acSMatt Jacob 		mbreg_t mbs;
5898e62a8acSMatt Jacob 
5908e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5918e62a8acSMatt Jacob 			break;
5928e62a8acSMatt Jacob 		}
5938e62a8acSMatt Jacob 
5948e62a8acSMatt Jacob 		memset(&mbs, 0, sizeof (mbs));
5958e62a8acSMatt Jacob 		needmarker = retval = 0;
596e5265237SMatt Jacob 		loopid = fct->loopid;
59710365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin == 0) {
598e5265237SMatt Jacob 			loopid <<= 8;
599e5265237SMatt Jacob 		}
6008e62a8acSMatt Jacob 		switch (fct->action) {
601f0f536d1SMatt Jacob 		case IPT_CLEAR_ACA:
6028e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_ACA;
603e5265237SMatt Jacob 			mbs.param[1] = loopid;
6048e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6058e62a8acSMatt Jacob 			break;
606f0f536d1SMatt Jacob 		case IPT_TARGET_RESET:
6078e62a8acSMatt Jacob 			mbs.param[0] = MBOX_TARGET_RESET;
608e5265237SMatt Jacob 			mbs.param[1] = loopid;
6098e62a8acSMatt Jacob 			needmarker = 1;
6108e62a8acSMatt Jacob 			break;
611f0f536d1SMatt Jacob 		case IPT_LUN_RESET:
6128e62a8acSMatt Jacob 			mbs.param[0] = MBOX_LUN_RESET;
613e5265237SMatt Jacob 			mbs.param[1] = loopid;
6148e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6158e62a8acSMatt Jacob 			needmarker = 1;
6168e62a8acSMatt Jacob 			break;
617f0f536d1SMatt Jacob 		case IPT_CLEAR_TASK_SET:
6188e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_TASK_SET;
619e5265237SMatt Jacob 			mbs.param[1] = loopid;
6208e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6218e62a8acSMatt Jacob 			needmarker = 1;
6228e62a8acSMatt Jacob 			break;
623f0f536d1SMatt Jacob 		case IPT_ABORT_TASK_SET:
6248e62a8acSMatt Jacob 			mbs.param[0] = MBOX_ABORT_TASK_SET;
625e5265237SMatt Jacob 			mbs.param[1] = loopid;
6268e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6278e62a8acSMatt Jacob 			needmarker = 1;
6288e62a8acSMatt Jacob 			break;
6298e62a8acSMatt Jacob 		default:
6308e62a8acSMatt Jacob 			retval = EINVAL;
6318e62a8acSMatt Jacob 			break;
6328e62a8acSMatt Jacob 		}
6338e62a8acSMatt Jacob 		if (retval == 0) {
6348e62a8acSMatt Jacob 			ISP_LOCK(isp);
6358e62a8acSMatt Jacob 			if (needmarker) {
6368e62a8acSMatt Jacob 				isp->isp_sendmarker |= 1;
6378e62a8acSMatt Jacob 			}
6388e62a8acSMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6398e62a8acSMatt Jacob 			ISP_UNLOCK(isp);
6408e62a8acSMatt Jacob 			if (retval)
6418e62a8acSMatt Jacob 				retval = EIO;
6428e62a8acSMatt Jacob 		}
6438e62a8acSMatt Jacob 		break;
6448e62a8acSMatt Jacob 	}
6455d571944SMatt Jacob 	default:
6465d571944SMatt Jacob 		break;
6475d571944SMatt Jacob 	}
6485d571944SMatt Jacob 	return (retval);
6490470d791SMatt Jacob }
650478f8a96SJustin T. Gibbs 
6519311717dSMatt Jacob #if __FreeBSD_version >= 500000
6529311717dSMatt Jacob static void
6539311717dSMatt Jacob isp_sysctl_update(ispsoftc_t *isp)
6549311717dSMatt Jacob {
6559311717dSMatt Jacob 	struct sysctl_ctx_list *ctx =
6569311717dSMatt Jacob 	    device_get_sysctl_ctx(isp->isp_osinfo.dev);
6579311717dSMatt Jacob 	struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev);
6589311717dSMatt Jacob 
6599311717dSMatt Jacob 	if (IS_SCSI(isp)) {
6609311717dSMatt Jacob 		return;
6619311717dSMatt Jacob 	}
662f7c631bcSMatt Jacob 
6639311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn,
6649311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x",
6659311717dSMatt Jacob 	    (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp));
6669311717dSMatt Jacob 
6679311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn,
6689311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x",
6699311717dSMatt Jacob 	    (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp));
6709311717dSMatt Jacob 
6719311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6729311717dSMatt Jacob 	       "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0,
6739311717dSMatt Jacob 	       "World Wide Node Name");
674f7c631bcSMatt Jacob 
6759311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6769311717dSMatt Jacob 	       "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0,
6779311717dSMatt Jacob 	       "World Wide Port Name");
678f7c631bcSMatt Jacob 
679f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
680f7c631bcSMatt Jacob 	    "loop_down_limit",
681f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0,
682f7c631bcSMatt Jacob 	    "How long to wait for loop to come back up");
683f7c631bcSMatt Jacob 
684f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
685f7c631bcSMatt Jacob 	    "gone_device_time",
686f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0,
687f7c631bcSMatt Jacob 	    "How long to wait for a device to reappear");
6889311717dSMatt Jacob }
6899311717dSMatt Jacob #endif
6909311717dSMatt Jacob 
691f6e75de2SMatt Jacob static void
692f6e75de2SMatt Jacob isp_intr_enable(void *arg)
693f6e75de2SMatt Jacob {
6949cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
695d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
69610365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
697d6e5500fSMatt Jacob 	}
698f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
699f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
700f6e75de2SMatt Jacob }
701d81ba9d5SMatt Jacob 
702d81ba9d5SMatt Jacob /*
703d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
704d81ba9d5SMatt Jacob  */
705d81ba9d5SMatt Jacob 
706d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
707d81ba9d5SMatt Jacob 
7089cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7099cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int);
7109cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7119cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *);
7129cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int);
713d81ba9d5SMatt Jacob static cam_status
7149cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7159cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7169cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *);
7179cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
7189cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *);
719f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
720a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
721a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
7229cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
7239cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
7249cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
7259cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *);
7269cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
7279cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
728d81ba9d5SMatt Jacob 
72953af7d22SMatt Jacob static __inline int
7309cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
731d81ba9d5SMatt Jacob {
732d81ba9d5SMatt Jacob 	tstate_t *tptr;
733a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
734a1bc34c6SMatt Jacob 	if (tptr == NULL) {
735d81ba9d5SMatt Jacob 		return (0);
736d81ba9d5SMatt Jacob 	}
737d81ba9d5SMatt Jacob 	do {
738a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
739d81ba9d5SMatt Jacob 			return (1);
740d81ba9d5SMatt Jacob 		}
741d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
742d81ba9d5SMatt Jacob 	return (0);
743d81ba9d5SMatt Jacob }
744d81ba9d5SMatt Jacob 
74553af7d22SMatt Jacob static __inline int
7469cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port)
747d81ba9d5SMatt Jacob {
748a1bc34c6SMatt Jacob 	int lo, hi;
749a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
750a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
751a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
752a1bc34c6SMatt Jacob 	} else {
753a1bc34c6SMatt Jacob 		lo = 0;
754a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
755a1bc34c6SMatt Jacob 	}
756a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
757a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
758d81ba9d5SMatt Jacob 			return (1);
759d81ba9d5SMatt Jacob 		}
760d81ba9d5SMatt Jacob 	}
761d81ba9d5SMatt Jacob 	return (0);
762d81ba9d5SMatt Jacob }
763d81ba9d5SMatt Jacob 
76453af7d22SMatt Jacob static __inline tstate_t *
7659cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
766d81ba9d5SMatt Jacob {
76764edff94SMatt Jacob 	tstate_t *tptr = NULL;
768d81ba9d5SMatt Jacob 
769d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
77064edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
771a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
772d81ba9d5SMatt Jacob 			tptr->hold++;
773d81ba9d5SMatt Jacob 			return (tptr);
774d81ba9d5SMatt Jacob 		}
77567ff51f1SMatt Jacob 		return (NULL);
776126ec864SMatt Jacob 	} else {
777126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
77864edff94SMatt Jacob 		if (tptr == NULL) {
77964edff94SMatt Jacob 			return (NULL);
78064edff94SMatt Jacob 		}
781126ec864SMatt Jacob 	}
782d81ba9d5SMatt Jacob 
783d81ba9d5SMatt Jacob 	do {
784a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
785d81ba9d5SMatt Jacob 			tptr->hold++;
786d81ba9d5SMatt Jacob 			return (tptr);
787d81ba9d5SMatt Jacob 		}
788d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
789d81ba9d5SMatt Jacob 	return (tptr);
790d81ba9d5SMatt Jacob }
791d81ba9d5SMatt Jacob 
79253af7d22SMatt Jacob static __inline void
7939cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
794d81ba9d5SMatt Jacob {
795d81ba9d5SMatt Jacob 	if (tptr->hold)
796d81ba9d5SMatt Jacob 		tptr->hold--;
797d81ba9d5SMatt Jacob }
798d81ba9d5SMatt Jacob 
79953af7d22SMatt Jacob static __inline atio_private_data_t *
8009cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag)
80153036e92SMatt Jacob {
80253036e92SMatt Jacob 	atio_private_data_t *atp;
80353036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
80453036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
80553036e92SMatt Jacob 		if (atp->tag == tag)
80653036e92SMatt Jacob 			return (atp);
80753036e92SMatt Jacob 	}
80853036e92SMatt Jacob 	return (NULL);
80953036e92SMatt Jacob }
81053036e92SMatt Jacob 
811d81ba9d5SMatt Jacob static cam_status
8129cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus,
813a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
814d81ba9d5SMatt Jacob {
815d81ba9d5SMatt Jacob 	cam_status status;
816d81ba9d5SMatt Jacob 	lun_id_t lun;
817a1bc34c6SMatt Jacob 	int hfx;
818d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
819d81ba9d5SMatt Jacob 
820d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
821d81ba9d5SMatt Jacob 	if (lun < 0) {
822d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
823d81ba9d5SMatt Jacob 	}
824a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
825d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
826d81ba9d5SMatt Jacob 	}
827ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
828d81ba9d5SMatt Jacob 	if (new == NULL) {
829d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
830d81ba9d5SMatt Jacob 	}
831d81ba9d5SMatt Jacob 
832d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
833d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
834d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
835d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
836d81ba9d5SMatt Jacob 		return (status);
837d81ba9d5SMatt Jacob 	}
838a1bc34c6SMatt Jacob 	new->bus = bus;
839d81ba9d5SMatt Jacob 	new->lun = lun;
840d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
841d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
842d81ba9d5SMatt Jacob 	new->hold = 1;
843d81ba9d5SMatt Jacob 
844a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
845a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
846a1bc34c6SMatt Jacob 	if (tptr == NULL) {
847a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
848d81ba9d5SMatt Jacob 	} else {
849d81ba9d5SMatt Jacob 		while (tptr->next)
850d81ba9d5SMatt Jacob 			tptr = tptr->next;
851d81ba9d5SMatt Jacob 		tptr->next = new;
852d81ba9d5SMatt Jacob 	}
853d81ba9d5SMatt Jacob 	*rslt = new;
854d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
855d81ba9d5SMatt Jacob }
856d81ba9d5SMatt Jacob 
85753af7d22SMatt Jacob static __inline void
8589cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
859d81ba9d5SMatt Jacob {
860a1bc34c6SMatt Jacob 	int hfx;
861d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
862d81ba9d5SMatt Jacob 
863d81ba9d5SMatt Jacob 	if (tptr->hold) {
864d81ba9d5SMatt Jacob 		return;
865d81ba9d5SMatt Jacob 	}
86667ff51f1SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
867a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
868d81ba9d5SMatt Jacob 	if (pw == NULL) {
869d81ba9d5SMatt Jacob 		return;
870a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
871a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
872d81ba9d5SMatt Jacob 	} else {
873d81ba9d5SMatt Jacob 		lw = pw;
874d81ba9d5SMatt Jacob 		pw = lw->next;
875d81ba9d5SMatt Jacob 		while (pw) {
876a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
877d81ba9d5SMatt Jacob 				lw->next = pw->next;
878d81ba9d5SMatt Jacob 				break;
879d81ba9d5SMatt Jacob 			}
880d81ba9d5SMatt Jacob 			lw = pw;
881d81ba9d5SMatt Jacob 			pw = pw->next;
882d81ba9d5SMatt Jacob 		}
883d81ba9d5SMatt Jacob 		if (pw == NULL) {
884d81ba9d5SMatt Jacob 			return;
885d81ba9d5SMatt Jacob 		}
886d81ba9d5SMatt Jacob 	}
887d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
888d81ba9d5SMatt Jacob }
889d81ba9d5SMatt Jacob 
8905d571944SMatt Jacob /*
89167ff51f1SMatt Jacob  * Enable luns.
8925d571944SMatt Jacob  */
89367ff51f1SMatt Jacob static int
8949cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb)
895d81ba9d5SMatt Jacob {
896d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
897d81ba9d5SMatt Jacob 	tstate_t *tptr;
8981dae40ebSMatt Jacob 	uint32_t seq;
899746e9c85SMatt Jacob 	int bus, cmd, av, wildcard, tm_on;
900d81ba9d5SMatt Jacob 	lun_id_t lun;
901d81ba9d5SMatt Jacob 	target_id_t tgt;
902d81ba9d5SMatt Jacob 
90367ff51f1SMatt Jacob 	bus = XS_CHANNEL(ccb);
90467ff51f1SMatt Jacob 	if (bus > 1) {
905dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus);
90667ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_PATH_INVALID;
90767ff51f1SMatt Jacob 		return (-1);
90867ff51f1SMatt Jacob 	}
909d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
910d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
911d81ba9d5SMatt Jacob 
912dd9fc7c3SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
913dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n",
91467ff51f1SMatt Jacob 	    	    cel->enable? "en" : "dis", lun, bus);
915dd9fc7c3SMatt Jacob 	}
916d81ba9d5SMatt Jacob 
917d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
918d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
919d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
92067ff51f1SMatt Jacob 		return (-1);
921d81ba9d5SMatt Jacob 	}
92264edff94SMatt Jacob 
9232ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
924a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
925a1bc34c6SMatt Jacob 		sdp += bus;
926d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
927a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
928d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
92967ff51f1SMatt Jacob 			return (-1);
930d81ba9d5SMatt Jacob 		}
931d81ba9d5SMatt Jacob 	} else {
932746e9c85SMatt Jacob 		/*
933746e9c85SMatt Jacob 		 * There's really no point in doing this yet w/o multi-tid
934746e9c85SMatt Jacob 		 * capability. Even then, it's problematic.
935746e9c85SMatt Jacob 		 */
936746e9c85SMatt Jacob #if	0
937d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
938d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
939d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
94067ff51f1SMatt Jacob 			return (-1);
941d81ba9d5SMatt Jacob 		}
942746e9c85SMatt Jacob #endif
94364edff94SMatt Jacob 		/*
94464edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
94564edff94SMatt Jacob 		 */
94610365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_tmode == 0) {
947dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
948dd9fc7c3SMatt Jacob 			    "firmware does not support target mode\n");
94964edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
95067ff51f1SMatt Jacob 			return (-1);
95164edff94SMatt Jacob 		}
95264edff94SMatt Jacob 		/*
95364edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
954dd9fc7c3SMatt Jacob 		 * XXX: dork with our already fragile enable/disable code.
95564edff94SMatt Jacob 		 */
95610365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw == 0) {
957dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
958dd9fc7c3SMatt Jacob 			    "firmware not SCCLUN capable\n");
959746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
96067ff51f1SMatt Jacob 			return (-1);
96164edff94SMatt Jacob 		}
962d81ba9d5SMatt Jacob 	}
963d81ba9d5SMatt Jacob 
964d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
96564edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
96664edff94SMatt Jacob 			wildcard = 1;
96764edff94SMatt Jacob 		} else {
968d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
96967ff51f1SMatt Jacob 			return (-1);
970d6e5500fSMatt Jacob 		}
971126ec864SMatt Jacob 	} else {
972126ec864SMatt Jacob 		wildcard = 0;
973126ec864SMatt Jacob 	}
974b6b6ad2fSMatt Jacob 
975746e9c85SMatt Jacob 	tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0;
976746e9c85SMatt Jacob 
977b6b6ad2fSMatt Jacob 	/*
978b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
97964edff94SMatt Jacob 	 *
98064edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
98164edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
98264edff94SMatt Jacob 	 * handle them locally (if we see them at all).
983b6b6ad2fSMatt Jacob 	 */
984126ec864SMatt Jacob 
985126ec864SMatt Jacob 	if (wildcard) {
986a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
987b6b6ad2fSMatt Jacob 		if (cel->enable) {
98867ff51f1SMatt Jacob 			if (tm_on) {
989b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
99067ff51f1SMatt Jacob 				return (-1);
991b6b6ad2fSMatt Jacob 			}
992b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
993b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
994b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
995b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
996b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
997b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
99867ff51f1SMatt Jacob 				return (-1);
999b6b6ad2fSMatt Jacob 			}
1000b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
1001b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
100264edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
1003126ec864SMatt Jacob 		} else {
100467ff51f1SMatt Jacob 			if (tm_on == 0) {
1005126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
100667ff51f1SMatt Jacob 				return (-1);
1007126ec864SMatt Jacob 			}
1008126ec864SMatt Jacob 			if (tptr->hold) {
1009126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
101067ff51f1SMatt Jacob 				return (-1);
1011126ec864SMatt Jacob 			}
1012126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
101364edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
1014126ec864SMatt Jacob 		}
1015126ec864SMatt Jacob 	}
1016126ec864SMatt Jacob 
1017126ec864SMatt Jacob 	/*
1018126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
1019126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
1020126ec864SMatt Jacob 	 */
1021126ec864SMatt Jacob 	av = bus << 31;
1022746e9c85SMatt Jacob 	if (cel->enable && tm_on == 0) {
1023a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
1024b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1025b6b6ad2fSMatt Jacob 		if (av) {
1026b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1027126ec864SMatt Jacob 			if (wildcard) {
102864edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
102964edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
1030b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
10315d571944SMatt Jacob 			}
103267ff51f1SMatt Jacob 			return (-1);
1033b6b6ad2fSMatt Jacob 		}
103464edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
1035dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n");
1036746e9c85SMatt Jacob 	} else if (cel->enable == 0 && tm_on && wildcard) {
1037a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
1038b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
103967ff51f1SMatt Jacob 			return (-1);
1040b6b6ad2fSMatt Jacob 		}
1041b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1042b6b6ad2fSMatt Jacob 		if (av) {
1043b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
104467ff51f1SMatt Jacob 			return (-1);
1045b6b6ad2fSMatt Jacob 		}
104664edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
1047dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n");
1048126ec864SMatt Jacob 	}
1049126ec864SMatt Jacob 
1050126ec864SMatt Jacob 	if (wildcard) {
105164edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
105267ff51f1SMatt Jacob 		return (-1);
1053b6b6ad2fSMatt Jacob 	}
1054b6b6ad2fSMatt Jacob 
105567ff51f1SMatt Jacob 	/*
105667ff51f1SMatt Jacob 	 * Find an empty slot
105767ff51f1SMatt Jacob 	 */
105867ff51f1SMatt Jacob 	for (seq = 0; seq < NLEACT; seq++) {
105967ff51f1SMatt Jacob 		if (isp->isp_osinfo.leact[seq] == 0) {
106067ff51f1SMatt Jacob 			break;
106167ff51f1SMatt Jacob 		}
106267ff51f1SMatt Jacob 	}
106367ff51f1SMatt Jacob 	if (seq >= NLEACT) {
106467ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
106567ff51f1SMatt Jacob 		return (-1);
106667ff51f1SMatt Jacob 
106767ff51f1SMatt Jacob 	}
106867ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = ccb;
106967ff51f1SMatt Jacob 
1070d81ba9d5SMatt Jacob 	if (cel->enable) {
1071d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
1072a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
1073d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
107467ff51f1SMatt Jacob 			isp->isp_osinfo.leact[seq] = 0;
107567ff51f1SMatt Jacob 			return (-1);
1076d81ba9d5SMatt Jacob 		}
1077d81ba9d5SMatt Jacob 	} else {
1078a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
1079d81ba9d5SMatt Jacob 		if (tptr == NULL) {
1080d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
108167ff51f1SMatt Jacob 			return (-1);
1082d81ba9d5SMatt Jacob 		}
1083d81ba9d5SMatt Jacob 	}
1084d81ba9d5SMatt Jacob 
1085d81ba9d5SMatt Jacob 	if (cel->enable) {
10865d571944SMatt Jacob 		int c, n, ulun = lun;
10875d571944SMatt Jacob 
10885d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
10895d571944SMatt Jacob 		c = DFLT_CMND_CNT;
10905d571944SMatt Jacob 		n = DFLT_INOT_CNT;
10915d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
10925d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
10935d571944SMatt Jacob 			n = 0;
10945d571944SMatt Jacob 			/*
10955d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
10965d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
10975d571944SMatt Jacob 			 */
10985d571944SMatt Jacob 			ulun = 0;
10995d571944SMatt Jacob 		}
110067ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
110167ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
110267ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
110367ff51f1SMatt Jacob 			return (seq);
1104d81ba9d5SMatt Jacob 		}
1105d81ba9d5SMatt Jacob 	} else {
11065d571944SMatt Jacob 		int c, n, ulun = lun;
1107d81ba9d5SMatt Jacob 
11085d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
11095d571944SMatt Jacob 		c = DFLT_CMND_CNT;
11105d571944SMatt Jacob 		n = DFLT_INOT_CNT;
11115d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
11125d571944SMatt Jacob 			n = 0;
11135d571944SMatt Jacob 			/*
11145d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
11155d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
11165d571944SMatt Jacob 			 */
11175d571944SMatt Jacob 			ulun = 0;
11185d571944SMatt Jacob 		}
111967ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
112067ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
112167ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
112267ff51f1SMatt Jacob 			return (seq);
1123d81ba9d5SMatt Jacob 		}
1124d81ba9d5SMatt Jacob 	}
112567ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
1126dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n");
112767ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
112867ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP_ERR;
112967ff51f1SMatt Jacob 	return (-1);
11305d571944SMatt Jacob }
11315d571944SMatt Jacob 
113267ff51f1SMatt Jacob static void
11339cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
113467ff51f1SMatt Jacob {
1135dd9fc7c3SMatt Jacob 	const char lfmt[] = "now %sabled for target mode";
113667ff51f1SMatt Jacob 	union ccb *ccb;
11371dae40ebSMatt Jacob 	uint32_t seq;
113867ff51f1SMatt Jacob 	tstate_t *tptr;
113967ff51f1SMatt Jacob 	int av;
114067ff51f1SMatt Jacob 	struct ccb_en_lun *cel;
1141d81ba9d5SMatt Jacob 
114267ff51f1SMatt Jacob 	seq = lep->le_reserved - 1;
114367ff51f1SMatt Jacob 	if (seq >= NLEACT) {
11443c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114567ff51f1SMatt Jacob 		    "seq out of range (%u) in isp_ledone", seq);
114667ff51f1SMatt Jacob 		return;
1147d81ba9d5SMatt Jacob 	}
114867ff51f1SMatt Jacob 	ccb = isp->isp_osinfo.leact[seq];
114967ff51f1SMatt Jacob 	if (ccb == 0) {
115067ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
115167ff51f1SMatt Jacob 		    "no ccb for seq %u in isp_ledone", seq);
115267ff51f1SMatt Jacob 		return;
115367ff51f1SMatt Jacob 	}
115467ff51f1SMatt Jacob 	cel = &ccb->cel;
115567ff51f1SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
115667ff51f1SMatt Jacob 	if (tptr == NULL) {
1157dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n");
115867ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
115967ff51f1SMatt Jacob 		return;
1160d81ba9d5SMatt Jacob 	}
116167ff51f1SMatt Jacob 
116267ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
1163dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1164dd9fc7c3SMatt Jacob 		    "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status);
116567ff51f1SMatt Jacob err:
116667ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
116767ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
116867ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
116967ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
117067ff51f1SMatt Jacob 		xpt_done(ccb);
117167ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
117267ff51f1SMatt Jacob 		return;
117367ff51f1SMatt Jacob 	} else {
117467ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
117567ff51f1SMatt Jacob 		    "isp_ledone: ENABLE/MODIFY done okay");
117667ff51f1SMatt Jacob 	}
117767ff51f1SMatt Jacob 
117867ff51f1SMatt Jacob 
117967ff51f1SMatt Jacob 	if (cel->enable) {
118067ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1181dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, lfmt, "en");
118267ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
118367ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
118467ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
118567ff51f1SMatt Jacob 		xpt_done(ccb);
118667ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
118767ff51f1SMatt Jacob 		return;
118867ff51f1SMatt Jacob 	}
118967ff51f1SMatt Jacob 
119067ff51f1SMatt Jacob 	if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) {
119167ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb),
119267ff51f1SMatt Jacob 		    XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) {
1193dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1194dd9fc7c3SMatt Jacob 			    "isp_ledone: isp_lun_cmd failed\n");
119567ff51f1SMatt Jacob 			goto err;
119667ff51f1SMatt Jacob 		}
119767ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
119867ff51f1SMatt Jacob 		return;
119967ff51f1SMatt Jacob 	}
120067ff51f1SMatt Jacob 
1201dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, lfmt, "dis");
120267ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
120367ff51f1SMatt Jacob 	destroy_lun_state(isp, tptr);
120467ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
120567ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
120667ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
120767ff51f1SMatt Jacob 	xpt_done(ccb);
120867ff51f1SMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
120967ff51f1SMatt Jacob 	if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) {
121067ff51f1SMatt Jacob 		int bus = XS_CHANNEL(ccb);
121167ff51f1SMatt Jacob 		av = bus << 31;
1212126ec864SMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1213126ec864SMatt Jacob 		if (av) {
1214126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
121567ff51f1SMatt Jacob 			    "disable target mode on channel %d failed", bus);
1216126ec864SMatt Jacob 		}
121767ff51f1SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
121867ff51f1SMatt Jacob 	}
1219126ec864SMatt Jacob }
1220126ec864SMatt Jacob 
1221d81ba9d5SMatt Jacob 
1222d81ba9d5SMatt Jacob static cam_status
12239cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb)
1224d81ba9d5SMatt Jacob {
1225d81ba9d5SMatt Jacob 	tstate_t *tptr;
1226d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
1227d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
1228746e9c85SMatt Jacob 	int found, *ctr;
1229d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
1230d81ba9d5SMatt Jacob 
1231dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb);
1232d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1233746e9c85SMatt Jacob 		int badpath = 0;
1234d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
1235d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
1236746e9c85SMatt Jacob 			badpath = 1;
1237d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
1238d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
1239746e9c85SMatt Jacob 			badpath = 1;
1240746e9c85SMatt Jacob 		}
1241746e9c85SMatt Jacob 		if (badpath) {
1242746e9c85SMatt Jacob 			/*
1243746e9c85SMatt Jacob 			 * Being restrictive about target ids is really about
1244746e9c85SMatt Jacob 			 * making sure we're aborting for the right multi-tid
1245746e9c85SMatt Jacob 			 * path. This doesn't really make much sense at present.
1246746e9c85SMatt Jacob 			 */
1247746e9c85SMatt Jacob #if	0
1248d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1249746e9c85SMatt Jacob #endif
1250d81ba9d5SMatt Jacob 		}
1251d81ba9d5SMatt Jacob 	}
1252a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
1253d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1254dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "can't get statep\n");
1255d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
1256d81ba9d5SMatt Jacob 	}
1257d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1258d81ba9d5SMatt Jacob 		lp = &tptr->atios;
1259746e9c85SMatt Jacob 		ctr = &tptr->atio_count;
1260d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
1261d81ba9d5SMatt Jacob 		lp = &tptr->inots;
1262746e9c85SMatt Jacob 		ctr = &tptr->inot_count;
1263d81ba9d5SMatt Jacob 	} else {
1264d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1265dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "bad function code %d\n",
1266dd9fc7c3SMatt Jacob 		    accb->ccb_h.func_code);
1267d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
1268d81ba9d5SMatt Jacob 	}
1269d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
1270d81ba9d5SMatt Jacob 	found = 0;
1271d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
1272d81ba9d5SMatt Jacob 		found = 1;
1273d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
1274d81ba9d5SMatt Jacob 	} else {
1275d81ba9d5SMatt Jacob 		while(curelm != NULL) {
1276d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
1277d81ba9d5SMatt Jacob 
1278d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
1279d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
1280d81ba9d5SMatt Jacob 				found = 1;
1281d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
1282d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
1283d81ba9d5SMatt Jacob 				break;
1284d81ba9d5SMatt Jacob 			}
1285d81ba9d5SMatt Jacob 			curelm = nextelm;
1286d81ba9d5SMatt Jacob 		}
1287d81ba9d5SMatt Jacob 	}
1288d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1289d81ba9d5SMatt Jacob 	if (found) {
1290c1504bc0SMatt Jacob 		(*ctr)--;
1291d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
1292746e9c85SMatt Jacob 		xpt_done(accb);
1293d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
1294d81ba9d5SMatt Jacob 	}
1295dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb);
1296d81ba9d5SMatt Jacob 	return (CAM_PATH_INVALID);
1297d81ba9d5SMatt Jacob }
1298d81ba9d5SMatt Jacob 
12999cd7268eSMatt Jacob static void
13009cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1301d81ba9d5SMatt Jacob {
1302d81ba9d5SMatt Jacob 	void *qe;
130300a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
130410365e5aSMatt Jacob 	uint32_t nxti, optr, handle;
13051dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1306d81ba9d5SMatt Jacob 
1307f48ce188SMatt Jacob 
13084fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1309dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1310dd9fc7c3SMatt Jacob 		    "Request Queue Overflow in isp_target_start_ctio\n");
13119cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
13129cd7268eSMatt Jacob 		goto out;
1313d81ba9d5SMatt Jacob 	}
131429f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1315d81ba9d5SMatt Jacob 
1316d81ba9d5SMatt Jacob 	/*
1317d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1318d81ba9d5SMatt Jacob 	 */
1319d81ba9d5SMatt Jacob 
1320d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
132153036e92SMatt Jacob 		atio_private_data_t *atp;
13224fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
132300a8e174SMatt Jacob 
1324d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1325d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
132610365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin) {
132729f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
132829f76675SMatt Jacob 		} else {
132900a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
133010365e5aSMatt Jacob 			if (FCPARAM(isp)->isp_sccfw == 0) {
1331d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
13322ad50ca5SMatt Jacob 			}
133329f76675SMatt Jacob 		}
133453036e92SMatt Jacob 
133553036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
133653036e92SMatt Jacob 		if (atp == NULL) {
1337dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1338dd9fc7c3SMatt Jacob 			    "cannot find private data adjunct for tag %x\n",
133953036e92SMatt Jacob 			    cso->tag_id);
13409cd7268eSMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
13419cd7268eSMatt Jacob 			goto out;
134253036e92SMatt Jacob 		}
1343f48ce188SMatt Jacob 
134400a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
134500a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
134600a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1347f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
134800a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1349f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
135053036e92SMatt Jacob 				cto->ct_resid =
135153036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1352570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1353570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1354570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1355570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1356570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1357570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1358570c7a3fSMatt Jacob 				}
1359f48ce188SMatt Jacob 			}
136000a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
136100a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
136229f76675SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp,
136329f76675SMatt Jacob 				    &cso->sense_data, m);
136400a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
136500a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
136600a8e174SMatt Jacob 			}
136700a8e174SMatt Jacob 		} else {
136800a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
136900a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
137000a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
137100a8e174SMatt Jacob 			} else {
137200a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1373d81ba9d5SMatt Jacob 			}
1374570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
1375d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1376d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
137700a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
137853036e92SMatt Jacob 				cto->ct_resid =
137953036e92SMatt Jacob 				    atp->orig_datalen -
138053036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
1381570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1382570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1383570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1384570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1385570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1386570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1387570c7a3fSMatt Jacob 				}
138853036e92SMatt Jacob 			} else {
138953036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1390d81ba9d5SMatt Jacob 			}
1391f48ce188SMatt Jacob 			/*
1392f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1393f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1394f48ce188SMatt Jacob 			 */
139500a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
139600a8e174SMatt Jacob 		}
139753036e92SMatt Jacob 
1398290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
139964edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
140053036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
140153036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
140253036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1403a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1404570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
14059cd7268eSMatt Jacob 		} else {
1406570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
14079cd7268eSMatt Jacob 		}
1408a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1409d81ba9d5SMatt Jacob 	} else {
14104fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
141100a8e174SMatt Jacob 
1412d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1413d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
141400a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1415a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1416d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1417d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1418a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1419a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
14201dae40ebSMatt Jacob 			cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id);
1421f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1422f48ce188SMatt Jacob 		}
1423f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1424f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1425f48ce188SMatt Jacob 		}
1426f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1427d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
142800a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
142900a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
143000a8e174SMatt Jacob 		} else {
143100a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1432d81ba9d5SMatt Jacob 		}
1433f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
143453036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
143500a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
143600a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
143764edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1438a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1439a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1440a1bc34c6SMatt Jacob 			    cso->tag_id);
144192a1e549SMatt Jacob 		}
144264edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1443a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1444d81ba9d5SMatt Jacob 	}
1445d81ba9d5SMatt Jacob 
144610365e5aSMatt Jacob 	if (isp_save_xs_tgt(isp, ccb, &handle)) {
1447dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1448dd9fc7c3SMatt Jacob 		    "No XFLIST pointers for isp_target_start_ctio\n");
14499cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14509cd7268eSMatt Jacob 		goto out;
1451d81ba9d5SMatt Jacob 	}
1452d81ba9d5SMatt Jacob 
1453d81ba9d5SMatt Jacob 
1454d81ba9d5SMatt Jacob 	/*
1455d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1456d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1457b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1458d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1459d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1460d81ba9d5SMatt Jacob 	 * format.
1461d81ba9d5SMatt Jacob 	 */
1462d81ba9d5SMatt Jacob 
146310365e5aSMatt Jacob 	if (IS_FC(isp)) {
146410365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
146510365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146610365e5aSMatt Jacob 	} else {
146710365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
146810365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146910365e5aSMatt Jacob 	}
1470a1bc34c6SMatt Jacob 
14714fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1472d81ba9d5SMatt Jacob 	case CMD_QUEUED:
14734fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
14749cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
14759cd7268eSMatt Jacob 		return;
1476d81ba9d5SMatt Jacob 
1477d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
14789cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14799cd7268eSMatt Jacob 		break;
1480d81ba9d5SMatt Jacob 
1481d81ba9d5SMatt Jacob 	default:
14829cd7268eSMatt Jacob 		break;
1483d81ba9d5SMatt Jacob 	}
148410365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
14859cd7268eSMatt Jacob 
14869cd7268eSMatt Jacob out:
14879cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
14889cd7268eSMatt Jacob 	xpt_done(ccb);
14899cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1490d81ba9d5SMatt Jacob }
1491d81ba9d5SMatt Jacob 
1492a1bc34c6SMatt Jacob static void
1493a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1494f48ce188SMatt Jacob {
1495a1bc34c6SMatt Jacob 	int s = splcam();
1496a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1497a1bc34c6SMatt Jacob 	splx(s);
1498a1bc34c6SMatt Jacob }
1499a1bc34c6SMatt Jacob 
1500a1bc34c6SMatt Jacob static void
1501a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1502a1bc34c6SMatt Jacob {
15039cd7268eSMatt Jacob 	ispsoftc_t *isp;
1504a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
150510365e5aSMatt Jacob 	uint32_t nxti, optr;
1506a1bc34c6SMatt Jacob 	void *qe;
1507a1bc34c6SMatt Jacob 
1508a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1509f48ce188SMatt Jacob 
15104fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1511dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1512dd9fc7c3SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow\n");
1513a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1514a1bc34c6SMatt Jacob 		return;
1515f48ce188SMatt Jacob 	}
151629f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1517a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1518f48ce188SMatt Jacob 	if (IS_FC(isp)) {
15194fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
15204fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1521f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1522f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
152310365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw) {
1524a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1525f48ce188SMatt Jacob 		} else {
1526a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1527f48ce188SMatt Jacob 		}
1528f48ce188SMatt Jacob 		at->at_status = CT_OK;
1529a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1530570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
15314fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1532f48ce188SMatt Jacob 	} else {
15334fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
15344fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1535f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1536f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1537a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1538a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1539a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1540a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1541f48ce188SMatt Jacob 		at->at_status = CT_OK;
1542a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1543a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
15444fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1545f48ce188SMatt Jacob 	}
1546f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
15474fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1548a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1549f48ce188SMatt Jacob }
1550f48ce188SMatt Jacob 
1551f48ce188SMatt Jacob static void
1552a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1553f48ce188SMatt Jacob {
15549cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
1555a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1556a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1557f48ce188SMatt Jacob 	}
1558a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1559a1bc34c6SMatt Jacob 	xpt_done(ccb);
15609cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1561f48ce188SMatt Jacob }
1562f48ce188SMatt Jacob 
1563d81ba9d5SMatt Jacob /*
1564d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1565d81ba9d5SMatt Jacob  * This means handling CDBs.
1566d81ba9d5SMatt Jacob  */
1567d81ba9d5SMatt Jacob 
1568d81ba9d5SMatt Jacob static int
15699cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1570d81ba9d5SMatt Jacob {
1571d81ba9d5SMatt Jacob 	tstate_t *tptr;
157264edff94SMatt Jacob 	int status, bus, iswildcard;
1573d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1574d81ba9d5SMatt Jacob 
1575d81ba9d5SMatt Jacob 	/*
1576d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1577d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1578d81ba9d5SMatt Jacob 	 *
1579d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1580d81ba9d5SMatt Jacob 	 *
1581d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
15825d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1583d81ba9d5SMatt Jacob 	 */
1584d81ba9d5SMatt Jacob 	status = aep->at_status;
1585d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1586d81ba9d5SMatt Jacob 		/*
1587d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1588d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1589d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1590d81ba9d5SMatt Jacob 		 */
15913c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1592d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1593d81ba9d5SMatt Jacob 		return (0);
1594d81ba9d5SMatt Jacob 	}
1595d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
15965d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
15973c75bb14SMatt Jacob 		    status);
1598d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1599d81ba9d5SMatt Jacob 		return (0);
1600d81ba9d5SMatt Jacob 	}
1601d81ba9d5SMatt Jacob 
16025d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1603a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1604d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1605a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1606746e9c85SMatt Jacob 		if (tptr == NULL) {
1607d81ba9d5SMatt Jacob 			/*
1608d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1609d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1610d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1611d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1612d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1613d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1614d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1615d81ba9d5SMatt Jacob 			 */
1616d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1617d81ba9d5SMatt Jacob 			return (0);
1618d81ba9d5SMatt Jacob 		}
16198c4e89e2SMatt Jacob 		iswildcard = 1;
16208c4e89e2SMatt Jacob 	} else {
16218c4e89e2SMatt Jacob 		iswildcard = 0;
16228c4e89e2SMatt Jacob 	}
1623d81ba9d5SMatt Jacob 
1624d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1625d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1626d81ba9d5SMatt Jacob 		/*
1627d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1628d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1629d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1630d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1631d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1632d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1633d81ba9d5SMatt Jacob 		 */
1634dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1635dd9fc7c3SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d\n",
16365d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1637d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1638d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1639d81ba9d5SMatt Jacob 		else
1640d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
164164edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1642d81ba9d5SMatt Jacob 		return (0);
1643d81ba9d5SMatt Jacob 	}
1644d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1645746e9c85SMatt Jacob 	tptr->atio_count--;
1646746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1647746e9c85SMatt Jacob 	    aep->at_lun, tptr->atio_count);
164864edff94SMatt Jacob 	if (iswildcard) {
1649d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1650d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1651d81ba9d5SMatt Jacob 	}
1652d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1653f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1654f48ce188SMatt Jacob 	} else {
1655f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1656d81ba9d5SMatt Jacob 	}
1657d81ba9d5SMatt Jacob 
1658f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1659f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1660f48ce188SMatt Jacob 		atiop->sense_len = amt;
1661f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1662f48ce188SMatt Jacob 	} else {
1663f48ce188SMatt Jacob 		atiop->sense_len = 0;
1664f48ce188SMatt Jacob 	}
1665d81ba9d5SMatt Jacob 
16665d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1667d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1668d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1669d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1670a1bc34c6SMatt Jacob 	/*
1671a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1672a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1673a1bc34c6SMatt Jacob 	 */
16746c81a0aeSMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id, bus, device_get_unit(isp->isp_dev), aep);
1675a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1676a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1677d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1678d81ba9d5SMatt Jacob 	}
1679d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
168064edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
16815d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
16825d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
16835d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
16845d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
16855d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1686d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1687d81ba9d5SMatt Jacob 	return (0);
1688d81ba9d5SMatt Jacob }
1689d81ba9d5SMatt Jacob 
1690d81ba9d5SMatt Jacob static int
16919cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
1692d81ba9d5SMatt Jacob {
169392a1e549SMatt Jacob 	lun_id_t lun;
1694d81ba9d5SMatt Jacob 	tstate_t *tptr;
1695d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
169653036e92SMatt Jacob 	atio_private_data_t *atp;
1697d81ba9d5SMatt Jacob 
1698d81ba9d5SMatt Jacob 	/*
1699d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1700d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1701d81ba9d5SMatt Jacob 	 *
1702d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1703d81ba9d5SMatt Jacob 	 */
1704d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
17053c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
17063c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1707d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1708d81ba9d5SMatt Jacob 		return (0);
1709d81ba9d5SMatt Jacob 	}
1710d81ba9d5SMatt Jacob 
171110365e5aSMatt Jacob 	if (FCPARAM(isp)->isp_sccfw) {
171292a1e549SMatt Jacob 		lun = aep->at_scclun;
17132ad50ca5SMatt Jacob 	} else {
171492a1e549SMatt Jacob 		lun = aep->at_lun;
17152ad50ca5SMatt Jacob 	}
1716a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1717d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1718746e9c85SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
1719746e9c85SMatt Jacob 		    "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
1720a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1721746e9c85SMatt Jacob 		if (tptr == NULL) {
1722746e9c85SMatt Jacob 			isp_endcmd(isp, aep,
1723746e9c85SMatt Jacob 			    SCSI_STATUS_CHECK_COND | ECMD_SVALID |
1724746e9c85SMatt Jacob 			    (0x5 << 12) | (0x25 << 16), 0);
1725746e9c85SMatt Jacob 			return (0);
1726746e9c85SMatt Jacob 		}
1727d81ba9d5SMatt Jacob 	}
1728d81ba9d5SMatt Jacob 
172953036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1730d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
173153036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1732746e9c85SMatt Jacob 
1733d81ba9d5SMatt Jacob 		/*
1734d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1735d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1736d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1737d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1738d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1739d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1740d81ba9d5SMatt Jacob 		 */
1741dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1742dd9fc7c3SMatt Jacob 		    "no %s for lun %d from initiator %d\n",
1743570c7a3fSMatt Jacob 		    (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
1744570c7a3fSMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
1745d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1746d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1747d81ba9d5SMatt Jacob 		return (0);
1748d81ba9d5SMatt Jacob 	}
1749570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1750d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1751570c7a3fSMatt Jacob 	tptr->atio_count--;
1752746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1753570c7a3fSMatt Jacob 	    lun, tptr->atio_count);
1754f48ce188SMatt Jacob 
1755a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
175610365e5aSMatt Jacob 		atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid;
175792a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1758d81ba9d5SMatt Jacob 	}
1759b0a3ba7eSMatt Jacob 	/*
1760b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1761b0a3ba7eSMatt Jacob 	 */
1762f48ce188SMatt Jacob 	atiop->sense_len = 0;
1763f48ce188SMatt Jacob 
1764d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1765d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1766d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1767d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1768d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1769d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1770d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1771d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1772d81ba9d5SMatt Jacob 		break;
1773d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1774d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1775d81ba9d5SMatt Jacob 		break;
1776d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1777d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1778d81ba9d5SMatt Jacob 		break;
1779d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1780d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1781d81ba9d5SMatt Jacob 	default:
1782d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1783d81ba9d5SMatt Jacob 		break;
1784d81ba9d5SMatt Jacob 	}
1785570c7a3fSMatt Jacob 	atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
1786f48ce188SMatt Jacob 
178753036e92SMatt Jacob 	atp->tag = atiop->tag_id;
1788570c7a3fSMatt Jacob 	atp->lun = lun;
178953036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
179053036e92SMatt Jacob 	atp->last_xframt = 0;
179153036e92SMatt Jacob 	atp->bytes_xfered = 0;
1792570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
179367ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(siP);
1794d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
1795570c7a3fSMatt Jacob 
179664edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
17975f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
17985f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1799b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1800d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1801d81ba9d5SMatt Jacob 	return (0);
1802d81ba9d5SMatt Jacob }
1803d81ba9d5SMatt Jacob 
1804d81ba9d5SMatt Jacob static int
18059cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
1806d81ba9d5SMatt Jacob {
1807d81ba9d5SMatt Jacob 	union ccb *ccb;
1808a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
18091dae40ebSMatt Jacob 	uint16_t tval;
1810d81ba9d5SMatt Jacob 
1811d81ba9d5SMatt Jacob 	/*
1812d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1813d81ba9d5SMatt Jacob 	 */
1814d81ba9d5SMatt Jacob 
181551e23558SNate Lawson 	ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle);
1816d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
181751e23558SNate Lawson 	isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1818d81ba9d5SMatt Jacob 
1819d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1820d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1821570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
1822570c7a3fSMatt Jacob 		if (atp == NULL) {
1823570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1824570c7a3fSMatt Jacob 			    "cannot find adjunct for %x after I/O",
1825570c7a3fSMatt Jacob 			    ct->ct_rxid);
1826570c7a3fSMatt Jacob 			return (0);
1827570c7a3fSMatt Jacob 		}
1828d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1829d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1830a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
183100a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
183200a8e174SMatt Jacob 		}
1833a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
18345d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
1835a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
183653036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
183753036e92SMatt Jacob 			atp->last_xframt = 0;
1838570c7a3fSMatt Jacob 		}
1839570c7a3fSMatt Jacob 		if (sentstatus || !ok) {
184053036e92SMatt Jacob 			atp->tag = 0;
184153036e92SMatt Jacob 		}
1842570c7a3fSMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
184364edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
184464edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
184564edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
184664edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
184764edff94SMatt Jacob 		tval = ct->ct_rxid;
1848570c7a3fSMatt Jacob 
1849570c7a3fSMatt Jacob 		/* XXX: should really come after isp_complete_ctio */
1850570c7a3fSMatt Jacob 		atp->state = ATPD_STATE_PDON;
1851d81ba9d5SMatt Jacob 	} else {
1852d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1853d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1854d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1855d81ba9d5SMatt Jacob 		/*
1856a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1857a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1858a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1859a1bc34c6SMatt Jacob 		 * private data.
1860a1bc34c6SMatt Jacob 		 *
1861a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1862a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1863a1bc34c6SMatt Jacob 		 */
1864a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1865a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1866a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1867a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1868a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1869a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1870a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1871a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1872a1bc34c6SMatt Jacob 		}
18735d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1874a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1875a1bc34c6SMatt Jacob 		}
187664edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
187764edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
187864edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
187964edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
188064edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
188164edff94SMatt Jacob 		tval = ct->ct_fwhandle;
18825d571944SMatt Jacob 	}
1883a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1884a1bc34c6SMatt Jacob 
1885a1bc34c6SMatt Jacob 	/*
1886a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1887a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1888a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1889d81ba9d5SMatt Jacob 	 *
1890d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1891d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1892a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1893a1bc34c6SMatt Jacob 	 * freed.
1894d81ba9d5SMatt Jacob 	 */
1895f48ce188SMatt Jacob 	if (notify_cam == 0) {
189664edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1897f48ce188SMatt Jacob 		return (0);
1898f48ce188SMatt Jacob 	}
1899d81ba9d5SMatt Jacob 
190053036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
190153036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1902a1bc34c6SMatt Jacob 
1903a1bc34c6SMatt Jacob 	if (!ok) {
1904a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1905d81ba9d5SMatt Jacob 	} else {
1906a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1907a1bc34c6SMatt Jacob 
1908d81ba9d5SMatt Jacob 	}
1909a1bc34c6SMatt Jacob 	return (0);
1910d81ba9d5SMatt Jacob }
1911570c7a3fSMatt Jacob 
1912570c7a3fSMatt Jacob static int
19139cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp)
1914570c7a3fSMatt Jacob {
1915570c7a3fSMatt Jacob 	return (0);	/* XXXX */
1916570c7a3fSMatt Jacob }
1917570c7a3fSMatt Jacob 
1918570c7a3fSMatt Jacob static int
19199cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
1920570c7a3fSMatt Jacob {
1921570c7a3fSMatt Jacob 
1922570c7a3fSMatt Jacob 	switch (inp->in_status) {
1923570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
1924570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
1925570c7a3fSMatt Jacob 		   inp->in_iid);
1926570c7a3fSMatt Jacob 		break;
1927570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
1928570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
1929570c7a3fSMatt Jacob 		   inp->in_iid);
1930570c7a3fSMatt Jacob 		break;
1931570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
1932570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
1933570c7a3fSMatt Jacob 		break;
1934570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
1935570c7a3fSMatt Jacob 	{
1936570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
1937570c7a3fSMatt Jacob 		struct ccb_immed_notify *inot = NULL;
1938570c7a3fSMatt Jacob 
1939570c7a3fSMatt Jacob 		if (atp) {
1940570c7a3fSMatt Jacob 			tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
1941570c7a3fSMatt Jacob 			if (tptr) {
1942570c7a3fSMatt Jacob 				inot = (struct ccb_immed_notify *)
1943570c7a3fSMatt Jacob 				    SLIST_FIRST(&tptr->inots);
1944570c7a3fSMatt Jacob 				if (inot) {
1945746e9c85SMatt Jacob 					tptr->inot_count--;
1946570c7a3fSMatt Jacob 					SLIST_REMOVE_HEAD(&tptr->inots,
1947570c7a3fSMatt Jacob 					    sim_links.sle);
1948746e9c85SMatt Jacob 					isp_prt(isp, ISP_LOGTDEBUG0,
1949746e9c85SMatt Jacob 					    "Take FREE INOT count now %d",
1950746e9c85SMatt Jacob 					    tptr->inot_count);
1951570c7a3fSMatt Jacob 				}
1952570c7a3fSMatt Jacob 			}
1953570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1954570c7a3fSMatt Jacob 			   "abort task RX_ID %x IID %d state %d",
1955570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid, atp->state);
1956570c7a3fSMatt Jacob 		} else {
1957570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1958570c7a3fSMatt Jacob 			   "abort task RX_ID %x from iid %d, state unknown",
1959570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid);
1960570c7a3fSMatt Jacob 		}
1961570c7a3fSMatt Jacob 		if (inot) {
1962570c7a3fSMatt Jacob 			inot->initiator_id = inp->in_iid;
1963570c7a3fSMatt Jacob 			inot->sense_len = 0;
1964570c7a3fSMatt Jacob 			inot->message_args[0] = MSG_ABORT_TAG;
1965570c7a3fSMatt Jacob 			inot->message_args[1] = inp->in_seqid & 0xff;
1966570c7a3fSMatt Jacob 			inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
19676b5ec766SMatt Jacob 			inot->ccb_h.status = CAM_MESSAGE_RECV;
1968570c7a3fSMatt Jacob 			xpt_done((union ccb *)inot);
1969570c7a3fSMatt Jacob 		}
1970570c7a3fSMatt Jacob 		break;
1971570c7a3fSMatt Jacob 	}
1972570c7a3fSMatt Jacob 	default:
1973570c7a3fSMatt Jacob 		break;
1974570c7a3fSMatt Jacob 	}
1975570c7a3fSMatt Jacob 	return (0);
1976570c7a3fSMatt Jacob }
1977d81ba9d5SMatt Jacob #endif
1978d81ba9d5SMatt Jacob 
1979478f8a96SJustin T. Gibbs static void
19801dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
1981478f8a96SJustin T. Gibbs {
1982478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
19839cd7268eSMatt Jacob 	ispsoftc_t *isp;
1984478f8a96SJustin T. Gibbs 
1985478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
19869cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
1987478f8a96SJustin T. Gibbs 	switch (code) {
1988478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1989ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
19901dae40ebSMatt Jacob 			uint16_t oflags, nflags;
1991478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1992a1bc34c6SMatt Jacob 			int tgt;
1993478f8a96SJustin T. Gibbs 
1994f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
199541ed683eSMatt Jacob 			if (tgt >= 0) {
1996ea6f23cdSMatt Jacob 				sdp += cam_sim_bus(sim);
199741ed683eSMatt Jacob 				ISP_LOCK(isp);
19989ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
1999a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
20009ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
2001a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
2002478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
2003478f8a96SJustin T. Gibbs 				}
2004a1bc34c6SMatt Jacob #else
2005a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
2006a1bc34c6SMatt Jacob #endif
20079ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
20089ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
2009478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
2010a1bc34c6SMatt Jacob 				isp->isp_update |= (1 << cam_sim_bus(sim));
201141ed683eSMatt Jacob 				(void) isp_control(isp,
201241ed683eSMatt Jacob 				    ISPCTL_UPDATE_PARAMS, NULL);
20139ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
2014f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
2015478f8a96SJustin T. Gibbs 			}
201641ed683eSMatt Jacob 		}
2017478f8a96SJustin T. Gibbs 		break;
2018478f8a96SJustin T. Gibbs 	default:
20193c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
2020478f8a96SJustin T. Gibbs 		break;
2021478f8a96SJustin T. Gibbs 	}
2022478f8a96SJustin T. Gibbs }
2023478f8a96SJustin T. Gibbs 
2024478f8a96SJustin T. Gibbs static void
2025c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
2026478f8a96SJustin T. Gibbs {
20279cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
202810365e5aSMatt Jacob 	uint32_t isr;
202910365e5aSMatt Jacob 	uint16_t sema, mbox;
2030126ec864SMatt Jacob 
2031c40e096eSMatt Jacob 	ISP_LOCK(isp);
2032126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2033126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
2034126ec864SMatt Jacob 	}
2035c40e096eSMatt Jacob 	ISP_UNLOCK(isp);
2036478f8a96SJustin T. Gibbs }
2037478f8a96SJustin T. Gibbs 
2038ab6c4b31SMatt Jacob 
2039f7c631bcSMatt Jacob static int isp_watchdog_work(ispsoftc_t *, XS_T *);
2040f7c631bcSMatt Jacob 
2041f7c631bcSMatt Jacob static int
2042f7c631bcSMatt Jacob isp_watchdog_work(ispsoftc_t *isp, XS_T *xs)
2043cc8df88bSMatt Jacob {
20441dae40ebSMatt Jacob 	uint32_t handle;
2045b85389e1SMatt Jacob 
2046cc8df88bSMatt Jacob 	/*
2047b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
2048b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
2049b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
2050cc8df88bSMatt Jacob 	 */
2051f6e75de2SMatt Jacob 	ISP_LOCK(isp);
2052cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
2053cc8df88bSMatt Jacob 	if (handle) {
205410365e5aSMatt Jacob 		uint32_t isr;
205510365e5aSMatt Jacob 		uint16_t sema, mbox;
2056126ec864SMatt Jacob 
2057b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2058b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
2059b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
2060f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2061f7c631bcSMatt Jacob 			return (1);;
2062b85389e1SMatt Jacob 		}
2063b85389e1SMatt Jacob 
2064b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
2065b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2066b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
2067f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2068f7c631bcSMatt Jacob 			return (1);
2069b85389e1SMatt Jacob 		}
2070b85389e1SMatt Jacob 
2071b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
2072126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2073126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
2074126ec864SMatt Jacob 		}
2075126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2076b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2077126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
2078f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2079b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
2080f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2081b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
20821fcf5debSMatt Jacob 			/*
20831fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
20841fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
20851fcf5debSMatt Jacob 			 */
2086f7c631bcSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, xs);
20871fcf5debSMatt Jacob 
20881fcf5debSMatt Jacob 			/*
20891fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
20901fcf5debSMatt Jacob 			 */
2091f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
2092f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
2093f6e75de2SMatt Jacob                 	}
2094cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
2095dd9fc7c3SMatt Jacob 			xpt_print(xs->ccb_h.path,
2096dd9fc7c3SMatt Jacob 			    "watchdog timeout for handle 0x%x\n", handle);
2097cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
2098b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2099f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2100cc8df88bSMatt Jacob 			isp_done(xs);
2101f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2102b85389e1SMatt Jacob 		} else {
2103b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2104b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
2105b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
210610365e5aSMatt Jacob 			isp->isp_sendmarker |= 1 << XS_CHANNEL(xs);
2107b85389e1SMatt Jacob 		}
2108f7c631bcSMatt Jacob 		ISP_UNLOCK(isp);
2109f7c631bcSMatt Jacob 		return (1);
2110cc8df88bSMatt Jacob 	}
2111f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
2112f7c631bcSMatt Jacob 	return (0);
2113f7c631bcSMatt Jacob }
2114f7c631bcSMatt Jacob 
2115f7c631bcSMatt Jacob static void
2116f7c631bcSMatt Jacob isp_watchdog(void *arg)
2117f7c631bcSMatt Jacob {
2118f7c631bcSMatt Jacob 	ispsoftc_t *isp;
2119f7c631bcSMatt Jacob 	XS_T *xs = arg;
2120f7c631bcSMatt Jacob 	for (isp = isplist; isp != NULL; isp = isp->isp_osinfo.next) {
2121f7c631bcSMatt Jacob 		if (isp_watchdog_work(isp, xs)) {
2122f7c631bcSMatt Jacob 			break;
2123f7c631bcSMatt Jacob 		}
2124f7c631bcSMatt Jacob 	}
2125f7c631bcSMatt Jacob 	if (isp == NULL) {
2126f7c631bcSMatt Jacob 		printf("isp_watchdog: nobody had %p active\n", arg);
2127f7c631bcSMatt Jacob 	}
2128f7c631bcSMatt Jacob }
2129f7c631bcSMatt Jacob 
2130f7c631bcSMatt Jacob 
2131f7c631bcSMatt Jacob #if __FreeBSD_version >= 500000
2132f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	isp_announce(isp, tgt, AC_FOUND_DEVICE)
2133f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	isp_announce(isp, tgt, AC_LOST_DEVICE)
2134f7c631bcSMatt Jacob 
2135f7c631bcSMatt Jacob /*
2136f7c631bcSMatt Jacob  * Support function for Announcement
2137f7c631bcSMatt Jacob  */
2138f7c631bcSMatt Jacob static void
2139f7c631bcSMatt Jacob isp_announce(ispsoftc_t *isp, int tgt, int action)
2140f7c631bcSMatt Jacob {
2141f7c631bcSMatt Jacob 	struct cam_path *tmppath;
2142f7c631bcSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
2143f7c631bcSMatt Jacob 	if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim), tgt,
2144f7c631bcSMatt Jacob 	    CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
2145f7c631bcSMatt Jacob 		xpt_async(action, tmppath, NULL);
2146f7c631bcSMatt Jacob 		xpt_free_path(tmppath);
2147f7c631bcSMatt Jacob 	}
2148f7c631bcSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
2149f7c631bcSMatt Jacob }
2150f7c631bcSMatt Jacob #else
2151f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	do { ; } while (0)
2152f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	do { ; } while (0)
2153f7c631bcSMatt Jacob #endif
2154f7c631bcSMatt Jacob 
2155f7c631bcSMatt Jacob 
2156f7c631bcSMatt Jacob /*
2157f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
2158f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
2159f7c631bcSMatt Jacob  * gone away.
2160f7c631bcSMatt Jacob  *
2161f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
2162f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
2163f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
2164f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
2165f7c631bcSMatt Jacob  */
2166f7c631bcSMatt Jacob static void
2167f7c631bcSMatt Jacob isp_gdt(void *arg)
2168f7c631bcSMatt Jacob {
2169f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2170f7c631bcSMatt Jacob 	fcportdb_t *lp;
2171f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
2172f7c631bcSMatt Jacob 
2173f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired");
2174f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2175f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2176f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2177f7c631bcSMatt Jacob 
2178f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
2179f7c631bcSMatt Jacob 			continue;
2180f7c631bcSMatt Jacob 		}
2181f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2182f7c631bcSMatt Jacob 			continue;
2183f7c631bcSMatt Jacob 		}
2184f7c631bcSMatt Jacob 		if (lp->new_reserved == 0) {
2185f7c631bcSMatt Jacob 			continue;
2186f7c631bcSMatt Jacob 		}
2187f7c631bcSMatt Jacob 		lp->new_reserved -= 1;
2188f7c631bcSMatt Jacob 		if (lp->new_reserved != 0) {
2189f7c631bcSMatt Jacob 			more_to_do++;
2190f7c631bcSMatt Jacob 			continue;
2191f7c631bcSMatt Jacob 		}
2192f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2193f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2194f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2195f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
2196f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2197f7c631bcSMatt Jacob 		    "Gone Device Timeout");
2198f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2199f7c631bcSMatt Jacob 	}
2200f7c631bcSMatt Jacob 	if (more_to_do) {
2201f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
2202f7c631bcSMatt Jacob 	} else {
2203f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2204f7c631bcSMatt Jacob 		    "stopping Gone Device Timer");
2205f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt_running = 0;
2206f7c631bcSMatt Jacob 	}
2207f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2208f7c631bcSMatt Jacob }
2209f7c631bcSMatt Jacob 
2210f7c631bcSMatt Jacob /*
2211f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
2212f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
2213f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
2214f7c631bcSMatt Jacob  *
2215f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
2216f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
2217f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
2218f7c631bcSMatt Jacob  */
2219f7c631bcSMatt Jacob static void
2220f7c631bcSMatt Jacob isp_ldt(void *arg)
2221f7c631bcSMatt Jacob {
2222f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2223f7c631bcSMatt Jacob 	fcportdb_t *lp;
2224f7c631bcSMatt Jacob 	int dbidx, tgt;
2225f7c631bcSMatt Jacob 
2226f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired");
2227f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2228f7c631bcSMatt Jacob 
2229f7c631bcSMatt Jacob 	/*
2230f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
2231f7c631bcSMatt Jacob 	 */
2232f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2233f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2234f7c631bcSMatt Jacob 
2235f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
2236f7c631bcSMatt Jacob 			continue;
2237f7c631bcSMatt Jacob 		}
2238f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2239f7c631bcSMatt Jacob 			continue;
2240f7c631bcSMatt Jacob 		}
2241f7c631bcSMatt Jacob 
2242f7c631bcSMatt Jacob 		/*
2243f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
2244f7c631bcSMatt Jacob 		 */
2245f7c631bcSMatt Jacob 
2246f7c631bcSMatt Jacob 		/*
2247f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
2248f7c631bcSMatt Jacob 		 */
2249f7c631bcSMatt Jacob 		lp->reserved = 1;
2250f7c631bcSMatt Jacob 
2251f7c631bcSMatt Jacob 		/*
2252f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
2253f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
2254f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
2255f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
2256f7c631bcSMatt Jacob 		 */
2257f7c631bcSMatt Jacob 
2258f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2259f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2260f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2261f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2262f7c631bcSMatt Jacob 		    "Loop Down Timeout");
2263f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2264f7c631bcSMatt Jacob 	}
2265f7c631bcSMatt Jacob 
2266f7c631bcSMatt Jacob 	/*
2267f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
2268f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
2269f7c631bcSMatt Jacob 	 */
2270f7c631bcSMatt Jacob 	isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1;
2271f7c631bcSMatt Jacob #if __FreeBSD_version < 500000
2272f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kproc);
2273f7c631bcSMatt Jacob #else
2274f7c631bcSMatt Jacob #ifdef	ISP_SMPLOCK
2275f7c631bcSMatt Jacob 	cv_signal(&isp->isp_osinfo.kthread_cv);
2276f7c631bcSMatt Jacob #else
2277f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kthread_cv);
2278f7c631bcSMatt Jacob #endif
2279f7c631bcSMatt Jacob #endif
2280f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2281cc8df88bSMatt Jacob }
2282cc8df88bSMatt Jacob 
22835d571944SMatt Jacob static void
22845d571944SMatt Jacob isp_kthread(void *arg)
22855d571944SMatt Jacob {
22869cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
2287f7c631bcSMatt Jacob 	int slp = 0;
22889cd7268eSMatt Jacob #if __FreeBSD_version < 500000
22899cd7268eSMatt Jacob         int s;
22909cd7268eSMatt Jacob 
22919cd7268eSMatt Jacob         s = splcam();
22929cd7268eSMatt Jacob #else
2293162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
22945d571944SMatt Jacob 	mtx_lock(&isp->isp_lock);
2295ee76282eSMatt Jacob #else
2296ee76282eSMatt Jacob 	mtx_lock(&Giant);
2297162e9893SMatt Jacob #endif
22989cd7268eSMatt Jacob #endif
2299fdeb9f2fSMatt Jacob 	/*
2300fdeb9f2fSMatt Jacob 	 * The first loop is for our usage where we have yet to have
2301fdeb9f2fSMatt Jacob 	 * gotten good fibre channel state.
2302fdeb9f2fSMatt Jacob 	 */
23035d571944SMatt Jacob 	for (;;) {
2304f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
2305fdeb9f2fSMatt Jacob 
2306f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2307f7c631bcSMatt Jacob 		    "isp_kthread: checking FC state");
2308f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
230910365e5aSMatt Jacob 		lb = isp_fc_runstate(isp, 250000);
2310f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
231110365e5aSMatt Jacob 		if (lb) {
2312f7c631bcSMatt Jacob 			/*
2313f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
2314f7c631bcSMatt Jacob 			 */
2315f7c631bcSMatt Jacob 			isp->isp_osinfo.loop_down_time += slp;
231610365e5aSMatt Jacob 
231710365e5aSMatt Jacob 			if (lb < 0) {
2318f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
231910365e5aSMatt Jacob 				    "kthread: FC loop not up (down count %d)",
232010365e5aSMatt Jacob 				    isp->isp_osinfo.loop_down_time);
232110365e5aSMatt Jacob 			} else {
2322f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
232310365e5aSMatt Jacob 				    "kthread: FC got to %d (down count %d)",
232410365e5aSMatt Jacob 				    lb, isp->isp_osinfo.loop_down_time);
2325f44257c2SMatt Jacob 			}
232610365e5aSMatt Jacob 
232710365e5aSMatt Jacob 
232810365e5aSMatt Jacob 			/*
232910365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
2330f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
2331f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
2332f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
233310365e5aSMatt Jacob 			 */
2334f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2335f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
233610365e5aSMatt Jacob 			} else {
2337f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2338f7c631bcSMatt Jacob 			}
2339f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2340f7c631bcSMatt Jacob 				isp_freeze_loopdown(isp, "loop limit hit");
2341f7c631bcSMatt Jacob 				slp = 0;
2342f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 10) {
234310365e5aSMatt Jacob 				slp = 1;
2344f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 30) {
2345f7c631bcSMatt Jacob 				slp = 5;
2346f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 60) {
2347f7c631bcSMatt Jacob 				slp = 10;
2348f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 120) {
2349f7c631bcSMatt Jacob 				slp = 20;
2350f7c631bcSMatt Jacob 			} else {
2351f7c631bcSMatt Jacob 				slp = 30;
2352f44257c2SMatt Jacob 			}
235310365e5aSMatt Jacob 
235410365e5aSMatt Jacob 		} else {
2355f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2356f7c631bcSMatt Jacob 			    "isp_kthread: FC state OK");
235710365e5aSMatt Jacob 			isp->isp_osinfo.loop_down_time = 0;
235810365e5aSMatt Jacob 			slp = 0;
23595d571944SMatt Jacob 		}
2360fdeb9f2fSMatt Jacob 
2361f44257c2SMatt Jacob 		/*
236210365e5aSMatt Jacob 		 * If we'd frozen the simq, unfreeze it now so that CAM
236310365e5aSMatt Jacob 		 * can start sending us commands. If the FC state isn't
236410365e5aSMatt Jacob 		 * okay yet, they'll hit that in isp_start which will
236510365e5aSMatt Jacob 		 * freeze the queue again.
2366f44257c2SMatt Jacob 		 */
23675d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
23685d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
23695d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
2370f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2371f7c631bcSMatt Jacob 			    "isp_kthread: releasing simq");
23725d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
23735d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
23745d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
23755d571944SMatt Jacob 		}
2376f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2377f7c631bcSMatt Jacob 		    "isp_kthread: sleep time %d", slp);
23789cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2379f7c631bcSMatt Jacob 		tsleep(&isp->isp_osinfo.kproc, PRIBIO, "ispf",
2380f7c631bcSMatt Jacob 		    slp * hz);
23819cd7268eSMatt Jacob #else
2382162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
2383f7c631bcSMatt Jacob 		cv_timed_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock,
2384f7c631bcSMatt Jacob 		    slp * hz);
2385162e9893SMatt Jacob #else
2386f7c631bcSMatt Jacob 		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "ispf",
2387f7c631bcSMatt Jacob 		    slp * hz);
2388162e9893SMatt Jacob #endif
23899cd7268eSMatt Jacob #endif
239010365e5aSMatt Jacob 		/*
239110365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
239210365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
239310365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
239410365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
239510365e5aSMatt Jacob 		 * to settle.
239610365e5aSMatt Jacob 		 */
239710365e5aSMatt Jacob 		if (slp == 0 && isp->isp_osinfo.hysteresis) {
2398f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2399f7c631bcSMatt Jacob 			    "isp_kthread: sleep hysteresis tick time %d",
2400f7c631bcSMatt Jacob 			    isp->isp_osinfo.hysteresis * hz);
240110365e5aSMatt Jacob 			(void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT",
240210365e5aSMatt Jacob 			    (isp->isp_osinfo.hysteresis * hz));
240310365e5aSMatt Jacob 		}
24045d571944SMatt Jacob 	}
24055d571944SMatt Jacob }
24065d571944SMatt Jacob 
2407cc8df88bSMatt Jacob static void
2408c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
2409478f8a96SJustin T. Gibbs {
2410f7c631bcSMatt Jacob 	int bus, tgt, error, lim;
24119cd7268eSMatt Jacob 	ispsoftc_t *isp;
24124663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
2413478f8a96SJustin T. Gibbs 
2414478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
2415478f8a96SJustin T. Gibbs 
24169cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
2417478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
2418478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
24190470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
24200470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
24215d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
242257c801f5SMatt Jacob 		isp_init(isp);
242357c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
2424f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
242557c801f5SMatt Jacob 			/*
242657c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
242757c801f5SMatt Jacob 			 */
2428b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
24290470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
243057c801f5SMatt Jacob 			xpt_done(ccb);
243157c801f5SMatt Jacob 			return;
243257c801f5SMatt Jacob 		}
243357c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
24345d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
243557c801f5SMatt Jacob 	}
2436b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
2437478f8a96SJustin T. Gibbs 
24385d571944SMatt Jacob 
2439478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
2440478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
2441478f8a96SJustin T. Gibbs 		/*
2442478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
2443478f8a96SJustin T. Gibbs 		 */
2444478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2445478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2446478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
2447478f8a96SJustin T. Gibbs 				xpt_done(ccb);
2448478f8a96SJustin T. Gibbs 				break;
2449478f8a96SJustin T. Gibbs 			}
2450478f8a96SJustin T. Gibbs 		}
24510470d791SMatt Jacob #ifdef	DIAGNOSTIC
24520470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
2453dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
2454478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
24550470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
2456dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
2457478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
2458478f8a96SJustin T. Gibbs 		}
2459478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
2460478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2461478f8a96SJustin T. Gibbs 			break;
2462478f8a96SJustin T. Gibbs 		}
24630470d791SMatt Jacob #endif
24640470d791SMatt Jacob 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
24655d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2466b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
24670470d791SMatt Jacob 		switch (error) {
2468478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
2469f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
2470f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2471478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2472cc8df88bSMatt Jacob 			if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
2473f7c631bcSMatt Jacob 				int ms = ccb->ccb_h.timeout;
2474f7c631bcSMatt Jacob 				if (ms == CAM_TIME_DEFAULT) {
2475f7c631bcSMatt Jacob 					ms = 60*1000;
2476d69a5f7dSMatt Jacob 				}
2477f7c631bcSMatt Jacob 				ccb->ccb_h.timeout_ch =
2478f7c631bcSMatt Jacob 				    timeout(isp_watchdog, ccb, isp_mstohz(ms));
2479b85389e1SMatt Jacob 			} else {
2480b85389e1SMatt Jacob 				callout_handle_init(&ccb->ccb_h.timeout_ch);
2481cc8df88bSMatt Jacob 			}
2482478f8a96SJustin T. Gibbs 			break;
24830470d791SMatt Jacob 		case CMD_RQLATER:
2484f44257c2SMatt Jacob 			/*
2485f44257c2SMatt Jacob 			 * This can only happen for Fibre Channel
2486f44257c2SMatt Jacob 			 */
2487f44257c2SMatt Jacob 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
2488f7c631bcSMatt Jacob 
248910365e5aSMatt Jacob 			/*
2490f7c631bcSMatt Jacob 			 * Handle initial and subsequent loop down cases
249110365e5aSMatt Jacob 			 */
2492f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2493f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
2494f7c631bcSMatt Jacob 			} else {
2495f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2496f7c631bcSMatt Jacob 			}
2497f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2498f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
2499f7c631bcSMatt Jacob 				    "%d.%d downtime (%d) > lim (%d)",
2500f7c631bcSMatt Jacob 				    XS_TGT(ccb), XS_LUN(ccb),
2501f7c631bcSMatt Jacob 				    isp->isp_osinfo.loop_down_time, lim);
2502f7c631bcSMatt Jacob 				ccb->ccb_h.status =
2503f7c631bcSMatt Jacob 				    CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
2504f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
2505f44257c2SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2506f44257c2SMatt Jacob 				xpt_done(ccb);
2507f44257c2SMatt Jacob 				break;
2508f44257c2SMatt Jacob 			}
2509f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2510f7c631bcSMatt Jacob 			    "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
2511f7c631bcSMatt Jacob 			/*
2512f7c631bcSMatt Jacob 			 * Otherwise, retry in a while.
2513f7c631bcSMatt Jacob 			 */
2514fdeb9f2fSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2515f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2516f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2517f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
2518f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
2519478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2520478f8a96SJustin T. Gibbs 			break;
25210470d791SMatt Jacob 		case CMD_EAGAIN:
25225d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2523f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2524f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2525f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
2526478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2527478f8a96SJustin T. Gibbs 			break;
25280470d791SMatt Jacob 		case CMD_COMPLETE:
25290470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
25305d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
25310470d791SMatt Jacob 			break;
25320470d791SMatt Jacob 		default:
2533f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2534bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2535bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
253691f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
2537b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
25380470d791SMatt Jacob 			xpt_done(ccb);
2539478f8a96SJustin T. Gibbs 		}
2540478f8a96SJustin T. Gibbs 		break;
2541478f8a96SJustin T. Gibbs 
2542d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2543478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
254464edff94SMatt Jacob 	{
254510365e5aSMatt Jacob 		int seq, i;
25465d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
254767ff51f1SMatt Jacob 		seq = isp_en_lun(isp, ccb);
254867ff51f1SMatt Jacob 		if (seq < 0) {
25495d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2550478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2551478f8a96SJustin T. Gibbs 			break;
255264edff94SMatt Jacob 		}
255367ff51f1SMatt Jacob 		for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) {
255410365e5aSMatt Jacob 			uint32_t isr;
255510365e5aSMatt Jacob 			uint16_t sema, mbox;
255667ff51f1SMatt Jacob 			if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
255767ff51f1SMatt Jacob 				isp_intr(isp, isr, sema, mbox);
255867ff51f1SMatt Jacob 			}
255967ff51f1SMatt Jacob 			DELAY(1000);
256067ff51f1SMatt Jacob 		}
256167ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
256267ff51f1SMatt Jacob 		break;
256367ff51f1SMatt Jacob 	}
2564d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
2565d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
2566d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
2567d81ba9d5SMatt Jacob 	{
2568a1bc34c6SMatt Jacob 		tstate_t *tptr =
2569a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
2570d81ba9d5SMatt Jacob 		if (tptr == NULL) {
2571d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
2572d81ba9d5SMatt Jacob 			xpt_done(ccb);
2573d81ba9d5SMatt Jacob 			break;
2574d81ba9d5SMatt Jacob 		}
2575f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2576f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
2577570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
2578570c7a3fSMatt Jacob 
25795d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2580d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
2581570c7a3fSMatt Jacob 			/*
2582570c7a3fSMatt Jacob 			 * Note that the command itself may not be done-
2583570c7a3fSMatt Jacob 			 * it may not even have had the first CTIO sent.
2584570c7a3fSMatt Jacob 			 */
2585570c7a3fSMatt Jacob 			tptr->atio_count++;
2586570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2587746e9c85SMatt Jacob 			    "Put FREE ATIO, lun %d, count now %d",
2588570c7a3fSMatt Jacob 			    ccb->ccb_h.target_lun, tptr->atio_count);
2589570c7a3fSMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
2590570c7a3fSMatt Jacob 			    sim_links.sle);
2591570c7a3fSMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
2592746e9c85SMatt Jacob 			tptr->inot_count++;
2593746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2594746e9c85SMatt Jacob 			    "Put FREE INOT, lun %d, count now %d",
2595746e9c85SMatt Jacob 			    ccb->ccb_h.target_lun, tptr->inot_count);
2596d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
2597d81ba9d5SMatt Jacob 			    sim_links.sle);
2598570c7a3fSMatt Jacob 		} else {
2599746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");;
2600d81ba9d5SMatt Jacob 		}
2601d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
2602d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
26035d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2604d81ba9d5SMatt Jacob 		break;
2605d81ba9d5SMatt Jacob 	}
2606d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
2607d81ba9d5SMatt Jacob 	{
26085d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
26099cd7268eSMatt Jacob 		isp_target_start_ctio(isp, ccb);
26105d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2611d81ba9d5SMatt Jacob 		break;
2612d81ba9d5SMatt Jacob 	}
2613d81ba9d5SMatt Jacob #endif
2614478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2615d81ba9d5SMatt Jacob 
2616d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2617d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2618d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2619d81ba9d5SMatt Jacob 
26205d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2621ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
26225d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2623478f8a96SJustin T. Gibbs 		if (error) {
2624478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2625478f8a96SJustin T. Gibbs 		} else {
2626478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2627478f8a96SJustin T. Gibbs 		}
2628478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2629478f8a96SJustin T. Gibbs 		break;
2630478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2631d81ba9d5SMatt Jacob 	{
2632d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
26335d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2634d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2635d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2636d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2637d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2638d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2639d81ba9d5SMatt Jacob 			break;
2640d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2641b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2642d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2643d81ba9d5SMatt Jacob 			break;
2644d81ba9d5SMatt Jacob #endif
2645d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2646478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2647478f8a96SJustin T. Gibbs 			if (error) {
2648d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2649478f8a96SJustin T. Gibbs 			} else {
2650478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2651478f8a96SJustin T. Gibbs 			}
2652d81ba9d5SMatt Jacob 			break;
2653d81ba9d5SMatt Jacob 		default:
2654d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2655d81ba9d5SMatt Jacob 			break;
2656d81ba9d5SMatt Jacob 		}
26575d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2658478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2659478f8a96SJustin T. Gibbs 		break;
2660d81ba9d5SMatt Jacob 	}
2661805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2662ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2663805e1f82SMatt Jacob #else
2664805e1f82SMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->flags & CCB_TRANS_CURRENT_SETTINGS)
2665805e1f82SMatt Jacob #endif
2666478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2667478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
26689ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
26699ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
26709ce9bdafSMatt Jacob 			xpt_done(ccb);
26719ce9bdafSMatt Jacob 			break;
26729ce9bdafSMatt Jacob 		}
2673478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
26745d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2675ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2676805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2677805e1f82SMatt Jacob 			sdparam *sdp = isp->isp_param;
2678805e1f82SMatt Jacob 			uint16_t *dptr;
2679805e1f82SMatt Jacob 
2680805e1f82SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2681805e1f82SMatt Jacob 
2682805e1f82SMatt Jacob 			sdp += bus;
2683805e1f82SMatt Jacob 			/*
2684805e1f82SMatt Jacob 			 * We always update (internally) from goal_flags
2685805e1f82SMatt Jacob 			 * so any request to change settings just gets
2686805e1f82SMatt Jacob 			 * vectored to that location.
2687805e1f82SMatt Jacob 			 */
2688805e1f82SMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2689805e1f82SMatt Jacob 
2690805e1f82SMatt Jacob 			/*
2691805e1f82SMatt Jacob 			 * Note that these operations affect the
2692805e1f82SMatt Jacob 			 * the goal flags (goal_flags)- not
2693805e1f82SMatt Jacob 			 * the current state flags. Then we mark
2694805e1f82SMatt Jacob 			 * things so that the next operation to
2695805e1f82SMatt Jacob 			 * this HBA will cause the update to occur.
2696805e1f82SMatt Jacob 			 */
2697805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_DISC_VALID) {
2698805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
2699805e1f82SMatt Jacob 					*dptr |= DPARM_DISC;
2700805e1f82SMatt Jacob 				} else {
2701805e1f82SMatt Jacob 					*dptr &= ~DPARM_DISC;
2702805e1f82SMatt Jacob 				}
2703805e1f82SMatt Jacob 			}
2704805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_TQ_VALID) {
2705805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
2706805e1f82SMatt Jacob 					*dptr |= DPARM_TQING;
2707805e1f82SMatt Jacob 				} else {
2708805e1f82SMatt Jacob 					*dptr &= ~DPARM_TQING;
2709805e1f82SMatt Jacob 				}
2710805e1f82SMatt Jacob 			}
2711805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
2712805e1f82SMatt Jacob 				switch (cts->bus_width) {
2713805e1f82SMatt Jacob 				case MSG_EXT_WDTR_BUS_16_BIT:
2714805e1f82SMatt Jacob 					*dptr |= DPARM_WIDE;
2715805e1f82SMatt Jacob 					break;
2716805e1f82SMatt Jacob 				default:
2717805e1f82SMatt Jacob 					*dptr &= ~DPARM_WIDE;
2718805e1f82SMatt Jacob 				}
2719805e1f82SMatt Jacob 			}
2720805e1f82SMatt Jacob 			/*
2721805e1f82SMatt Jacob 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
2722805e1f82SMatt Jacob 			 * of nonzero will cause us to go to the
2723805e1f82SMatt Jacob 			 * selected (from NVRAM) maximum value for
2724805e1f82SMatt Jacob 			 * this device. At a later point, we'll
2725805e1f82SMatt Jacob 			 * allow finer control.
2726805e1f82SMatt Jacob 			 */
2727805e1f82SMatt Jacob 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
2728805e1f82SMatt Jacob 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
2729805e1f82SMatt Jacob 			    (cts->sync_offset > 0)) {
2730805e1f82SMatt Jacob 				*dptr |= DPARM_SYNC;
2731805e1f82SMatt Jacob 			} else {
2732805e1f82SMatt Jacob 				*dptr &= ~DPARM_SYNC;
2733805e1f82SMatt Jacob 			}
2734805e1f82SMatt Jacob 			*dptr |= DPARM_SAFE_DFLT;
2735805e1f82SMatt Jacob #else
2736ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2737ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2738ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2739ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2740ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
27411dae40ebSMatt Jacob 			uint16_t *dptr;
2742ab163f5fSMatt Jacob 
2743b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
2744b61386a4SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2745b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
2746b61386a4SMatt Jacob 				xpt_done(ccb);
2747b61386a4SMatt Jacob 				break;
2748b61386a4SMatt Jacob 			}
2749b61386a4SMatt Jacob 
2750ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2751ab163f5fSMatt Jacob 			sdp += bus;
2752ab163f5fSMatt Jacob 			/*
27539ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2754ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2755ab163f5fSMatt Jacob 			 * vectored to that location.
2756ab163f5fSMatt Jacob 			 */
27579ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2758ab163f5fSMatt Jacob 
2759ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2760ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2761ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2762ab163f5fSMatt Jacob 				else
2763ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2764ab163f5fSMatt Jacob 			}
2765ab163f5fSMatt Jacob 
2766ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2767ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2768ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2769ab163f5fSMatt Jacob 				else
2770ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2771ab163f5fSMatt Jacob 			}
2772ab163f5fSMatt Jacob 
2773ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2774ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2775ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2776ab163f5fSMatt Jacob 				else
2777ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2778ab163f5fSMatt Jacob 			}
2779ab163f5fSMatt Jacob 
2780ab163f5fSMatt Jacob 			/*
2781ab163f5fSMatt Jacob 			 * XXX: FIX ME
2782ab163f5fSMatt Jacob 			 */
2783ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
27849ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
27859ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2786ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
27879ce9bdafSMatt Jacob 				/*
27889ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
27899ce9bdafSMatt Jacob 				 */
27909ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
27919ce9bdafSMatt Jacob 				    spi->sync_period;
27929ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
27939ce9bdafSMatt Jacob 				    spi->sync_offset;
2794ab163f5fSMatt Jacob 			} else {
2795ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2796ab163f5fSMatt Jacob 			}
2797805e1f82SMatt Jacob #endif
2798bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2799b61386a4SMatt Jacob 			    "SET (%d.%d.%d) to flags %x off %x per %x",
2800b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun,
2801b61386a4SMatt Jacob 			    sdp->isp_devparam[tgt].goal_flags,
28029ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
28039ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2804478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2805ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2806478f8a96SJustin T. Gibbs 		}
28075d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2808478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2809478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2810478f8a96SJustin T. Gibbs 		break;
2811478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2812478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2813478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2814ab163f5fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2815ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2816805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2817805e1f82SMatt Jacob 			/*
2818805e1f82SMatt Jacob 			 * a lot of normal SCSI things don't make sense.
2819805e1f82SMatt Jacob 			 */
2820805e1f82SMatt Jacob 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
2821805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2822805e1f82SMatt Jacob 			/*
2823805e1f82SMatt Jacob 			 * How do you measure the width of a high
2824805e1f82SMatt Jacob 			 * speed serial bus? Well, in bytes.
2825805e1f82SMatt Jacob 			 *
2826805e1f82SMatt Jacob 			 * Offset and period make no sense, though, so we set
2827805e1f82SMatt Jacob 			 * (above) a 'base' transfer speed to be gigabit.
2828805e1f82SMatt Jacob 			 */
2829805e1f82SMatt Jacob 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2830805e1f82SMatt Jacob #else
2831ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
28329b03492aSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
28339b03492aSMatt Jacob 			    &cts->proto_specific.scsi;
2834ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2835ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2836478f8a96SJustin T. Gibbs 
2837ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2838ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2839ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2840ab163f5fSMatt Jacob 			cts->transport_version = 0;
2841ab163f5fSMatt Jacob 
28429b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
28439b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2844ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
28459b03492aSMatt Jacob 			if (fcp->isp_gbspeed == 2) {
284653036e92SMatt Jacob 				fc->bitrate = 200000;
28479b03492aSMatt Jacob 			} else {
2848ab163f5fSMatt Jacob 				fc->bitrate = 100000;
28499b03492aSMatt Jacob 			}
2850ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
285110365e5aSMatt Jacob 				fcportdb_t *lp = &fcp->portdb[tgt];
2852ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2853ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2854ab163f5fSMatt Jacob 				fc->port = lp->portid;
2855ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2856ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2857ab163f5fSMatt Jacob 			}
2858805e1f82SMatt Jacob #endif
2859ab163f5fSMatt Jacob 		} else {
2860805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2861ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2862ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2863ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2864ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2865805e1f82SMatt Jacob #endif
2866ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2867ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
28681dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
2869ab163f5fSMatt Jacob 
2870ea6f23cdSMatt Jacob 			sdp += bus;
2871ab163f5fSMatt Jacob 
2872ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
287383ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
287483ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
287583ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
287683ae4407SMatt Jacob 				    NULL);
28779ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
28789ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
28799ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
28804394c92fSMatt Jacob 			} else {
28819ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
28829ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
28839ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
28844394c92fSMatt Jacob 			}
2885478f8a96SJustin T. Gibbs 
2886805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2887805e1f82SMatt Jacob 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
2888805e1f82SMatt Jacob 
2889805e1f82SMatt Jacob 			if (dval & DPARM_DISC) {
2890805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_DISC_ENB;
2891805e1f82SMatt Jacob 			}
2892805e1f82SMatt Jacob 			if (dval & DPARM_TQING) {
2893805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_TAG_ENB;
2894805e1f82SMatt Jacob 			}
2895805e1f82SMatt Jacob 			if (dval & DPARM_WIDE) {
2896805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2897805e1f82SMatt Jacob 			} else {
2898805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2899805e1f82SMatt Jacob 			}
2900805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
2901805e1f82SMatt Jacob 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2902805e1f82SMatt Jacob 
2903805e1f82SMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
2904805e1f82SMatt Jacob 				cts->sync_period = pval;
2905805e1f82SMatt Jacob 				cts->sync_offset = oval;
2906805e1f82SMatt Jacob 				cts->valid |=
2907805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_RATE_VALID |
2908805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_OFFSET_VALID;
2909805e1f82SMatt Jacob 			}
2910805e1f82SMatt Jacob #else
2911ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2912ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2913ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2914ab163f5fSMatt Jacob 			cts->transport_version = 2;
2915ab163f5fSMatt Jacob 
2916b61386a4SMatt Jacob 			spi->valid = 0;
2917b61386a4SMatt Jacob 			scsi->valid = 0;
2918b61386a4SMatt Jacob 			spi->flags = 0;
2919b61386a4SMatt Jacob 			scsi->flags = 0;
2920ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2921ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2922ab163f5fSMatt Jacob 			}
29239ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2924ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2925ab163f5fSMatt Jacob 				spi->sync_period = pval;
2926b61386a4SMatt Jacob 			} else {
2927b61386a4SMatt Jacob 				spi->sync_offset = 0;
2928b61386a4SMatt Jacob 				spi->sync_period = 0;
2929b61386a4SMatt Jacob 			}
2930ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2931ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2932ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2933ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2934ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2935ab163f5fSMatt Jacob 			} else {
2936ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2937ab163f5fSMatt Jacob 			}
2938ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2939ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2940b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
2941b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2942b61386a4SMatt Jacob 				}
2943ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2944ab163f5fSMatt Jacob 			}
2945805e1f82SMatt Jacob #endif
2946bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2947b61386a4SMatt Jacob 			    "GET %s (%d.%d.%d) to flags %x off %x per %x",
29489ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
2949b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
2950478f8a96SJustin T. Gibbs 		}
2951ab163f5fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2952478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2953478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2954478f8a96SJustin T. Gibbs 		break;
2955478f8a96SJustin T. Gibbs 
2956478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
29579cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2958478f8a96SJustin T. Gibbs 	{
2959478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
29609cd7268eSMatt Jacob 		u_int32_t secs_per_cylinder;
29619cd7268eSMatt Jacob 		u_int32_t size_mb;
2962478f8a96SJustin T. Gibbs 
2963478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2964478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2965478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2966478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2967478f8a96SJustin T. Gibbs 			break;
2968478f8a96SJustin T. Gibbs 		}
29699cd7268eSMatt Jacob 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
29709cd7268eSMatt Jacob 		if (size_mb > 1024) {
29719cd7268eSMatt Jacob 			ccg->heads = 255;
29729cd7268eSMatt Jacob 			ccg->secs_per_track = 63;
29739cd7268eSMatt Jacob 		} else {
29749cd7268eSMatt Jacob 			ccg->heads = 64;
29759cd7268eSMatt Jacob 			ccg->secs_per_track = 32;
29769cd7268eSMatt Jacob 		}
29779cd7268eSMatt Jacob 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
29789cd7268eSMatt Jacob 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
29799cd7268eSMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
2980478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2981478f8a96SJustin T. Gibbs 		break;
2982478f8a96SJustin T. Gibbs 	}
29839cd7268eSMatt Jacob #else
29849cd7268eSMatt Jacob 	{
29859cd7268eSMatt Jacob 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
29869cd7268eSMatt Jacob 		xpt_done(ccb);
29879cd7268eSMatt Jacob 		break;
29889cd7268eSMatt Jacob 	}
29899cd7268eSMatt Jacob #endif
2990478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
2991ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
29925d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2993ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
29945d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2995478f8a96SJustin T. Gibbs 		if (error)
2996478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
29972b052931SMatt Jacob 		else {
2998ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
2999ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
3000ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
30012b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
3002478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
30032b052931SMatt Jacob 		}
3004478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3005478f8a96SJustin T. Gibbs 		break;
3006478f8a96SJustin T. Gibbs 
3007478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
3008478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
3009478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3010478f8a96SJustin T. Gibbs 		break;
3011478f8a96SJustin T. Gibbs 
3012478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
3013478f8a96SJustin T. Gibbs 	{
3014478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
3015478f8a96SJustin T. Gibbs 
3016478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
3017d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3018a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
3019d81ba9d5SMatt Jacob #else
3020478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
3021d81ba9d5SMatt Jacob #endif
3022478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
30230470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
30240470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
30250470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
30264394c92fSMatt Jacob 		if (IS_FC(isp)) {
30274394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
30280470d791SMatt Jacob 			/*
30290470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
30300470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
30310470d791SMatt Jacob 			 */
30320470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
30330470d791SMatt Jacob 
30349deea857SKenneth D. Merry 			/*
30359deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
30369deea857SKenneth D. Merry 			 * Technically not correct because we don't know
30379deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
30389deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
30399deea857SKenneth D. Merry 			 */
304053036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
304153036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
304253036e92SMatt Jacob 			else
30439deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
30440470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
3045805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3046ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
3047805e1f82SMatt Jacob 			cpi->transport_version = 0;
3048805e1f82SMatt Jacob #endif
3049478f8a96SJustin T. Gibbs 		} else {
3050ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
3051ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
30520470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
30534394c92fSMatt Jacob 			cpi->hba_misc = 0;
3054ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
30559deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
3056805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3057ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
3058805e1f82SMatt Jacob 			cpi->transport_version = 2;
3059805e1f82SMatt Jacob #endif
3060478f8a96SJustin T. Gibbs 		}
3061805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3062ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
3063ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
3064805e1f82SMatt Jacob #endif
3065478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
3066478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
3067478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
3068478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
3069478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
3070478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3071478f8a96SJustin T. Gibbs 		break;
3072478f8a96SJustin T. Gibbs 	}
3073478f8a96SJustin T. Gibbs 	default:
3074478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
3075478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3076478f8a96SJustin T. Gibbs 		break;
3077478f8a96SJustin T. Gibbs 	}
3078478f8a96SJustin T. Gibbs }
3079d3a9eb2eSMatt Jacob 
3080d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
3081f7c631bcSMatt Jacob 
3082d3a9eb2eSMatt Jacob void
3083c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
3084d3a9eb2eSMatt Jacob {
30859cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
3086d3a9eb2eSMatt Jacob 
3087d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
3088d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
3089b85389e1SMatt Jacob 
3090d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
3091d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
3092d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
309392a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
309492a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
309592a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
309692a1e549SMatt Jacob 		} else {
3097d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
3098d3a9eb2eSMatt Jacob 		}
309992a1e549SMatt Jacob 	}
3100b85389e1SMatt Jacob 
31010470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
3102d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3103f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0,
3104f7c631bcSMatt Jacob 		    "target %d lun %d CAM status 0x%x SCSI status 0x%x",
3105f7c631bcSMatt Jacob 		    XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status,
3106f7c631bcSMatt Jacob 		    sccb->scsi_status);
3107d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
3108d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
31090470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
3110d3a9eb2eSMatt Jacob 		}
3111d3a9eb2eSMatt Jacob 	}
3112b85389e1SMatt Jacob 
3113b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
3114d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3115dd9fc7c3SMatt Jacob 		xpt_print(sccb->ccb_h.path,
3116dd9fc7c3SMatt Jacob 		    "cam completion status 0x%x\n", sccb->ccb_h.status);
3117d3a9eb2eSMatt Jacob 	}
3118b85389e1SMatt Jacob 
3119b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
3120b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
3121f7c631bcSMatt Jacob 		untimeout(isp_watchdog, sccb, sccb->ccb_h.timeout_ch);
3122b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
3123b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
3124b09b0095SMatt Jacob 			    "finished command on borrowed time");
3125b85389e1SMatt Jacob 		}
3126b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
31275d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3128d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
31295d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3130d3a9eb2eSMatt Jacob 	}
3131b85389e1SMatt Jacob }
3132d3a9eb2eSMatt Jacob 
3133cbf57b47SMatt Jacob int
31349cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg)
3135cbf57b47SMatt Jacob {
3136ea6f23cdSMatt Jacob 	int bus, rv = 0;
313710365e5aSMatt Jacob 	static const char prom[] =
313810365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s\n"
313910365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
314010365e5aSMatt Jacob 	static const char prom2[] =
314110365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s tgt %u\n"
314210365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
3143f7c631bcSMatt Jacob 	char *msg = NULL;
314410365e5aSMatt Jacob 	target_id_t tgt;
314510365e5aSMatt Jacob 	fcportdb_t *lp;
314610365e5aSMatt Jacob 	struct cam_path *tmppath;
314710365e5aSMatt Jacob 
3148cbf57b47SMatt Jacob 	switch (cmd) {
3149cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
31500470d791SMatt Jacob 	{
3151805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3152ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
3153ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
3154805e1f82SMatt Jacob #endif
3155cbf57b47SMatt Jacob 		int flags, tgt;
3156cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
3157ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
3158cbf57b47SMatt Jacob 
315929f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
3160ab163f5fSMatt Jacob 
3161cbf57b47SMatt Jacob 		tgt = *((int *)arg);
3162ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
3163ea6f23cdSMatt Jacob 		tgt &= 0xffff;
3164ea6f23cdSMatt Jacob 		sdp += bus;
316545c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3166cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
3167ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
3168ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
316945c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3170bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3171bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
3172bfbab170SMatt Jacob 			    tgt, bus);
3173cbf57b47SMatt Jacob 			rv = -1;
3174cbf57b47SMatt Jacob 			break;
3175cbf57b47SMatt Jacob 		}
317645c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
31779ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
3178805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3179ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
3180ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
3181ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
3182ab163f5fSMatt Jacob 
3183ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
3184ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
3185ab163f5fSMatt Jacob 
3186ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
3187ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
3188ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3189ab163f5fSMatt Jacob 		}
3190ab163f5fSMatt Jacob 
3191cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
3192ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
3193ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3194ab163f5fSMatt Jacob 		}
3195ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
3196ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
3197ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
3198ab163f5fSMatt Jacob 		} else {
3199ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
3200ab163f5fSMatt Jacob 		}
3201ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
3202ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3203ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
32049ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
32059ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
3206ab163f5fSMatt Jacob 		}
3207805e1f82SMatt Jacob #else
3208805e1f82SMatt Jacob 		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
3209805e1f82SMatt Jacob 		cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
3210805e1f82SMatt Jacob 		if (flags & DPARM_DISC) {
3211805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_DISC_ENB;
3212805e1f82SMatt Jacob 		}
3213805e1f82SMatt Jacob 		if (flags & DPARM_TQING) {
3214805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_TAG_ENB;
3215805e1f82SMatt Jacob 		}
3216805e1f82SMatt Jacob 		cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
3217805e1f82SMatt Jacob 		cts.bus_width = (flags & DPARM_WIDE)?
3218805e1f82SMatt Jacob 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
3219805e1f82SMatt Jacob 		cts.sync_period = sdp->isp_devparam[tgt].actv_period;
3220805e1f82SMatt Jacob 		cts.sync_offset = sdp->isp_devparam[tgt].actv_offset;
3221805e1f82SMatt Jacob 		if (flags & DPARM_SYNC) {
3222805e1f82SMatt Jacob 			cts.valid |=
3223805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_RATE_VALID |
3224805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_OFFSET_VALID;
3225805e1f82SMatt Jacob 		}
3226805e1f82SMatt Jacob #endif
3227b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
3228b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
32299ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
32309ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
3231ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
32325d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3233ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
3234cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
3235f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3236cbf57b47SMatt Jacob 		break;
32370470d791SMatt Jacob 	}
323857c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
3239ea6f23cdSMatt Jacob 		bus = *((int *)arg);
3240b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
3241b09b0095SMatt Jacob 		    bus);
3242ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
32435d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
3244ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
32455d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3246ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
32475d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
324857c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
32495d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
325057c801f5SMatt Jacob 		}
325157c801f5SMatt Jacob 		break;
32525d571944SMatt Jacob 	case ISPASYNC_LIP:
3253f7c631bcSMatt Jacob 		if (msg == NULL) {
3254f7c631bcSMatt Jacob 			msg = "LIP Received";
32555d571944SMatt Jacob 		}
3256f7c631bcSMatt Jacob 		/* FALLTHROUGH */
32575d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
3258f7c631bcSMatt Jacob 		if (msg == NULL) {
3259f7c631bcSMatt Jacob 			msg = "LOOP Reset";
32605d571944SMatt Jacob 		}
3261f7c631bcSMatt Jacob 		/* FALLTHROUGH */
326257c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
3263f7c631bcSMatt Jacob 		if (msg == NULL) {
3264f7c631bcSMatt Jacob 			msg = "LOOP Down";
326557c801f5SMatt Jacob 		}
3266f7c631bcSMatt Jacob 		if (isp->isp_path) {
3267f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, msg);
3268f7c631bcSMatt Jacob 		}
3269f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running == 0) {
3270f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt = timeout(isp_ldt, isp,
3271f7c631bcSMatt Jacob 			    isp->isp_osinfo.loop_down_limit * hz);
3272f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
3273f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3274f7c631bcSMatt Jacob 			   "starting Loop Down Timer");
3275f7c631bcSMatt Jacob 		}
3276f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
327757c801f5SMatt Jacob 		break;
327857c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
32795d571944SMatt Jacob 		/*
32805d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
32815d571944SMatt Jacob 		 * actually do anything because we're waiting for a
32825d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
32835d571944SMatt Jacob 		 * thread to look at the state of the loop again.
32845d571944SMatt Jacob 		 */
3285b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
328657c801f5SMatt Jacob 		break;
328710365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
328810365e5aSMatt Jacob 		lp = arg;
3289f7c631bcSMatt Jacob 		lp->reserved = 0;
3290f7c631bcSMatt Jacob 		if ((isp->isp_role & ISP_ROLE_INITIATOR) &&
3291f7c631bcSMatt Jacob 		    (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
3292f7c631bcSMatt Jacob 			int dbidx = lp - FCPARAM(isp)->portdb;
3293f7c631bcSMatt Jacob 			int i;
329402ab3379SMatt Jacob 
3295f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
3296f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
3297f7c631bcSMatt Jacob 					continue;
3298f7c631bcSMatt Jacob 				}
3299f7c631bcSMatt Jacob 				if (FCPARAM(isp)->isp_ini_map[i] == 0) {
3300f7c631bcSMatt Jacob 					break;
3301f7c631bcSMatt Jacob 				}
3302f7c631bcSMatt Jacob 			}
3303f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
3304f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[i] = dbidx + 1;
3305f7c631bcSMatt Jacob 				lp->ini_map_idx = i + 1;
3306f7c631bcSMatt Jacob 			} else {
3307f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
3308f7c631bcSMatt Jacob 				isp_dump_portdb(isp);
3309f7c631bcSMatt Jacob 			}
3310f7c631bcSMatt Jacob 		}
331110365e5aSMatt Jacob 		if (lp->ini_map_idx) {
331210365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
331310365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
331410365e5aSMatt Jacob 			    lp->portid, lp->handle,
3315f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived at", tgt,
33161dae40ebSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
331710365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
331810365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
331910365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3320f7c631bcSMatt Jacob 			isp_make_here(isp, tgt);
332110365e5aSMatt Jacob 		} else {
332210365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
332310365e5aSMatt Jacob 			    lp->portid, lp->handle,
3324f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived",
332510365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
332610365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
332710365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
332810365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
332910365e5aSMatt Jacob 		}
333010365e5aSMatt Jacob 		break;
333110365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
333210365e5aSMatt Jacob 		lp = arg;
3333f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
3334f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
333510365e5aSMatt Jacob 			if (lp->ini_map_idx) {
333610365e5aSMatt Jacob 				tgt = lp->ini_map_idx - 1;
3337f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[tgt] = 0;
3338f7c631bcSMatt Jacob 				lp->ini_map_idx = 0;
3339f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3,
3340f7c631bcSMatt Jacob 				    lp->portid, tgt, "change is bad");
3341f7c631bcSMatt Jacob 				isp_make_gone(isp, tgt);
3342f7c631bcSMatt Jacob 			} else {
3343f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
3344f7c631bcSMatt Jacob 				    lp->portid, lp->handle,
3345f7c631bcSMatt Jacob 				    roles[lp->roles],
3346f7c631bcSMatt Jacob 				    "changed and departed",
3347f7c631bcSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
3348f7c631bcSMatt Jacob 				    (uint32_t) lp->node_wwn,
3349f7c631bcSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
3350f7c631bcSMatt Jacob 				    (uint32_t) lp->port_wwn);
3351f7c631bcSMatt Jacob 			}
3352f7c631bcSMatt Jacob 		} else {
3353f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
3354f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
3355f7c631bcSMatt Jacob 			if (lp->ini_map_idx) {
3356f7c631bcSMatt Jacob 				int t = lp->ini_map_idx - 1;
3357f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[t] =
3358f7c631bcSMatt Jacob 				    (lp - FCPARAM(isp)->portdb) + 1;
3359f7c631bcSMatt Jacob 				tgt = lp->ini_map_idx - 1;
336010365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2,
336110365e5aSMatt Jacob 				    lp->portid, lp->handle,
3362f7c631bcSMatt Jacob 				    roles[lp->roles], "changed at", tgt,
336310365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
336410365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
336510365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
336610365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
336710365e5aSMatt Jacob 			} else {
336810365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
336910365e5aSMatt Jacob 				    lp->portid, lp->handle,
3370f7c631bcSMatt Jacob 				    roles[lp->roles], "changed",
337110365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
337210365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
337310365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
337410365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
337510365e5aSMatt Jacob 			}
3376f7c631bcSMatt Jacob 		}
337710365e5aSMatt Jacob 		break;
337810365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
337910365e5aSMatt Jacob 		lp = arg;
338010365e5aSMatt Jacob 		if (lp->ini_map_idx) {
338110365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
338210365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
338310365e5aSMatt Jacob 			    lp->portid, lp->handle,
3384f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed at", tgt,
338510365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
338610365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
338710365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
338810365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
338910365e5aSMatt Jacob 		} else {
339010365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
339110365e5aSMatt Jacob 			    lp->portid, lp->handle,
3392f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed",
339310365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
339410365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
339510365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
339610365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
339710365e5aSMatt Jacob 		}
339810365e5aSMatt Jacob 		break;
339910365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
340010365e5aSMatt Jacob 		lp = arg;
3401f7c631bcSMatt Jacob 		/*
3402f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
3403f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
3404f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
3405f7c631bcSMatt Jacob 		 *
3406f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
3407f7c631bcSMatt Jacob 		 * announce that it's gone.
3408f7c631bcSMatt Jacob 		 */
3409f7c631bcSMatt Jacob 		if (lp->ini_map_idx && lp->reserved == 0) {
3410f7c631bcSMatt Jacob 			lp->reserved = 1;
3411f7c631bcSMatt Jacob 			lp->new_reserved = isp->isp_osinfo.gone_device_time;
3412f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
3413f7c631bcSMatt Jacob 			if (isp->isp_osinfo.gdt_running == 0) {
3414f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3415f7c631bcSMatt Jacob 				    "starting Gone Device Timer");
3416f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
3417f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt_running = 1;
3418f7c631bcSMatt Jacob 			}
341910365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
342010365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
342110365e5aSMatt Jacob 			    lp->portid, lp->handle,
3422f7c631bcSMatt Jacob 		            roles[lp->roles], "gone zombie at", tgt,
342310365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
342410365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
342510365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
342610365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3427f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
342810365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
342910365e5aSMatt Jacob 			    lp->portid, lp->handle,
3430f7c631bcSMatt Jacob 			    roles[lp->roles], "departed",
343110365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
343210365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
343310365e5aSMatt Jacob 			    (uint32_t) (lp->port_wwn >> 32),
343410365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
34354b9d588eSMatt Jacob 		}
343610365e5aSMatt Jacob 		break;
343710365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
343810365e5aSMatt Jacob 	{
343910365e5aSMatt Jacob 		char *msg;
344010365e5aSMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
344110365e5aSMatt Jacob 			msg = "Port Database Changed";
344210365e5aSMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
344310365e5aSMatt Jacob 			msg = "Name Server Database Changed";
344410365e5aSMatt Jacob 		} else {
344510365e5aSMatt Jacob 			msg = "Other Change Notify";
344610365e5aSMatt Jacob 		}
3447f7c631bcSMatt Jacob 		/*
3448f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
3449f7c631bcSMatt Jacob 		 */
3450f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running) {
3451f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3452f7c631bcSMatt Jacob 			   "Stopping Loop Down Timer");
3453f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 0;
3454f7c631bcSMatt Jacob 			untimeout(isp_ldt, isp, isp->isp_osinfo.ldt);
3455f7c631bcSMatt Jacob 			callout_handle_init(&isp->isp_osinfo.ldt);
3456f7c631bcSMatt Jacob 		}
345710365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
345810365e5aSMatt Jacob 		isp_freeze_loopdown(isp, msg);
34599cd7268eSMatt Jacob #if __FreeBSD_version < 500000
34609cd7268eSMatt Jacob 		wakeup(&isp->isp_osinfo.kproc);
34619cd7268eSMatt Jacob #else
3462162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
34635d571944SMatt Jacob 		cv_signal(&isp->isp_osinfo.kthread_cv);
3464162e9893SMatt Jacob #else
3465162e9893SMatt Jacob 		wakeup(&isp->isp_osinfo.kthread_cv);
3466162e9893SMatt Jacob #endif
34679cd7268eSMatt Jacob #endif
346857c801f5SMatt Jacob 		break;
346902ab3379SMatt Jacob 	}
3470d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3471e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
3472d81ba9d5SMatt Jacob 	{
3473e5265237SMatt Jacob 		tmd_notify_t *nt = arg;
347464edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3475e5265237SMatt Jacob 		    "target notify code 0x%x", nt->nt_ncode);
3476d81ba9d5SMatt Jacob 		break;
3477d81ba9d5SMatt Jacob 	}
3478d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
3479d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
3480cbf57b47SMatt Jacob 		default:
3481bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3482bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
3483bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
3484d81ba9d5SMatt Jacob 			break;
3485570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
3486570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
3487570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_scsi(isp,
3488570c7a3fSMatt Jacob 				    (in_entry_t *) arg);
3489570c7a3fSMatt Jacob 			} else {
3490570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_fc(isp,
3491570c7a3fSMatt Jacob 				    (in_fcentry_t *) arg);
3492570c7a3fSMatt Jacob 			}
3493570c7a3fSMatt Jacob 			break;
3494d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
3495d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
3496d81ba9d5SMatt Jacob 			break;
3497d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
3498d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
3499d81ba9d5SMatt Jacob 			break;
3500d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
3501d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
3502d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
3503d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
3504d81ba9d5SMatt Jacob 			break;
3505d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
3506d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
350767ff51f1SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) arg);
3508d81ba9d5SMatt Jacob 			break;
3509d81ba9d5SMatt Jacob 		}
3510d81ba9d5SMatt Jacob 		break;
3511d81ba9d5SMatt Jacob #endif
3512ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
3513ab163f5fSMatt Jacob 	{
35141dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
3515ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
3516ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
3517ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
3518ab163f5fSMatt Jacob 		} else {
3519ab163f5fSMatt Jacob 			mbox6 = 0;
3520ab163f5fSMatt Jacob 		}
3521ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
3522570c7a3fSMatt Jacob                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
3523ab163f5fSMatt Jacob                     mbox6, mbox1);
35248a5f89b9SMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
35258a5f89b9SMatt Jacob 		/*
35268a5f89b9SMatt Jacob 		 * XXX: really need a thread to do this right.
35278a5f89b9SMatt Jacob 		 */
35288a5f89b9SMatt Jacob 		if (IS_FC(isp)) {
35298a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
35308a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_loopstate = LOOP_NIL;
35318a5f89b9SMatt Jacob 			isp_freeze_loopdown(isp, "f/w crash");
35328a5f89b9SMatt Jacob 			isp_fw_dump(isp);
35338a5f89b9SMatt Jacob 		}
3534ab163f5fSMatt Jacob 		isp_reinit(isp);
35358a5f89b9SMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
35368a5f89b9SMatt Jacob #endif
3537ab163f5fSMatt Jacob 		break;
3538ab163f5fSMatt Jacob 	}
3539be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
3540be534d5fSMatt Jacob 		break;
3541d81ba9d5SMatt Jacob 	default:
3542b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
3543cbf57b47SMatt Jacob 		break;
3544cbf57b47SMatt Jacob 	}
3545cbf57b47SMatt Jacob 	return (rv);
3546cbf57b47SMatt Jacob }
3547cbf57b47SMatt Jacob 
354892718a7fSMatt Jacob 
354992718a7fSMatt Jacob /*
355092718a7fSMatt Jacob  * Locks are held before coming here.
355192718a7fSMatt Jacob  */
355292718a7fSMatt Jacob void
35539cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
355492718a7fSMatt Jacob {
355510365e5aSMatt Jacob 	if (IS_24XX(isp)) {
355610365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
355710365e5aSMatt Jacob 	} else {
3558ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
355910365e5aSMatt Jacob 	}
356010365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
356192718a7fSMatt Jacob }
3562b09b0095SMatt Jacob 
3563b09b0095SMatt Jacob void
35649cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
3565b09b0095SMatt Jacob {
3566b09b0095SMatt Jacob 	va_list ap;
3567b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
3568b09b0095SMatt Jacob 		return;
3569b09b0095SMatt Jacob 	}
35703c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
3571b09b0095SMatt Jacob 	va_start(ap, fmt);
3572b09b0095SMatt Jacob 	vprintf(fmt, ap);
3573b09b0095SMatt Jacob 	va_end(ap);
3574b09b0095SMatt Jacob 	printf("\n");
3575b09b0095SMatt Jacob }
3576f7c631bcSMatt Jacob 
3577f7c631bcSMatt Jacob uint64_t
3578f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
3579f7c631bcSMatt Jacob {
3580f7c631bcSMatt Jacob 	uint64_t elapsed;
3581f7c631bcSMatt Jacob 	struct timespec x = *b;
3582f7c631bcSMatt Jacob 	timespecsub(&x, a);
3583f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
3584f7c631bcSMatt Jacob 	if (elapsed == 0)
3585f7c631bcSMatt Jacob 		elapsed++;
3586f7c631bcSMatt Jacob 	return (elapsed);
3587f7c631bcSMatt Jacob }
3588f7c631bcSMatt Jacob 
3589f7c631bcSMatt Jacob int
3590f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
3591f7c631bcSMatt Jacob {
3592f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
3593f7c631bcSMatt Jacob 		return (1);
3594f7c631bcSMatt Jacob 	} else {
3595f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
3596f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
3597f7c631bcSMatt Jacob 		return (0);
3598f7c631bcSMatt Jacob 	}
3599f7c631bcSMatt Jacob }
3600f7c631bcSMatt Jacob 
3601f7c631bcSMatt Jacob void
3602f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
3603f7c631bcSMatt Jacob {
3604a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
3605a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
3606f7c631bcSMatt Jacob 
3607f7c631bcSMatt Jacob 	if (usecs == 0) {
3608f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
3609f7c631bcSMatt Jacob 	}
3610a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
3611a4f3a2beSMatt Jacob 
3612f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
3613a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
3614a4f3a2beSMatt Jacob 
3615f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
3616f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
3617a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
3618f7c631bcSMatt Jacob #if __FreeBSD_version < 500000  || !defined(ISP_SMPLOCK)
3619f7c631bcSMatt Jacob 			tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep",
3620f7c631bcSMatt Jacob 			    isp_mstohz(ms));
3621f7c631bcSMatt Jacob #else
3622f7c631bcSMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_mtx, PRIBIO,
3623f7c631bcSMatt Jacob 			    "ispmbx_sleep", isp_mstohz(ms));
3624f7c631bcSMatt Jacob #endif
3625a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3626a4f3a2beSMatt Jacob 				break;
3627a4f3a2beSMatt Jacob 			}
3628a4f3a2beSMatt Jacob 		}
3629f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
3630f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
3631f7c631bcSMatt Jacob 	} else {
3632a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
3633a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
3634f7c631bcSMatt Jacob 				uint32_t isr;
3635f7c631bcSMatt Jacob 				uint16_t sema, mbox;
3636f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
3637f7c631bcSMatt Jacob 					break;
3638f7c631bcSMatt Jacob 				}
3639f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3640f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
3641f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
3642f7c631bcSMatt Jacob 						break;
3643f7c631bcSMatt Jacob 					}
3644f7c631bcSMatt Jacob 				}
3645f7c631bcSMatt Jacob 				USEC_DELAY(100);
3646f7c631bcSMatt Jacob 			}
3647a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3648a4f3a2beSMatt Jacob 				break;
3649a4f3a2beSMatt Jacob 			}
3650a4f3a2beSMatt Jacob 		}
3651f7c631bcSMatt Jacob 	}
3652f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
3653f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
3654f7c631bcSMatt Jacob 		    "%s Mailbox Command (0x%x) Timeout",
3655f7c631bcSMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled",
3656f7c631bcSMatt Jacob 		    isp->isp_lastmbxcmd);
3657f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
3658f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
3659f7c631bcSMatt Jacob 	}
3660f7c631bcSMatt Jacob }
3661f7c631bcSMatt Jacob 
3662f7c631bcSMatt Jacob void
3663f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
3664f7c631bcSMatt Jacob {
3665f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
3666f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
3667f7c631bcSMatt Jacob 	}
3668f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
3669f7c631bcSMatt Jacob }
3670f7c631bcSMatt Jacob 
3671f7c631bcSMatt Jacob void
3672f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
3673f7c631bcSMatt Jacob {
3674f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
3675f7c631bcSMatt Jacob }
3676f7c631bcSMatt Jacob 
3677f7c631bcSMatt Jacob int
3678f7c631bcSMatt Jacob isp_mstohz(int ms)
3679f7c631bcSMatt Jacob {
3680a4f3a2beSMatt Jacob 	int hz;
3681f7c631bcSMatt Jacob 	struct timeval t;
3682f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
3683f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
3684a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
3685a4f3a2beSMatt Jacob 	if (hz < 0) {
3686a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
3687f7c631bcSMatt Jacob 	}
3688a4f3a2beSMatt Jacob 	if (hz == 0) {
3689a4f3a2beSMatt Jacob 		hz = 1;
3690a4f3a2beSMatt Jacob 	}
3691a4f3a2beSMatt Jacob 	return (hz);
3692f7c631bcSMatt Jacob }
3693