xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 70273f90)
1098ca2bdSWarner Losh /*-
2e5265237SMatt Jacob  * Copyright (c) 1997-2006 by Matthew Jacob
3e5265237SMatt Jacob  * All rights reserved.
46054c3f6SMatt Jacob  *
56054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
66054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
76054c3f6SMatt Jacob  * are met:
86054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
96054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
106054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
11aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
12aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
136054c3f6SMatt Jacob  *
146054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
156054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
166054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
176054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
186054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
196054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
206054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
216054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
226054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
236054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
246054c3f6SMatt Jacob  * SUCH DAMAGE.
256054c3f6SMatt Jacob  */
26aad970f1SDavid E. O'Brien 
27799881e0SMatt Jacob /*
28799881e0SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
29799881e0SMatt Jacob  */
30aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
326054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
335d571944SMatt Jacob #include <sys/unistd.h>
345d571944SMatt Jacob #include <sys/kthread.h>
353ea883b4SMatt Jacob #include <machine/stdarg.h>	/* for use by isp_prt below */
365d571944SMatt Jacob #include <sys/conf.h>
374eb49427SMatt Jacob #include <sys/module.h>
385d571944SMatt Jacob #include <sys/ioccom.h>
395d571944SMatt Jacob #include <dev/isp/isp_ioctl.h>
409311717dSMatt Jacob #if	__FreeBSD_version >= 500000
419311717dSMatt Jacob #include <sys/sysctl.h>
4270273f90SMatt Jacob #else
4370273f90SMatt Jacob #include <sys/devicestat.h>
449311717dSMatt Jacob #endif
45f7c631bcSMatt Jacob #include <cam/cam_periph.h>
466c81a0aeSMatt Jacob #include <cam/cam_xpt_periph.h>
476054c3f6SMatt Jacob 
48805e1f82SMatt Jacob #if !defined(CAM_NEW_TRAN_CODE) && __FreeBSD_version >= 700025
49805e1f82SMatt Jacob #define	CAM_NEW_TRAN_CODE	1
50805e1f82SMatt Jacob #endif
51805e1f82SMatt Jacob 
52a1bc34c6SMatt Jacob 
534eb49427SMatt Jacob MODULE_VERSION(isp, 1);
5456c5b842SMark Murray MODULE_DEPEND(isp, cam, 1, 1, 1);
5573030e03SMatt Jacob int isp_announced = 0;
5610365e5aSMatt Jacob int isp_fabric_hysteresis = 5;
5710365e5aSMatt Jacob int isp_loop_down_limit = 300;	/* default loop down limit */
58f7c631bcSMatt Jacob int isp_change_is_bad = 0;	/* "changed" devices are bad */
59f7c631bcSMatt Jacob int isp_quickboot_time = 15;	/* don't wait more than N secs for loop up */
60f7c631bcSMatt Jacob int isp_gone_device_time = 30;	/* grace time before reporting device lost */
61f7c631bcSMatt Jacob static const char *roles[4] = {
62f7c631bcSMatt Jacob     "(none)", "Target", "Initiator", "Target/Initiator"
63f7c631bcSMatt Jacob };
64f7c631bcSMatt Jacob static const char prom3[] =
65f7c631bcSMatt Jacob     "PortID 0x%06x Departed from Target %u because of %s";
6673030e03SMatt Jacob 
67f7c631bcSMatt Jacob static void isp_freeze_loopdown(ispsoftc_t *, char *);
685d571944SMatt Jacob static d_ioctl_t ispioctl;
69f6e75de2SMatt Jacob static void isp_intr_enable(void *);
701dae40ebSMatt Jacob static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
710470d791SMatt Jacob static void isp_poll(struct cam_sim *);
72b85389e1SMatt Jacob static timeout_t isp_watchdog;
73f7c631bcSMatt Jacob static timeout_t isp_ldt;
745d571944SMatt Jacob static void isp_kthread(void *);
75d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
760470d791SMatt Jacob 
77784ed707SMatt Jacob #if __FreeBSD_version < 700000
78784ed707SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
79784ed707SMatt Jacob #endif
80cc8df88bSMatt Jacob 
819cd7268eSMatt Jacob #if __FreeBSD_version < 500000
829cd7268eSMatt Jacob #define ISP_CDEV_MAJOR	248
839cd7268eSMatt Jacob static struct cdevsw isp_cdevsw = {
849cd7268eSMatt Jacob 	/* open */	nullopen,
859cd7268eSMatt Jacob 	/* close */	nullclose,
869cd7268eSMatt Jacob 	/* read */	noread,
879cd7268eSMatt Jacob 	/* write */	nowrite,
889cd7268eSMatt Jacob 	/* ioctl */	ispioctl,
899cd7268eSMatt Jacob 	/* poll */	nopoll,
909cd7268eSMatt Jacob 	/* mmap */	nommap,
919cd7268eSMatt Jacob 	/* strategy */	nostrategy,
929cd7268eSMatt Jacob 	/* name */	"isp",
939cd7268eSMatt Jacob 	/* maj */	ISP_CDEV_MAJOR,
949cd7268eSMatt Jacob 	/* dump */	nodump,
959cd7268eSMatt Jacob 	/* psize */	nopsize,
969cd7268eSMatt Jacob 	/* flags */	D_TAPE,
979cd7268eSMatt Jacob };
989311717dSMatt Jacob #define	isp_sysctl_update(x)	do { ; } while (0)
999cd7268eSMatt Jacob #else
1005d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
101dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
102dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1037ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
1047ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
1055d571944SMatt Jacob };
1069311717dSMatt Jacob static void isp_sysctl_update(ispsoftc_t *);
1079cd7268eSMatt Jacob #endif
1085d571944SMatt Jacob 
1099cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL;
110478f8a96SJustin T. Gibbs 
111478f8a96SJustin T. Gibbs void
1129cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp)
113478f8a96SJustin T. Gibbs {
114ea6f23cdSMatt Jacob 	int primary, secondary;
115478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
116478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
117ea6f23cdSMatt Jacob 	struct cam_sim *sim;
118ea6f23cdSMatt Jacob 	struct cam_path *path;
119478f8a96SJustin T. Gibbs 
120478f8a96SJustin T. Gibbs 	/*
121ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
122ea6f23cdSMatt Jacob 	 */
123ea6f23cdSMatt Jacob 
124ea6f23cdSMatt Jacob 	primary = 0;
125ea6f23cdSMatt Jacob 	secondary = 1;
126ea6f23cdSMatt Jacob 
127ea6f23cdSMatt Jacob 	/*
128ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
129478f8a96SJustin T. Gibbs 	 */
130ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
131478f8a96SJustin T. Gibbs 	if (devq == NULL) {
132478f8a96SJustin T. Gibbs 		return;
133478f8a96SJustin T. Gibbs 	}
134478f8a96SJustin T. Gibbs 
135478f8a96SJustin T. Gibbs 	/*
136ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
137478f8a96SJustin T. Gibbs 	 */
13845c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
139ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
1403c75bb14SMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
141ea6f23cdSMatt Jacob 	if (sim == NULL) {
142478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
14345c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
144478f8a96SJustin T. Gibbs 		return;
145478f8a96SJustin T. Gibbs 	}
14645c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
147f6e75de2SMatt Jacob 
148f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
149f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
15045c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
151f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
15245c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
15345c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
154bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
155bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
156f6e75de2SMatt Jacob 		return;
157f6e75de2SMatt Jacob 	}
158f6e75de2SMatt Jacob 
159ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
160ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
16145c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
162478f8a96SJustin T. Gibbs 		return;
163478f8a96SJustin T. Gibbs 	}
164478f8a96SJustin T. Gibbs 
165ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
166478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
167ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
168ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1695d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
17045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
171478f8a96SJustin T. Gibbs 		return;
172478f8a96SJustin T. Gibbs 	}
173478f8a96SJustin T. Gibbs 
174ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
175478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
176478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
177cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
178ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
179478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
18045c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
181ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
182ea6f23cdSMatt Jacob 	isp->isp_path = path;
1835d571944SMatt Jacob 	/*
1845d571944SMatt Jacob 	 * Create a kernel thread for fibre channel instances. We
1855d571944SMatt Jacob 	 * don't have dual channel FC cards.
1865d571944SMatt Jacob 	 */
1875d571944SMatt Jacob 	if (IS_FC(isp)) {
18845c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
1899cd7268eSMatt Jacob #if __FreeBSD_version >= 500000
1905d571944SMatt Jacob 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
1915d571944SMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
192316ec49aSScott Long 		    RFHIGHPID, 0, "%s: fc_thrd",
1939cd7268eSMatt Jacob 		    device_get_nameunit(isp->isp_dev)))
1949cd7268eSMatt Jacob #else
1959cd7268eSMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
1969cd7268eSMatt Jacob 		    "%s: fc_thrd", device_get_nameunit(isp->isp_dev)))
1979cd7268eSMatt Jacob #endif
1989cd7268eSMatt Jacob 		{
1995d571944SMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
2005d571944SMatt Jacob 			cam_sim_free(sim, TRUE);
2015d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
20245c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
20345c9a36aSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
2045d571944SMatt Jacob 			return;
2055d571944SMatt Jacob 		}
2068e6a12fcSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
207f7c631bcSMatt Jacob 		/*
208f7c631bcSMatt Jacob 		 * We start by being "loop down" if we have an initiator role
209f7c631bcSMatt Jacob 		 */
210f7c631bcSMatt Jacob 		if (isp->isp_role & ISP_ROLE_INITIATOR) {
211f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, "isp_attach");
212f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt =
213f7c631bcSMatt Jacob 			    timeout(isp_ldt, isp, isp_quickboot_time * hz);
214f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
215f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
216f7c631bcSMatt Jacob 			   "Starting Initial Loop Down Timer");
217f7c631bcSMatt Jacob 		}
2185d571944SMatt Jacob 	}
2195d571944SMatt Jacob 
220478f8a96SJustin T. Gibbs 
221ea6f23cdSMatt Jacob 	/*
222ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
223ea6f23cdSMatt Jacob 	 */
22422e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
22545c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
226ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
2273c75bb14SMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
228ea6f23cdSMatt Jacob 		if (sim == NULL) {
229ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
230ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
231ea6f23cdSMatt Jacob 			cam_simq_free(devq);
2325d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
233ea6f23cdSMatt Jacob 			return;
234ea6f23cdSMatt Jacob 		}
235ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
236ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
237ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
238ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2395d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
24045c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
241ea6f23cdSMatt Jacob 			return;
242ea6f23cdSMatt Jacob 		}
243ea6f23cdSMatt Jacob 
244ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
245ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
246ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
247ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
248ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
249ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2505d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
25145c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
252ea6f23cdSMatt Jacob 			return;
253ea6f23cdSMatt Jacob 		}
254ea6f23cdSMatt Jacob 
255ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
256ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
257ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
258ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
259ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
260ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
26145c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
262ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
263ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
264ea6f23cdSMatt Jacob 	}
2655d571944SMatt Jacob 
2665d571944SMatt Jacob 	/*
2675d571944SMatt Jacob 	 * Create device nodes
2685d571944SMatt Jacob 	 */
2695d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2705d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2715d571944SMatt Jacob 
272d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
273478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
27410365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
275d6e5500fSMatt Jacob 	}
276d81ba9d5SMatt Jacob 	if (isplist == NULL) {
277d81ba9d5SMatt Jacob 		isplist = isp;
278d81ba9d5SMatt Jacob 	} else {
2799cd7268eSMatt Jacob 		ispsoftc_t *tmp = isplist;
280d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
281d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
282d81ba9d5SMatt Jacob 		}
283d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
284478f8a96SJustin T. Gibbs 	}
2859311717dSMatt Jacob 	isp_sysctl_update(isp);
2865d571944SMatt Jacob }
2875d571944SMatt Jacob 
288f7c631bcSMatt Jacob static void
2899cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg)
290fdeb9f2fSMatt Jacob {
291fdeb9f2fSMatt Jacob 	if (isp->isp_osinfo.simqfrozen == 0) {
292fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg);
293fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
294fdeb9f2fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
295fdeb9f2fSMatt Jacob 		xpt_freeze_simq(isp->isp_sim, 1);
296fdeb9f2fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
297fdeb9f2fSMatt Jacob 	} else {
298fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg);
299fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
300fdeb9f2fSMatt Jacob 	}
301fdeb9f2fSMatt Jacob }
302fdeb9f2fSMatt Jacob 
3039cd7268eSMatt Jacob 
3049cd7268eSMatt Jacob #if __FreeBSD_version < 500000
3059cd7268eSMatt Jacob #define	_DEV	dev_t
3069cd7268eSMatt Jacob #define	_IOP	struct proc
3079cd7268eSMatt Jacob #else
3089cd7268eSMatt Jacob #define	_IOP	struct thread
3099cd7268eSMatt Jacob #define	_DEV	struct cdev *
3109cd7268eSMatt Jacob #endif
3119cd7268eSMatt Jacob 
3125d571944SMatt Jacob static int
3139cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td)
3145d571944SMatt Jacob {
3159cd7268eSMatt Jacob 	ispsoftc_t *isp;
316746e9c85SMatt Jacob 	int nr, retval = ENOTTY;
3175d571944SMatt Jacob 
3185d571944SMatt Jacob 	isp = isplist;
3195d571944SMatt Jacob 	while (isp) {
3205d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
3215d571944SMatt Jacob 			break;
3225d571944SMatt Jacob 		}
3235d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
3245d571944SMatt Jacob 	}
3255d571944SMatt Jacob 	if (isp == NULL)
3265d571944SMatt Jacob 		return (ENXIO);
3275d571944SMatt Jacob 
328c1504bc0SMatt Jacob 	switch (c) {
329d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
330d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
33102e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
3321dae40ebSMatt Jacob 			uint16_t *ptr = FCPARAM(isp)->isp_dump_data;
333d134aa0bSMatt Jacob 			size_t sz;
334d134aa0bSMatt Jacob 
335d134aa0bSMatt Jacob 			retval = 0;
33602e2b2d9SMatt Jacob 			if (IS_2200(isp)) {
337d134aa0bSMatt Jacob 				sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
33802e2b2d9SMatt Jacob 			} else {
339d134aa0bSMatt Jacob 				sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
34002e2b2d9SMatt Jacob 			}
341d134aa0bSMatt Jacob 			ISP_LOCK(isp);
342d134aa0bSMatt Jacob 			if (ptr && *ptr) {
343d134aa0bSMatt Jacob 				void *uaddr = *((void **) addr);
344d134aa0bSMatt Jacob 				if (copyout(ptr, uaddr, sz)) {
345d134aa0bSMatt Jacob 					retval = EFAULT;
346d134aa0bSMatt Jacob 				} else {
347d134aa0bSMatt Jacob 					*ptr = 0;
348d134aa0bSMatt Jacob 				}
349d134aa0bSMatt Jacob 			} else {
350d134aa0bSMatt Jacob 				retval = ENXIO;
351d134aa0bSMatt Jacob 			}
352d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
353d134aa0bSMatt Jacob 		}
35402e2b2d9SMatt Jacob 		break;
355d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
35602e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
357d134aa0bSMatt Jacob 			ISP_LOCK(isp);
35802e2b2d9SMatt Jacob 			isp_freeze_loopdown(isp,
35902e2b2d9SMatt Jacob 			    "ispioctl(ISP_FORCE_CRASH_DUMP)");
360d134aa0bSMatt Jacob 			isp_fw_dump(isp);
361d134aa0bSMatt Jacob 			isp_reinit(isp);
362d134aa0bSMatt Jacob 			ISP_UNLOCK(isp);
363d134aa0bSMatt Jacob 			retval = 0;
36402e2b2d9SMatt Jacob 		}
365d134aa0bSMatt Jacob 		break;
366d134aa0bSMatt Jacob #endif
3675d571944SMatt Jacob 	case ISP_SDBLEV:
3685d571944SMatt Jacob 	{
3695d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3705d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3715d571944SMatt Jacob 		*(int *)addr = olddblev;
3725d571944SMatt Jacob 		retval = 0;
3735d571944SMatt Jacob 		break;
3745d571944SMatt Jacob 	}
375746e9c85SMatt Jacob 	case ISP_GETROLE:
376746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
377746e9c85SMatt Jacob 		retval = 0;
378746e9c85SMatt Jacob 		break;
379746e9c85SMatt Jacob 	case ISP_SETROLE:
380746e9c85SMatt Jacob 		nr = *(int *)addr;
381746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
382746e9c85SMatt Jacob 			retval = EINVAL;
383746e9c85SMatt Jacob 			break;
384746e9c85SMatt Jacob 		}
385746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
386746e9c85SMatt Jacob 		isp->isp_role = nr;
387746e9c85SMatt Jacob 		/* FALLTHROUGH */
3885d571944SMatt Jacob 	case ISP_RESETHBA:
3895d571944SMatt Jacob 		ISP_LOCK(isp);
3905d571944SMatt Jacob 		isp_reinit(isp);
3915d571944SMatt Jacob 		ISP_UNLOCK(isp);
3925d571944SMatt Jacob 		retval = 0;
3935d571944SMatt Jacob 		break;
394f553351eSMatt Jacob 	case ISP_RESCAN:
3955d571944SMatt Jacob 		if (IS_FC(isp)) {
3965d571944SMatt Jacob 			ISP_LOCK(isp);
3975d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
3985d571944SMatt Jacob 				retval = EIO;
3995d571944SMatt Jacob 			} else {
4005d571944SMatt Jacob 				retval = 0;
4015d571944SMatt Jacob 			}
4025d571944SMatt Jacob 			ISP_UNLOCK(isp);
4035d571944SMatt Jacob 		}
4045d571944SMatt Jacob 		break;
4055d571944SMatt Jacob 	case ISP_FC_LIP:
4065d571944SMatt Jacob 		if (IS_FC(isp)) {
4075d571944SMatt Jacob 			ISP_LOCK(isp);
4085d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
4095d571944SMatt Jacob 				retval = EIO;
4105d571944SMatt Jacob 			} else {
4115d571944SMatt Jacob 				retval = 0;
4125d571944SMatt Jacob 			}
4135d571944SMatt Jacob 			ISP_UNLOCK(isp);
4145d571944SMatt Jacob 		}
4155d571944SMatt Jacob 		break;
4165d571944SMatt Jacob 	case ISP_FC_GETDINFO:
4175d571944SMatt Jacob 	{
4185d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
41910365e5aSMatt Jacob 		fcportdb_t *lp;
4205d571944SMatt Jacob 
42102e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
42202e2b2d9SMatt Jacob 			break;
42302e2b2d9SMatt Jacob 		}
4245d571944SMatt Jacob 		if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
4255d571944SMatt Jacob 			retval = EINVAL;
4265d571944SMatt Jacob 			break;
4275d571944SMatt Jacob 		}
4285d571944SMatt Jacob 		ISP_LOCK(isp);
4295d571944SMatt Jacob 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
43010365e5aSMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID) {
431c6435ff3SMatt Jacob 			ifc->role = lp->roles;
43210365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4335d571944SMatt Jacob 			ifc->portid = lp->portid;
4345d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4355d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4365d571944SMatt Jacob 			retval = 0;
4375d571944SMatt Jacob 		} else {
4385d571944SMatt Jacob 			retval = ENODEV;
4395d571944SMatt Jacob 		}
4405d571944SMatt Jacob 		ISP_UNLOCK(isp);
4415d571944SMatt Jacob 		break;
4425d571944SMatt Jacob 	}
4432903b272SMatt Jacob 	case ISP_GET_STATS:
4442903b272SMatt Jacob 	{
4452903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4462903b272SMatt Jacob 
4472903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
4482903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4492903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
4502903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
4512903b272SMatt Jacob 		ISP_LOCK(isp);
4522903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
4532903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
4542903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
4552903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
4562903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
4572903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
4582903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
4592903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
4602903b272SMatt Jacob 		ISP_UNLOCK(isp);
4612903b272SMatt Jacob 		retval = 0;
4622903b272SMatt Jacob 		break;
4632903b272SMatt Jacob 	}
4642903b272SMatt Jacob 	case ISP_CLR_STATS:
4652903b272SMatt Jacob 		ISP_LOCK(isp);
4662903b272SMatt Jacob 		isp->isp_intcnt = 0;
4672903b272SMatt Jacob 		isp->isp_intbogus = 0;
4682903b272SMatt Jacob 		isp->isp_intmboxc = 0;
4692903b272SMatt Jacob 		isp->isp_intoasync = 0;
4702903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
4712903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
4722903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
4732903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
4742903b272SMatt Jacob 		ISP_UNLOCK(isp);
4752903b272SMatt Jacob 		retval = 0;
4762903b272SMatt Jacob 		break;
477570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
478570c7a3fSMatt Jacob 	{
479570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
480570c7a3fSMatt Jacob 		MEMZERO(hba, sizeof (*hba));
48102e2b2d9SMatt Jacob 
482a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
483a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
484a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
48502e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
486570c7a3fSMatt Jacob 			hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
487570c7a3fSMatt Jacob 			hba->fc_scsi_supported = 1;
488570c7a3fSMatt Jacob 			hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
489570c7a3fSMatt Jacob 			hba->fc_loopid = FCPARAM(isp)->isp_loopid;
4906c81a0aeSMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp)->isp_wwnn_nvram;
4916c81a0aeSMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp)->isp_wwpn_nvram;
492fd6eb9f7SMatt Jacob 			hba->active_node_wwn = ISP_NODEWWN(isp);
493fd6eb9f7SMatt Jacob 			hba->active_port_wwn = ISP_PORTWWN(isp);
49402e2b2d9SMatt Jacob 		}
495570c7a3fSMatt Jacob 		retval = 0;
496570c7a3fSMatt Jacob 		break;
497570c7a3fSMatt Jacob 	}
498fdeb9f2fSMatt Jacob 	case ISP_GET_FC_PARAM:
499fdeb9f2fSMatt Jacob 	{
500fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
501fdeb9f2fSMatt Jacob 
50202e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
503fdeb9f2fSMatt Jacob 			break;
504fdeb9f2fSMatt Jacob 		}
505fdeb9f2fSMatt Jacob 		f->parameter = 0;
506fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
507fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_maxfrmlen;
508fdeb9f2fSMatt Jacob 			retval = 0;
509fdeb9f2fSMatt Jacob 			break;
510fdeb9f2fSMatt Jacob 		}
511fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
512fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_execthrottle;
513fdeb9f2fSMatt Jacob 			retval = 0;
514fdeb9f2fSMatt Jacob 			break;
515fdeb9f2fSMatt Jacob 		}
516fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
517fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX)
518fdeb9f2fSMatt Jacob 				f->parameter = 1;
519fdeb9f2fSMatt Jacob 			retval = 0;
520fdeb9f2fSMatt Jacob 			break;
521fdeb9f2fSMatt Jacob 		}
522fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
523fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_loopid;
524fdeb9f2fSMatt Jacob 			retval = 0;
525fdeb9f2fSMatt Jacob 			break;
526fdeb9f2fSMatt Jacob 		}
527fdeb9f2fSMatt Jacob 		retval = EINVAL;
528fdeb9f2fSMatt Jacob 		break;
529fdeb9f2fSMatt Jacob 	}
530fdeb9f2fSMatt Jacob 	case ISP_SET_FC_PARAM:
531fdeb9f2fSMatt Jacob 	{
532fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
5331dae40ebSMatt Jacob 		uint32_t param = f->parameter;
534fdeb9f2fSMatt Jacob 
53502e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
536fdeb9f2fSMatt Jacob 			break;
537fdeb9f2fSMatt Jacob 		}
538fdeb9f2fSMatt Jacob 		f->parameter = 0;
539fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
540fdeb9f2fSMatt Jacob 			if (param != 512 && param != 1024 && param != 1024) {
541fdeb9f2fSMatt Jacob 				retval = EINVAL;
542fdeb9f2fSMatt Jacob 				break;
543fdeb9f2fSMatt Jacob 			}
544fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_maxfrmlen = param;
545fdeb9f2fSMatt Jacob 			retval = 0;
546fdeb9f2fSMatt Jacob 			break;
547fdeb9f2fSMatt Jacob 		}
548fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
549fdeb9f2fSMatt Jacob 			if (param < 16 || param > 255) {
550fdeb9f2fSMatt Jacob 				retval = EINVAL;
551fdeb9f2fSMatt Jacob 				break;
552fdeb9f2fSMatt Jacob 			}
553fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_execthrottle = param;
554fdeb9f2fSMatt Jacob 			retval = 0;
555fdeb9f2fSMatt Jacob 			break;
556fdeb9f2fSMatt Jacob 		}
557fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
558fdeb9f2fSMatt Jacob 			if (param != 0 && param != 1) {
559fdeb9f2fSMatt Jacob 				retval = EINVAL;
560fdeb9f2fSMatt Jacob 				break;
561fdeb9f2fSMatt Jacob 			}
562fdeb9f2fSMatt Jacob 			if (param) {
563fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions |=
564fdeb9f2fSMatt Jacob 				    ICBOPT_FULL_DUPLEX;
565fdeb9f2fSMatt Jacob 			} else {
566fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions &=
567fdeb9f2fSMatt Jacob 				    ~ICBOPT_FULL_DUPLEX;
568fdeb9f2fSMatt Jacob 			}
569fdeb9f2fSMatt Jacob 			retval = 0;
570fdeb9f2fSMatt Jacob 			break;
571fdeb9f2fSMatt Jacob 		}
572fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
573fdeb9f2fSMatt Jacob 			if (param < 0 || param > 125) {
574fdeb9f2fSMatt Jacob 				retval = EINVAL;
575fdeb9f2fSMatt Jacob 				break;
576fdeb9f2fSMatt Jacob 			}
577fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_loopid = param;
578fdeb9f2fSMatt Jacob 			retval = 0;
579fdeb9f2fSMatt Jacob 			break;
580fdeb9f2fSMatt Jacob 		}
581fdeb9f2fSMatt Jacob 		retval = EINVAL;
582fdeb9f2fSMatt Jacob 		break;
583fdeb9f2fSMatt Jacob 	}
5848e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5858e62a8acSMatt Jacob 	{
5868e62a8acSMatt Jacob 		int needmarker;
5878e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5881dae40ebSMatt Jacob 		uint16_t loopid;
5898e62a8acSMatt Jacob 		mbreg_t mbs;
5908e62a8acSMatt Jacob 
5918e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5928e62a8acSMatt Jacob 			break;
5938e62a8acSMatt Jacob 		}
5948e62a8acSMatt Jacob 
5958e62a8acSMatt Jacob 		memset(&mbs, 0, sizeof (mbs));
5968e62a8acSMatt Jacob 		needmarker = retval = 0;
597e5265237SMatt Jacob 		loopid = fct->loopid;
59810365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin == 0) {
599e5265237SMatt Jacob 			loopid <<= 8;
600e5265237SMatt Jacob 		}
6018e62a8acSMatt Jacob 		switch (fct->action) {
602f0f536d1SMatt Jacob 		case IPT_CLEAR_ACA:
6038e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_ACA;
604e5265237SMatt Jacob 			mbs.param[1] = loopid;
6058e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6068e62a8acSMatt Jacob 			break;
607f0f536d1SMatt Jacob 		case IPT_TARGET_RESET:
6088e62a8acSMatt Jacob 			mbs.param[0] = MBOX_TARGET_RESET;
609e5265237SMatt Jacob 			mbs.param[1] = loopid;
6108e62a8acSMatt Jacob 			needmarker = 1;
6118e62a8acSMatt Jacob 			break;
612f0f536d1SMatt Jacob 		case IPT_LUN_RESET:
6138e62a8acSMatt Jacob 			mbs.param[0] = MBOX_LUN_RESET;
614e5265237SMatt Jacob 			mbs.param[1] = loopid;
6158e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6168e62a8acSMatt Jacob 			needmarker = 1;
6178e62a8acSMatt Jacob 			break;
618f0f536d1SMatt Jacob 		case IPT_CLEAR_TASK_SET:
6198e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_TASK_SET;
620e5265237SMatt Jacob 			mbs.param[1] = loopid;
6218e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6228e62a8acSMatt Jacob 			needmarker = 1;
6238e62a8acSMatt Jacob 			break;
624f0f536d1SMatt Jacob 		case IPT_ABORT_TASK_SET:
6258e62a8acSMatt Jacob 			mbs.param[0] = MBOX_ABORT_TASK_SET;
626e5265237SMatt Jacob 			mbs.param[1] = loopid;
6278e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6288e62a8acSMatt Jacob 			needmarker = 1;
6298e62a8acSMatt Jacob 			break;
6308e62a8acSMatt Jacob 		default:
6318e62a8acSMatt Jacob 			retval = EINVAL;
6328e62a8acSMatt Jacob 			break;
6338e62a8acSMatt Jacob 		}
6348e62a8acSMatt Jacob 		if (retval == 0) {
6358e62a8acSMatt Jacob 			ISP_LOCK(isp);
6368e62a8acSMatt Jacob 			if (needmarker) {
6378e62a8acSMatt Jacob 				isp->isp_sendmarker |= 1;
6388e62a8acSMatt Jacob 			}
6398e62a8acSMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6408e62a8acSMatt Jacob 			ISP_UNLOCK(isp);
6418e62a8acSMatt Jacob 			if (retval)
6428e62a8acSMatt Jacob 				retval = EIO;
6438e62a8acSMatt Jacob 		}
6448e62a8acSMatt Jacob 		break;
6458e62a8acSMatt Jacob 	}
6465d571944SMatt Jacob 	default:
6475d571944SMatt Jacob 		break;
6485d571944SMatt Jacob 	}
6495d571944SMatt Jacob 	return (retval);
6500470d791SMatt Jacob }
651478f8a96SJustin T. Gibbs 
6529311717dSMatt Jacob #if __FreeBSD_version >= 500000
6539311717dSMatt Jacob static void
6549311717dSMatt Jacob isp_sysctl_update(ispsoftc_t *isp)
6559311717dSMatt Jacob {
6569311717dSMatt Jacob 	struct sysctl_ctx_list *ctx =
6579311717dSMatt Jacob 	    device_get_sysctl_ctx(isp->isp_osinfo.dev);
6589311717dSMatt Jacob 	struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev);
6599311717dSMatt Jacob 
6609311717dSMatt Jacob 	if (IS_SCSI(isp)) {
6619311717dSMatt Jacob 		return;
6629311717dSMatt Jacob 	}
663f7c631bcSMatt Jacob 
6649311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn,
6659311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x",
6669311717dSMatt Jacob 	    (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp));
6679311717dSMatt Jacob 
6689311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn,
6699311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x",
6709311717dSMatt Jacob 	    (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp));
6719311717dSMatt Jacob 
6729311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6739311717dSMatt Jacob 	       "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0,
6749311717dSMatt Jacob 	       "World Wide Node Name");
675f7c631bcSMatt Jacob 
6769311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6779311717dSMatt Jacob 	       "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0,
6789311717dSMatt Jacob 	       "World Wide Port Name");
679f7c631bcSMatt Jacob 
680f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
681f7c631bcSMatt Jacob 	    "loop_down_limit",
682f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0,
683f7c631bcSMatt Jacob 	    "How long to wait for loop to come back up");
684f7c631bcSMatt Jacob 
685f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
686f7c631bcSMatt Jacob 	    "gone_device_time",
687f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0,
688f7c631bcSMatt Jacob 	    "How long to wait for a device to reappear");
6899311717dSMatt Jacob }
6909311717dSMatt Jacob #endif
6919311717dSMatt Jacob 
692f6e75de2SMatt Jacob static void
693f6e75de2SMatt Jacob isp_intr_enable(void *arg)
694f6e75de2SMatt Jacob {
6959cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
696d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
69710365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
698d6e5500fSMatt Jacob 	}
699f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
700f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
701f6e75de2SMatt Jacob }
702d81ba9d5SMatt Jacob 
703d81ba9d5SMatt Jacob /*
704d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
705d81ba9d5SMatt Jacob  */
706d81ba9d5SMatt Jacob 
707d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
708d81ba9d5SMatt Jacob 
7099cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7109cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int);
7119cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7129cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *);
7139cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int);
714d81ba9d5SMatt Jacob static cam_status
7159cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7169cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7179cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *);
7189cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
7199cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *);
720f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
721a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
722a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
7239cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
7249cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
7259cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
7269cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *);
7279cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
7289cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
729d81ba9d5SMatt Jacob 
73053af7d22SMatt Jacob static __inline int
7319cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
732d81ba9d5SMatt Jacob {
733d81ba9d5SMatt Jacob 	tstate_t *tptr;
734a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
735a1bc34c6SMatt Jacob 	if (tptr == NULL) {
736d81ba9d5SMatt Jacob 		return (0);
737d81ba9d5SMatt Jacob 	}
738d81ba9d5SMatt Jacob 	do {
739a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
740d81ba9d5SMatt Jacob 			return (1);
741d81ba9d5SMatt Jacob 		}
742d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
743d81ba9d5SMatt Jacob 	return (0);
744d81ba9d5SMatt Jacob }
745d81ba9d5SMatt Jacob 
74653af7d22SMatt Jacob static __inline int
7479cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port)
748d81ba9d5SMatt Jacob {
749a1bc34c6SMatt Jacob 	int lo, hi;
750a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
751a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
752a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
753a1bc34c6SMatt Jacob 	} else {
754a1bc34c6SMatt Jacob 		lo = 0;
755a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
756a1bc34c6SMatt Jacob 	}
757a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
758a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
759d81ba9d5SMatt Jacob 			return (1);
760d81ba9d5SMatt Jacob 		}
761d81ba9d5SMatt Jacob 	}
762d81ba9d5SMatt Jacob 	return (0);
763d81ba9d5SMatt Jacob }
764d81ba9d5SMatt Jacob 
76553af7d22SMatt Jacob static __inline tstate_t *
7669cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
767d81ba9d5SMatt Jacob {
76864edff94SMatt Jacob 	tstate_t *tptr = NULL;
769d81ba9d5SMatt Jacob 
770d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
77164edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
772a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
773d81ba9d5SMatt Jacob 			tptr->hold++;
774d81ba9d5SMatt Jacob 			return (tptr);
775d81ba9d5SMatt Jacob 		}
77667ff51f1SMatt Jacob 		return (NULL);
777126ec864SMatt Jacob 	} else {
778126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
77964edff94SMatt Jacob 		if (tptr == NULL) {
78064edff94SMatt Jacob 			return (NULL);
78164edff94SMatt Jacob 		}
782126ec864SMatt Jacob 	}
783d81ba9d5SMatt Jacob 
784d81ba9d5SMatt Jacob 	do {
785a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
786d81ba9d5SMatt Jacob 			tptr->hold++;
787d81ba9d5SMatt Jacob 			return (tptr);
788d81ba9d5SMatt Jacob 		}
789d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
790d81ba9d5SMatt Jacob 	return (tptr);
791d81ba9d5SMatt Jacob }
792d81ba9d5SMatt Jacob 
79353af7d22SMatt Jacob static __inline void
7949cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
795d81ba9d5SMatt Jacob {
796d81ba9d5SMatt Jacob 	if (tptr->hold)
797d81ba9d5SMatt Jacob 		tptr->hold--;
798d81ba9d5SMatt Jacob }
799d81ba9d5SMatt Jacob 
80053af7d22SMatt Jacob static __inline atio_private_data_t *
8019cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag)
80253036e92SMatt Jacob {
80353036e92SMatt Jacob 	atio_private_data_t *atp;
80453036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
80553036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
80653036e92SMatt Jacob 		if (atp->tag == tag)
80753036e92SMatt Jacob 			return (atp);
80853036e92SMatt Jacob 	}
80953036e92SMatt Jacob 	return (NULL);
81053036e92SMatt Jacob }
81153036e92SMatt Jacob 
812d81ba9d5SMatt Jacob static cam_status
8139cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus,
814a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
815d81ba9d5SMatt Jacob {
816d81ba9d5SMatt Jacob 	cam_status status;
817d81ba9d5SMatt Jacob 	lun_id_t lun;
818a1bc34c6SMatt Jacob 	int hfx;
819d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
820d81ba9d5SMatt Jacob 
821d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
822d81ba9d5SMatt Jacob 	if (lun < 0) {
823d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
824d81ba9d5SMatt Jacob 	}
825a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
826d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
827d81ba9d5SMatt Jacob 	}
828ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
829d81ba9d5SMatt Jacob 	if (new == NULL) {
830d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
831d81ba9d5SMatt Jacob 	}
832d81ba9d5SMatt Jacob 
833d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
834d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
835d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
836d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
837d81ba9d5SMatt Jacob 		return (status);
838d81ba9d5SMatt Jacob 	}
839a1bc34c6SMatt Jacob 	new->bus = bus;
840d81ba9d5SMatt Jacob 	new->lun = lun;
841d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
842d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
843d81ba9d5SMatt Jacob 	new->hold = 1;
844d81ba9d5SMatt Jacob 
845a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
846a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
847a1bc34c6SMatt Jacob 	if (tptr == NULL) {
848a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
849d81ba9d5SMatt Jacob 	} else {
850d81ba9d5SMatt Jacob 		while (tptr->next)
851d81ba9d5SMatt Jacob 			tptr = tptr->next;
852d81ba9d5SMatt Jacob 		tptr->next = new;
853d81ba9d5SMatt Jacob 	}
854d81ba9d5SMatt Jacob 	*rslt = new;
855d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
856d81ba9d5SMatt Jacob }
857d81ba9d5SMatt Jacob 
85853af7d22SMatt Jacob static __inline void
8599cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
860d81ba9d5SMatt Jacob {
861a1bc34c6SMatt Jacob 	int hfx;
862d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
863d81ba9d5SMatt Jacob 
864d81ba9d5SMatt Jacob 	if (tptr->hold) {
865d81ba9d5SMatt Jacob 		return;
866d81ba9d5SMatt Jacob 	}
86767ff51f1SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
868a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
869d81ba9d5SMatt Jacob 	if (pw == NULL) {
870d81ba9d5SMatt Jacob 		return;
871a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
872a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
873d81ba9d5SMatt Jacob 	} else {
874d81ba9d5SMatt Jacob 		lw = pw;
875d81ba9d5SMatt Jacob 		pw = lw->next;
876d81ba9d5SMatt Jacob 		while (pw) {
877a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
878d81ba9d5SMatt Jacob 				lw->next = pw->next;
879d81ba9d5SMatt Jacob 				break;
880d81ba9d5SMatt Jacob 			}
881d81ba9d5SMatt Jacob 			lw = pw;
882d81ba9d5SMatt Jacob 			pw = pw->next;
883d81ba9d5SMatt Jacob 		}
884d81ba9d5SMatt Jacob 		if (pw == NULL) {
885d81ba9d5SMatt Jacob 			return;
886d81ba9d5SMatt Jacob 		}
887d81ba9d5SMatt Jacob 	}
888d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
889d81ba9d5SMatt Jacob }
890d81ba9d5SMatt Jacob 
8915d571944SMatt Jacob /*
89267ff51f1SMatt Jacob  * Enable luns.
8935d571944SMatt Jacob  */
89467ff51f1SMatt Jacob static int
8959cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb)
896d81ba9d5SMatt Jacob {
897d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
898d81ba9d5SMatt Jacob 	tstate_t *tptr;
8991dae40ebSMatt Jacob 	uint32_t seq;
900746e9c85SMatt Jacob 	int bus, cmd, av, wildcard, tm_on;
901d81ba9d5SMatt Jacob 	lun_id_t lun;
902d81ba9d5SMatt Jacob 	target_id_t tgt;
903d81ba9d5SMatt Jacob 
90467ff51f1SMatt Jacob 	bus = XS_CHANNEL(ccb);
90567ff51f1SMatt Jacob 	if (bus > 1) {
906dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus);
90767ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_PATH_INVALID;
90867ff51f1SMatt Jacob 		return (-1);
90967ff51f1SMatt Jacob 	}
910d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
911d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
912d81ba9d5SMatt Jacob 
913dd9fc7c3SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
914dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n",
91567ff51f1SMatt Jacob 	    	    cel->enable? "en" : "dis", lun, bus);
916dd9fc7c3SMatt Jacob 	}
917d81ba9d5SMatt Jacob 
918d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
919d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
920d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
92167ff51f1SMatt Jacob 		return (-1);
922d81ba9d5SMatt Jacob 	}
92364edff94SMatt Jacob 
9242ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
925a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
926a1bc34c6SMatt Jacob 		sdp += bus;
927d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
928a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
929d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
93067ff51f1SMatt Jacob 			return (-1);
931d81ba9d5SMatt Jacob 		}
932d81ba9d5SMatt Jacob 	} else {
933746e9c85SMatt Jacob 		/*
934746e9c85SMatt Jacob 		 * There's really no point in doing this yet w/o multi-tid
935746e9c85SMatt Jacob 		 * capability. Even then, it's problematic.
936746e9c85SMatt Jacob 		 */
937746e9c85SMatt Jacob #if	0
938d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
939d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
940d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
94167ff51f1SMatt Jacob 			return (-1);
942d81ba9d5SMatt Jacob 		}
943746e9c85SMatt Jacob #endif
94464edff94SMatt Jacob 		/*
94564edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
94664edff94SMatt Jacob 		 */
94710365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_tmode == 0) {
948dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
949dd9fc7c3SMatt Jacob 			    "firmware does not support target mode\n");
95064edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
95167ff51f1SMatt Jacob 			return (-1);
95264edff94SMatt Jacob 		}
95364edff94SMatt Jacob 		/*
95464edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
955dd9fc7c3SMatt Jacob 		 * XXX: dork with our already fragile enable/disable code.
95664edff94SMatt Jacob 		 */
95710365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw == 0) {
958dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
959dd9fc7c3SMatt Jacob 			    "firmware not SCCLUN capable\n");
960746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
96167ff51f1SMatt Jacob 			return (-1);
96264edff94SMatt Jacob 		}
963d81ba9d5SMatt Jacob 	}
964d81ba9d5SMatt Jacob 
965d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
96664edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
96764edff94SMatt Jacob 			wildcard = 1;
96864edff94SMatt Jacob 		} else {
969d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
97067ff51f1SMatt Jacob 			return (-1);
971d6e5500fSMatt Jacob 		}
972126ec864SMatt Jacob 	} else {
973126ec864SMatt Jacob 		wildcard = 0;
974126ec864SMatt Jacob 	}
975b6b6ad2fSMatt Jacob 
976746e9c85SMatt Jacob 	tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0;
977746e9c85SMatt Jacob 
978b6b6ad2fSMatt Jacob 	/*
979b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
98064edff94SMatt Jacob 	 *
98164edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
98264edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
98364edff94SMatt Jacob 	 * handle them locally (if we see them at all).
984b6b6ad2fSMatt Jacob 	 */
985126ec864SMatt Jacob 
986126ec864SMatt Jacob 	if (wildcard) {
987a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
988b6b6ad2fSMatt Jacob 		if (cel->enable) {
98967ff51f1SMatt Jacob 			if (tm_on) {
990b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
99167ff51f1SMatt Jacob 				return (-1);
992b6b6ad2fSMatt Jacob 			}
993b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
994b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
995b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
996b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
997b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
998b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
99967ff51f1SMatt Jacob 				return (-1);
1000b6b6ad2fSMatt Jacob 			}
1001b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
1002b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
100364edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
1004126ec864SMatt Jacob 		} else {
100567ff51f1SMatt Jacob 			if (tm_on == 0) {
1006126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
100767ff51f1SMatt Jacob 				return (-1);
1008126ec864SMatt Jacob 			}
1009126ec864SMatt Jacob 			if (tptr->hold) {
1010126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
101167ff51f1SMatt Jacob 				return (-1);
1012126ec864SMatt Jacob 			}
1013126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
101464edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
1015126ec864SMatt Jacob 		}
1016126ec864SMatt Jacob 	}
1017126ec864SMatt Jacob 
1018126ec864SMatt Jacob 	/*
1019126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
1020126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
1021126ec864SMatt Jacob 	 */
1022126ec864SMatt Jacob 	av = bus << 31;
1023746e9c85SMatt Jacob 	if (cel->enable && tm_on == 0) {
1024a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
1025b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1026b6b6ad2fSMatt Jacob 		if (av) {
1027b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1028126ec864SMatt Jacob 			if (wildcard) {
102964edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
103064edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
1031b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
10325d571944SMatt Jacob 			}
103367ff51f1SMatt Jacob 			return (-1);
1034b6b6ad2fSMatt Jacob 		}
103564edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
1036dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n");
1037746e9c85SMatt Jacob 	} else if (cel->enable == 0 && tm_on && wildcard) {
1038a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
1039b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
104067ff51f1SMatt Jacob 			return (-1);
1041b6b6ad2fSMatt Jacob 		}
1042b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1043b6b6ad2fSMatt Jacob 		if (av) {
1044b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
104567ff51f1SMatt Jacob 			return (-1);
1046b6b6ad2fSMatt Jacob 		}
104764edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
1048dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n");
1049126ec864SMatt Jacob 	}
1050126ec864SMatt Jacob 
1051126ec864SMatt Jacob 	if (wildcard) {
105264edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
105367ff51f1SMatt Jacob 		return (-1);
1054b6b6ad2fSMatt Jacob 	}
1055b6b6ad2fSMatt Jacob 
105667ff51f1SMatt Jacob 	/*
105767ff51f1SMatt Jacob 	 * Find an empty slot
105867ff51f1SMatt Jacob 	 */
105967ff51f1SMatt Jacob 	for (seq = 0; seq < NLEACT; seq++) {
106067ff51f1SMatt Jacob 		if (isp->isp_osinfo.leact[seq] == 0) {
106167ff51f1SMatt Jacob 			break;
106267ff51f1SMatt Jacob 		}
106367ff51f1SMatt Jacob 	}
106467ff51f1SMatt Jacob 	if (seq >= NLEACT) {
106567ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
106667ff51f1SMatt Jacob 		return (-1);
106767ff51f1SMatt Jacob 
106867ff51f1SMatt Jacob 	}
106967ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = ccb;
107067ff51f1SMatt Jacob 
1071d81ba9d5SMatt Jacob 	if (cel->enable) {
1072d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
1073a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
1074d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
107567ff51f1SMatt Jacob 			isp->isp_osinfo.leact[seq] = 0;
107667ff51f1SMatt Jacob 			return (-1);
1077d81ba9d5SMatt Jacob 		}
1078d81ba9d5SMatt Jacob 	} else {
1079a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
1080d81ba9d5SMatt Jacob 		if (tptr == NULL) {
1081d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
108267ff51f1SMatt Jacob 			return (-1);
1083d81ba9d5SMatt Jacob 		}
1084d81ba9d5SMatt Jacob 	}
1085d81ba9d5SMatt Jacob 
1086d81ba9d5SMatt Jacob 	if (cel->enable) {
10875d571944SMatt Jacob 		int c, n, ulun = lun;
10885d571944SMatt Jacob 
10895d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
10905d571944SMatt Jacob 		c = DFLT_CMND_CNT;
10915d571944SMatt Jacob 		n = DFLT_INOT_CNT;
10925d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
10935d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
10945d571944SMatt Jacob 			n = 0;
10955d571944SMatt Jacob 			/*
10965d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
10975d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
10985d571944SMatt Jacob 			 */
10995d571944SMatt Jacob 			ulun = 0;
11005d571944SMatt Jacob 		}
110167ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
110267ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
110367ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
110467ff51f1SMatt Jacob 			return (seq);
1105d81ba9d5SMatt Jacob 		}
1106d81ba9d5SMatt Jacob 	} else {
11075d571944SMatt Jacob 		int c, n, ulun = lun;
1108d81ba9d5SMatt Jacob 
11095d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
11105d571944SMatt Jacob 		c = DFLT_CMND_CNT;
11115d571944SMatt Jacob 		n = DFLT_INOT_CNT;
11125d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
11135d571944SMatt Jacob 			n = 0;
11145d571944SMatt Jacob 			/*
11155d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
11165d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
11175d571944SMatt Jacob 			 */
11185d571944SMatt Jacob 			ulun = 0;
11195d571944SMatt Jacob 		}
112067ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
112167ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
112267ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
112367ff51f1SMatt Jacob 			return (seq);
1124d81ba9d5SMatt Jacob 		}
1125d81ba9d5SMatt Jacob 	}
112667ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
1127dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n");
112867ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
112967ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP_ERR;
113067ff51f1SMatt Jacob 	return (-1);
11315d571944SMatt Jacob }
11325d571944SMatt Jacob 
113367ff51f1SMatt Jacob static void
11349cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
113567ff51f1SMatt Jacob {
1136dd9fc7c3SMatt Jacob 	const char lfmt[] = "now %sabled for target mode";
113767ff51f1SMatt Jacob 	union ccb *ccb;
11381dae40ebSMatt Jacob 	uint32_t seq;
113967ff51f1SMatt Jacob 	tstate_t *tptr;
114067ff51f1SMatt Jacob 	int av;
114167ff51f1SMatt Jacob 	struct ccb_en_lun *cel;
1142d81ba9d5SMatt Jacob 
114367ff51f1SMatt Jacob 	seq = lep->le_reserved - 1;
114467ff51f1SMatt Jacob 	if (seq >= NLEACT) {
11453c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114667ff51f1SMatt Jacob 		    "seq out of range (%u) in isp_ledone", seq);
114767ff51f1SMatt Jacob 		return;
1148d81ba9d5SMatt Jacob 	}
114967ff51f1SMatt Jacob 	ccb = isp->isp_osinfo.leact[seq];
115067ff51f1SMatt Jacob 	if (ccb == 0) {
115167ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
115267ff51f1SMatt Jacob 		    "no ccb for seq %u in isp_ledone", seq);
115367ff51f1SMatt Jacob 		return;
115467ff51f1SMatt Jacob 	}
115567ff51f1SMatt Jacob 	cel = &ccb->cel;
115667ff51f1SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
115767ff51f1SMatt Jacob 	if (tptr == NULL) {
1158dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n");
115967ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
116067ff51f1SMatt Jacob 		return;
1161d81ba9d5SMatt Jacob 	}
116267ff51f1SMatt Jacob 
116367ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
1164dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1165dd9fc7c3SMatt Jacob 		    "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status);
116667ff51f1SMatt Jacob err:
116767ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
116867ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
116967ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
117067ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
117167ff51f1SMatt Jacob 		xpt_done(ccb);
117267ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
117367ff51f1SMatt Jacob 		return;
117467ff51f1SMatt Jacob 	} else {
117567ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
117667ff51f1SMatt Jacob 		    "isp_ledone: ENABLE/MODIFY done okay");
117767ff51f1SMatt Jacob 	}
117867ff51f1SMatt Jacob 
117967ff51f1SMatt Jacob 
118067ff51f1SMatt Jacob 	if (cel->enable) {
118167ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1182dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, lfmt, "en");
118367ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
118467ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
118567ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
118667ff51f1SMatt Jacob 		xpt_done(ccb);
118767ff51f1SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
118867ff51f1SMatt Jacob 		return;
118967ff51f1SMatt Jacob 	}
119067ff51f1SMatt Jacob 
119167ff51f1SMatt Jacob 	if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) {
119267ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb),
119367ff51f1SMatt Jacob 		    XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) {
1194dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1195dd9fc7c3SMatt Jacob 			    "isp_ledone: isp_lun_cmd failed\n");
119667ff51f1SMatt Jacob 			goto err;
119767ff51f1SMatt Jacob 		}
119867ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
119967ff51f1SMatt Jacob 		return;
120067ff51f1SMatt Jacob 	}
120167ff51f1SMatt Jacob 
1202dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, lfmt, "dis");
120367ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
120467ff51f1SMatt Jacob 	destroy_lun_state(isp, tptr);
120567ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
120667ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
120767ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
120867ff51f1SMatt Jacob 	xpt_done(ccb);
120967ff51f1SMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
121067ff51f1SMatt Jacob 	if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) {
121167ff51f1SMatt Jacob 		int bus = XS_CHANNEL(ccb);
121267ff51f1SMatt Jacob 		av = bus << 31;
1213126ec864SMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1214126ec864SMatt Jacob 		if (av) {
1215126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
121667ff51f1SMatt Jacob 			    "disable target mode on channel %d failed", bus);
1217126ec864SMatt Jacob 		}
121867ff51f1SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
121967ff51f1SMatt Jacob 	}
1220126ec864SMatt Jacob }
1221126ec864SMatt Jacob 
1222d81ba9d5SMatt Jacob 
1223d81ba9d5SMatt Jacob static cam_status
12249cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb)
1225d81ba9d5SMatt Jacob {
1226d81ba9d5SMatt Jacob 	tstate_t *tptr;
1227d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
1228d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
1229746e9c85SMatt Jacob 	int found, *ctr;
1230d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
1231d81ba9d5SMatt Jacob 
1232dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb);
1233d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1234746e9c85SMatt Jacob 		int badpath = 0;
1235d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
1236d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
1237746e9c85SMatt Jacob 			badpath = 1;
1238d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
1239d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
1240746e9c85SMatt Jacob 			badpath = 1;
1241746e9c85SMatt Jacob 		}
1242746e9c85SMatt Jacob 		if (badpath) {
1243746e9c85SMatt Jacob 			/*
1244746e9c85SMatt Jacob 			 * Being restrictive about target ids is really about
1245746e9c85SMatt Jacob 			 * making sure we're aborting for the right multi-tid
1246746e9c85SMatt Jacob 			 * path. This doesn't really make much sense at present.
1247746e9c85SMatt Jacob 			 */
1248746e9c85SMatt Jacob #if	0
1249d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1250746e9c85SMatt Jacob #endif
1251d81ba9d5SMatt Jacob 		}
1252d81ba9d5SMatt Jacob 	}
1253a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
1254d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1255dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "can't get statep\n");
1256d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
1257d81ba9d5SMatt Jacob 	}
1258d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1259d81ba9d5SMatt Jacob 		lp = &tptr->atios;
1260746e9c85SMatt Jacob 		ctr = &tptr->atio_count;
1261d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
1262d81ba9d5SMatt Jacob 		lp = &tptr->inots;
1263746e9c85SMatt Jacob 		ctr = &tptr->inot_count;
1264d81ba9d5SMatt Jacob 	} else {
1265d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1266dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "bad function code %d\n",
1267dd9fc7c3SMatt Jacob 		    accb->ccb_h.func_code);
1268d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
1269d81ba9d5SMatt Jacob 	}
1270d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
1271d81ba9d5SMatt Jacob 	found = 0;
1272d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
1273d81ba9d5SMatt Jacob 		found = 1;
1274d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
1275d81ba9d5SMatt Jacob 	} else {
1276d81ba9d5SMatt Jacob 		while(curelm != NULL) {
1277d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
1278d81ba9d5SMatt Jacob 
1279d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
1280d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
1281d81ba9d5SMatt Jacob 				found = 1;
1282d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
1283d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
1284d81ba9d5SMatt Jacob 				break;
1285d81ba9d5SMatt Jacob 			}
1286d81ba9d5SMatt Jacob 			curelm = nextelm;
1287d81ba9d5SMatt Jacob 		}
1288d81ba9d5SMatt Jacob 	}
1289d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1290d81ba9d5SMatt Jacob 	if (found) {
1291c1504bc0SMatt Jacob 		(*ctr)--;
1292d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
1293746e9c85SMatt Jacob 		xpt_done(accb);
1294d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
1295d81ba9d5SMatt Jacob 	}
1296dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb);
1297d81ba9d5SMatt Jacob 	return (CAM_PATH_INVALID);
1298d81ba9d5SMatt Jacob }
1299d81ba9d5SMatt Jacob 
13009cd7268eSMatt Jacob static void
13019cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1302d81ba9d5SMatt Jacob {
1303d81ba9d5SMatt Jacob 	void *qe;
130400a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
130510365e5aSMatt Jacob 	uint32_t nxti, optr, handle;
13061dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1307d81ba9d5SMatt Jacob 
1308f48ce188SMatt Jacob 
13094fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1310dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1311dd9fc7c3SMatt Jacob 		    "Request Queue Overflow in isp_target_start_ctio\n");
13129cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
13139cd7268eSMatt Jacob 		goto out;
1314d81ba9d5SMatt Jacob 	}
131529f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1316d81ba9d5SMatt Jacob 
1317d81ba9d5SMatt Jacob 	/*
1318d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1319d81ba9d5SMatt Jacob 	 */
1320d81ba9d5SMatt Jacob 
1321d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
132253036e92SMatt Jacob 		atio_private_data_t *atp;
13234fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
132400a8e174SMatt Jacob 
1325d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1326d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
132710365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin) {
132829f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
132929f76675SMatt Jacob 		} else {
133000a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
133110365e5aSMatt Jacob 			if (FCPARAM(isp)->isp_sccfw == 0) {
1332d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
13332ad50ca5SMatt Jacob 			}
133429f76675SMatt Jacob 		}
133553036e92SMatt Jacob 
133653036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
133753036e92SMatt Jacob 		if (atp == NULL) {
1338dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1339dd9fc7c3SMatt Jacob 			    "cannot find private data adjunct for tag %x\n",
134053036e92SMatt Jacob 			    cso->tag_id);
13419cd7268eSMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
13429cd7268eSMatt Jacob 			goto out;
134353036e92SMatt Jacob 		}
1344f48ce188SMatt Jacob 
134500a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
134600a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
134700a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1348f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
134900a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1350f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
135153036e92SMatt Jacob 				cto->ct_resid =
135253036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1353570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1354570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1355570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1356570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1357570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1358570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1359570c7a3fSMatt Jacob 				}
1360f48ce188SMatt Jacob 			}
136100a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
136200a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
136329f76675SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp,
136429f76675SMatt Jacob 				    &cso->sense_data, m);
136500a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
136600a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
136700a8e174SMatt Jacob 			}
136800a8e174SMatt Jacob 		} else {
136900a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
137000a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
137100a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
137200a8e174SMatt Jacob 			} else {
137300a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1374d81ba9d5SMatt Jacob 			}
1375570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
1376d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1377d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
137800a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
137953036e92SMatt Jacob 				cto->ct_resid =
138053036e92SMatt Jacob 				    atp->orig_datalen -
138153036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
1382570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1383570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1384570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1385570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1386570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1387570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1388570c7a3fSMatt Jacob 				}
138953036e92SMatt Jacob 			} else {
139053036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1391d81ba9d5SMatt Jacob 			}
1392f48ce188SMatt Jacob 			/*
1393f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1394f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1395f48ce188SMatt Jacob 			 */
139600a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
139700a8e174SMatt Jacob 		}
139853036e92SMatt Jacob 
1399290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
140064edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
140153036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
140253036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
140353036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1404a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1405570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
14069cd7268eSMatt Jacob 		} else {
1407570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
14089cd7268eSMatt Jacob 		}
1409a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1410d81ba9d5SMatt Jacob 	} else {
14114fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
141200a8e174SMatt Jacob 
1413d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1414d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
141500a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1416a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1417d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1418d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1419a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1420a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
14211dae40ebSMatt Jacob 			cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id);
1422f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1423f48ce188SMatt Jacob 		}
1424f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1425f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1426f48ce188SMatt Jacob 		}
1427f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1428d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
142900a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
143000a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
143100a8e174SMatt Jacob 		} else {
143200a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1433d81ba9d5SMatt Jacob 		}
1434f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
143553036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
143600a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
143700a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
143864edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1439a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1440a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1441a1bc34c6SMatt Jacob 			    cso->tag_id);
144292a1e549SMatt Jacob 		}
144364edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1444a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1445d81ba9d5SMatt Jacob 	}
1446d81ba9d5SMatt Jacob 
144710365e5aSMatt Jacob 	if (isp_save_xs_tgt(isp, ccb, &handle)) {
1448dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1449dd9fc7c3SMatt Jacob 		    "No XFLIST pointers for isp_target_start_ctio\n");
14509cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14519cd7268eSMatt Jacob 		goto out;
1452d81ba9d5SMatt Jacob 	}
1453d81ba9d5SMatt Jacob 
1454d81ba9d5SMatt Jacob 
1455d81ba9d5SMatt Jacob 	/*
1456d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1457d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1458b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1459d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1460d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1461d81ba9d5SMatt Jacob 	 * format.
1462d81ba9d5SMatt Jacob 	 */
1463d81ba9d5SMatt Jacob 
146410365e5aSMatt Jacob 	if (IS_FC(isp)) {
146510365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
146610365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146710365e5aSMatt Jacob 	} else {
146810365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
146910365e5aSMatt Jacob 		cto->ct_syshandle = handle;
147010365e5aSMatt Jacob 	}
1471a1bc34c6SMatt Jacob 
14724fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1473d81ba9d5SMatt Jacob 	case CMD_QUEUED:
14744fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
14759cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
14769cd7268eSMatt Jacob 		return;
1477d81ba9d5SMatt Jacob 
1478d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
14799cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14809cd7268eSMatt Jacob 		break;
1481d81ba9d5SMatt Jacob 
1482d81ba9d5SMatt Jacob 	default:
14839cd7268eSMatt Jacob 		break;
1484d81ba9d5SMatt Jacob 	}
148510365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
14869cd7268eSMatt Jacob 
14879cd7268eSMatt Jacob out:
14889cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
14899cd7268eSMatt Jacob 	xpt_done(ccb);
14909cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1491d81ba9d5SMatt Jacob }
1492d81ba9d5SMatt Jacob 
1493a1bc34c6SMatt Jacob static void
1494a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1495f48ce188SMatt Jacob {
1496a1bc34c6SMatt Jacob 	int s = splcam();
1497a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1498a1bc34c6SMatt Jacob 	splx(s);
1499a1bc34c6SMatt Jacob }
1500a1bc34c6SMatt Jacob 
1501a1bc34c6SMatt Jacob static void
1502a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1503a1bc34c6SMatt Jacob {
15049cd7268eSMatt Jacob 	ispsoftc_t *isp;
1505a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
150610365e5aSMatt Jacob 	uint32_t nxti, optr;
1507a1bc34c6SMatt Jacob 	void *qe;
1508a1bc34c6SMatt Jacob 
1509a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1510f48ce188SMatt Jacob 
15114fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1512dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1513dd9fc7c3SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow\n");
1514a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1515a1bc34c6SMatt Jacob 		return;
1516f48ce188SMatt Jacob 	}
151729f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1518a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1519f48ce188SMatt Jacob 	if (IS_FC(isp)) {
15204fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
15214fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1522f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1523f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
152410365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw) {
1525a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1526f48ce188SMatt Jacob 		} else {
1527a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1528f48ce188SMatt Jacob 		}
1529f48ce188SMatt Jacob 		at->at_status = CT_OK;
1530a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1531570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
15324fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1533f48ce188SMatt Jacob 	} else {
15344fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
15354fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1536f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1537f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1538a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1539a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1540a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1541a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1542f48ce188SMatt Jacob 		at->at_status = CT_OK;
1543a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1544a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
15454fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1546f48ce188SMatt Jacob 	}
1547f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
15484fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1549a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1550f48ce188SMatt Jacob }
1551f48ce188SMatt Jacob 
1552f48ce188SMatt Jacob static void
1553a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1554f48ce188SMatt Jacob {
15559cd7268eSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
1556a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1557a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1558f48ce188SMatt Jacob 	}
1559a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1560a1bc34c6SMatt Jacob 	xpt_done(ccb);
15619cd7268eSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
1562f48ce188SMatt Jacob }
1563f48ce188SMatt Jacob 
1564d81ba9d5SMatt Jacob /*
1565d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1566d81ba9d5SMatt Jacob  * This means handling CDBs.
1567d81ba9d5SMatt Jacob  */
1568d81ba9d5SMatt Jacob 
1569d81ba9d5SMatt Jacob static int
15709cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1571d81ba9d5SMatt Jacob {
1572d81ba9d5SMatt Jacob 	tstate_t *tptr;
157364edff94SMatt Jacob 	int status, bus, iswildcard;
1574d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1575d81ba9d5SMatt Jacob 
1576d81ba9d5SMatt Jacob 	/*
1577d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1578d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1579d81ba9d5SMatt Jacob 	 *
1580d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1581d81ba9d5SMatt Jacob 	 *
1582d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
15835d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1584d81ba9d5SMatt Jacob 	 */
1585d81ba9d5SMatt Jacob 	status = aep->at_status;
1586d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1587d81ba9d5SMatt Jacob 		/*
1588d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1589d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1590d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1591d81ba9d5SMatt Jacob 		 */
15923c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1593d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1594d81ba9d5SMatt Jacob 		return (0);
1595d81ba9d5SMatt Jacob 	}
1596d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
15975d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
15983c75bb14SMatt Jacob 		    status);
1599d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1600d81ba9d5SMatt Jacob 		return (0);
1601d81ba9d5SMatt Jacob 	}
1602d81ba9d5SMatt Jacob 
16035d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1604a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1605d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1606a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1607746e9c85SMatt Jacob 		if (tptr == NULL) {
1608d81ba9d5SMatt Jacob 			/*
1609d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1610d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1611d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1612d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1613d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1614d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1615d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1616d81ba9d5SMatt Jacob 			 */
1617d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1618d81ba9d5SMatt Jacob 			return (0);
1619d81ba9d5SMatt Jacob 		}
16208c4e89e2SMatt Jacob 		iswildcard = 1;
16218c4e89e2SMatt Jacob 	} else {
16228c4e89e2SMatt Jacob 		iswildcard = 0;
16238c4e89e2SMatt Jacob 	}
1624d81ba9d5SMatt Jacob 
1625d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1626d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1627d81ba9d5SMatt Jacob 		/*
1628d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1629d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1630d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1631d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1632d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1633d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1634d81ba9d5SMatt Jacob 		 */
1635dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1636dd9fc7c3SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d\n",
16375d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1638d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1639d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1640d81ba9d5SMatt Jacob 		else
1641d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
164264edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1643d81ba9d5SMatt Jacob 		return (0);
1644d81ba9d5SMatt Jacob 	}
1645d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1646746e9c85SMatt Jacob 	tptr->atio_count--;
1647746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1648746e9c85SMatt Jacob 	    aep->at_lun, tptr->atio_count);
164964edff94SMatt Jacob 	if (iswildcard) {
1650d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1651d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1652d81ba9d5SMatt Jacob 	}
1653d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1654f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1655f48ce188SMatt Jacob 	} else {
1656f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1657d81ba9d5SMatt Jacob 	}
1658d81ba9d5SMatt Jacob 
1659f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1660f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1661f48ce188SMatt Jacob 		atiop->sense_len = amt;
1662f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1663f48ce188SMatt Jacob 	} else {
1664f48ce188SMatt Jacob 		atiop->sense_len = 0;
1665f48ce188SMatt Jacob 	}
1666d81ba9d5SMatt Jacob 
16675d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1668d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1669d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1670d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1671a1bc34c6SMatt Jacob 	/*
1672a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1673a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1674a1bc34c6SMatt Jacob 	 */
16756c81a0aeSMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id, bus, device_get_unit(isp->isp_dev), aep);
1676a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1677a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1678d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1679d81ba9d5SMatt Jacob 	}
1680d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
168164edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
16825d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
16835d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
16845d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
16855d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
16865d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1687d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1688d81ba9d5SMatt Jacob 	return (0);
1689d81ba9d5SMatt Jacob }
1690d81ba9d5SMatt Jacob 
1691d81ba9d5SMatt Jacob static int
16929cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
1693d81ba9d5SMatt Jacob {
169492a1e549SMatt Jacob 	lun_id_t lun;
1695d81ba9d5SMatt Jacob 	tstate_t *tptr;
1696d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
169753036e92SMatt Jacob 	atio_private_data_t *atp;
1698d81ba9d5SMatt Jacob 
1699d81ba9d5SMatt Jacob 	/*
1700d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1701d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1702d81ba9d5SMatt Jacob 	 *
1703d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1704d81ba9d5SMatt Jacob 	 */
1705d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
17063c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
17073c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1708d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1709d81ba9d5SMatt Jacob 		return (0);
1710d81ba9d5SMatt Jacob 	}
1711d81ba9d5SMatt Jacob 
171210365e5aSMatt Jacob 	if (FCPARAM(isp)->isp_sccfw) {
171392a1e549SMatt Jacob 		lun = aep->at_scclun;
17142ad50ca5SMatt Jacob 	} else {
171592a1e549SMatt Jacob 		lun = aep->at_lun;
17162ad50ca5SMatt Jacob 	}
1717a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1718d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1719746e9c85SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
1720746e9c85SMatt Jacob 		    "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
1721a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1722746e9c85SMatt Jacob 		if (tptr == NULL) {
1723746e9c85SMatt Jacob 			isp_endcmd(isp, aep,
1724746e9c85SMatt Jacob 			    SCSI_STATUS_CHECK_COND | ECMD_SVALID |
1725746e9c85SMatt Jacob 			    (0x5 << 12) | (0x25 << 16), 0);
1726746e9c85SMatt Jacob 			return (0);
1727746e9c85SMatt Jacob 		}
1728d81ba9d5SMatt Jacob 	}
1729d81ba9d5SMatt Jacob 
173053036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1731d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
173253036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1733746e9c85SMatt Jacob 
1734d81ba9d5SMatt Jacob 		/*
1735d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1736d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1737d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1738d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1739d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1740d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1741d81ba9d5SMatt Jacob 		 */
1742dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1743dd9fc7c3SMatt Jacob 		    "no %s for lun %d from initiator %d\n",
1744570c7a3fSMatt Jacob 		    (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
1745570c7a3fSMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
1746d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1747d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1748d81ba9d5SMatt Jacob 		return (0);
1749d81ba9d5SMatt Jacob 	}
1750570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1751d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1752570c7a3fSMatt Jacob 	tptr->atio_count--;
1753746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1754570c7a3fSMatt Jacob 	    lun, tptr->atio_count);
1755f48ce188SMatt Jacob 
1756a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
175710365e5aSMatt Jacob 		atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid;
175892a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1759d81ba9d5SMatt Jacob 	}
1760b0a3ba7eSMatt Jacob 	/*
1761b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1762b0a3ba7eSMatt Jacob 	 */
1763f48ce188SMatt Jacob 	atiop->sense_len = 0;
1764f48ce188SMatt Jacob 
1765d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1766d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1767d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1768d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1769d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1770d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1771d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1772d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1773d81ba9d5SMatt Jacob 		break;
1774d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1775d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1776d81ba9d5SMatt Jacob 		break;
1777d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1778d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1779d81ba9d5SMatt Jacob 		break;
1780d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1781d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1782d81ba9d5SMatt Jacob 	default:
1783d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1784d81ba9d5SMatt Jacob 		break;
1785d81ba9d5SMatt Jacob 	}
1786570c7a3fSMatt Jacob 	atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
1787f48ce188SMatt Jacob 
178853036e92SMatt Jacob 	atp->tag = atiop->tag_id;
1789570c7a3fSMatt Jacob 	atp->lun = lun;
179053036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
179153036e92SMatt Jacob 	atp->last_xframt = 0;
179253036e92SMatt Jacob 	atp->bytes_xfered = 0;
1793570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
179467ff51f1SMatt Jacob 	ISPLOCK_2_CAMLOCK(siP);
1795d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
1796570c7a3fSMatt Jacob 
179764edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
17985f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
17995f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1800b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1801d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1802d81ba9d5SMatt Jacob 	return (0);
1803d81ba9d5SMatt Jacob }
1804d81ba9d5SMatt Jacob 
1805d81ba9d5SMatt Jacob static int
18069cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
1807d81ba9d5SMatt Jacob {
1808d81ba9d5SMatt Jacob 	union ccb *ccb;
1809a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
18101dae40ebSMatt Jacob 	uint16_t tval;
1811d81ba9d5SMatt Jacob 
1812d81ba9d5SMatt Jacob 	/*
1813d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1814d81ba9d5SMatt Jacob 	 */
1815d81ba9d5SMatt Jacob 
181651e23558SNate Lawson 	ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle);
1817d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
181851e23558SNate Lawson 	isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1819d81ba9d5SMatt Jacob 
1820d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1821d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1822570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
1823570c7a3fSMatt Jacob 		if (atp == NULL) {
1824570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1825570c7a3fSMatt Jacob 			    "cannot find adjunct for %x after I/O",
1826570c7a3fSMatt Jacob 			    ct->ct_rxid);
1827570c7a3fSMatt Jacob 			return (0);
1828570c7a3fSMatt Jacob 		}
1829d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1830d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1831a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
183200a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
183300a8e174SMatt Jacob 		}
1834a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
18355d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
1836a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
183753036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
183853036e92SMatt Jacob 			atp->last_xframt = 0;
1839570c7a3fSMatt Jacob 		}
1840570c7a3fSMatt Jacob 		if (sentstatus || !ok) {
184153036e92SMatt Jacob 			atp->tag = 0;
184253036e92SMatt Jacob 		}
1843570c7a3fSMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
184464edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
184564edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
184664edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
184764edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
184864edff94SMatt Jacob 		tval = ct->ct_rxid;
1849570c7a3fSMatt Jacob 
1850570c7a3fSMatt Jacob 		/* XXX: should really come after isp_complete_ctio */
1851570c7a3fSMatt Jacob 		atp->state = ATPD_STATE_PDON;
1852d81ba9d5SMatt Jacob 	} else {
1853d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1854d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1855d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1856d81ba9d5SMatt Jacob 		/*
1857a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1858a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1859a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1860a1bc34c6SMatt Jacob 		 * private data.
1861a1bc34c6SMatt Jacob 		 *
1862a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1863a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1864a1bc34c6SMatt Jacob 		 */
1865a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1866a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1867a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1868a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1869a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1870a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1871a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1872a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1873a1bc34c6SMatt Jacob 		}
18745d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1875a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1876a1bc34c6SMatt Jacob 		}
187764edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
187864edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
187964edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
188064edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
188164edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
188264edff94SMatt Jacob 		tval = ct->ct_fwhandle;
18835d571944SMatt Jacob 	}
1884a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1885a1bc34c6SMatt Jacob 
1886a1bc34c6SMatt Jacob 	/*
1887a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1888a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1889a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1890d81ba9d5SMatt Jacob 	 *
1891d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1892d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1893a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1894a1bc34c6SMatt Jacob 	 * freed.
1895d81ba9d5SMatt Jacob 	 */
1896f48ce188SMatt Jacob 	if (notify_cam == 0) {
189764edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1898f48ce188SMatt Jacob 		return (0);
1899f48ce188SMatt Jacob 	}
1900d81ba9d5SMatt Jacob 
190153036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
190253036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1903a1bc34c6SMatt Jacob 
1904a1bc34c6SMatt Jacob 	if (!ok) {
1905a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1906d81ba9d5SMatt Jacob 	} else {
1907a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1908a1bc34c6SMatt Jacob 
1909d81ba9d5SMatt Jacob 	}
1910a1bc34c6SMatt Jacob 	return (0);
1911d81ba9d5SMatt Jacob }
1912570c7a3fSMatt Jacob 
1913570c7a3fSMatt Jacob static int
19149cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp)
1915570c7a3fSMatt Jacob {
1916570c7a3fSMatt Jacob 	return (0);	/* XXXX */
1917570c7a3fSMatt Jacob }
1918570c7a3fSMatt Jacob 
1919570c7a3fSMatt Jacob static int
19209cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
1921570c7a3fSMatt Jacob {
1922570c7a3fSMatt Jacob 
1923570c7a3fSMatt Jacob 	switch (inp->in_status) {
1924570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
1925570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
1926570c7a3fSMatt Jacob 		   inp->in_iid);
1927570c7a3fSMatt Jacob 		break;
1928570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
1929570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
1930570c7a3fSMatt Jacob 		   inp->in_iid);
1931570c7a3fSMatt Jacob 		break;
1932570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
1933570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
1934570c7a3fSMatt Jacob 		break;
1935570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
1936570c7a3fSMatt Jacob 	{
1937570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
1938570c7a3fSMatt Jacob 		struct ccb_immed_notify *inot = NULL;
1939570c7a3fSMatt Jacob 
1940570c7a3fSMatt Jacob 		if (atp) {
1941570c7a3fSMatt Jacob 			tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
1942570c7a3fSMatt Jacob 			if (tptr) {
1943570c7a3fSMatt Jacob 				inot = (struct ccb_immed_notify *)
1944570c7a3fSMatt Jacob 				    SLIST_FIRST(&tptr->inots);
1945570c7a3fSMatt Jacob 				if (inot) {
1946746e9c85SMatt Jacob 					tptr->inot_count--;
1947570c7a3fSMatt Jacob 					SLIST_REMOVE_HEAD(&tptr->inots,
1948570c7a3fSMatt Jacob 					    sim_links.sle);
1949746e9c85SMatt Jacob 					isp_prt(isp, ISP_LOGTDEBUG0,
1950746e9c85SMatt Jacob 					    "Take FREE INOT count now %d",
1951746e9c85SMatt Jacob 					    tptr->inot_count);
1952570c7a3fSMatt Jacob 				}
1953570c7a3fSMatt Jacob 			}
1954570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1955570c7a3fSMatt Jacob 			   "abort task RX_ID %x IID %d state %d",
1956570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid, atp->state);
1957570c7a3fSMatt Jacob 		} else {
1958570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1959570c7a3fSMatt Jacob 			   "abort task RX_ID %x from iid %d, state unknown",
1960570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid);
1961570c7a3fSMatt Jacob 		}
1962570c7a3fSMatt Jacob 		if (inot) {
1963570c7a3fSMatt Jacob 			inot->initiator_id = inp->in_iid;
1964570c7a3fSMatt Jacob 			inot->sense_len = 0;
1965570c7a3fSMatt Jacob 			inot->message_args[0] = MSG_ABORT_TAG;
1966570c7a3fSMatt Jacob 			inot->message_args[1] = inp->in_seqid & 0xff;
1967570c7a3fSMatt Jacob 			inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
19686b5ec766SMatt Jacob 			inot->ccb_h.status = CAM_MESSAGE_RECV;
1969570c7a3fSMatt Jacob 			xpt_done((union ccb *)inot);
1970570c7a3fSMatt Jacob 		}
1971570c7a3fSMatt Jacob 		break;
1972570c7a3fSMatt Jacob 	}
1973570c7a3fSMatt Jacob 	default:
1974570c7a3fSMatt Jacob 		break;
1975570c7a3fSMatt Jacob 	}
1976570c7a3fSMatt Jacob 	return (0);
1977570c7a3fSMatt Jacob }
1978d81ba9d5SMatt Jacob #endif
1979d81ba9d5SMatt Jacob 
1980478f8a96SJustin T. Gibbs static void
19811dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
1982478f8a96SJustin T. Gibbs {
1983478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
19849cd7268eSMatt Jacob 	ispsoftc_t *isp;
1985478f8a96SJustin T. Gibbs 
1986478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
19879cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
1988478f8a96SJustin T. Gibbs 	switch (code) {
1989478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1990ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
19911dae40ebSMatt Jacob 			uint16_t oflags, nflags;
1992478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1993a1bc34c6SMatt Jacob 			int tgt;
1994478f8a96SJustin T. Gibbs 
1995f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
199641ed683eSMatt Jacob 			if (tgt >= 0) {
1997ea6f23cdSMatt Jacob 				sdp += cam_sim_bus(sim);
199841ed683eSMatt Jacob 				ISP_LOCK(isp);
19999ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
2000a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
20019ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
2002a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
2003478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
2004478f8a96SJustin T. Gibbs 				}
2005a1bc34c6SMatt Jacob #else
2006a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
2007a1bc34c6SMatt Jacob #endif
20089ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
20099ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
2010478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
2011a1bc34c6SMatt Jacob 				isp->isp_update |= (1 << cam_sim_bus(sim));
201241ed683eSMatt Jacob 				(void) isp_control(isp,
201341ed683eSMatt Jacob 				    ISPCTL_UPDATE_PARAMS, NULL);
20149ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
2015f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
2016478f8a96SJustin T. Gibbs 			}
201741ed683eSMatt Jacob 		}
2018478f8a96SJustin T. Gibbs 		break;
2019478f8a96SJustin T. Gibbs 	default:
20203c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
2021478f8a96SJustin T. Gibbs 		break;
2022478f8a96SJustin T. Gibbs 	}
2023478f8a96SJustin T. Gibbs }
2024478f8a96SJustin T. Gibbs 
2025478f8a96SJustin T. Gibbs static void
2026c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
2027478f8a96SJustin T. Gibbs {
20289cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
202910365e5aSMatt Jacob 	uint32_t isr;
203010365e5aSMatt Jacob 	uint16_t sema, mbox;
2031126ec864SMatt Jacob 
2032c40e096eSMatt Jacob 	ISP_LOCK(isp);
2033126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2034126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
2035126ec864SMatt Jacob 	}
2036c40e096eSMatt Jacob 	ISP_UNLOCK(isp);
2037478f8a96SJustin T. Gibbs }
2038478f8a96SJustin T. Gibbs 
2039ab6c4b31SMatt Jacob 
2040f7c631bcSMatt Jacob static int isp_watchdog_work(ispsoftc_t *, XS_T *);
2041f7c631bcSMatt Jacob 
2042f7c631bcSMatt Jacob static int
2043f7c631bcSMatt Jacob isp_watchdog_work(ispsoftc_t *isp, XS_T *xs)
2044cc8df88bSMatt Jacob {
20451dae40ebSMatt Jacob 	uint32_t handle;
2046b85389e1SMatt Jacob 
2047cc8df88bSMatt Jacob 	/*
2048b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
2049b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
2050b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
2051cc8df88bSMatt Jacob 	 */
2052f6e75de2SMatt Jacob 	ISP_LOCK(isp);
2053cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
2054cc8df88bSMatt Jacob 	if (handle) {
205510365e5aSMatt Jacob 		uint32_t isr;
205610365e5aSMatt Jacob 		uint16_t sema, mbox;
2057126ec864SMatt Jacob 
2058b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2059b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
2060b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
2061f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2062f7c631bcSMatt Jacob 			return (1);;
2063b85389e1SMatt Jacob 		}
2064b85389e1SMatt Jacob 
2065b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
2066b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2067b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
2068f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
2069f7c631bcSMatt Jacob 			return (1);
2070b85389e1SMatt Jacob 		}
2071b85389e1SMatt Jacob 
2072b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
2073126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2074126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
2075126ec864SMatt Jacob 		}
2076126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2077b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2078126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
2079f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2080b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
2081f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2082b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
20831fcf5debSMatt Jacob 			/*
20841fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
20851fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
20861fcf5debSMatt Jacob 			 */
2087f7c631bcSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, xs);
20881fcf5debSMatt Jacob 
20891fcf5debSMatt Jacob 			/*
20901fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
20911fcf5debSMatt Jacob 			 */
2092f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
2093f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
2094f6e75de2SMatt Jacob                 	}
2095cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
2096dd9fc7c3SMatt Jacob 			xpt_print(xs->ccb_h.path,
2097dd9fc7c3SMatt Jacob 			    "watchdog timeout for handle 0x%x\n", handle);
2098cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
2099b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2100f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2101cc8df88bSMatt Jacob 			isp_done(xs);
2102f7c631bcSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2103b85389e1SMatt Jacob 		} else {
2104b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2105b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
2106b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
210710365e5aSMatt Jacob 			isp->isp_sendmarker |= 1 << XS_CHANNEL(xs);
2108b85389e1SMatt Jacob 		}
2109f7c631bcSMatt Jacob 		ISP_UNLOCK(isp);
2110f7c631bcSMatt Jacob 		return (1);
2111cc8df88bSMatt Jacob 	}
2112f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
2113f7c631bcSMatt Jacob 	return (0);
2114f7c631bcSMatt Jacob }
2115f7c631bcSMatt Jacob 
2116f7c631bcSMatt Jacob static void
2117f7c631bcSMatt Jacob isp_watchdog(void *arg)
2118f7c631bcSMatt Jacob {
2119f7c631bcSMatt Jacob 	ispsoftc_t *isp;
2120f7c631bcSMatt Jacob 	XS_T *xs = arg;
2121f7c631bcSMatt Jacob 	for (isp = isplist; isp != NULL; isp = isp->isp_osinfo.next) {
2122f7c631bcSMatt Jacob 		if (isp_watchdog_work(isp, xs)) {
2123f7c631bcSMatt Jacob 			break;
2124f7c631bcSMatt Jacob 		}
2125f7c631bcSMatt Jacob 	}
2126f7c631bcSMatt Jacob 	if (isp == NULL) {
2127f7c631bcSMatt Jacob 		printf("isp_watchdog: nobody had %p active\n", arg);
2128f7c631bcSMatt Jacob 	}
2129f7c631bcSMatt Jacob }
2130f7c631bcSMatt Jacob 
2131f7c631bcSMatt Jacob 
213270273f90SMatt Jacob #if __FreeBSD_version >= 600000
2133f7c631bcSMatt Jacob static void
2134ffcf6651SMatt Jacob isp_make_here(ispsoftc_t *isp, int tgt)
2135f7c631bcSMatt Jacob {
2136ffcf6651SMatt Jacob 	union ccb *ccb;
2137ffcf6651SMatt Jacob 	ISPLOCK_2_CAMLOCK(mpt);
2138ffcf6651SMatt Jacob 	/*
2139ffcf6651SMatt Jacob 	 * Allocate a CCB, create a wildcard path for this bus,
2140ffcf6651SMatt Jacob 	 * and schedule a rescan.
2141ffcf6651SMatt Jacob 	 */
2142ffcf6651SMatt Jacob 	ccb = xpt_alloc_ccb_nowait();
2143ffcf6651SMatt Jacob 	if (ccb == NULL) {
2144ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to alloc CCB for rescan");
2145ffcf6651SMatt Jacob 		CAMLOCK_2_ISPLOCK(mpt);
2146ffcf6651SMatt Jacob 		return;
2147ffcf6651SMatt Jacob 	}
2148ffcf6651SMatt Jacob 	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph,
2149ffcf6651SMatt Jacob 	    cam_sim_path(isp->isp_sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2150ffcf6651SMatt Jacob 		CAMLOCK_2_ISPLOCK(mpt);
2151ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
2152ffcf6651SMatt Jacob 		xpt_free_ccb(ccb);
2153ffcf6651SMatt Jacob 		return;
2154ffcf6651SMatt Jacob 	}
2155ffcf6651SMatt Jacob 	xpt_rescan(ccb);
2156ffcf6651SMatt Jacob 	CAMLOCK_2_ISPLOCK(mpt);
2157ffcf6651SMatt Jacob }
2158ffcf6651SMatt Jacob 
2159ffcf6651SMatt Jacob static void
2160ffcf6651SMatt Jacob isp_make_gone(ispsoftc_t *isp, int tgt)
2161ffcf6651SMatt Jacob {
2162ffcf6651SMatt Jacob 	struct cam_path *tp;
2163f7c631bcSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
2164ffcf6651SMatt Jacob 	if (xpt_create_path(&tp, NULL, cam_sim_path(isp->isp_sim), tgt,
2165f7c631bcSMatt Jacob 	    CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
2166ffcf6651SMatt Jacob 		xpt_async(AC_LOST_DEVICE, tp, NULL);
2167ffcf6651SMatt Jacob 		xpt_free_path(tp);
2168f7c631bcSMatt Jacob 	}
2169f7c631bcSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
2170f7c631bcSMatt Jacob }
2171f7c631bcSMatt Jacob #else
2172f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	do { ; } while (0)
2173f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	do { ; } while (0)
2174f7c631bcSMatt Jacob #endif
2175f7c631bcSMatt Jacob 
2176f7c631bcSMatt Jacob 
2177f7c631bcSMatt Jacob /*
2178f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
2179f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
2180f7c631bcSMatt Jacob  * gone away.
2181f7c631bcSMatt Jacob  *
2182f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
2183f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
2184f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
2185f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
2186f7c631bcSMatt Jacob  */
2187f7c631bcSMatt Jacob static void
2188f7c631bcSMatt Jacob isp_gdt(void *arg)
2189f7c631bcSMatt Jacob {
2190f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2191f7c631bcSMatt Jacob 	fcportdb_t *lp;
2192f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
2193f7c631bcSMatt Jacob 
2194f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired");
2195f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2196f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2197f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2198f7c631bcSMatt Jacob 
2199f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
2200f7c631bcSMatt Jacob 			continue;
2201f7c631bcSMatt Jacob 		}
2202f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2203f7c631bcSMatt Jacob 			continue;
2204f7c631bcSMatt Jacob 		}
2205f7c631bcSMatt Jacob 		if (lp->new_reserved == 0) {
2206f7c631bcSMatt Jacob 			continue;
2207f7c631bcSMatt Jacob 		}
2208f7c631bcSMatt Jacob 		lp->new_reserved -= 1;
2209f7c631bcSMatt Jacob 		if (lp->new_reserved != 0) {
2210f7c631bcSMatt Jacob 			more_to_do++;
2211f7c631bcSMatt Jacob 			continue;
2212f7c631bcSMatt Jacob 		}
2213f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2214f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2215f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2216f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
2217f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2218f7c631bcSMatt Jacob 		    "Gone Device Timeout");
2219f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2220f7c631bcSMatt Jacob 	}
2221f7c631bcSMatt Jacob 	if (more_to_do) {
2222f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
2223f7c631bcSMatt Jacob 	} else {
2224f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2225f7c631bcSMatt Jacob 		    "stopping Gone Device Timer");
2226f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt_running = 0;
2227f7c631bcSMatt Jacob 	}
2228f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2229f7c631bcSMatt Jacob }
2230f7c631bcSMatt Jacob 
2231f7c631bcSMatt Jacob /*
2232f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
2233f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
2234f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
2235f7c631bcSMatt Jacob  *
2236f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
2237f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
2238f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
2239f7c631bcSMatt Jacob  */
2240f7c631bcSMatt Jacob static void
2241f7c631bcSMatt Jacob isp_ldt(void *arg)
2242f7c631bcSMatt Jacob {
2243f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2244f7c631bcSMatt Jacob 	fcportdb_t *lp;
2245f7c631bcSMatt Jacob 	int dbidx, tgt;
2246f7c631bcSMatt Jacob 
2247f7c631bcSMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired");
2248f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2249f7c631bcSMatt Jacob 
2250f7c631bcSMatt Jacob 	/*
2251f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
2252f7c631bcSMatt Jacob 	 */
2253f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2254f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2255f7c631bcSMatt Jacob 
2256f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
2257f7c631bcSMatt Jacob 			continue;
2258f7c631bcSMatt Jacob 		}
2259f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2260f7c631bcSMatt Jacob 			continue;
2261f7c631bcSMatt Jacob 		}
2262f7c631bcSMatt Jacob 
2263f7c631bcSMatt Jacob 		/*
2264f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
2265f7c631bcSMatt Jacob 		 */
2266f7c631bcSMatt Jacob 
2267f7c631bcSMatt Jacob 		/*
2268f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
2269f7c631bcSMatt Jacob 		 */
2270f7c631bcSMatt Jacob 		lp->reserved = 1;
2271f7c631bcSMatt Jacob 
2272f7c631bcSMatt Jacob 		/*
2273f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
2274f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
2275f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
2276f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
2277f7c631bcSMatt Jacob 		 */
2278f7c631bcSMatt Jacob 
2279f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2280f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2281f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2282f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2283f7c631bcSMatt Jacob 		    "Loop Down Timeout");
2284f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2285f7c631bcSMatt Jacob 	}
2286f7c631bcSMatt Jacob 
2287f7c631bcSMatt Jacob 	/*
2288f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
2289f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
2290f7c631bcSMatt Jacob 	 */
2291f7c631bcSMatt Jacob 	isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1;
2292f7c631bcSMatt Jacob #if __FreeBSD_version < 500000
2293f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kproc);
2294f7c631bcSMatt Jacob #else
2295f7c631bcSMatt Jacob #ifdef	ISP_SMPLOCK
2296f7c631bcSMatt Jacob 	cv_signal(&isp->isp_osinfo.kthread_cv);
2297f7c631bcSMatt Jacob #else
2298f7c631bcSMatt Jacob 	wakeup(&isp->isp_osinfo.kthread_cv);
2299f7c631bcSMatt Jacob #endif
2300f7c631bcSMatt Jacob #endif
2301f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2302cc8df88bSMatt Jacob }
2303cc8df88bSMatt Jacob 
23045d571944SMatt Jacob static void
23055d571944SMatt Jacob isp_kthread(void *arg)
23065d571944SMatt Jacob {
23079cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
2308f7c631bcSMatt Jacob 	int slp = 0;
23099cd7268eSMatt Jacob #if __FreeBSD_version < 500000
23109cd7268eSMatt Jacob         int s;
23119cd7268eSMatt Jacob 
23129cd7268eSMatt Jacob         s = splcam();
23139cd7268eSMatt Jacob #else
2314162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
23155d571944SMatt Jacob 	mtx_lock(&isp->isp_lock);
2316ee76282eSMatt Jacob #else
2317ee76282eSMatt Jacob 	mtx_lock(&Giant);
2318162e9893SMatt Jacob #endif
23199cd7268eSMatt Jacob #endif
2320fdeb9f2fSMatt Jacob 	/*
2321fdeb9f2fSMatt Jacob 	 * The first loop is for our usage where we have yet to have
2322fdeb9f2fSMatt Jacob 	 * gotten good fibre channel state.
2323fdeb9f2fSMatt Jacob 	 */
23245d571944SMatt Jacob 	for (;;) {
2325f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
2326fdeb9f2fSMatt Jacob 
2327f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2328f7c631bcSMatt Jacob 		    "isp_kthread: checking FC state");
2329f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
233010365e5aSMatt Jacob 		lb = isp_fc_runstate(isp, 250000);
2331f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
233210365e5aSMatt Jacob 		if (lb) {
2333f7c631bcSMatt Jacob 			/*
2334f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
2335f7c631bcSMatt Jacob 			 */
2336f7c631bcSMatt Jacob 			isp->isp_osinfo.loop_down_time += slp;
233710365e5aSMatt Jacob 
233810365e5aSMatt Jacob 			if (lb < 0) {
2339f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
234010365e5aSMatt Jacob 				    "kthread: FC loop not up (down count %d)",
234110365e5aSMatt Jacob 				    isp->isp_osinfo.loop_down_time);
234210365e5aSMatt Jacob 			} else {
2343f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
234410365e5aSMatt Jacob 				    "kthread: FC got to %d (down count %d)",
234510365e5aSMatt Jacob 				    lb, isp->isp_osinfo.loop_down_time);
2346f44257c2SMatt Jacob 			}
234710365e5aSMatt Jacob 
234810365e5aSMatt Jacob 
234910365e5aSMatt Jacob 			/*
235010365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
2351f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
2352f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
2353f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
235410365e5aSMatt Jacob 			 */
2355f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2356f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
235710365e5aSMatt Jacob 			} else {
2358f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2359f7c631bcSMatt Jacob 			}
2360f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2361f7c631bcSMatt Jacob 				isp_freeze_loopdown(isp, "loop limit hit");
2362f7c631bcSMatt Jacob 				slp = 0;
2363f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 10) {
236410365e5aSMatt Jacob 				slp = 1;
2365f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 30) {
2366f7c631bcSMatt Jacob 				slp = 5;
2367f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 60) {
2368f7c631bcSMatt Jacob 				slp = 10;
2369f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 120) {
2370f7c631bcSMatt Jacob 				slp = 20;
2371f7c631bcSMatt Jacob 			} else {
2372f7c631bcSMatt Jacob 				slp = 30;
2373f44257c2SMatt Jacob 			}
237410365e5aSMatt Jacob 
237510365e5aSMatt Jacob 		} else {
2376f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2377f7c631bcSMatt Jacob 			    "isp_kthread: FC state OK");
237810365e5aSMatt Jacob 			isp->isp_osinfo.loop_down_time = 0;
237910365e5aSMatt Jacob 			slp = 0;
23805d571944SMatt Jacob 		}
2381fdeb9f2fSMatt Jacob 
2382f44257c2SMatt Jacob 		/*
238310365e5aSMatt Jacob 		 * If we'd frozen the simq, unfreeze it now so that CAM
238410365e5aSMatt Jacob 		 * can start sending us commands. If the FC state isn't
238510365e5aSMatt Jacob 		 * okay yet, they'll hit that in isp_start which will
238610365e5aSMatt Jacob 		 * freeze the queue again.
2387f44257c2SMatt Jacob 		 */
23885d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
23895d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
23905d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
2391f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2392f7c631bcSMatt Jacob 			    "isp_kthread: releasing simq");
23935d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
23945d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
23955d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
23965d571944SMatt Jacob 		}
2397f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2398f7c631bcSMatt Jacob 		    "isp_kthread: sleep time %d", slp);
23999cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2400f7c631bcSMatt Jacob 		tsleep(&isp->isp_osinfo.kproc, PRIBIO, "ispf",
2401f7c631bcSMatt Jacob 		    slp * hz);
24029cd7268eSMatt Jacob #else
2403162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
2404f7c631bcSMatt Jacob 		cv_timed_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock,
2405f7c631bcSMatt Jacob 		    slp * hz);
2406162e9893SMatt Jacob #else
2407f7c631bcSMatt Jacob 		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "ispf",
2408f7c631bcSMatt Jacob 		    slp * hz);
2409162e9893SMatt Jacob #endif
24109cd7268eSMatt Jacob #endif
241110365e5aSMatt Jacob 		/*
241210365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
241310365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
241410365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
241510365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
241610365e5aSMatt Jacob 		 * to settle.
241710365e5aSMatt Jacob 		 */
241810365e5aSMatt Jacob 		if (slp == 0 && isp->isp_osinfo.hysteresis) {
2419f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2420f7c631bcSMatt Jacob 			    "isp_kthread: sleep hysteresis tick time %d",
2421f7c631bcSMatt Jacob 			    isp->isp_osinfo.hysteresis * hz);
242210365e5aSMatt Jacob 			(void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT",
242310365e5aSMatt Jacob 			    (isp->isp_osinfo.hysteresis * hz));
242410365e5aSMatt Jacob 		}
24255d571944SMatt Jacob 	}
24265d571944SMatt Jacob }
24275d571944SMatt Jacob 
2428cc8df88bSMatt Jacob static void
2429c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
2430478f8a96SJustin T. Gibbs {
2431f7c631bcSMatt Jacob 	int bus, tgt, error, lim;
24329cd7268eSMatt Jacob 	ispsoftc_t *isp;
24334663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
2434478f8a96SJustin T. Gibbs 
2435478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
2436478f8a96SJustin T. Gibbs 
24379cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
2438478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
2439478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
24400470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
24410470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
24425d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
244357c801f5SMatt Jacob 		isp_init(isp);
244457c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
2445f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
244657c801f5SMatt Jacob 			/*
244757c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
244857c801f5SMatt Jacob 			 */
2449b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
24500470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
245157c801f5SMatt Jacob 			xpt_done(ccb);
245257c801f5SMatt Jacob 			return;
245357c801f5SMatt Jacob 		}
245457c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
24555d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
245657c801f5SMatt Jacob 	}
2457b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
2458478f8a96SJustin T. Gibbs 
24595d571944SMatt Jacob 
2460478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
2461478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
2462478f8a96SJustin T. Gibbs 		/*
2463478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
2464478f8a96SJustin T. Gibbs 		 */
2465478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2466478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2467478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
2468478f8a96SJustin T. Gibbs 				xpt_done(ccb);
2469478f8a96SJustin T. Gibbs 				break;
2470478f8a96SJustin T. Gibbs 			}
2471478f8a96SJustin T. Gibbs 		}
24720470d791SMatt Jacob #ifdef	DIAGNOSTIC
24730470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
2474dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
2475478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
24760470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
2477dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
2478478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
2479478f8a96SJustin T. Gibbs 		}
2480478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
2481478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2482478f8a96SJustin T. Gibbs 			break;
2483478f8a96SJustin T. Gibbs 		}
24840470d791SMatt Jacob #endif
24850470d791SMatt Jacob 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
24865d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2487b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
24880470d791SMatt Jacob 		switch (error) {
2489478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
2490f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
2491f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2492478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2493cc8df88bSMatt Jacob 			if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
2494f7c631bcSMatt Jacob 				int ms = ccb->ccb_h.timeout;
2495f7c631bcSMatt Jacob 				if (ms == CAM_TIME_DEFAULT) {
2496f7c631bcSMatt Jacob 					ms = 60*1000;
2497d69a5f7dSMatt Jacob 				}
2498f7c631bcSMatt Jacob 				ccb->ccb_h.timeout_ch =
2499f7c631bcSMatt Jacob 				    timeout(isp_watchdog, ccb, isp_mstohz(ms));
2500b85389e1SMatt Jacob 			} else {
2501b85389e1SMatt Jacob 				callout_handle_init(&ccb->ccb_h.timeout_ch);
2502cc8df88bSMatt Jacob 			}
2503478f8a96SJustin T. Gibbs 			break;
25040470d791SMatt Jacob 		case CMD_RQLATER:
2505f44257c2SMatt Jacob 			/*
2506f44257c2SMatt Jacob 			 * This can only happen for Fibre Channel
2507f44257c2SMatt Jacob 			 */
2508f44257c2SMatt Jacob 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
2509f7c631bcSMatt Jacob 
251010365e5aSMatt Jacob 			/*
2511f7c631bcSMatt Jacob 			 * Handle initial and subsequent loop down cases
251210365e5aSMatt Jacob 			 */
2513f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2514f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
2515f7c631bcSMatt Jacob 			} else {
2516f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2517f7c631bcSMatt Jacob 			}
2518f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2519f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
2520f7c631bcSMatt Jacob 				    "%d.%d downtime (%d) > lim (%d)",
2521f7c631bcSMatt Jacob 				    XS_TGT(ccb), XS_LUN(ccb),
2522f7c631bcSMatt Jacob 				    isp->isp_osinfo.loop_down_time, lim);
2523f7c631bcSMatt Jacob 				ccb->ccb_h.status =
2524f7c631bcSMatt Jacob 				    CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
2525f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
2526f44257c2SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2527f44257c2SMatt Jacob 				xpt_done(ccb);
2528f44257c2SMatt Jacob 				break;
2529f44257c2SMatt Jacob 			}
2530f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2531f7c631bcSMatt Jacob 			    "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
2532f7c631bcSMatt Jacob 			/*
2533f7c631bcSMatt Jacob 			 * Otherwise, retry in a while.
2534f7c631bcSMatt Jacob 			 */
2535fdeb9f2fSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2536f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2537f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2538f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
2539f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
2540478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2541478f8a96SJustin T. Gibbs 			break;
25420470d791SMatt Jacob 		case CMD_EAGAIN:
25435d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2544f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2545f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2546f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
2547478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2548478f8a96SJustin T. Gibbs 			break;
25490470d791SMatt Jacob 		case CMD_COMPLETE:
25500470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
25515d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
25520470d791SMatt Jacob 			break;
25530470d791SMatt Jacob 		default:
2554f7c631bcSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2555bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2556bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
255791f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
2558b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
25590470d791SMatt Jacob 			xpt_done(ccb);
2560478f8a96SJustin T. Gibbs 		}
2561478f8a96SJustin T. Gibbs 		break;
2562478f8a96SJustin T. Gibbs 
2563d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2564478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
256564edff94SMatt Jacob 	{
256610365e5aSMatt Jacob 		int seq, i;
25675d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
256867ff51f1SMatt Jacob 		seq = isp_en_lun(isp, ccb);
256967ff51f1SMatt Jacob 		if (seq < 0) {
25705d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2571478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2572478f8a96SJustin T. Gibbs 			break;
257364edff94SMatt Jacob 		}
257467ff51f1SMatt Jacob 		for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) {
257510365e5aSMatt Jacob 			uint32_t isr;
257610365e5aSMatt Jacob 			uint16_t sema, mbox;
257767ff51f1SMatt Jacob 			if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
257867ff51f1SMatt Jacob 				isp_intr(isp, isr, sema, mbox);
257967ff51f1SMatt Jacob 			}
258067ff51f1SMatt Jacob 			DELAY(1000);
258167ff51f1SMatt Jacob 		}
258267ff51f1SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
258367ff51f1SMatt Jacob 		break;
258467ff51f1SMatt Jacob 	}
2585d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
2586d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
2587d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
2588d81ba9d5SMatt Jacob 	{
2589a1bc34c6SMatt Jacob 		tstate_t *tptr =
2590a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
2591d81ba9d5SMatt Jacob 		if (tptr == NULL) {
2592d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
2593d81ba9d5SMatt Jacob 			xpt_done(ccb);
2594d81ba9d5SMatt Jacob 			break;
2595d81ba9d5SMatt Jacob 		}
2596f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2597f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
2598570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
2599570c7a3fSMatt Jacob 
26005d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2601d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
2602570c7a3fSMatt Jacob 			/*
2603570c7a3fSMatt Jacob 			 * Note that the command itself may not be done-
2604570c7a3fSMatt Jacob 			 * it may not even have had the first CTIO sent.
2605570c7a3fSMatt Jacob 			 */
2606570c7a3fSMatt Jacob 			tptr->atio_count++;
2607570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2608746e9c85SMatt Jacob 			    "Put FREE ATIO, lun %d, count now %d",
2609570c7a3fSMatt Jacob 			    ccb->ccb_h.target_lun, tptr->atio_count);
2610570c7a3fSMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
2611570c7a3fSMatt Jacob 			    sim_links.sle);
2612570c7a3fSMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
2613746e9c85SMatt Jacob 			tptr->inot_count++;
2614746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2615746e9c85SMatt Jacob 			    "Put FREE INOT, lun %d, count now %d",
2616746e9c85SMatt Jacob 			    ccb->ccb_h.target_lun, tptr->inot_count);
2617d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
2618d81ba9d5SMatt Jacob 			    sim_links.sle);
2619570c7a3fSMatt Jacob 		} else {
2620746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");;
2621d81ba9d5SMatt Jacob 		}
2622d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
2623d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
26245d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2625d81ba9d5SMatt Jacob 		break;
2626d81ba9d5SMatt Jacob 	}
2627d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
2628d81ba9d5SMatt Jacob 	{
26295d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
26309cd7268eSMatt Jacob 		isp_target_start_ctio(isp, ccb);
26315d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2632d81ba9d5SMatt Jacob 		break;
2633d81ba9d5SMatt Jacob 	}
2634d81ba9d5SMatt Jacob #endif
2635478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2636d81ba9d5SMatt Jacob 
2637d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2638d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2639d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2640d81ba9d5SMatt Jacob 
26415d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2642ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
26435d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2644478f8a96SJustin T. Gibbs 		if (error) {
2645478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2646478f8a96SJustin T. Gibbs 		} else {
2647478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2648478f8a96SJustin T. Gibbs 		}
2649478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2650478f8a96SJustin T. Gibbs 		break;
2651478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2652d81ba9d5SMatt Jacob 	{
2653d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
26545d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2655d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2656d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2657d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2658d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2659d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2660d81ba9d5SMatt Jacob 			break;
2661d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2662b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2663d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2664d81ba9d5SMatt Jacob 			break;
2665d81ba9d5SMatt Jacob #endif
2666d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2667478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2668478f8a96SJustin T. Gibbs 			if (error) {
2669d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2670478f8a96SJustin T. Gibbs 			} else {
2671478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2672478f8a96SJustin T. Gibbs 			}
2673d81ba9d5SMatt Jacob 			break;
2674d81ba9d5SMatt Jacob 		default:
2675d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2676d81ba9d5SMatt Jacob 			break;
2677d81ba9d5SMatt Jacob 		}
26785d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2679478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2680478f8a96SJustin T. Gibbs 		break;
2681d81ba9d5SMatt Jacob 	}
2682805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2683ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2684805e1f82SMatt Jacob #else
2685805e1f82SMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->flags & CCB_TRANS_CURRENT_SETTINGS)
2686805e1f82SMatt Jacob #endif
2687478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2688478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
26899ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
26909ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
26919ce9bdafSMatt Jacob 			xpt_done(ccb);
26929ce9bdafSMatt Jacob 			break;
26939ce9bdafSMatt Jacob 		}
2694478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
26955d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2696ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2697805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2698805e1f82SMatt Jacob 			sdparam *sdp = isp->isp_param;
2699805e1f82SMatt Jacob 			uint16_t *dptr;
2700805e1f82SMatt Jacob 
2701805e1f82SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2702805e1f82SMatt Jacob 
2703805e1f82SMatt Jacob 			sdp += bus;
2704805e1f82SMatt Jacob 			/*
2705805e1f82SMatt Jacob 			 * We always update (internally) from goal_flags
2706805e1f82SMatt Jacob 			 * so any request to change settings just gets
2707805e1f82SMatt Jacob 			 * vectored to that location.
2708805e1f82SMatt Jacob 			 */
2709805e1f82SMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2710805e1f82SMatt Jacob 
2711805e1f82SMatt Jacob 			/*
2712805e1f82SMatt Jacob 			 * Note that these operations affect the
2713805e1f82SMatt Jacob 			 * the goal flags (goal_flags)- not
2714805e1f82SMatt Jacob 			 * the current state flags. Then we mark
2715805e1f82SMatt Jacob 			 * things so that the next operation to
2716805e1f82SMatt Jacob 			 * this HBA will cause the update to occur.
2717805e1f82SMatt Jacob 			 */
2718805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_DISC_VALID) {
2719805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
2720805e1f82SMatt Jacob 					*dptr |= DPARM_DISC;
2721805e1f82SMatt Jacob 				} else {
2722805e1f82SMatt Jacob 					*dptr &= ~DPARM_DISC;
2723805e1f82SMatt Jacob 				}
2724805e1f82SMatt Jacob 			}
2725805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_TQ_VALID) {
2726805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
2727805e1f82SMatt Jacob 					*dptr |= DPARM_TQING;
2728805e1f82SMatt Jacob 				} else {
2729805e1f82SMatt Jacob 					*dptr &= ~DPARM_TQING;
2730805e1f82SMatt Jacob 				}
2731805e1f82SMatt Jacob 			}
2732805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
2733805e1f82SMatt Jacob 				switch (cts->bus_width) {
2734805e1f82SMatt Jacob 				case MSG_EXT_WDTR_BUS_16_BIT:
2735805e1f82SMatt Jacob 					*dptr |= DPARM_WIDE;
2736805e1f82SMatt Jacob 					break;
2737805e1f82SMatt Jacob 				default:
2738805e1f82SMatt Jacob 					*dptr &= ~DPARM_WIDE;
2739805e1f82SMatt Jacob 				}
2740805e1f82SMatt Jacob 			}
2741805e1f82SMatt Jacob 			/*
2742805e1f82SMatt Jacob 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
2743805e1f82SMatt Jacob 			 * of nonzero will cause us to go to the
2744805e1f82SMatt Jacob 			 * selected (from NVRAM) maximum value for
2745805e1f82SMatt Jacob 			 * this device. At a later point, we'll
2746805e1f82SMatt Jacob 			 * allow finer control.
2747805e1f82SMatt Jacob 			 */
2748805e1f82SMatt Jacob 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
2749805e1f82SMatt Jacob 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
2750805e1f82SMatt Jacob 			    (cts->sync_offset > 0)) {
2751805e1f82SMatt Jacob 				*dptr |= DPARM_SYNC;
2752805e1f82SMatt Jacob 			} else {
2753805e1f82SMatt Jacob 				*dptr &= ~DPARM_SYNC;
2754805e1f82SMatt Jacob 			}
2755805e1f82SMatt Jacob 			*dptr |= DPARM_SAFE_DFLT;
2756805e1f82SMatt Jacob #else
2757ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2758ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2759ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2760ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2761ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
27621dae40ebSMatt Jacob 			uint16_t *dptr;
2763ab163f5fSMatt Jacob 
2764b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
2765b61386a4SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2766b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
2767b61386a4SMatt Jacob 				xpt_done(ccb);
2768b61386a4SMatt Jacob 				break;
2769b61386a4SMatt Jacob 			}
2770b61386a4SMatt Jacob 
2771ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2772ab163f5fSMatt Jacob 			sdp += bus;
2773ab163f5fSMatt Jacob 			/*
27749ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2775ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2776ab163f5fSMatt Jacob 			 * vectored to that location.
2777ab163f5fSMatt Jacob 			 */
27789ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2779ab163f5fSMatt Jacob 
2780ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2781ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2782ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2783ab163f5fSMatt Jacob 				else
2784ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2785ab163f5fSMatt Jacob 			}
2786ab163f5fSMatt Jacob 
2787ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2788ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2789ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2790ab163f5fSMatt Jacob 				else
2791ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2792ab163f5fSMatt Jacob 			}
2793ab163f5fSMatt Jacob 
2794ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2795ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2796ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2797ab163f5fSMatt Jacob 				else
2798ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2799ab163f5fSMatt Jacob 			}
2800ab163f5fSMatt Jacob 
2801ab163f5fSMatt Jacob 			/*
2802ab163f5fSMatt Jacob 			 * XXX: FIX ME
2803ab163f5fSMatt Jacob 			 */
2804ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
28059ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
28069ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2807ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
28089ce9bdafSMatt Jacob 				/*
28099ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
28109ce9bdafSMatt Jacob 				 */
28119ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
28129ce9bdafSMatt Jacob 				    spi->sync_period;
28139ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
28149ce9bdafSMatt Jacob 				    spi->sync_offset;
2815ab163f5fSMatt Jacob 			} else {
2816ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2817ab163f5fSMatt Jacob 			}
2818805e1f82SMatt Jacob #endif
2819bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2820b61386a4SMatt Jacob 			    "SET (%d.%d.%d) to flags %x off %x per %x",
2821b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun,
2822b61386a4SMatt Jacob 			    sdp->isp_devparam[tgt].goal_flags,
28239ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
28249ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2825478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2826ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2827478f8a96SJustin T. Gibbs 		}
28285d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2829478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2830478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2831478f8a96SJustin T. Gibbs 		break;
2832478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2833478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2834478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2835ab163f5fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2836ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2837805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2838805e1f82SMatt Jacob 			/*
2839805e1f82SMatt Jacob 			 * a lot of normal SCSI things don't make sense.
2840805e1f82SMatt Jacob 			 */
2841805e1f82SMatt Jacob 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
2842805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2843805e1f82SMatt Jacob 			/*
2844805e1f82SMatt Jacob 			 * How do you measure the width of a high
2845805e1f82SMatt Jacob 			 * speed serial bus? Well, in bytes.
2846805e1f82SMatt Jacob 			 *
2847805e1f82SMatt Jacob 			 * Offset and period make no sense, though, so we set
2848805e1f82SMatt Jacob 			 * (above) a 'base' transfer speed to be gigabit.
2849805e1f82SMatt Jacob 			 */
2850805e1f82SMatt Jacob 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2851805e1f82SMatt Jacob #else
2852ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
28539b03492aSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
28549b03492aSMatt Jacob 			    &cts->proto_specific.scsi;
2855ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2856ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2857478f8a96SJustin T. Gibbs 
2858ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2859ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2860ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2861ab163f5fSMatt Jacob 			cts->transport_version = 0;
2862ab163f5fSMatt Jacob 
28639b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
28649b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2865ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
28669b03492aSMatt Jacob 			if (fcp->isp_gbspeed == 2) {
286753036e92SMatt Jacob 				fc->bitrate = 200000;
28689b03492aSMatt Jacob 			} else {
2869ab163f5fSMatt Jacob 				fc->bitrate = 100000;
28709b03492aSMatt Jacob 			}
2871ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
287210365e5aSMatt Jacob 				fcportdb_t *lp = &fcp->portdb[tgt];
2873ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2874ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2875ab163f5fSMatt Jacob 				fc->port = lp->portid;
2876ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2877ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2878ab163f5fSMatt Jacob 			}
2879805e1f82SMatt Jacob #endif
2880ab163f5fSMatt Jacob 		} else {
2881805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2882ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2883ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2884ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2885ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2886805e1f82SMatt Jacob #endif
2887ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2888ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
28891dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
2890ab163f5fSMatt Jacob 
2891ea6f23cdSMatt Jacob 			sdp += bus;
2892ab163f5fSMatt Jacob 
2893ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
289483ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
289583ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
289683ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
289783ae4407SMatt Jacob 				    NULL);
28989ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
28999ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
29009ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
29014394c92fSMatt Jacob 			} else {
29029ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
29039ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
29049ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
29054394c92fSMatt Jacob 			}
2906478f8a96SJustin T. Gibbs 
2907805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2908805e1f82SMatt Jacob 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
2909805e1f82SMatt Jacob 
2910805e1f82SMatt Jacob 			if (dval & DPARM_DISC) {
2911805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_DISC_ENB;
2912805e1f82SMatt Jacob 			}
2913805e1f82SMatt Jacob 			if (dval & DPARM_TQING) {
2914805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_TAG_ENB;
2915805e1f82SMatt Jacob 			}
2916805e1f82SMatt Jacob 			if (dval & DPARM_WIDE) {
2917805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2918805e1f82SMatt Jacob 			} else {
2919805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2920805e1f82SMatt Jacob 			}
2921805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
2922805e1f82SMatt Jacob 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2923805e1f82SMatt Jacob 
2924805e1f82SMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
2925805e1f82SMatt Jacob 				cts->sync_period = pval;
2926805e1f82SMatt Jacob 				cts->sync_offset = oval;
2927805e1f82SMatt Jacob 				cts->valid |=
2928805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_RATE_VALID |
2929805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_OFFSET_VALID;
2930805e1f82SMatt Jacob 			}
2931805e1f82SMatt Jacob #else
2932ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2933ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2934ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2935ab163f5fSMatt Jacob 			cts->transport_version = 2;
2936ab163f5fSMatt Jacob 
2937b61386a4SMatt Jacob 			spi->valid = 0;
2938b61386a4SMatt Jacob 			scsi->valid = 0;
2939b61386a4SMatt Jacob 			spi->flags = 0;
2940b61386a4SMatt Jacob 			scsi->flags = 0;
2941ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2942ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2943ab163f5fSMatt Jacob 			}
29449ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2945ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2946ab163f5fSMatt Jacob 				spi->sync_period = pval;
2947b61386a4SMatt Jacob 			} else {
2948b61386a4SMatt Jacob 				spi->sync_offset = 0;
2949b61386a4SMatt Jacob 				spi->sync_period = 0;
2950b61386a4SMatt Jacob 			}
2951ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2952ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2953ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2954ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2955ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2956ab163f5fSMatt Jacob 			} else {
2957ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2958ab163f5fSMatt Jacob 			}
2959ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2960ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2961b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
2962b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2963b61386a4SMatt Jacob 				}
2964ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2965ab163f5fSMatt Jacob 			}
2966805e1f82SMatt Jacob #endif
2967bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2968b61386a4SMatt Jacob 			    "GET %s (%d.%d.%d) to flags %x off %x per %x",
29699ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
2970b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
2971478f8a96SJustin T. Gibbs 		}
2972ab163f5fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2973478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2974478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2975478f8a96SJustin T. Gibbs 		break;
2976478f8a96SJustin T. Gibbs 
2977478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
29789cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2979478f8a96SJustin T. Gibbs 	{
2980478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
29819cd7268eSMatt Jacob 		u_int32_t secs_per_cylinder;
29829cd7268eSMatt Jacob 		u_int32_t size_mb;
2983478f8a96SJustin T. Gibbs 
2984478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2985478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2986478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2987478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2988478f8a96SJustin T. Gibbs 			break;
2989478f8a96SJustin T. Gibbs 		}
29909cd7268eSMatt Jacob 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
29919cd7268eSMatt Jacob 		if (size_mb > 1024) {
29929cd7268eSMatt Jacob 			ccg->heads = 255;
29939cd7268eSMatt Jacob 			ccg->secs_per_track = 63;
29949cd7268eSMatt Jacob 		} else {
29959cd7268eSMatt Jacob 			ccg->heads = 64;
29969cd7268eSMatt Jacob 			ccg->secs_per_track = 32;
29979cd7268eSMatt Jacob 		}
29989cd7268eSMatt Jacob 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
29999cd7268eSMatt Jacob 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
30009cd7268eSMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
3001478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3002478f8a96SJustin T. Gibbs 		break;
3003478f8a96SJustin T. Gibbs 	}
30049cd7268eSMatt Jacob #else
30059cd7268eSMatt Jacob 	{
30069cd7268eSMatt Jacob 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
30079cd7268eSMatt Jacob 		xpt_done(ccb);
30089cd7268eSMatt Jacob 		break;
30099cd7268eSMatt Jacob 	}
30109cd7268eSMatt Jacob #endif
3011478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
3012ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
30135d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3014ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
30155d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3016478f8a96SJustin T. Gibbs 		if (error)
3017478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
30182b052931SMatt Jacob 		else {
3019ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
3020ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
3021ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
30222b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
3023478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
30242b052931SMatt Jacob 		}
3025478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3026478f8a96SJustin T. Gibbs 		break;
3027478f8a96SJustin T. Gibbs 
3028478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
3029478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
3030478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3031478f8a96SJustin T. Gibbs 		break;
3032478f8a96SJustin T. Gibbs 
3033478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
3034478f8a96SJustin T. Gibbs 	{
3035478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
3036478f8a96SJustin T. Gibbs 
3037478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
3038d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3039a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
3040d81ba9d5SMatt Jacob #else
3041478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
3042d81ba9d5SMatt Jacob #endif
3043478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
30440470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
30450470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
30460470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
30474394c92fSMatt Jacob 		if (IS_FC(isp)) {
30484394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
30490470d791SMatt Jacob 			/*
30500470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
30510470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
30520470d791SMatt Jacob 			 */
30530470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
30540470d791SMatt Jacob 
30559deea857SKenneth D. Merry 			/*
30569deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
30579deea857SKenneth D. Merry 			 * Technically not correct because we don't know
30589deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
30599deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
30609deea857SKenneth D. Merry 			 */
306153036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
306253036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
306353036e92SMatt Jacob 			else
30649deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
30650470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
3066805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3067ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
3068805e1f82SMatt Jacob 			cpi->transport_version = 0;
3069805e1f82SMatt Jacob #endif
3070478f8a96SJustin T. Gibbs 		} else {
3071ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
3072ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
30730470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
30744394c92fSMatt Jacob 			cpi->hba_misc = 0;
3075ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
30769deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
3077805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3078ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
3079805e1f82SMatt Jacob 			cpi->transport_version = 2;
3080805e1f82SMatt Jacob #endif
3081478f8a96SJustin T. Gibbs 		}
3082805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3083ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
3084ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
3085805e1f82SMatt Jacob #endif
3086478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
3087478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
3088478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
3089478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
3090478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
3091478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3092478f8a96SJustin T. Gibbs 		break;
3093478f8a96SJustin T. Gibbs 	}
3094478f8a96SJustin T. Gibbs 	default:
3095478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
3096478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3097478f8a96SJustin T. Gibbs 		break;
3098478f8a96SJustin T. Gibbs 	}
3099478f8a96SJustin T. Gibbs }
3100d3a9eb2eSMatt Jacob 
3101d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
3102f7c631bcSMatt Jacob 
3103d3a9eb2eSMatt Jacob void
3104c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
3105d3a9eb2eSMatt Jacob {
31069cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
3107d3a9eb2eSMatt Jacob 
3108d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
3109d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
3110b85389e1SMatt Jacob 
3111d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
3112d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
3113d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
311492a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
311592a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
311692a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
311792a1e549SMatt Jacob 		} else {
3118d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
3119d3a9eb2eSMatt Jacob 		}
312092a1e549SMatt Jacob 	}
3121b85389e1SMatt Jacob 
31220470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
3123d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3124f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0,
3125f7c631bcSMatt Jacob 		    "target %d lun %d CAM status 0x%x SCSI status 0x%x",
3126f7c631bcSMatt Jacob 		    XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status,
3127f7c631bcSMatt Jacob 		    sccb->scsi_status);
3128d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
3129d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
31300470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
3131d3a9eb2eSMatt Jacob 		}
3132d3a9eb2eSMatt Jacob 	}
3133b85389e1SMatt Jacob 
3134b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
3135d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3136dd9fc7c3SMatt Jacob 		xpt_print(sccb->ccb_h.path,
3137dd9fc7c3SMatt Jacob 		    "cam completion status 0x%x\n", sccb->ccb_h.status);
3138d3a9eb2eSMatt Jacob 	}
3139b85389e1SMatt Jacob 
3140b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
3141b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
3142f7c631bcSMatt Jacob 		untimeout(isp_watchdog, sccb, sccb->ccb_h.timeout_ch);
3143b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
3144b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
3145b09b0095SMatt Jacob 			    "finished command on borrowed time");
3146b85389e1SMatt Jacob 		}
3147b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
31485d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3149d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
31505d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3151d3a9eb2eSMatt Jacob 	}
3152b85389e1SMatt Jacob }
3153d3a9eb2eSMatt Jacob 
3154cbf57b47SMatt Jacob int
31559cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg)
3156cbf57b47SMatt Jacob {
3157ea6f23cdSMatt Jacob 	int bus, rv = 0;
315810365e5aSMatt Jacob 	static const char prom[] =
315910365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s\n"
316010365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
316110365e5aSMatt Jacob 	static const char prom2[] =
316210365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s tgt %u\n"
316310365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
3164f7c631bcSMatt Jacob 	char *msg = NULL;
316510365e5aSMatt Jacob 	target_id_t tgt;
316610365e5aSMatt Jacob 	fcportdb_t *lp;
316710365e5aSMatt Jacob 	struct cam_path *tmppath;
316810365e5aSMatt Jacob 
3169cbf57b47SMatt Jacob 	switch (cmd) {
3170cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
31710470d791SMatt Jacob 	{
3172805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3173ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
3174ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
3175805e1f82SMatt Jacob #endif
3176cbf57b47SMatt Jacob 		int flags, tgt;
3177cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
3178ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
3179cbf57b47SMatt Jacob 
318029f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
3181ab163f5fSMatt Jacob 
3182cbf57b47SMatt Jacob 		tgt = *((int *)arg);
3183ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
3184ea6f23cdSMatt Jacob 		tgt &= 0xffff;
3185ea6f23cdSMatt Jacob 		sdp += bus;
318645c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3187cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
3188ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
3189ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
319045c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3191bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3192bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
3193bfbab170SMatt Jacob 			    tgt, bus);
3194cbf57b47SMatt Jacob 			rv = -1;
3195cbf57b47SMatt Jacob 			break;
3196cbf57b47SMatt Jacob 		}
319745c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
31989ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
3199805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3200ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
3201ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
3202ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
3203ab163f5fSMatt Jacob 
3204ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
3205ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
3206ab163f5fSMatt Jacob 
3207ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
3208ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
3209ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3210ab163f5fSMatt Jacob 		}
3211ab163f5fSMatt Jacob 
3212cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
3213ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
3214ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3215ab163f5fSMatt Jacob 		}
3216ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
3217ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
3218ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
3219ab163f5fSMatt Jacob 		} else {
3220ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
3221ab163f5fSMatt Jacob 		}
3222ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
3223ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3224ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
32259ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
32269ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
3227ab163f5fSMatt Jacob 		}
3228805e1f82SMatt Jacob #else
3229805e1f82SMatt Jacob 		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
3230805e1f82SMatt Jacob 		cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
3231805e1f82SMatt Jacob 		if (flags & DPARM_DISC) {
3232805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_DISC_ENB;
3233805e1f82SMatt Jacob 		}
3234805e1f82SMatt Jacob 		if (flags & DPARM_TQING) {
3235805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_TAG_ENB;
3236805e1f82SMatt Jacob 		}
3237805e1f82SMatt Jacob 		cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
3238805e1f82SMatt Jacob 		cts.bus_width = (flags & DPARM_WIDE)?
3239805e1f82SMatt Jacob 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
3240805e1f82SMatt Jacob 		cts.sync_period = sdp->isp_devparam[tgt].actv_period;
3241805e1f82SMatt Jacob 		cts.sync_offset = sdp->isp_devparam[tgt].actv_offset;
3242805e1f82SMatt Jacob 		if (flags & DPARM_SYNC) {
3243805e1f82SMatt Jacob 			cts.valid |=
3244805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_RATE_VALID |
3245805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_OFFSET_VALID;
3246805e1f82SMatt Jacob 		}
3247805e1f82SMatt Jacob #endif
3248b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
3249b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
32509ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
32519ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
3252ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
32535d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
3254ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
3255cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
3256f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
3257cbf57b47SMatt Jacob 		break;
32580470d791SMatt Jacob 	}
325957c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
3260ea6f23cdSMatt Jacob 		bus = *((int *)arg);
3261b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
3262b09b0095SMatt Jacob 		    bus);
3263ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
32645d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
3265ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
32665d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
3267ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
32685d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
326957c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
32705d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
327157c801f5SMatt Jacob 		}
327257c801f5SMatt Jacob 		break;
32735d571944SMatt Jacob 	case ISPASYNC_LIP:
3274f7c631bcSMatt Jacob 		if (msg == NULL) {
3275f7c631bcSMatt Jacob 			msg = "LIP Received";
32765d571944SMatt Jacob 		}
3277f7c631bcSMatt Jacob 		/* FALLTHROUGH */
32785d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
3279f7c631bcSMatt Jacob 		if (msg == NULL) {
3280f7c631bcSMatt Jacob 			msg = "LOOP Reset";
32815d571944SMatt Jacob 		}
3282f7c631bcSMatt Jacob 		/* FALLTHROUGH */
328357c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
3284f7c631bcSMatt Jacob 		if (msg == NULL) {
3285f7c631bcSMatt Jacob 			msg = "LOOP Down";
328657c801f5SMatt Jacob 		}
3287f7c631bcSMatt Jacob 		if (isp->isp_path) {
3288f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, msg);
3289f7c631bcSMatt Jacob 		}
3290f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running == 0) {
3291f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt = timeout(isp_ldt, isp,
3292f7c631bcSMatt Jacob 			    isp->isp_osinfo.loop_down_limit * hz);
3293f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
3294f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3295f7c631bcSMatt Jacob 			   "starting Loop Down Timer");
3296f7c631bcSMatt Jacob 		}
3297f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
329857c801f5SMatt Jacob 		break;
329957c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
33005d571944SMatt Jacob 		/*
33015d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
33025d571944SMatt Jacob 		 * actually do anything because we're waiting for a
33035d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
33045d571944SMatt Jacob 		 * thread to look at the state of the loop again.
33055d571944SMatt Jacob 		 */
3306b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
330757c801f5SMatt Jacob 		break;
330810365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
330910365e5aSMatt Jacob 		lp = arg;
3310f7c631bcSMatt Jacob 		lp->reserved = 0;
3311f7c631bcSMatt Jacob 		if ((isp->isp_role & ISP_ROLE_INITIATOR) &&
3312f7c631bcSMatt Jacob 		    (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
3313f7c631bcSMatt Jacob 			int dbidx = lp - FCPARAM(isp)->portdb;
3314f7c631bcSMatt Jacob 			int i;
331502ab3379SMatt Jacob 
3316f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
3317f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
3318f7c631bcSMatt Jacob 					continue;
3319f7c631bcSMatt Jacob 				}
3320f7c631bcSMatt Jacob 				if (FCPARAM(isp)->isp_ini_map[i] == 0) {
3321f7c631bcSMatt Jacob 					break;
3322f7c631bcSMatt Jacob 				}
3323f7c631bcSMatt Jacob 			}
3324f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
3325f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[i] = dbidx + 1;
3326f7c631bcSMatt Jacob 				lp->ini_map_idx = i + 1;
3327f7c631bcSMatt Jacob 			} else {
3328f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
3329f7c631bcSMatt Jacob 				isp_dump_portdb(isp);
3330f7c631bcSMatt Jacob 			}
3331f7c631bcSMatt Jacob 		}
333210365e5aSMatt Jacob 		if (lp->ini_map_idx) {
333310365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
333410365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
333510365e5aSMatt Jacob 			    lp->portid, lp->handle,
3336f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived at", tgt,
33371dae40ebSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
333810365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
333910365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
334010365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3341f7c631bcSMatt Jacob 			isp_make_here(isp, tgt);
334210365e5aSMatt Jacob 		} else {
334310365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
334410365e5aSMatt Jacob 			    lp->portid, lp->handle,
3345f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived",
334610365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
334710365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
334810365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
334910365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
335010365e5aSMatt Jacob 		}
335110365e5aSMatt Jacob 		break;
335210365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
335310365e5aSMatt Jacob 		lp = arg;
3354f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
3355f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
335610365e5aSMatt Jacob 			if (lp->ini_map_idx) {
335710365e5aSMatt Jacob 				tgt = lp->ini_map_idx - 1;
3358f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[tgt] = 0;
3359f7c631bcSMatt Jacob 				lp->ini_map_idx = 0;
3360f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3,
3361f7c631bcSMatt Jacob 				    lp->portid, tgt, "change is bad");
3362f7c631bcSMatt Jacob 				isp_make_gone(isp, tgt);
3363f7c631bcSMatt Jacob 			} else {
3364f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
3365f7c631bcSMatt Jacob 				    lp->portid, lp->handle,
3366f7c631bcSMatt Jacob 				    roles[lp->roles],
3367f7c631bcSMatt Jacob 				    "changed and departed",
3368f7c631bcSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
3369f7c631bcSMatt Jacob 				    (uint32_t) lp->node_wwn,
3370f7c631bcSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
3371f7c631bcSMatt Jacob 				    (uint32_t) lp->port_wwn);
3372f7c631bcSMatt Jacob 			}
3373f7c631bcSMatt Jacob 		} else {
3374f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
3375f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
3376f7c631bcSMatt Jacob 			if (lp->ini_map_idx) {
3377f7c631bcSMatt Jacob 				int t = lp->ini_map_idx - 1;
3378f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[t] =
3379f7c631bcSMatt Jacob 				    (lp - FCPARAM(isp)->portdb) + 1;
3380f7c631bcSMatt Jacob 				tgt = lp->ini_map_idx - 1;
338110365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2,
338210365e5aSMatt Jacob 				    lp->portid, lp->handle,
3383f7c631bcSMatt Jacob 				    roles[lp->roles], "changed at", tgt,
338410365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
338510365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
338610365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
338710365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
338810365e5aSMatt Jacob 			} else {
338910365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
339010365e5aSMatt Jacob 				    lp->portid, lp->handle,
3391f7c631bcSMatt Jacob 				    roles[lp->roles], "changed",
339210365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
339310365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
339410365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
339510365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
339610365e5aSMatt Jacob 			}
3397f7c631bcSMatt Jacob 		}
339810365e5aSMatt Jacob 		break;
339910365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
340010365e5aSMatt Jacob 		lp = arg;
340110365e5aSMatt Jacob 		if (lp->ini_map_idx) {
340210365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
340310365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
340410365e5aSMatt Jacob 			    lp->portid, lp->handle,
3405f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed at", tgt,
340610365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
340710365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
340810365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
340910365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
341010365e5aSMatt Jacob 		} else {
341110365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
341210365e5aSMatt Jacob 			    lp->portid, lp->handle,
3413f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed",
341410365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
341510365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
341610365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
341710365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
341810365e5aSMatt Jacob 		}
341910365e5aSMatt Jacob 		break;
342010365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
342110365e5aSMatt Jacob 		lp = arg;
3422f7c631bcSMatt Jacob 		/*
3423f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
3424f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
3425f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
3426f7c631bcSMatt Jacob 		 *
3427f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
3428f7c631bcSMatt Jacob 		 * announce that it's gone.
3429f7c631bcSMatt Jacob 		 */
3430f7c631bcSMatt Jacob 		if (lp->ini_map_idx && lp->reserved == 0) {
3431f7c631bcSMatt Jacob 			lp->reserved = 1;
3432f7c631bcSMatt Jacob 			lp->new_reserved = isp->isp_osinfo.gone_device_time;
3433f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
3434f7c631bcSMatt Jacob 			if (isp->isp_osinfo.gdt_running == 0) {
3435f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3436f7c631bcSMatt Jacob 				    "starting Gone Device Timer");
3437f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt = timeout(isp_gdt, isp, hz);
3438f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt_running = 1;
3439f7c631bcSMatt Jacob 			}
344010365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
344110365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
344210365e5aSMatt Jacob 			    lp->portid, lp->handle,
3443f7c631bcSMatt Jacob 		            roles[lp->roles], "gone zombie at", tgt,
344410365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
344510365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
344610365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
344710365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3448f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
344910365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
345010365e5aSMatt Jacob 			    lp->portid, lp->handle,
3451f7c631bcSMatt Jacob 			    roles[lp->roles], "departed",
345210365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
345310365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
345410365e5aSMatt Jacob 			    (uint32_t) (lp->port_wwn >> 32),
345510365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
34564b9d588eSMatt Jacob 		}
345710365e5aSMatt Jacob 		break;
345810365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
345910365e5aSMatt Jacob 	{
346010365e5aSMatt Jacob 		char *msg;
346110365e5aSMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
346210365e5aSMatt Jacob 			msg = "Port Database Changed";
346310365e5aSMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
346410365e5aSMatt Jacob 			msg = "Name Server Database Changed";
346510365e5aSMatt Jacob 		} else {
346610365e5aSMatt Jacob 			msg = "Other Change Notify";
346710365e5aSMatt Jacob 		}
3468f7c631bcSMatt Jacob 		/*
3469f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
3470f7c631bcSMatt Jacob 		 */
3471f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running) {
3472f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3473f7c631bcSMatt Jacob 			   "Stopping Loop Down Timer");
3474f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 0;
3475f7c631bcSMatt Jacob 			untimeout(isp_ldt, isp, isp->isp_osinfo.ldt);
3476f7c631bcSMatt Jacob 			callout_handle_init(&isp->isp_osinfo.ldt);
3477f7c631bcSMatt Jacob 		}
347810365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
347910365e5aSMatt Jacob 		isp_freeze_loopdown(isp, msg);
34809cd7268eSMatt Jacob #if __FreeBSD_version < 500000
34819cd7268eSMatt Jacob 		wakeup(&isp->isp_osinfo.kproc);
34829cd7268eSMatt Jacob #else
3483162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
34845d571944SMatt Jacob 		cv_signal(&isp->isp_osinfo.kthread_cv);
3485162e9893SMatt Jacob #else
3486162e9893SMatt Jacob 		wakeup(&isp->isp_osinfo.kthread_cv);
3487162e9893SMatt Jacob #endif
34889cd7268eSMatt Jacob #endif
348957c801f5SMatt Jacob 		break;
349002ab3379SMatt Jacob 	}
3491d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3492e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
3493d81ba9d5SMatt Jacob 	{
3494e5265237SMatt Jacob 		tmd_notify_t *nt = arg;
349564edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3496e5265237SMatt Jacob 		    "target notify code 0x%x", nt->nt_ncode);
3497d81ba9d5SMatt Jacob 		break;
3498d81ba9d5SMatt Jacob 	}
3499d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
3500d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
3501cbf57b47SMatt Jacob 		default:
3502bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3503bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
3504bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
3505d81ba9d5SMatt Jacob 			break;
3506570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
3507570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
3508570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_scsi(isp,
3509570c7a3fSMatt Jacob 				    (in_entry_t *) arg);
3510570c7a3fSMatt Jacob 			} else {
3511570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_fc(isp,
3512570c7a3fSMatt Jacob 				    (in_fcentry_t *) arg);
3513570c7a3fSMatt Jacob 			}
3514570c7a3fSMatt Jacob 			break;
3515d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
3516d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
3517d81ba9d5SMatt Jacob 			break;
3518d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
3519d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
3520d81ba9d5SMatt Jacob 			break;
3521d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
3522d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
3523d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
3524d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
3525d81ba9d5SMatt Jacob 			break;
3526d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
3527d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
352867ff51f1SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) arg);
3529d81ba9d5SMatt Jacob 			break;
3530d81ba9d5SMatt Jacob 		}
3531d81ba9d5SMatt Jacob 		break;
3532d81ba9d5SMatt Jacob #endif
3533ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
3534ab163f5fSMatt Jacob 	{
35351dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
3536ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
3537ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
3538ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
3539ab163f5fSMatt Jacob 		} else {
3540ab163f5fSMatt Jacob 			mbox6 = 0;
3541ab163f5fSMatt Jacob 		}
3542ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
3543570c7a3fSMatt Jacob                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
3544ab163f5fSMatt Jacob                     mbox6, mbox1);
35458a5f89b9SMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
35468a5f89b9SMatt Jacob 		/*
35478a5f89b9SMatt Jacob 		 * XXX: really need a thread to do this right.
35488a5f89b9SMatt Jacob 		 */
35498a5f89b9SMatt Jacob 		if (IS_FC(isp)) {
35508a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
35518a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_loopstate = LOOP_NIL;
35528a5f89b9SMatt Jacob 			isp_freeze_loopdown(isp, "f/w crash");
35538a5f89b9SMatt Jacob 			isp_fw_dump(isp);
35548a5f89b9SMatt Jacob 		}
3555ab163f5fSMatt Jacob 		isp_reinit(isp);
35568a5f89b9SMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
35578a5f89b9SMatt Jacob #endif
3558ab163f5fSMatt Jacob 		break;
3559ab163f5fSMatt Jacob 	}
3560be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
3561be534d5fSMatt Jacob 		break;
3562d81ba9d5SMatt Jacob 	default:
3563b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
3564cbf57b47SMatt Jacob 		break;
3565cbf57b47SMatt Jacob 	}
3566cbf57b47SMatt Jacob 	return (rv);
3567cbf57b47SMatt Jacob }
3568cbf57b47SMatt Jacob 
356992718a7fSMatt Jacob 
357092718a7fSMatt Jacob /*
357192718a7fSMatt Jacob  * Locks are held before coming here.
357292718a7fSMatt Jacob  */
357392718a7fSMatt Jacob void
35749cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
357592718a7fSMatt Jacob {
357610365e5aSMatt Jacob 	if (IS_24XX(isp)) {
357710365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
357810365e5aSMatt Jacob 	} else {
3579ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
358010365e5aSMatt Jacob 	}
358110365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
358292718a7fSMatt Jacob }
3583b09b0095SMatt Jacob 
3584b09b0095SMatt Jacob void
35859cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
3586b09b0095SMatt Jacob {
3587b09b0095SMatt Jacob 	va_list ap;
3588b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
3589b09b0095SMatt Jacob 		return;
3590b09b0095SMatt Jacob 	}
35913c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
3592b09b0095SMatt Jacob 	va_start(ap, fmt);
3593b09b0095SMatt Jacob 	vprintf(fmt, ap);
3594b09b0095SMatt Jacob 	va_end(ap);
3595b09b0095SMatt Jacob 	printf("\n");
3596b09b0095SMatt Jacob }
3597f7c631bcSMatt Jacob 
3598f7c631bcSMatt Jacob uint64_t
3599f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
3600f7c631bcSMatt Jacob {
3601f7c631bcSMatt Jacob 	uint64_t elapsed;
3602f7c631bcSMatt Jacob 	struct timespec x = *b;
3603f7c631bcSMatt Jacob 	timespecsub(&x, a);
3604f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
3605f7c631bcSMatt Jacob 	if (elapsed == 0)
3606f7c631bcSMatt Jacob 		elapsed++;
3607f7c631bcSMatt Jacob 	return (elapsed);
3608f7c631bcSMatt Jacob }
3609f7c631bcSMatt Jacob 
3610f7c631bcSMatt Jacob int
3611f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
3612f7c631bcSMatt Jacob {
3613f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
3614f7c631bcSMatt Jacob 		return (1);
3615f7c631bcSMatt Jacob 	} else {
3616f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
3617f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
3618f7c631bcSMatt Jacob 		return (0);
3619f7c631bcSMatt Jacob 	}
3620f7c631bcSMatt Jacob }
3621f7c631bcSMatt Jacob 
3622f7c631bcSMatt Jacob void
3623f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
3624f7c631bcSMatt Jacob {
3625a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
3626a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
3627f7c631bcSMatt Jacob 
3628f7c631bcSMatt Jacob 	if (usecs == 0) {
3629f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
3630f7c631bcSMatt Jacob 	}
3631a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
3632a4f3a2beSMatt Jacob 
3633f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
3634a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
3635a4f3a2beSMatt Jacob 
3636f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
3637f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
3638a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
3639f7c631bcSMatt Jacob #if __FreeBSD_version < 500000  || !defined(ISP_SMPLOCK)
3640f7c631bcSMatt Jacob 			tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep",
3641f7c631bcSMatt Jacob 			    isp_mstohz(ms));
3642f7c631bcSMatt Jacob #else
3643f7c631bcSMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_mtx, PRIBIO,
3644f7c631bcSMatt Jacob 			    "ispmbx_sleep", isp_mstohz(ms));
3645f7c631bcSMatt Jacob #endif
3646a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3647a4f3a2beSMatt Jacob 				break;
3648a4f3a2beSMatt Jacob 			}
3649a4f3a2beSMatt Jacob 		}
3650f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
3651f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
3652f7c631bcSMatt Jacob 	} else {
3653a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
3654a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
3655f7c631bcSMatt Jacob 				uint32_t isr;
3656f7c631bcSMatt Jacob 				uint16_t sema, mbox;
3657f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
3658f7c631bcSMatt Jacob 					break;
3659f7c631bcSMatt Jacob 				}
3660f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3661f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
3662f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
3663f7c631bcSMatt Jacob 						break;
3664f7c631bcSMatt Jacob 					}
3665f7c631bcSMatt Jacob 				}
3666f7c631bcSMatt Jacob 				USEC_DELAY(100);
3667f7c631bcSMatt Jacob 			}
3668a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3669a4f3a2beSMatt Jacob 				break;
3670a4f3a2beSMatt Jacob 			}
3671a4f3a2beSMatt Jacob 		}
3672f7c631bcSMatt Jacob 	}
3673f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
3674f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
3675ffcf6651SMatt Jacob 		    "%s Mailbox Command (0x%x) Timeout (%uus)",
3676f7c631bcSMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled",
3677ffcf6651SMatt Jacob 		    isp->isp_lastmbxcmd, usecs);
3678f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
3679f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
3680f7c631bcSMatt Jacob 	}
3681f7c631bcSMatt Jacob }
3682f7c631bcSMatt Jacob 
3683f7c631bcSMatt Jacob void
3684f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
3685f7c631bcSMatt Jacob {
3686f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
3687f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
3688f7c631bcSMatt Jacob 	}
3689f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
3690f7c631bcSMatt Jacob }
3691f7c631bcSMatt Jacob 
3692f7c631bcSMatt Jacob void
3693f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
3694f7c631bcSMatt Jacob {
3695f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
3696f7c631bcSMatt Jacob }
3697f7c631bcSMatt Jacob 
3698f7c631bcSMatt Jacob int
3699f7c631bcSMatt Jacob isp_mstohz(int ms)
3700f7c631bcSMatt Jacob {
3701a4f3a2beSMatt Jacob 	int hz;
3702f7c631bcSMatt Jacob 	struct timeval t;
3703f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
3704f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
3705a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
3706a4f3a2beSMatt Jacob 	if (hz < 0) {
3707a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
3708f7c631bcSMatt Jacob 	}
3709a4f3a2beSMatt Jacob 	if (hz == 0) {
3710a4f3a2beSMatt Jacob 		hz = 1;
3711a4f3a2beSMatt Jacob 	}
3712a4f3a2beSMatt Jacob 	return (hz);
3713f7c631bcSMatt Jacob }
3714