xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 1fd47020d8c43524289e7138f08c2074755cea0a)
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,
1020a70657fSMatt Jacob #if	__FreeBSD_version < 700037
103dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1040a70657fSMatt Jacob #endif
1057ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
1067ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
1075d571944SMatt Jacob };
1089311717dSMatt Jacob static void isp_sysctl_update(ispsoftc_t *);
1099cd7268eSMatt Jacob #endif
1105d571944SMatt Jacob 
1119cd7268eSMatt Jacob static ispsoftc_t *isplist = NULL;
112478f8a96SJustin T. Gibbs 
113478f8a96SJustin T. Gibbs void
1149cd7268eSMatt Jacob isp_attach(ispsoftc_t *isp)
115478f8a96SJustin T. Gibbs {
116ea6f23cdSMatt Jacob 	int primary, secondary;
117478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
118478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
119ea6f23cdSMatt Jacob 	struct cam_sim *sim;
120ea6f23cdSMatt Jacob 	struct cam_path *path;
121478f8a96SJustin T. Gibbs 
122478f8a96SJustin T. Gibbs 	/*
123ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
124ea6f23cdSMatt Jacob 	 */
125ea6f23cdSMatt Jacob 
126ea6f23cdSMatt Jacob 	primary = 0;
127ea6f23cdSMatt Jacob 	secondary = 1;
128ea6f23cdSMatt Jacob 
129ea6f23cdSMatt Jacob 	/*
130ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
131478f8a96SJustin T. Gibbs 	 */
132ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
133478f8a96SJustin T. Gibbs 	if (devq == NULL) {
134478f8a96SJustin T. Gibbs 		return;
135478f8a96SJustin T. Gibbs 	}
136478f8a96SJustin T. Gibbs 
137478f8a96SJustin T. Gibbs 	/*
138ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
139478f8a96SJustin T. Gibbs 	 */
1400a70657fSMatt Jacob 	sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp,
1410a70657fSMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
142ea6f23cdSMatt Jacob 	if (sim == NULL) {
143478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
144478f8a96SJustin T. Gibbs 		return;
145478f8a96SJustin T. Gibbs 	}
146f6e75de2SMatt Jacob 
147f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
148f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
149abeda21eSMatt Jacob 	ISP_UNLOCK(isp);
150f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
151abeda21eSMatt Jacob 		ISP_LOCK(isp);
15245c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
153bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
154bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
155f6e75de2SMatt Jacob 		return;
156f6e75de2SMatt Jacob 	}
157abeda21eSMatt Jacob 	ISP_LOCK(isp);
158f6e75de2SMatt Jacob 
159ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
160ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
161478f8a96SJustin T. Gibbs 		return;
162478f8a96SJustin T. Gibbs 	}
163478f8a96SJustin T. Gibbs 
164ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
165478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
166ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
167ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1685d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
169478f8a96SJustin T. Gibbs 		return;
170478f8a96SJustin T. Gibbs 	}
171478f8a96SJustin T. Gibbs 
172ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
173478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
174478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
175cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
176ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
177478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
178ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
179ea6f23cdSMatt Jacob 	isp->isp_path = path;
180478f8a96SJustin T. Gibbs 
181ea6f23cdSMatt Jacob 	/*
182ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
183ea6f23cdSMatt Jacob 	 */
18422e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
1850a70657fSMatt Jacob 		sim = isp_sim_alloc(isp_action, isp_poll, "isp", isp,
1860a70657fSMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
187ea6f23cdSMatt Jacob 		if (sim == NULL) {
188ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
189ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
190ea6f23cdSMatt Jacob 			cam_simq_free(devq);
1915d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
192ea6f23cdSMatt Jacob 			return;
193ea6f23cdSMatt Jacob 		}
194ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
195ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
196ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
197ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
1985d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
199ea6f23cdSMatt Jacob 			return;
200ea6f23cdSMatt Jacob 		}
201ea6f23cdSMatt Jacob 
202ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
203ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
204ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
205ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
206ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
207ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
2085d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
209ea6f23cdSMatt Jacob 			return;
210ea6f23cdSMatt Jacob 		}
211ea6f23cdSMatt Jacob 
212ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
213ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
214ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
215ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
216ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
217ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
218ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
219ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
220ea6f23cdSMatt Jacob 	}
2215d571944SMatt Jacob 
2225d571944SMatt Jacob 	/*
2235d571944SMatt Jacob 	 * Create device nodes
2245d571944SMatt Jacob 	 */
2250a70657fSMatt Jacob 	ISP_UNLOCK(isp);
2265d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2275d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2280a70657fSMatt Jacob 	isp_sysctl_update(isp);
2290a70657fSMatt Jacob 	ISP_LOCK(isp);
2305d571944SMatt Jacob 
231d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
232478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
23310365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
234d6e5500fSMatt Jacob 	}
235d81ba9d5SMatt Jacob 	if (isplist == NULL) {
236d81ba9d5SMatt Jacob 		isplist = isp;
237d81ba9d5SMatt Jacob 	} else {
2389cd7268eSMatt Jacob 		ispsoftc_t *tmp = isplist;
239d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
240d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
241d81ba9d5SMatt Jacob 		}
242d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
243478f8a96SJustin T. Gibbs 	}
2440a70657fSMatt Jacob 
2450a70657fSMatt Jacob 	/*
2460a70657fSMatt Jacob 	 * Create a kernel thread for fibre channel instances.
2470a70657fSMatt Jacob 	 */
2480a70657fSMatt Jacob 	if (IS_FC(isp)) {
2490a70657fSMatt Jacob 		isp_callout_init(&isp->isp_osinfo.ldt);
2500a70657fSMatt Jacob 		isp_callout_init(&isp->isp_osinfo.gdt);
2510a70657fSMatt Jacob 		ISP_UNLOCK(isp);
2520a70657fSMatt Jacob #if __FreeBSD_version >= 500000
2530a70657fSMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
2540a70657fSMatt Jacob 		    RFHIGHPID, 0, "%s: fc_thrd",
2550a70657fSMatt Jacob 		    device_get_nameunit(isp->isp_dev)))
2560a70657fSMatt Jacob #else
2570a70657fSMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
2580a70657fSMatt Jacob 		    "%s: fc_thrd", device_get_nameunit(isp->isp_dev)))
2590a70657fSMatt Jacob #endif
2600a70657fSMatt Jacob 		{
2610a70657fSMatt Jacob 			ISP_LOCK(isp);
2620a70657fSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
2630a70657fSMatt Jacob 			cam_sim_free(sim, TRUE);
2640a70657fSMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
2650a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
2660a70657fSMatt Jacob 			return;
2670a70657fSMatt Jacob 		}
2680a70657fSMatt Jacob 		ISP_LOCK(isp);
2690a70657fSMatt Jacob 		/*
2700a70657fSMatt Jacob 		 * We start by being "loop down" if we have an initiator role
2710a70657fSMatt Jacob 		 */
2720a70657fSMatt Jacob 		if (isp->isp_role & ISP_ROLE_INITIATOR) {
2730a70657fSMatt Jacob 			isp_freeze_loopdown(isp, "isp_attach");
2740a70657fSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
2750a70657fSMatt Jacob 			callout_reset(&isp->isp_osinfo.ldt,
2760a70657fSMatt Jacob 			    isp_quickboot_time * hz, isp_ldt, isp);
2770a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2780a70657fSMatt Jacob 			   "Starting Initial Loop Down Timer");
2790a70657fSMatt Jacob 		}
2800a70657fSMatt Jacob 	}
2815d571944SMatt Jacob }
2825d571944SMatt Jacob 
283f7c631bcSMatt Jacob static void
2849cd7268eSMatt Jacob isp_freeze_loopdown(ispsoftc_t *isp, char *msg)
285fdeb9f2fSMatt Jacob {
286fdeb9f2fSMatt Jacob 	if (isp->isp_osinfo.simqfrozen == 0) {
287fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg);
288fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
289fdeb9f2fSMatt Jacob 		xpt_freeze_simq(isp->isp_sim, 1);
290fdeb9f2fSMatt Jacob 	} else {
291fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg);
292fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
293fdeb9f2fSMatt Jacob 	}
294fdeb9f2fSMatt Jacob }
295fdeb9f2fSMatt Jacob 
2969cd7268eSMatt Jacob 
2979cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2989cd7268eSMatt Jacob #define	_DEV	dev_t
2999cd7268eSMatt Jacob #define	_IOP	struct proc
3009cd7268eSMatt Jacob #else
3019cd7268eSMatt Jacob #define	_IOP	struct thread
3029cd7268eSMatt Jacob #define	_DEV	struct cdev *
3039cd7268eSMatt Jacob #endif
3049cd7268eSMatt Jacob 
3055d571944SMatt Jacob static int
3069cd7268eSMatt Jacob ispioctl(_DEV dev, u_long c, caddr_t addr, int flags, _IOP *td)
3075d571944SMatt Jacob {
3089cd7268eSMatt Jacob 	ispsoftc_t *isp;
309746e9c85SMatt Jacob 	int nr, retval = ENOTTY;
3100a70657fSMatt Jacob #if __FreeBSD_version < 500000
3110a70657fSMatt Jacob 	int s = splcam();
3120a70657fSMatt Jacob #else
3130a70657fSMatt Jacob 	GIANT_REQUIRED;
3140a70657fSMatt Jacob #endif
3155d571944SMatt Jacob 
3165d571944SMatt Jacob 	isp = isplist;
3175d571944SMatt Jacob 	while (isp) {
3185d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
3195d571944SMatt Jacob 			break;
3205d571944SMatt Jacob 		}
3215d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
3225d571944SMatt Jacob 	}
3230a70657fSMatt Jacob 	if (isp == NULL) {
3240a70657fSMatt Jacob #if __FreeBSD_version < 500000
3250a70657fSMatt Jacob 		splx(s);
3260a70657fSMatt Jacob #endif
3275d571944SMatt Jacob 		return (ENXIO);
3280a70657fSMatt Jacob 	}
3295d571944SMatt Jacob 
330c1504bc0SMatt Jacob 	switch (c) {
331d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
332d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
33302e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
3341dae40ebSMatt Jacob 			uint16_t *ptr = FCPARAM(isp)->isp_dump_data;
335d134aa0bSMatt Jacob 			size_t sz;
336d134aa0bSMatt Jacob 
337d134aa0bSMatt Jacob 			retval = 0;
33802e2b2d9SMatt Jacob 			if (IS_2200(isp)) {
339d134aa0bSMatt Jacob 				sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
34002e2b2d9SMatt Jacob 			} else {
341d134aa0bSMatt Jacob 				sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
34202e2b2d9SMatt Jacob 			}
343d134aa0bSMatt Jacob 			if (ptr && *ptr) {
344d134aa0bSMatt Jacob 				void *uaddr = *((void **) addr);
345d134aa0bSMatt Jacob 				if (copyout(ptr, uaddr, sz)) {
346d134aa0bSMatt Jacob 					retval = EFAULT;
347d134aa0bSMatt Jacob 				} else {
348d134aa0bSMatt Jacob 					*ptr = 0;
349d134aa0bSMatt Jacob 				}
350d134aa0bSMatt Jacob 			} else {
351d134aa0bSMatt Jacob 				retval = ENXIO;
352d134aa0bSMatt Jacob 			}
353d134aa0bSMatt Jacob 		}
35402e2b2d9SMatt Jacob 		break;
355d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
35602e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
35702e2b2d9SMatt Jacob 			isp_freeze_loopdown(isp,
35802e2b2d9SMatt Jacob 			    "ispioctl(ISP_FORCE_CRASH_DUMP)");
359d134aa0bSMatt Jacob 			isp_fw_dump(isp);
360d134aa0bSMatt Jacob 			isp_reinit(isp);
361d134aa0bSMatt Jacob 			retval = 0;
36202e2b2d9SMatt Jacob 		}
363d134aa0bSMatt Jacob 		break;
364d134aa0bSMatt Jacob #endif
3655d571944SMatt Jacob 	case ISP_SDBLEV:
3665d571944SMatt Jacob 	{
3675d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3685d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3695d571944SMatt Jacob 		*(int *)addr = olddblev;
3705d571944SMatt Jacob 		retval = 0;
3715d571944SMatt Jacob 		break;
3725d571944SMatt Jacob 	}
373746e9c85SMatt Jacob 	case ISP_GETROLE:
374746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
375746e9c85SMatt Jacob 		retval = 0;
376746e9c85SMatt Jacob 		break;
377746e9c85SMatt Jacob 	case ISP_SETROLE:
378746e9c85SMatt Jacob 		nr = *(int *)addr;
379746e9c85SMatt Jacob 		if (nr & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) {
380746e9c85SMatt Jacob 			retval = EINVAL;
381746e9c85SMatt Jacob 			break;
382746e9c85SMatt Jacob 		}
3839a1b0d43SMatt Jacob 		/*
3849a1b0d43SMatt Jacob 		 * XXX: Current
3859a1b0d43SMatt Jacob 		 */
3869a1b0d43SMatt Jacob 		if (nr == ISP_ROLE_BOTH) {
3879a1b0d43SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "dual roles not supported");
3889a1b0d43SMatt Jacob 			retval = EINVAL;
3899a1b0d43SMatt Jacob 			break;
3909a1b0d43SMatt Jacob 		}
391746e9c85SMatt Jacob 		*(int *)addr = isp->isp_role;
392746e9c85SMatt Jacob 		isp->isp_role = nr;
393746e9c85SMatt Jacob 		/* FALLTHROUGH */
3945d571944SMatt Jacob 	case ISP_RESETHBA:
3955d571944SMatt Jacob 		isp_reinit(isp);
3965d571944SMatt Jacob 		retval = 0;
3975d571944SMatt Jacob 		break;
398f553351eSMatt Jacob 	case ISP_RESCAN:
3995d571944SMatt Jacob 		if (IS_FC(isp)) {
4005d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
4015d571944SMatt Jacob 				retval = EIO;
4025d571944SMatt Jacob 			} else {
4035d571944SMatt Jacob 				retval = 0;
4045d571944SMatt Jacob 			}
4055d571944SMatt Jacob 		}
4065d571944SMatt Jacob 		break;
4075d571944SMatt Jacob 	case ISP_FC_LIP:
4085d571944SMatt Jacob 		if (IS_FC(isp)) {
4095d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
4105d571944SMatt Jacob 				retval = EIO;
4115d571944SMatt Jacob 			} else {
4125d571944SMatt Jacob 				retval = 0;
4135d571944SMatt Jacob 			}
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 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
42910365e5aSMatt Jacob 		if (lp->state == FC_PORTDB_STATE_VALID) {
430c6435ff3SMatt Jacob 			ifc->role = lp->roles;
43110365e5aSMatt Jacob 			ifc->loopid = lp->handle;
4325d571944SMatt Jacob 			ifc->portid = lp->portid;
4335d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
4345d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
4355d571944SMatt Jacob 			retval = 0;
4365d571944SMatt Jacob 		} else {
4375d571944SMatt Jacob 			retval = ENODEV;
4385d571944SMatt Jacob 		}
4395d571944SMatt Jacob 		break;
4405d571944SMatt Jacob 	}
4412903b272SMatt Jacob 	case ISP_GET_STATS:
4422903b272SMatt Jacob 	{
4432903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
4442903b272SMatt Jacob 
4452903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
4462903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
4472903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
4482903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
4492903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
4502903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
4512903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
4522903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
4532903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
4542903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
4552903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
4562903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
4572903b272SMatt Jacob 		retval = 0;
4582903b272SMatt Jacob 		break;
4592903b272SMatt Jacob 	}
4602903b272SMatt Jacob 	case ISP_CLR_STATS:
4612903b272SMatt Jacob 		isp->isp_intcnt = 0;
4622903b272SMatt Jacob 		isp->isp_intbogus = 0;
4632903b272SMatt Jacob 		isp->isp_intmboxc = 0;
4642903b272SMatt Jacob 		isp->isp_intoasync = 0;
4652903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
4662903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
4672903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
4682903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
4692903b272SMatt Jacob 		retval = 0;
4702903b272SMatt Jacob 		break;
471570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
472570c7a3fSMatt Jacob 	{
473570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
474570c7a3fSMatt Jacob 		MEMZERO(hba, sizeof (*hba));
47502e2b2d9SMatt Jacob 
476a556b68eSMatt Jacob 		hba->fc_fw_major = ISP_FW_MAJORX(isp->isp_fwrev);
477a556b68eSMatt Jacob 		hba->fc_fw_minor = ISP_FW_MINORX(isp->isp_fwrev);
478a556b68eSMatt Jacob 		hba->fc_fw_micro = ISP_FW_MICROX(isp->isp_fwrev);
47902e2b2d9SMatt Jacob 		if (IS_FC(isp)) {
480570c7a3fSMatt Jacob 			hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
481570c7a3fSMatt Jacob 			hba->fc_scsi_supported = 1;
482570c7a3fSMatt Jacob 			hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
483570c7a3fSMatt Jacob 			hba->fc_loopid = FCPARAM(isp)->isp_loopid;
4846c81a0aeSMatt Jacob 			hba->nvram_node_wwn = FCPARAM(isp)->isp_wwnn_nvram;
4856c81a0aeSMatt Jacob 			hba->nvram_port_wwn = FCPARAM(isp)->isp_wwpn_nvram;
486fd6eb9f7SMatt Jacob 			hba->active_node_wwn = ISP_NODEWWN(isp);
487fd6eb9f7SMatt Jacob 			hba->active_port_wwn = ISP_PORTWWN(isp);
48802e2b2d9SMatt Jacob 		}
489570c7a3fSMatt Jacob 		retval = 0;
490570c7a3fSMatt Jacob 		break;
491570c7a3fSMatt Jacob 	}
492fdeb9f2fSMatt Jacob 	case ISP_GET_FC_PARAM:
493fdeb9f2fSMatt Jacob 	{
494fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
495fdeb9f2fSMatt Jacob 
49602e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
497fdeb9f2fSMatt Jacob 			break;
498fdeb9f2fSMatt Jacob 		}
499fdeb9f2fSMatt Jacob 		f->parameter = 0;
500fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
501fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_maxfrmlen;
502fdeb9f2fSMatt Jacob 			retval = 0;
503fdeb9f2fSMatt Jacob 			break;
504fdeb9f2fSMatt Jacob 		}
505fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
506fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_execthrottle;
507fdeb9f2fSMatt Jacob 			retval = 0;
508fdeb9f2fSMatt Jacob 			break;
509fdeb9f2fSMatt Jacob 		}
510fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
511fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX)
512fdeb9f2fSMatt Jacob 				f->parameter = 1;
513fdeb9f2fSMatt Jacob 			retval = 0;
514fdeb9f2fSMatt Jacob 			break;
515fdeb9f2fSMatt Jacob 		}
516fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
517fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_loopid;
518fdeb9f2fSMatt Jacob 			retval = 0;
519fdeb9f2fSMatt Jacob 			break;
520fdeb9f2fSMatt Jacob 		}
521fdeb9f2fSMatt Jacob 		retval = EINVAL;
522fdeb9f2fSMatt Jacob 		break;
523fdeb9f2fSMatt Jacob 	}
524fdeb9f2fSMatt Jacob 	case ISP_SET_FC_PARAM:
525fdeb9f2fSMatt Jacob 	{
526fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
5271dae40ebSMatt Jacob 		uint32_t param = f->parameter;
528fdeb9f2fSMatt Jacob 
52902e2b2d9SMatt Jacob 		if (IS_SCSI(isp)) {
530fdeb9f2fSMatt Jacob 			break;
531fdeb9f2fSMatt Jacob 		}
532fdeb9f2fSMatt Jacob 		f->parameter = 0;
533fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
534fdeb9f2fSMatt Jacob 			if (param != 512 && param != 1024 && param != 1024) {
535fdeb9f2fSMatt Jacob 				retval = EINVAL;
536fdeb9f2fSMatt Jacob 				break;
537fdeb9f2fSMatt Jacob 			}
538fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_maxfrmlen = param;
539fdeb9f2fSMatt Jacob 			retval = 0;
540fdeb9f2fSMatt Jacob 			break;
541fdeb9f2fSMatt Jacob 		}
542fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
543fdeb9f2fSMatt Jacob 			if (param < 16 || param > 255) {
544fdeb9f2fSMatt Jacob 				retval = EINVAL;
545fdeb9f2fSMatt Jacob 				break;
546fdeb9f2fSMatt Jacob 			}
547fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_execthrottle = param;
548fdeb9f2fSMatt Jacob 			retval = 0;
549fdeb9f2fSMatt Jacob 			break;
550fdeb9f2fSMatt Jacob 		}
551fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
552fdeb9f2fSMatt Jacob 			if (param != 0 && param != 1) {
553fdeb9f2fSMatt Jacob 				retval = EINVAL;
554fdeb9f2fSMatt Jacob 				break;
555fdeb9f2fSMatt Jacob 			}
556fdeb9f2fSMatt Jacob 			if (param) {
557fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions |=
558fdeb9f2fSMatt Jacob 				    ICBOPT_FULL_DUPLEX;
559fdeb9f2fSMatt Jacob 			} else {
560fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions &=
561fdeb9f2fSMatt Jacob 				    ~ICBOPT_FULL_DUPLEX;
562fdeb9f2fSMatt Jacob 			}
563fdeb9f2fSMatt Jacob 			retval = 0;
564fdeb9f2fSMatt Jacob 			break;
565fdeb9f2fSMatt Jacob 		}
566fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
567fdeb9f2fSMatt Jacob 			if (param < 0 || param > 125) {
568fdeb9f2fSMatt Jacob 				retval = EINVAL;
569fdeb9f2fSMatt Jacob 				break;
570fdeb9f2fSMatt Jacob 			}
571fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_loopid = param;
572fdeb9f2fSMatt Jacob 			retval = 0;
573fdeb9f2fSMatt Jacob 			break;
574fdeb9f2fSMatt Jacob 		}
575fdeb9f2fSMatt Jacob 		retval = EINVAL;
576fdeb9f2fSMatt Jacob 		break;
577fdeb9f2fSMatt Jacob 	}
5788e62a8acSMatt Jacob 	case ISP_TSK_MGMT:
5798e62a8acSMatt Jacob 	{
5808e62a8acSMatt Jacob 		int needmarker;
5818e62a8acSMatt Jacob 		struct isp_fc_tsk_mgmt *fct = (struct isp_fc_tsk_mgmt *) addr;
5821dae40ebSMatt Jacob 		uint16_t loopid;
5838e62a8acSMatt Jacob 		mbreg_t mbs;
5848e62a8acSMatt Jacob 
5858e62a8acSMatt Jacob 		if (IS_SCSI(isp)) {
5868e62a8acSMatt Jacob 			break;
5878e62a8acSMatt Jacob 		}
5888e62a8acSMatt Jacob 
5898e62a8acSMatt Jacob 		memset(&mbs, 0, sizeof (mbs));
5908e62a8acSMatt Jacob 		needmarker = retval = 0;
591e5265237SMatt Jacob 		loopid = fct->loopid;
59210365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin == 0) {
593e5265237SMatt Jacob 			loopid <<= 8;
594e5265237SMatt Jacob 		}
5958e62a8acSMatt Jacob 		switch (fct->action) {
596f0f536d1SMatt Jacob 		case IPT_CLEAR_ACA:
5978e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_ACA;
598e5265237SMatt Jacob 			mbs.param[1] = loopid;
5998e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6008e62a8acSMatt Jacob 			break;
601f0f536d1SMatt Jacob 		case IPT_TARGET_RESET:
6028e62a8acSMatt Jacob 			mbs.param[0] = MBOX_TARGET_RESET;
603e5265237SMatt Jacob 			mbs.param[1] = loopid;
6048e62a8acSMatt Jacob 			needmarker = 1;
6058e62a8acSMatt Jacob 			break;
606f0f536d1SMatt Jacob 		case IPT_LUN_RESET:
6078e62a8acSMatt Jacob 			mbs.param[0] = MBOX_LUN_RESET;
608e5265237SMatt Jacob 			mbs.param[1] = loopid;
6098e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6108e62a8acSMatt Jacob 			needmarker = 1;
6118e62a8acSMatt Jacob 			break;
612f0f536d1SMatt Jacob 		case IPT_CLEAR_TASK_SET:
6138e62a8acSMatt Jacob 			mbs.param[0] = MBOX_CLEAR_TASK_SET;
614e5265237SMatt Jacob 			mbs.param[1] = loopid;
6158e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6168e62a8acSMatt Jacob 			needmarker = 1;
6178e62a8acSMatt Jacob 			break;
618f0f536d1SMatt Jacob 		case IPT_ABORT_TASK_SET:
6198e62a8acSMatt Jacob 			mbs.param[0] = MBOX_ABORT_TASK_SET;
620e5265237SMatt Jacob 			mbs.param[1] = loopid;
6218e62a8acSMatt Jacob 			mbs.param[2] = fct->lun;
6228e62a8acSMatt Jacob 			needmarker = 1;
6238e62a8acSMatt Jacob 			break;
6248e62a8acSMatt Jacob 		default:
6258e62a8acSMatt Jacob 			retval = EINVAL;
6268e62a8acSMatt Jacob 			break;
6278e62a8acSMatt Jacob 		}
6288e62a8acSMatt Jacob 		if (retval == 0) {
6298e62a8acSMatt Jacob 			if (needmarker) {
6308e62a8acSMatt Jacob 				isp->isp_sendmarker |= 1;
6318e62a8acSMatt Jacob 			}
6328e62a8acSMatt Jacob 			retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
6338e62a8acSMatt Jacob 			if (retval)
6348e62a8acSMatt Jacob 				retval = EIO;
6358e62a8acSMatt Jacob 		}
6368e62a8acSMatt Jacob 		break;
6378e62a8acSMatt Jacob 	}
6385d571944SMatt Jacob 	default:
6395d571944SMatt Jacob 		break;
6405d571944SMatt Jacob 	}
6410a70657fSMatt Jacob #if __FreeBSD_version < 500000
6420a70657fSMatt Jacob 	splx(s);
6430a70657fSMatt Jacob #endif
6445d571944SMatt Jacob 	return (retval);
6450470d791SMatt Jacob }
646478f8a96SJustin T. Gibbs 
6479311717dSMatt Jacob #if __FreeBSD_version >= 500000
6489311717dSMatt Jacob static void
6499311717dSMatt Jacob isp_sysctl_update(ispsoftc_t *isp)
6509311717dSMatt Jacob {
6519311717dSMatt Jacob 	struct sysctl_ctx_list *ctx =
6529311717dSMatt Jacob 	    device_get_sysctl_ctx(isp->isp_osinfo.dev);
6539311717dSMatt Jacob 	struct sysctl_oid *tree = device_get_sysctl_tree(isp->isp_osinfo.dev);
6549311717dSMatt Jacob 
6559311717dSMatt Jacob 	if (IS_SCSI(isp)) {
6569311717dSMatt Jacob 		return;
6579311717dSMatt Jacob 	}
658f7c631bcSMatt Jacob 
6599311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwnn,
6609311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwnn), "0x%08x%08x",
6619311717dSMatt Jacob 	    (uint32_t) (ISP_NODEWWN(isp) >> 32), (uint32_t) ISP_NODEWWN(isp));
6629311717dSMatt Jacob 
6639311717dSMatt Jacob 	snprintf(isp->isp_osinfo.sysctl_info.fc.wwpn,
6649311717dSMatt Jacob 	    sizeof (isp->isp_osinfo.sysctl_info.fc.wwpn), "0x%08x%08x",
6659311717dSMatt Jacob 	    (uint32_t) (ISP_PORTWWN(isp) >> 32), (uint32_t) ISP_PORTWWN(isp));
6669311717dSMatt Jacob 
6679311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6689311717dSMatt Jacob 	       "wwnn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwnn, 0,
6699311717dSMatt Jacob 	       "World Wide Node Name");
670f7c631bcSMatt Jacob 
6719311717dSMatt Jacob 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
6729311717dSMatt Jacob 	       "wwpn", CTLFLAG_RD, isp->isp_osinfo.sysctl_info.fc.wwpn, 0,
6739311717dSMatt Jacob 	       "World Wide Port Name");
674f7c631bcSMatt Jacob 
675f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
676f7c631bcSMatt Jacob 	    "loop_down_limit",
677f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0,
678f7c631bcSMatt Jacob 	    "How long to wait for loop to come back up");
679f7c631bcSMatt Jacob 
680f7c631bcSMatt Jacob 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
681f7c631bcSMatt Jacob 	    "gone_device_time",
682f7c631bcSMatt Jacob 	    CTLFLAG_RW, &isp->isp_osinfo.gone_device_time, 0,
683f7c631bcSMatt Jacob 	    "How long to wait for a device to reappear");
6849311717dSMatt Jacob }
6859311717dSMatt Jacob #endif
6869311717dSMatt Jacob 
687f6e75de2SMatt Jacob static void
688f6e75de2SMatt Jacob isp_intr_enable(void *arg)
689f6e75de2SMatt Jacob {
6909cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
6910a70657fSMatt Jacob 	ISP_LOCK(isp);
692d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
69310365e5aSMatt Jacob 		ISP_ENABLE_INTS(isp);
694d6e5500fSMatt Jacob 	}
6950a70657fSMatt Jacob 	ISP_UNLOCK(isp);
696f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
697f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
698f6e75de2SMatt Jacob }
699d81ba9d5SMatt Jacob 
700d81ba9d5SMatt Jacob /*
701d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
702d81ba9d5SMatt Jacob  */
703d81ba9d5SMatt Jacob 
704d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
705d81ba9d5SMatt Jacob 
7069cd7268eSMatt Jacob static __inline int is_lun_enabled(ispsoftc_t *, int, lun_id_t);
7079cd7268eSMatt Jacob static __inline int are_any_luns_enabled(ispsoftc_t *, int);
7089cd7268eSMatt Jacob static __inline tstate_t *get_lun_statep(ispsoftc_t *, int, lun_id_t);
7099cd7268eSMatt Jacob static __inline void rls_lun_statep(ispsoftc_t *, tstate_t *);
7109cd7268eSMatt Jacob static __inline atio_private_data_t *isp_get_atpd(ispsoftc_t *, int);
711d81ba9d5SMatt Jacob static cam_status
7129cd7268eSMatt Jacob create_lun_state(ispsoftc_t *, int, struct cam_path *, tstate_t **);
7139cd7268eSMatt Jacob static void destroy_lun_state(ispsoftc_t *, tstate_t *);
7149cd7268eSMatt Jacob static int isp_en_lun(ispsoftc_t *, union ccb *);
7159cd7268eSMatt Jacob static void isp_ledone(ispsoftc_t *, lun_entry_t *);
7169cd7268eSMatt Jacob static cam_status isp_abort_tgt_ccb(ispsoftc_t *, union ccb *);
717f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
718a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
719a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
7209cd7268eSMatt Jacob static void isp_target_start_ctio(ispsoftc_t *, union ccb *);
7219cd7268eSMatt Jacob static int isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
7229cd7268eSMatt Jacob static int isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
7239cd7268eSMatt Jacob static int isp_handle_platform_ctio(ispsoftc_t *, void *);
7249cd7268eSMatt Jacob static int isp_handle_platform_notify_scsi(ispsoftc_t *, in_entry_t *);
7259cd7268eSMatt Jacob static int isp_handle_platform_notify_fc(ispsoftc_t *, in_fcentry_t *);
726d81ba9d5SMatt Jacob 
72753af7d22SMatt Jacob static __inline int
7289cd7268eSMatt Jacob is_lun_enabled(ispsoftc_t *isp, int bus, lun_id_t lun)
729d81ba9d5SMatt Jacob {
730d81ba9d5SMatt Jacob 	tstate_t *tptr;
731a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
732a1bc34c6SMatt Jacob 	if (tptr == NULL) {
733d81ba9d5SMatt Jacob 		return (0);
734d81ba9d5SMatt Jacob 	}
735d81ba9d5SMatt Jacob 	do {
736a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
737d81ba9d5SMatt Jacob 			return (1);
738d81ba9d5SMatt Jacob 		}
739d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
740d81ba9d5SMatt Jacob 	return (0);
741d81ba9d5SMatt Jacob }
742d81ba9d5SMatt Jacob 
74353af7d22SMatt Jacob static __inline int
7449cd7268eSMatt Jacob are_any_luns_enabled(ispsoftc_t *isp, int port)
745d81ba9d5SMatt Jacob {
746a1bc34c6SMatt Jacob 	int lo, hi;
747a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
748a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
749a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
750a1bc34c6SMatt Jacob 	} else {
751a1bc34c6SMatt Jacob 		lo = 0;
752a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
753a1bc34c6SMatt Jacob 	}
754a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
755a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
756d81ba9d5SMatt Jacob 			return (1);
757d81ba9d5SMatt Jacob 		}
758d81ba9d5SMatt Jacob 	}
759d81ba9d5SMatt Jacob 	return (0);
760d81ba9d5SMatt Jacob }
761d81ba9d5SMatt Jacob 
76253af7d22SMatt Jacob static __inline tstate_t *
7639cd7268eSMatt Jacob get_lun_statep(ispsoftc_t *isp, int bus, lun_id_t lun)
764d81ba9d5SMatt Jacob {
76564edff94SMatt Jacob 	tstate_t *tptr = NULL;
766d81ba9d5SMatt Jacob 
767d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
76864edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
769a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
770d81ba9d5SMatt Jacob 			tptr->hold++;
771d81ba9d5SMatt Jacob 			return (tptr);
772d81ba9d5SMatt Jacob 		}
77367ff51f1SMatt Jacob 		return (NULL);
774126ec864SMatt Jacob 	} else {
775126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
77664edff94SMatt Jacob 		if (tptr == NULL) {
77764edff94SMatt Jacob 			return (NULL);
77864edff94SMatt Jacob 		}
779126ec864SMatt Jacob 	}
780d81ba9d5SMatt Jacob 
781d81ba9d5SMatt Jacob 	do {
782a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
783d81ba9d5SMatt Jacob 			tptr->hold++;
784d81ba9d5SMatt Jacob 			return (tptr);
785d81ba9d5SMatt Jacob 		}
786d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
787d81ba9d5SMatt Jacob 	return (tptr);
788d81ba9d5SMatt Jacob }
789d81ba9d5SMatt Jacob 
79053af7d22SMatt Jacob static __inline void
7919cd7268eSMatt Jacob rls_lun_statep(ispsoftc_t *isp, tstate_t *tptr)
792d81ba9d5SMatt Jacob {
793d81ba9d5SMatt Jacob 	if (tptr->hold)
794d81ba9d5SMatt Jacob 		tptr->hold--;
795d81ba9d5SMatt Jacob }
796d81ba9d5SMatt Jacob 
79753af7d22SMatt Jacob static __inline atio_private_data_t *
7989cd7268eSMatt Jacob isp_get_atpd(ispsoftc_t *isp, int tag)
79953036e92SMatt Jacob {
80053036e92SMatt Jacob 	atio_private_data_t *atp;
80153036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
80253036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
80353036e92SMatt Jacob 		if (atp->tag == tag)
80453036e92SMatt Jacob 			return (atp);
80553036e92SMatt Jacob 	}
80653036e92SMatt Jacob 	return (NULL);
80753036e92SMatt Jacob }
80853036e92SMatt Jacob 
809d81ba9d5SMatt Jacob static cam_status
8109cd7268eSMatt Jacob create_lun_state(ispsoftc_t *isp, int bus,
811a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
812d81ba9d5SMatt Jacob {
813d81ba9d5SMatt Jacob 	cam_status status;
814d81ba9d5SMatt Jacob 	lun_id_t lun;
815a1bc34c6SMatt Jacob 	int hfx;
816d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
817d81ba9d5SMatt Jacob 
818d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
819d81ba9d5SMatt Jacob 	if (lun < 0) {
820d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
821d81ba9d5SMatt Jacob 	}
822a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
823d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
824d81ba9d5SMatt Jacob 	}
825ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
826d81ba9d5SMatt Jacob 	if (new == NULL) {
827d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
828d81ba9d5SMatt Jacob 	}
829d81ba9d5SMatt Jacob 
830d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
831d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
832d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
833d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
834d81ba9d5SMatt Jacob 		return (status);
835d81ba9d5SMatt Jacob 	}
836a1bc34c6SMatt Jacob 	new->bus = bus;
837d81ba9d5SMatt Jacob 	new->lun = lun;
838d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
839d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
840d81ba9d5SMatt Jacob 	new->hold = 1;
841d81ba9d5SMatt Jacob 
842a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
843a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
844a1bc34c6SMatt Jacob 	if (tptr == NULL) {
845a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
846d81ba9d5SMatt Jacob 	} else {
847d81ba9d5SMatt Jacob 		while (tptr->next)
848d81ba9d5SMatt Jacob 			tptr = tptr->next;
849d81ba9d5SMatt Jacob 		tptr->next = new;
850d81ba9d5SMatt Jacob 	}
851d81ba9d5SMatt Jacob 	*rslt = new;
852d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
853d81ba9d5SMatt Jacob }
854d81ba9d5SMatt Jacob 
85553af7d22SMatt Jacob static __inline void
8569cd7268eSMatt Jacob destroy_lun_state(ispsoftc_t *isp, tstate_t *tptr)
857d81ba9d5SMatt Jacob {
858a1bc34c6SMatt Jacob 	int hfx;
859d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
860d81ba9d5SMatt Jacob 
861d81ba9d5SMatt Jacob 	if (tptr->hold) {
862d81ba9d5SMatt Jacob 		return;
863d81ba9d5SMatt Jacob 	}
86467ff51f1SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
865a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
866d81ba9d5SMatt Jacob 	if (pw == NULL) {
867d81ba9d5SMatt Jacob 		return;
868a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
869a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
870d81ba9d5SMatt Jacob 	} else {
871d81ba9d5SMatt Jacob 		lw = pw;
872d81ba9d5SMatt Jacob 		pw = lw->next;
873d81ba9d5SMatt Jacob 		while (pw) {
874a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
875d81ba9d5SMatt Jacob 				lw->next = pw->next;
876d81ba9d5SMatt Jacob 				break;
877d81ba9d5SMatt Jacob 			}
878d81ba9d5SMatt Jacob 			lw = pw;
879d81ba9d5SMatt Jacob 			pw = pw->next;
880d81ba9d5SMatt Jacob 		}
881d81ba9d5SMatt Jacob 		if (pw == NULL) {
882d81ba9d5SMatt Jacob 			return;
883d81ba9d5SMatt Jacob 		}
884d81ba9d5SMatt Jacob 	}
885d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
886d81ba9d5SMatt Jacob }
887d81ba9d5SMatt Jacob 
8885d571944SMatt Jacob /*
88967ff51f1SMatt Jacob  * Enable luns.
8905d571944SMatt Jacob  */
89167ff51f1SMatt Jacob static int
8929cd7268eSMatt Jacob isp_en_lun(ispsoftc_t *isp, union ccb *ccb)
893d81ba9d5SMatt Jacob {
894d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
8951fd47020SMatt Jacob 	tstate_t *tptr = NULL;
8961dae40ebSMatt Jacob 	uint32_t seq;
897746e9c85SMatt Jacob 	int bus, cmd, av, wildcard, tm_on;
898d81ba9d5SMatt Jacob 	lun_id_t lun;
899d81ba9d5SMatt Jacob 	target_id_t tgt;
900d81ba9d5SMatt Jacob 
90167ff51f1SMatt Jacob 	bus = XS_CHANNEL(ccb);
90267ff51f1SMatt Jacob 	if (bus > 1) {
903dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "illegal bus %d\n", bus);
90467ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_PATH_INVALID;
90567ff51f1SMatt Jacob 		return (-1);
90667ff51f1SMatt Jacob 	}
907d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
908d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
909d81ba9d5SMatt Jacob 
910dd9fc7c3SMatt Jacob 	if (isp->isp_dblev & ISP_LOGTDEBUG0) {
911dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "%sabling lun 0x%x on channel %d\n",
91267ff51f1SMatt Jacob 	    	    cel->enable? "en" : "dis", lun, bus);
913dd9fc7c3SMatt Jacob 	}
914d81ba9d5SMatt Jacob 
915d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
916d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
917d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
91867ff51f1SMatt Jacob 		return (-1);
919d81ba9d5SMatt Jacob 	}
92064edff94SMatt Jacob 
9212ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
922a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
923a1bc34c6SMatt Jacob 		sdp += bus;
924d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
925a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
926d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
92767ff51f1SMatt Jacob 			return (-1);
928d81ba9d5SMatt Jacob 		}
929d81ba9d5SMatt Jacob 	} else {
930746e9c85SMatt Jacob 		/*
931746e9c85SMatt Jacob 		 * There's really no point in doing this yet w/o multi-tid
932746e9c85SMatt Jacob 		 * capability. Even then, it's problematic.
933746e9c85SMatt Jacob 		 */
934746e9c85SMatt Jacob #if	0
935d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
936d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
937d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
93867ff51f1SMatt Jacob 			return (-1);
939d81ba9d5SMatt Jacob 		}
940746e9c85SMatt Jacob #endif
94164edff94SMatt Jacob 		/*
94264edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
94364edff94SMatt Jacob 		 */
94410365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_tmode == 0) {
945dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
946dd9fc7c3SMatt Jacob 			    "firmware does not support target mode\n");
94764edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
94867ff51f1SMatt Jacob 			return (-1);
94964edff94SMatt Jacob 		}
95064edff94SMatt Jacob 		/*
95164edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
952dd9fc7c3SMatt Jacob 		 * XXX: dork with our already fragile enable/disable code.
95364edff94SMatt Jacob 		 */
95410365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw == 0) {
955dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
956dd9fc7c3SMatt Jacob 			    "firmware not SCCLUN capable\n");
957746e9c85SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
95867ff51f1SMatt Jacob 			return (-1);
95964edff94SMatt Jacob 		}
960d81ba9d5SMatt Jacob 	}
961d81ba9d5SMatt Jacob 
962d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
96364edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
96464edff94SMatt Jacob 			wildcard = 1;
96564edff94SMatt Jacob 		} else {
966d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
96767ff51f1SMatt Jacob 			return (-1);
968d6e5500fSMatt Jacob 		}
969126ec864SMatt Jacob 	} else {
970126ec864SMatt Jacob 		wildcard = 0;
971126ec864SMatt Jacob 	}
972b6b6ad2fSMatt Jacob 
973746e9c85SMatt Jacob 	tm_on = (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) != 0;
974746e9c85SMatt Jacob 
975b6b6ad2fSMatt Jacob 	/*
976b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
97764edff94SMatt Jacob 	 *
97864edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
97964edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
98064edff94SMatt Jacob 	 * handle them locally (if we see them at all).
981b6b6ad2fSMatt Jacob 	 */
982126ec864SMatt Jacob 
983126ec864SMatt Jacob 	if (wildcard) {
984a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
985b6b6ad2fSMatt Jacob 		if (cel->enable) {
98667ff51f1SMatt Jacob 			if (tm_on) {
987b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
98867ff51f1SMatt Jacob 				return (-1);
989b6b6ad2fSMatt Jacob 			}
990b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
991b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
992b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
993b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
994b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
995b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
99667ff51f1SMatt Jacob 				return (-1);
997b6b6ad2fSMatt Jacob 			}
998b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
999b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
100064edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
1001126ec864SMatt Jacob 		} else {
100267ff51f1SMatt Jacob 			if (tm_on == 0) {
1003126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
100467ff51f1SMatt Jacob 				return (-1);
1005126ec864SMatt Jacob 			}
1006126ec864SMatt Jacob 			if (tptr->hold) {
1007126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
100867ff51f1SMatt Jacob 				return (-1);
1009126ec864SMatt Jacob 			}
1010126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
101164edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
1012126ec864SMatt Jacob 		}
1013126ec864SMatt Jacob 	}
1014126ec864SMatt Jacob 
1015126ec864SMatt Jacob 	/*
1016126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
1017126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
1018126ec864SMatt Jacob 	 */
1019126ec864SMatt Jacob 	av = bus << 31;
1020746e9c85SMatt Jacob 	if (cel->enable && tm_on == 0) {
1021a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
1022b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1023b6b6ad2fSMatt Jacob 		if (av) {
1024b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1025126ec864SMatt Jacob 			if (wildcard) {
102664edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
102764edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
1028b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
10295d571944SMatt Jacob 			}
103067ff51f1SMatt Jacob 			return (-1);
1031b6b6ad2fSMatt Jacob 		}
103264edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
1033dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Enabled\n");
1034746e9c85SMatt Jacob 	} else if (cel->enable == 0 && tm_on && wildcard) {
1035a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
1036b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
103767ff51f1SMatt Jacob 			return (-1);
1038b6b6ad2fSMatt Jacob 		}
1039b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1040b6b6ad2fSMatt Jacob 		if (av) {
1041b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
104267ff51f1SMatt Jacob 			return (-1);
1043b6b6ad2fSMatt Jacob 		}
104464edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
1045dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "Target Mode Disabled\n");
1046126ec864SMatt Jacob 	}
1047126ec864SMatt Jacob 
1048126ec864SMatt Jacob 	if (wildcard) {
104964edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
105067ff51f1SMatt Jacob 		return (-1);
1051b6b6ad2fSMatt Jacob 	}
1052b6b6ad2fSMatt Jacob 
105367ff51f1SMatt Jacob 	/*
105467ff51f1SMatt Jacob 	 * Find an empty slot
105567ff51f1SMatt Jacob 	 */
105667ff51f1SMatt Jacob 	for (seq = 0; seq < NLEACT; seq++) {
105767ff51f1SMatt Jacob 		if (isp->isp_osinfo.leact[seq] == 0) {
105867ff51f1SMatt Jacob 			break;
105967ff51f1SMatt Jacob 		}
106067ff51f1SMatt Jacob 	}
106167ff51f1SMatt Jacob 	if (seq >= NLEACT) {
106267ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
106367ff51f1SMatt Jacob 		return (-1);
106467ff51f1SMatt Jacob 
106567ff51f1SMatt Jacob 	}
106667ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = ccb;
106767ff51f1SMatt Jacob 
1068d81ba9d5SMatt Jacob 	if (cel->enable) {
1069d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
1070a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
1071d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
107267ff51f1SMatt Jacob 			isp->isp_osinfo.leact[seq] = 0;
107367ff51f1SMatt Jacob 			return (-1);
1074d81ba9d5SMatt Jacob 		}
1075d81ba9d5SMatt Jacob 	} else {
1076a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
1077d81ba9d5SMatt Jacob 		if (tptr == NULL) {
1078d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
107967ff51f1SMatt Jacob 			return (-1);
1080d81ba9d5SMatt Jacob 		}
1081d81ba9d5SMatt Jacob 	}
1082d81ba9d5SMatt Jacob 
1083d81ba9d5SMatt Jacob 	if (cel->enable) {
10845d571944SMatt Jacob 		int c, n, ulun = lun;
10855d571944SMatt Jacob 
10865d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
10875d571944SMatt Jacob 		c = DFLT_CMND_CNT;
10885d571944SMatt Jacob 		n = DFLT_INOT_CNT;
10895d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
10905d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
10915d571944SMatt Jacob 			n = 0;
10925d571944SMatt Jacob 			/*
10935d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
10945d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
10955d571944SMatt Jacob 			 */
10965d571944SMatt Jacob 			ulun = 0;
10975d571944SMatt Jacob 		}
109867ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
109967ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
110067ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
110167ff51f1SMatt Jacob 			return (seq);
1102d81ba9d5SMatt Jacob 		}
1103d81ba9d5SMatt Jacob 	} else {
11045d571944SMatt Jacob 		int c, n, ulun = lun;
1105d81ba9d5SMatt Jacob 
11065d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
11075d571944SMatt Jacob 		c = DFLT_CMND_CNT;
11085d571944SMatt Jacob 		n = DFLT_INOT_CNT;
11095d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
11105d571944SMatt Jacob 			n = 0;
11115d571944SMatt Jacob 			/*
11125d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
11135d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
11145d571944SMatt Jacob 			 */
11155d571944SMatt Jacob 			ulun = 0;
11165d571944SMatt Jacob 		}
111767ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq+1) == 0) {
111867ff51f1SMatt Jacob 			rls_lun_statep(isp, tptr);
111967ff51f1SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INPROG;
112067ff51f1SMatt Jacob 			return (seq);
1121d81ba9d5SMatt Jacob 		}
1122d81ba9d5SMatt Jacob 	}
112367ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
1124dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "isp_lun_cmd failed\n");
112567ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
112667ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP_ERR;
112767ff51f1SMatt Jacob 	return (-1);
11285d571944SMatt Jacob }
11295d571944SMatt Jacob 
113067ff51f1SMatt Jacob static void
11319cd7268eSMatt Jacob isp_ledone(ispsoftc_t *isp, lun_entry_t *lep)
113267ff51f1SMatt Jacob {
11339a1b0d43SMatt Jacob 	const char lfmt[] = "now %sabled for target mode\n";
113467ff51f1SMatt Jacob 	union ccb *ccb;
11351dae40ebSMatt Jacob 	uint32_t seq;
113667ff51f1SMatt Jacob 	tstate_t *tptr;
113767ff51f1SMatt Jacob 	int av;
113867ff51f1SMatt Jacob 	struct ccb_en_lun *cel;
1139d81ba9d5SMatt Jacob 
114067ff51f1SMatt Jacob 	seq = lep->le_reserved - 1;
114167ff51f1SMatt Jacob 	if (seq >= NLEACT) {
11423c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114367ff51f1SMatt Jacob 		    "seq out of range (%u) in isp_ledone", seq);
114467ff51f1SMatt Jacob 		return;
1145d81ba9d5SMatt Jacob 	}
114667ff51f1SMatt Jacob 	ccb = isp->isp_osinfo.leact[seq];
114767ff51f1SMatt Jacob 	if (ccb == 0) {
114867ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
114967ff51f1SMatt Jacob 		    "no ccb for seq %u in isp_ledone", seq);
115067ff51f1SMatt Jacob 		return;
115167ff51f1SMatt Jacob 	}
115267ff51f1SMatt Jacob 	cel = &ccb->cel;
115367ff51f1SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
115467ff51f1SMatt Jacob 	if (tptr == NULL) {
1155dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "null tptr in isp_ledone\n");
115667ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
115767ff51f1SMatt Jacob 		return;
1158d81ba9d5SMatt Jacob 	}
115967ff51f1SMatt Jacob 
116067ff51f1SMatt Jacob 	if (lep->le_status != LUN_OK) {
1161dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1162dd9fc7c3SMatt Jacob 		    "ENABLE/MODIFY LUN returned 0x%x\n", lep->le_status);
116367ff51f1SMatt Jacob err:
116467ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
116567ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
116667ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
116767ff51f1SMatt Jacob 		xpt_done(ccb);
116867ff51f1SMatt Jacob 		return;
116967ff51f1SMatt Jacob 	} else {
117067ff51f1SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
117167ff51f1SMatt Jacob 		    "isp_ledone: ENABLE/MODIFY done okay");
117267ff51f1SMatt Jacob 	}
117367ff51f1SMatt Jacob 
117467ff51f1SMatt Jacob 
117567ff51f1SMatt Jacob 	if (cel->enable) {
117667ff51f1SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1177dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, lfmt, "en");
117867ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
117967ff51f1SMatt Jacob 		isp->isp_osinfo.leact[seq] = 0;
118067ff51f1SMatt Jacob 		xpt_done(ccb);
118167ff51f1SMatt Jacob 		return;
118267ff51f1SMatt Jacob 	}
118367ff51f1SMatt Jacob 
118467ff51f1SMatt Jacob 	if (lep->le_header.rqs_entry_type == RQSTYPE_MODIFY_LUN) {
118567ff51f1SMatt Jacob 		if (isp_lun_cmd(isp, -RQSTYPE_ENABLE_LUN, XS_CHANNEL(ccb),
118667ff51f1SMatt Jacob 		    XS_TGT(ccb), XS_LUN(ccb), 0, 0, seq+1)) {
1187dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1188dd9fc7c3SMatt Jacob 			    "isp_ledone: isp_lun_cmd failed\n");
118967ff51f1SMatt Jacob 			goto err;
119067ff51f1SMatt Jacob 		}
119167ff51f1SMatt Jacob 		rls_lun_statep(isp, tptr);
119267ff51f1SMatt Jacob 		return;
119367ff51f1SMatt Jacob 	}
119467ff51f1SMatt Jacob 
1195dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, lfmt, "dis");
119667ff51f1SMatt Jacob 	rls_lun_statep(isp, tptr);
119767ff51f1SMatt Jacob 	destroy_lun_state(isp, tptr);
119867ff51f1SMatt Jacob 	ccb->ccb_h.status = CAM_REQ_CMP;
119967ff51f1SMatt Jacob 	isp->isp_osinfo.leact[seq] = 0;
120067ff51f1SMatt Jacob 	xpt_done(ccb);
120167ff51f1SMatt Jacob 	if (are_any_luns_enabled(isp, XS_CHANNEL(ccb)) == 0) {
120267ff51f1SMatt Jacob 		int bus = XS_CHANNEL(ccb);
120367ff51f1SMatt Jacob 		av = bus << 31;
1204126ec864SMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1205126ec864SMatt Jacob 		if (av) {
1206126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
120767ff51f1SMatt Jacob 			    "disable target mode on channel %d failed", bus);
1208126ec864SMatt Jacob 		}
120967ff51f1SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
121067ff51f1SMatt Jacob 	}
1211126ec864SMatt Jacob }
1212126ec864SMatt Jacob 
1213d81ba9d5SMatt Jacob 
1214d81ba9d5SMatt Jacob static cam_status
12159cd7268eSMatt Jacob isp_abort_tgt_ccb(ispsoftc_t *isp, union ccb *ccb)
1216d81ba9d5SMatt Jacob {
1217d81ba9d5SMatt Jacob 	tstate_t *tptr;
1218d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
1219d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
1220746e9c85SMatt Jacob 	int found, *ctr;
1221d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
1222d81ba9d5SMatt Jacob 
1223dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "aborting ccb %p\n", accb);
1224d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1225746e9c85SMatt Jacob 		int badpath = 0;
1226d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
1227d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
1228746e9c85SMatt Jacob 			badpath = 1;
1229d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
1230d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
1231746e9c85SMatt Jacob 			badpath = 1;
1232746e9c85SMatt Jacob 		}
1233746e9c85SMatt Jacob 		if (badpath) {
1234746e9c85SMatt Jacob 			/*
1235746e9c85SMatt Jacob 			 * Being restrictive about target ids is really about
1236746e9c85SMatt Jacob 			 * making sure we're aborting for the right multi-tid
1237746e9c85SMatt Jacob 			 * path. This doesn't really make much sense at present.
1238746e9c85SMatt Jacob 			 */
1239746e9c85SMatt Jacob #if	0
1240d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1241746e9c85SMatt Jacob #endif
1242d81ba9d5SMatt Jacob 		}
1243d81ba9d5SMatt Jacob 	}
1244a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
1245d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1246dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "can't get statep\n");
1247d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
1248d81ba9d5SMatt Jacob 	}
1249d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1250d81ba9d5SMatt Jacob 		lp = &tptr->atios;
1251746e9c85SMatt Jacob 		ctr = &tptr->atio_count;
1252d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
1253d81ba9d5SMatt Jacob 		lp = &tptr->inots;
1254746e9c85SMatt Jacob 		ctr = &tptr->inot_count;
1255d81ba9d5SMatt Jacob 	} else {
1256d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1257dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path, "bad function code %d\n",
1258dd9fc7c3SMatt Jacob 		    accb->ccb_h.func_code);
1259d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
1260d81ba9d5SMatt Jacob 	}
1261d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
1262d81ba9d5SMatt Jacob 	found = 0;
1263d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
1264d81ba9d5SMatt Jacob 		found = 1;
1265d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
1266d81ba9d5SMatt Jacob 	} else {
1267d81ba9d5SMatt Jacob 		while(curelm != NULL) {
1268d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
1269d81ba9d5SMatt Jacob 
1270d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
1271d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
1272d81ba9d5SMatt Jacob 				found = 1;
1273d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
1274d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
1275d81ba9d5SMatt Jacob 				break;
1276d81ba9d5SMatt Jacob 			}
1277d81ba9d5SMatt Jacob 			curelm = nextelm;
1278d81ba9d5SMatt Jacob 		}
1279d81ba9d5SMatt Jacob 	}
1280d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1281d81ba9d5SMatt Jacob 	if (found) {
1282c1504bc0SMatt Jacob 		(*ctr)--;
1283d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
1284746e9c85SMatt Jacob 		xpt_done(accb);
1285d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
1286d81ba9d5SMatt Jacob 	}
1287dd9fc7c3SMatt Jacob 	xpt_print(ccb->ccb_h.path, "ccb %p not found\n", accb);
1288d81ba9d5SMatt Jacob 	return (CAM_PATH_INVALID);
1289d81ba9d5SMatt Jacob }
1290d81ba9d5SMatt Jacob 
12919cd7268eSMatt Jacob static void
12929cd7268eSMatt Jacob isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb)
1293d81ba9d5SMatt Jacob {
1294d81ba9d5SMatt Jacob 	void *qe;
129500a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
129610365e5aSMatt Jacob 	uint32_t nxti, optr, handle;
12971dae40ebSMatt Jacob 	uint8_t local[QENTRY_LEN];
1298d81ba9d5SMatt Jacob 
1299f48ce188SMatt Jacob 
13004fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1301dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1302dd9fc7c3SMatt Jacob 		    "Request Queue Overflow in isp_target_start_ctio\n");
13039cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
13049cd7268eSMatt Jacob 		goto out;
1305d81ba9d5SMatt Jacob 	}
130629f76675SMatt Jacob 	memset(local, 0, QENTRY_LEN);
1307d81ba9d5SMatt Jacob 
1308d81ba9d5SMatt Jacob 	/*
1309d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1310d81ba9d5SMatt Jacob 	 */
1311d81ba9d5SMatt Jacob 
1312d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
131353036e92SMatt Jacob 		atio_private_data_t *atp;
13144fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
131500a8e174SMatt Jacob 
1316d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1317d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
131810365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_2klogin) {
131929f76675SMatt Jacob 			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
132029f76675SMatt Jacob 		} else {
132100a8e174SMatt Jacob 			cto->ct_iid = cso->init_id;
132210365e5aSMatt Jacob 			if (FCPARAM(isp)->isp_sccfw == 0) {
1323d81ba9d5SMatt Jacob 				cto->ct_lun = ccb->ccb_h.target_lun;
13242ad50ca5SMatt Jacob 			}
132529f76675SMatt Jacob 		}
132653036e92SMatt Jacob 
132753036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
132853036e92SMatt Jacob 		if (atp == NULL) {
1329dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path,
1330dd9fc7c3SMatt Jacob 			    "cannot find private data adjunct for tag %x\n",
133153036e92SMatt Jacob 			    cso->tag_id);
13329cd7268eSMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
13339cd7268eSMatt Jacob 			goto out;
133453036e92SMatt Jacob 		}
1335f48ce188SMatt Jacob 
133600a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
133700a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
133800a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1339f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
134000a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1341f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
134253036e92SMatt Jacob 				cto->ct_resid =
134353036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1344570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1345570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1346570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1347570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1348570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1349570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1350570c7a3fSMatt Jacob 				}
1351f48ce188SMatt Jacob 			}
135200a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
135300a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
135429f76675SMatt Jacob 				memcpy(cto->rsp.m1.ct_resp,
135529f76675SMatt Jacob 				    &cso->sense_data, m);
135600a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
135700a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
135800a8e174SMatt Jacob 			}
135900a8e174SMatt Jacob 		} else {
136000a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
136100a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
136200a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
136300a8e174SMatt Jacob 			} else {
136400a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1365d81ba9d5SMatt Jacob 			}
1366570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
1367d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1368d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
136900a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
137053036e92SMatt Jacob 				cto->ct_resid =
137153036e92SMatt Jacob 				    atp->orig_datalen -
137253036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
1373570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1374570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1375570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1376570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1377570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1378570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1379570c7a3fSMatt Jacob 				}
138053036e92SMatt Jacob 			} else {
138153036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1382d81ba9d5SMatt Jacob 			}
1383f48ce188SMatt Jacob 			/*
1384f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1385f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1386f48ce188SMatt Jacob 			 */
138700a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
138800a8e174SMatt Jacob 		}
138953036e92SMatt Jacob 
1390290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
139164edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
139253036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
139353036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
139453036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1395a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1396570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
13979cd7268eSMatt Jacob 		} else {
1398570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
13999cd7268eSMatt Jacob 		}
1400a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1401d81ba9d5SMatt Jacob 	} else {
14024fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
140300a8e174SMatt Jacob 
1404d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1405d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
140600a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1407a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1408d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1409d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1410a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1411a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
14121dae40ebSMatt Jacob 			cto->ct_tag_val = (uint8_t) AT_GET_TAG(cso->tag_id);
1413f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1414f48ce188SMatt Jacob 		}
1415f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1416f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1417f48ce188SMatt Jacob 		}
1418f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1419d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
142000a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
142100a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
142200a8e174SMatt Jacob 		} else {
142300a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1424d81ba9d5SMatt Jacob 		}
1425f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
142653036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
142700a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
142800a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
142964edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1430a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1431a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1432a1bc34c6SMatt Jacob 			    cso->tag_id);
143392a1e549SMatt Jacob 		}
143464edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1435a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
1436d81ba9d5SMatt Jacob 	}
1437d81ba9d5SMatt Jacob 
143810365e5aSMatt Jacob 	if (isp_save_xs_tgt(isp, ccb, &handle)) {
1439dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1440dd9fc7c3SMatt Jacob 		    "No XFLIST pointers for isp_target_start_ctio\n");
14419cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14429cd7268eSMatt Jacob 		goto out;
1443d81ba9d5SMatt Jacob 	}
1444d81ba9d5SMatt Jacob 
1445d81ba9d5SMatt Jacob 
1446d81ba9d5SMatt Jacob 	/*
1447d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1448d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1449b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1450d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1451d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1452d81ba9d5SMatt Jacob 	 * format.
1453d81ba9d5SMatt Jacob 	 */
1454d81ba9d5SMatt Jacob 
145510365e5aSMatt Jacob 	if (IS_FC(isp)) {
145610365e5aSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
145710365e5aSMatt Jacob 		cto->ct_syshandle = handle;
145810365e5aSMatt Jacob 	} else {
145910365e5aSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
146010365e5aSMatt Jacob 		cto->ct_syshandle = handle;
146110365e5aSMatt Jacob 	}
1462a1bc34c6SMatt Jacob 
14634fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1464d81ba9d5SMatt Jacob 	case CMD_QUEUED:
14654fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
14669cd7268eSMatt Jacob 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
14679cd7268eSMatt Jacob 		return;
1468d81ba9d5SMatt Jacob 
1469d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
14709cd7268eSMatt Jacob 		XS_SETERR(ccb, CAM_REQUEUE_REQ);
14719cd7268eSMatt Jacob 		break;
1472d81ba9d5SMatt Jacob 
1473d81ba9d5SMatt Jacob 	default:
14749cd7268eSMatt Jacob 		break;
1475d81ba9d5SMatt Jacob 	}
147610365e5aSMatt Jacob 	isp_destroy_tgt_handle(isp, handle);
14779cd7268eSMatt Jacob 
14789cd7268eSMatt Jacob out:
14799cd7268eSMatt Jacob 	xpt_done(ccb);
1480d81ba9d5SMatt Jacob }
1481d81ba9d5SMatt Jacob 
1482a1bc34c6SMatt Jacob static void
1483a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1484f48ce188SMatt Jacob {
1485a1bc34c6SMatt Jacob 	int s = splcam();
1486a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1487a1bc34c6SMatt Jacob 	splx(s);
1488a1bc34c6SMatt Jacob }
1489a1bc34c6SMatt Jacob 
1490a1bc34c6SMatt Jacob static void
1491a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1492a1bc34c6SMatt Jacob {
14939cd7268eSMatt Jacob 	ispsoftc_t *isp;
1494a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
149510365e5aSMatt Jacob 	uint32_t nxti, optr;
1496a1bc34c6SMatt Jacob 	void *qe;
1497a1bc34c6SMatt Jacob 
1498a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1499f48ce188SMatt Jacob 
15004fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1501dd9fc7c3SMatt Jacob 		xpt_print(ccb->ccb_h.path,
1502dd9fc7c3SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow\n");
1503a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1504a1bc34c6SMatt Jacob 		return;
1505f48ce188SMatt Jacob 	}
150629f76675SMatt Jacob 	memset(qe, 0, QENTRY_LEN);
1507a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1508f48ce188SMatt Jacob 	if (IS_FC(isp)) {
15094fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
15104fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1511f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1512f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
151310365e5aSMatt Jacob 		if (FCPARAM(isp)->isp_sccfw) {
1514a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1515f48ce188SMatt Jacob 		} else {
1516a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1517f48ce188SMatt Jacob 		}
1518f48ce188SMatt Jacob 		at->at_status = CT_OK;
1519a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1520570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
15214fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1522f48ce188SMatt Jacob 	} else {
15234fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
15244fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1525f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1526f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1527a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1528a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1529a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1530a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1531f48ce188SMatt Jacob 		at->at_status = CT_OK;
1532a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1533a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
15344fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1535f48ce188SMatt Jacob 	}
1536f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
15374fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1538a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1539f48ce188SMatt Jacob }
1540f48ce188SMatt Jacob 
1541f48ce188SMatt Jacob static void
1542a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1543f48ce188SMatt Jacob {
1544a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1545a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1546f48ce188SMatt Jacob 	}
1547a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1548a1bc34c6SMatt Jacob 	xpt_done(ccb);
1549f48ce188SMatt Jacob }
1550f48ce188SMatt Jacob 
1551d81ba9d5SMatt Jacob /*
1552d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1553d81ba9d5SMatt Jacob  * This means handling CDBs.
1554d81ba9d5SMatt Jacob  */
1555d81ba9d5SMatt Jacob 
1556d81ba9d5SMatt Jacob static int
15579cd7268eSMatt Jacob isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep)
1558d81ba9d5SMatt Jacob {
1559d81ba9d5SMatt Jacob 	tstate_t *tptr;
156064edff94SMatt Jacob 	int status, bus, iswildcard;
1561d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1562d81ba9d5SMatt Jacob 
1563d81ba9d5SMatt Jacob 	/*
1564d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1565d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1566d81ba9d5SMatt Jacob 	 *
1567d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1568d81ba9d5SMatt Jacob 	 *
1569d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
15705d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1571d81ba9d5SMatt Jacob 	 */
1572d81ba9d5SMatt Jacob 	status = aep->at_status;
1573d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1574d81ba9d5SMatt Jacob 		/*
1575d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1576d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1577d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1578d81ba9d5SMatt Jacob 		 */
15793c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1580d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1581d81ba9d5SMatt Jacob 		return (0);
1582d81ba9d5SMatt Jacob 	}
1583d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
15845d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
15853c75bb14SMatt Jacob 		    status);
1586d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1587d81ba9d5SMatt Jacob 		return (0);
1588d81ba9d5SMatt Jacob 	}
1589d81ba9d5SMatt Jacob 
15905d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1591a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1592d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1593a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
1594746e9c85SMatt Jacob 		if (tptr == NULL) {
1595d81ba9d5SMatt Jacob 			/*
1596d81ba9d5SMatt Jacob 			 * Because we can't autofeed sense data back with
1597d81ba9d5SMatt Jacob 			 * a command for parallel SCSI, we can't give back
1598d81ba9d5SMatt Jacob 			 * a CHECK CONDITION. We'll give back a BUSY status
1599d81ba9d5SMatt Jacob 			 * instead. This works out okay because the only
1600d81ba9d5SMatt Jacob 			 * time we should, in fact, get this, is in the
1601d81ba9d5SMatt Jacob 			 * case that somebody configured us without the
1602d81ba9d5SMatt Jacob 			 * blackhole driver, so they get what they deserve.
1603d81ba9d5SMatt Jacob 			 */
1604d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1605d81ba9d5SMatt Jacob 			return (0);
1606d81ba9d5SMatt Jacob 		}
16078c4e89e2SMatt Jacob 		iswildcard = 1;
16088c4e89e2SMatt Jacob 	} else {
16098c4e89e2SMatt Jacob 		iswildcard = 0;
16108c4e89e2SMatt Jacob 	}
1611d81ba9d5SMatt Jacob 
1612d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1613d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1614d81ba9d5SMatt Jacob 		/*
1615d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1616d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1617d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1618d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1619d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1620d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1621d81ba9d5SMatt Jacob 		 */
1622dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1623dd9fc7c3SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d\n",
16245d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1625d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1626d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1627d81ba9d5SMatt Jacob 		else
1628d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
162964edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1630d81ba9d5SMatt Jacob 		return (0);
1631d81ba9d5SMatt Jacob 	}
1632d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1633746e9c85SMatt Jacob 	tptr->atio_count--;
1634746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1635746e9c85SMatt Jacob 	    aep->at_lun, tptr->atio_count);
163664edff94SMatt Jacob 	if (iswildcard) {
1637d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1638d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1639d81ba9d5SMatt Jacob 	}
1640d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1641f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1642f48ce188SMatt Jacob 	} else {
1643f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1644d81ba9d5SMatt Jacob 	}
1645d81ba9d5SMatt Jacob 
1646f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1647f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1648f48ce188SMatt Jacob 		atiop->sense_len = amt;
1649f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1650f48ce188SMatt Jacob 	} else {
1651f48ce188SMatt Jacob 		atiop->sense_len = 0;
1652f48ce188SMatt Jacob 	}
1653d81ba9d5SMatt Jacob 
16545d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1655d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1656d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1657d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1658a1bc34c6SMatt Jacob 	/*
1659a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1660a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1661a1bc34c6SMatt Jacob 	 */
16626c81a0aeSMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id, bus, device_get_unit(isp->isp_dev), aep);
1663a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1664a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1665d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1666d81ba9d5SMatt Jacob 	}
1667d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
166864edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
16695d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
16705d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
16715d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
16725d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
16735d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1674d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1675d81ba9d5SMatt Jacob 	return (0);
1676d81ba9d5SMatt Jacob }
1677d81ba9d5SMatt Jacob 
1678d81ba9d5SMatt Jacob static int
16799cd7268eSMatt Jacob isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep)
1680d81ba9d5SMatt Jacob {
168192a1e549SMatt Jacob 	lun_id_t lun;
1682d81ba9d5SMatt Jacob 	tstate_t *tptr;
1683d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
168453036e92SMatt Jacob 	atio_private_data_t *atp;
1685d81ba9d5SMatt Jacob 
1686d81ba9d5SMatt Jacob 	/*
1687d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1688d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1689d81ba9d5SMatt Jacob 	 *
1690d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1691d81ba9d5SMatt Jacob 	 */
1692d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
16933c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
16943c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1695d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1696d81ba9d5SMatt Jacob 		return (0);
1697d81ba9d5SMatt Jacob 	}
1698d81ba9d5SMatt Jacob 
169910365e5aSMatt Jacob 	if (FCPARAM(isp)->isp_sccfw) {
170092a1e549SMatt Jacob 		lun = aep->at_scclun;
17012ad50ca5SMatt Jacob 	} else {
170292a1e549SMatt Jacob 		lun = aep->at_lun;
17032ad50ca5SMatt Jacob 	}
1704a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1705d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1706746e9c85SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
1707746e9c85SMatt Jacob 		    "[0x%x] no state pointer for lun %d", aep->at_rxid, lun);
1708a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1709746e9c85SMatt Jacob 		if (tptr == NULL) {
1710746e9c85SMatt Jacob 			isp_endcmd(isp, aep,
1711746e9c85SMatt Jacob 			    SCSI_STATUS_CHECK_COND | ECMD_SVALID |
1712746e9c85SMatt Jacob 			    (0x5 << 12) | (0x25 << 16), 0);
1713746e9c85SMatt Jacob 			return (0);
1714746e9c85SMatt Jacob 		}
1715d81ba9d5SMatt Jacob 	}
1716d81ba9d5SMatt Jacob 
171753036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1718d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
171953036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1720746e9c85SMatt Jacob 
1721d81ba9d5SMatt Jacob 		/*
1722d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1723d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1724d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1725d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1726d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1727d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1728d81ba9d5SMatt Jacob 		 */
1729dd9fc7c3SMatt Jacob 		xpt_print(tptr->owner,
1730dd9fc7c3SMatt Jacob 		    "no %s for lun %d from initiator %d\n",
1731570c7a3fSMatt Jacob 		    (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
1732570c7a3fSMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
1733d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1734d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1735d81ba9d5SMatt Jacob 		return (0);
1736d81ba9d5SMatt Jacob 	}
1737570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1738d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1739570c7a3fSMatt Jacob 	tptr->atio_count--;
1740746e9c85SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO lun %d, count now %d",
1741570c7a3fSMatt Jacob 	    lun, tptr->atio_count);
1742f48ce188SMatt Jacob 
1743a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
174410365e5aSMatt Jacob 		atiop->ccb_h.target_id = FCPARAM(isp)->isp_loopid;
174592a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1746d81ba9d5SMatt Jacob 	}
1747b0a3ba7eSMatt Jacob 	/*
1748b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1749b0a3ba7eSMatt Jacob 	 */
1750f48ce188SMatt Jacob 	atiop->sense_len = 0;
1751f48ce188SMatt Jacob 
1752d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1753d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1754d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1755d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1756d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1757d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1758d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1759d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1760d81ba9d5SMatt Jacob 		break;
1761d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1762d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1763d81ba9d5SMatt Jacob 		break;
1764d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1765d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1766d81ba9d5SMatt Jacob 		break;
1767d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1768d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1769d81ba9d5SMatt Jacob 	default:
1770d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1771d81ba9d5SMatt Jacob 		break;
1772d81ba9d5SMatt Jacob 	}
1773570c7a3fSMatt Jacob 	atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
1774f48ce188SMatt Jacob 
177553036e92SMatt Jacob 	atp->tag = atiop->tag_id;
1776570c7a3fSMatt Jacob 	atp->lun = lun;
177753036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
177853036e92SMatt Jacob 	atp->last_xframt = 0;
177953036e92SMatt Jacob 	atp->bytes_xfered = 0;
1780570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
1781d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
1782570c7a3fSMatt Jacob 
178364edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
17845f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
17855f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1786b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1787d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1788d81ba9d5SMatt Jacob 	return (0);
1789d81ba9d5SMatt Jacob }
1790d81ba9d5SMatt Jacob 
1791d81ba9d5SMatt Jacob static int
17929cd7268eSMatt Jacob isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
1793d81ba9d5SMatt Jacob {
1794d81ba9d5SMatt Jacob 	union ccb *ccb;
1795a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
17961dae40ebSMatt Jacob 	uint16_t tval;
1797d81ba9d5SMatt Jacob 
1798d81ba9d5SMatt Jacob 	/*
1799d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1800d81ba9d5SMatt Jacob 	 */
1801d81ba9d5SMatt Jacob 
180251e23558SNate Lawson 	ccb = isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle);
1803d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
180451e23558SNate Lawson 	isp_destroy_tgt_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1805d81ba9d5SMatt Jacob 
1806d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1807d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1808570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
1809570c7a3fSMatt Jacob 		if (atp == NULL) {
1810570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1811570c7a3fSMatt Jacob 			    "cannot find adjunct for %x after I/O",
1812570c7a3fSMatt Jacob 			    ct->ct_rxid);
1813570c7a3fSMatt Jacob 			return (0);
1814570c7a3fSMatt Jacob 		}
1815d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1816d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1817a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
181800a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
181900a8e174SMatt Jacob 		}
1820a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
18215d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
1822a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
182353036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
182453036e92SMatt Jacob 			atp->last_xframt = 0;
1825570c7a3fSMatt Jacob 		}
1826570c7a3fSMatt Jacob 		if (sentstatus || !ok) {
182753036e92SMatt Jacob 			atp->tag = 0;
182853036e92SMatt Jacob 		}
1829570c7a3fSMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
183064edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
183164edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
183264edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
183364edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
183464edff94SMatt Jacob 		tval = ct->ct_rxid;
1835570c7a3fSMatt Jacob 
1836570c7a3fSMatt Jacob 		/* XXX: should really come after isp_complete_ctio */
1837570c7a3fSMatt Jacob 		atp->state = ATPD_STATE_PDON;
1838d81ba9d5SMatt Jacob 	} else {
1839d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1840d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1841d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1842d81ba9d5SMatt Jacob 		/*
1843a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1844a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1845a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1846a1bc34c6SMatt Jacob 		 * private data.
1847a1bc34c6SMatt Jacob 		 *
1848a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1849a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1850a1bc34c6SMatt Jacob 		 */
1851a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1852a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1853a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1854a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1855a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1856a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1857a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1858a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1859a1bc34c6SMatt Jacob 		}
18605d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1861a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1862a1bc34c6SMatt Jacob 		}
186364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
186464edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
186564edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
186664edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
186764edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
186864edff94SMatt Jacob 		tval = ct->ct_fwhandle;
18695d571944SMatt Jacob 	}
1870a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1871a1bc34c6SMatt Jacob 
1872a1bc34c6SMatt Jacob 	/*
1873a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1874a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1875a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1876d81ba9d5SMatt Jacob 	 *
1877d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1878d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1879a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1880a1bc34c6SMatt Jacob 	 * freed.
1881d81ba9d5SMatt Jacob 	 */
1882f48ce188SMatt Jacob 	if (notify_cam == 0) {
188364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1884f48ce188SMatt Jacob 		return (0);
1885f48ce188SMatt Jacob 	}
1886d81ba9d5SMatt Jacob 
188753036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
188853036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1889a1bc34c6SMatt Jacob 
1890a1bc34c6SMatt Jacob 	if (!ok) {
1891a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1892d81ba9d5SMatt Jacob 	} else {
1893a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1894a1bc34c6SMatt Jacob 
1895d81ba9d5SMatt Jacob 	}
1896a1bc34c6SMatt Jacob 	return (0);
1897d81ba9d5SMatt Jacob }
1898570c7a3fSMatt Jacob 
1899570c7a3fSMatt Jacob static int
19009cd7268eSMatt Jacob isp_handle_platform_notify_scsi(ispsoftc_t *isp, in_entry_t *inp)
1901570c7a3fSMatt Jacob {
1902570c7a3fSMatt Jacob 	return (0);	/* XXXX */
1903570c7a3fSMatt Jacob }
1904570c7a3fSMatt Jacob 
1905570c7a3fSMatt Jacob static int
19069cd7268eSMatt Jacob isp_handle_platform_notify_fc(ispsoftc_t *isp, in_fcentry_t *inp)
1907570c7a3fSMatt Jacob {
1908570c7a3fSMatt Jacob 
1909570c7a3fSMatt Jacob 	switch (inp->in_status) {
1910570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
1911570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
1912570c7a3fSMatt Jacob 		   inp->in_iid);
1913570c7a3fSMatt Jacob 		break;
1914570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
1915570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
1916570c7a3fSMatt Jacob 		   inp->in_iid);
1917570c7a3fSMatt Jacob 		break;
1918570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
1919570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
1920570c7a3fSMatt Jacob 		break;
1921570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
1922570c7a3fSMatt Jacob 	{
1923570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
1924570c7a3fSMatt Jacob 		struct ccb_immed_notify *inot = NULL;
1925570c7a3fSMatt Jacob 
1926570c7a3fSMatt Jacob 		if (atp) {
1927570c7a3fSMatt Jacob 			tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
1928570c7a3fSMatt Jacob 			if (tptr) {
1929570c7a3fSMatt Jacob 				inot = (struct ccb_immed_notify *)
1930570c7a3fSMatt Jacob 				    SLIST_FIRST(&tptr->inots);
1931570c7a3fSMatt Jacob 				if (inot) {
1932746e9c85SMatt Jacob 					tptr->inot_count--;
1933570c7a3fSMatt Jacob 					SLIST_REMOVE_HEAD(&tptr->inots,
1934570c7a3fSMatt Jacob 					    sim_links.sle);
1935746e9c85SMatt Jacob 					isp_prt(isp, ISP_LOGTDEBUG0,
1936746e9c85SMatt Jacob 					    "Take FREE INOT count now %d",
1937746e9c85SMatt Jacob 					    tptr->inot_count);
1938570c7a3fSMatt Jacob 				}
1939570c7a3fSMatt Jacob 			}
1940570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1941570c7a3fSMatt Jacob 			   "abort task RX_ID %x IID %d state %d",
1942570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid, atp->state);
1943570c7a3fSMatt Jacob 		} else {
1944570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1945570c7a3fSMatt Jacob 			   "abort task RX_ID %x from iid %d, state unknown",
1946570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid);
1947570c7a3fSMatt Jacob 		}
1948570c7a3fSMatt Jacob 		if (inot) {
1949570c7a3fSMatt Jacob 			inot->initiator_id = inp->in_iid;
1950570c7a3fSMatt Jacob 			inot->sense_len = 0;
1951570c7a3fSMatt Jacob 			inot->message_args[0] = MSG_ABORT_TAG;
1952570c7a3fSMatt Jacob 			inot->message_args[1] = inp->in_seqid & 0xff;
1953570c7a3fSMatt Jacob 			inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
19546b5ec766SMatt Jacob 			inot->ccb_h.status = CAM_MESSAGE_RECV;
1955570c7a3fSMatt Jacob 			xpt_done((union ccb *)inot);
1956570c7a3fSMatt Jacob 		}
1957570c7a3fSMatt Jacob 		break;
1958570c7a3fSMatt Jacob 	}
1959570c7a3fSMatt Jacob 	default:
1960570c7a3fSMatt Jacob 		break;
1961570c7a3fSMatt Jacob 	}
1962570c7a3fSMatt Jacob 	return (0);
1963570c7a3fSMatt Jacob }
1964d81ba9d5SMatt Jacob #endif
1965d81ba9d5SMatt Jacob 
1966478f8a96SJustin T. Gibbs static void
19671dae40ebSMatt Jacob isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg)
1968478f8a96SJustin T. Gibbs {
1969478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
19709cd7268eSMatt Jacob 	ispsoftc_t *isp;
1971478f8a96SJustin T. Gibbs 
1972478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
19739cd7268eSMatt Jacob 	isp = (ispsoftc_t *) cam_sim_softc(sim);
1974478f8a96SJustin T. Gibbs 	switch (code) {
1975478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1976ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
19771dae40ebSMatt Jacob 			uint16_t oflags, nflags;
1978478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1979a1bc34c6SMatt Jacob 			int tgt;
1980478f8a96SJustin T. Gibbs 
1981f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
198241ed683eSMatt Jacob 			if (tgt >= 0) {
1983ea6f23cdSMatt Jacob 				sdp += cam_sim_bus(sim);
19849ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
1985a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
19869ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
1987a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
1988478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
1989478f8a96SJustin T. Gibbs 				}
1990a1bc34c6SMatt Jacob #else
1991a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
1992a1bc34c6SMatt Jacob #endif
19939ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
19949ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
1995478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
1996a1bc34c6SMatt Jacob 				isp->isp_update |= (1 << cam_sim_bus(sim));
199741ed683eSMatt Jacob 				(void) isp_control(isp,
199841ed683eSMatt Jacob 				    ISPCTL_UPDATE_PARAMS, NULL);
19999ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
2000478f8a96SJustin T. Gibbs 			}
200141ed683eSMatt Jacob 		}
2002478f8a96SJustin T. Gibbs 		break;
2003478f8a96SJustin T. Gibbs 	default:
20043c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
2005478f8a96SJustin T. Gibbs 		break;
2006478f8a96SJustin T. Gibbs 	}
2007478f8a96SJustin T. Gibbs }
2008478f8a96SJustin T. Gibbs 
2009478f8a96SJustin T. Gibbs static void
2010c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
2011478f8a96SJustin T. Gibbs {
20129cd7268eSMatt Jacob 	ispsoftc_t *isp = cam_sim_softc(sim);
201310365e5aSMatt Jacob 	uint32_t isr;
201410365e5aSMatt Jacob 	uint16_t sema, mbox;
2015126ec864SMatt Jacob 
2016126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2017126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
2018126ec864SMatt Jacob 	}
2019478f8a96SJustin T. Gibbs }
2020478f8a96SJustin T. Gibbs 
2021ab6c4b31SMatt Jacob 
2022f7c631bcSMatt Jacob static int isp_watchdog_work(ispsoftc_t *, XS_T *);
2023f7c631bcSMatt Jacob 
2024f7c631bcSMatt Jacob static int
2025f7c631bcSMatt Jacob isp_watchdog_work(ispsoftc_t *isp, XS_T *xs)
2026cc8df88bSMatt Jacob {
20271dae40ebSMatt Jacob 	uint32_t handle;
2028b85389e1SMatt Jacob 
2029cc8df88bSMatt Jacob 	/*
2030b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
2031b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
2032b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
2033cc8df88bSMatt Jacob 	 */
2034cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
2035cc8df88bSMatt Jacob 	if (handle) {
203610365e5aSMatt Jacob 		uint32_t isr;
203710365e5aSMatt Jacob 		uint16_t sema, mbox;
2038126ec864SMatt Jacob 
2039b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2040b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
2041b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
2042f7c631bcSMatt Jacob 			return (1);;
2043b85389e1SMatt Jacob 		}
2044b85389e1SMatt Jacob 
2045b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
2046b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2047b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
2048f7c631bcSMatt Jacob 			return (1);
2049b85389e1SMatt Jacob 		}
2050b85389e1SMatt Jacob 
2051b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
2052126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
2053126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
2054126ec864SMatt Jacob 		}
2055126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
2056b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2057126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
20580a70657fSMatt Jacob 			isp_free_pcmd(isp, (union ccb *)xs);
2059b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
2060b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
20611fcf5debSMatt Jacob 			/*
20621fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
20631fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
20641fcf5debSMatt Jacob 			 */
2065f7c631bcSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, xs);
20661fcf5debSMatt Jacob 
20671fcf5debSMatt Jacob 			/*
20681fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
20691fcf5debSMatt Jacob 			 */
2070f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
2071f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
2072f6e75de2SMatt Jacob                 	}
2073cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
2074dd9fc7c3SMatt Jacob 			xpt_print(xs->ccb_h.path,
2075dd9fc7c3SMatt Jacob 			    "watchdog timeout for handle 0x%x\n", handle);
2076cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
2077b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2078cc8df88bSMatt Jacob 			isp_done(xs);
2079b85389e1SMatt Jacob 		} else {
2080b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
2081b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
2082b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
208310365e5aSMatt Jacob 			isp->isp_sendmarker |= 1 << XS_CHANNEL(xs);
2084b85389e1SMatt Jacob 		}
2085f7c631bcSMatt Jacob 		return (1);
2086cc8df88bSMatt Jacob 	}
2087f7c631bcSMatt Jacob 	return (0);
2088f7c631bcSMatt Jacob }
2089f7c631bcSMatt Jacob 
2090f7c631bcSMatt Jacob static void
2091f7c631bcSMatt Jacob isp_watchdog(void *arg)
2092f7c631bcSMatt Jacob {
2093f7c631bcSMatt Jacob 	ispsoftc_t *isp;
2094f7c631bcSMatt Jacob 	XS_T *xs = arg;
20950a70657fSMatt Jacob 	int r;
20960a70657fSMatt Jacob 
20970a70657fSMatt Jacob 	for (r = 0, isp = isplist; r && isp; isp = isp->isp_osinfo.next) {
20980a70657fSMatt Jacob 		ISP_LOCK(isp);
20990a70657fSMatt Jacob 		r = isp_watchdog_work(isp, xs);
21000a70657fSMatt Jacob 		ISP_UNLOCK(isp);
2101f7c631bcSMatt Jacob 	}
2102f7c631bcSMatt Jacob 	if (isp == NULL) {
2103f7c631bcSMatt Jacob 		printf("isp_watchdog: nobody had %p active\n", arg);
2104f7c631bcSMatt Jacob 	}
2105f7c631bcSMatt Jacob }
2106f7c631bcSMatt Jacob 
2107f7c631bcSMatt Jacob 
210870273f90SMatt Jacob #if __FreeBSD_version >= 600000
2109f7c631bcSMatt Jacob static void
2110ffcf6651SMatt Jacob isp_make_here(ispsoftc_t *isp, int tgt)
2111f7c631bcSMatt Jacob {
2112ffcf6651SMatt Jacob 	union ccb *ccb;
2113ffcf6651SMatt Jacob 	/*
2114ffcf6651SMatt Jacob 	 * Allocate a CCB, create a wildcard path for this bus,
2115ffcf6651SMatt Jacob 	 * and schedule a rescan.
2116ffcf6651SMatt Jacob 	 */
21178008a935SScott Long 	ccb = xpt_alloc_ccb_nowait();
2118ffcf6651SMatt Jacob 	if (ccb == NULL) {
2119ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to alloc CCB for rescan");
2120ffcf6651SMatt Jacob 		return;
2121ffcf6651SMatt Jacob 	}
2122ffcf6651SMatt Jacob 	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph,
2123ffcf6651SMatt Jacob 	    cam_sim_path(isp->isp_sim), tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2124ffcf6651SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "unable to create path for rescan");
2125ffcf6651SMatt Jacob 		xpt_free_ccb(ccb);
2126ffcf6651SMatt Jacob 		return;
2127ffcf6651SMatt Jacob 	}
2128ffcf6651SMatt Jacob 	xpt_rescan(ccb);
2129ffcf6651SMatt Jacob }
2130ffcf6651SMatt Jacob 
2131ffcf6651SMatt Jacob static void
2132ffcf6651SMatt Jacob isp_make_gone(ispsoftc_t *isp, int tgt)
2133ffcf6651SMatt Jacob {
2134ffcf6651SMatt Jacob 	struct cam_path *tp;
2135ffcf6651SMatt Jacob 	if (xpt_create_path(&tp, NULL, cam_sim_path(isp->isp_sim), tgt,
2136f7c631bcSMatt Jacob 	    CAM_LUN_WILDCARD) == CAM_REQ_CMP) {
2137ffcf6651SMatt Jacob 		xpt_async(AC_LOST_DEVICE, tp, NULL);
2138ffcf6651SMatt Jacob 		xpt_free_path(tp);
2139f7c631bcSMatt Jacob 	}
2140f7c631bcSMatt Jacob }
2141f7c631bcSMatt Jacob #else
2142f7c631bcSMatt Jacob #define	isp_make_here(isp, tgt)	do { ; } while (0)
2143f7c631bcSMatt Jacob #define	isp_make_gone(isp, tgt)	do { ; } while (0)
2144f7c631bcSMatt Jacob #endif
2145f7c631bcSMatt Jacob 
2146f7c631bcSMatt Jacob 
2147f7c631bcSMatt Jacob /*
2148f7c631bcSMatt Jacob  * Gone Device Timer Function- when we have decided that a device has gone
2149f7c631bcSMatt Jacob  * away, we wait a specific period of time prior to telling the OS it has
2150f7c631bcSMatt Jacob  * gone away.
2151f7c631bcSMatt Jacob  *
2152f7c631bcSMatt Jacob  * This timer function fires once a second and then scans the port database
2153f7c631bcSMatt Jacob  * for devices that are marked dead but still have a virtual target assigned.
2154f7c631bcSMatt Jacob  * We decrement a counter for that port database entry, and when it hits zero,
2155f7c631bcSMatt Jacob  * we tell the OS the device has gone away.
2156f7c631bcSMatt Jacob  */
2157f7c631bcSMatt Jacob static void
2158f7c631bcSMatt Jacob isp_gdt(void *arg)
2159f7c631bcSMatt Jacob {
2160f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2161f7c631bcSMatt Jacob 	fcportdb_t *lp;
2162f7c631bcSMatt Jacob 	int dbidx, tgt, more_to_do = 0;
2163f7c631bcSMatt Jacob 
2164f7c631bcSMatt Jacob 	ISP_LOCK(isp);
21650a70657fSMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG0, "GDT timer expired");
2166f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2167f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2168f7c631bcSMatt Jacob 
2169f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_ZOMBIE) {
2170f7c631bcSMatt Jacob 			continue;
2171f7c631bcSMatt Jacob 		}
2172f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2173f7c631bcSMatt Jacob 			continue;
2174f7c631bcSMatt Jacob 		}
2175f7c631bcSMatt Jacob 		if (lp->new_reserved == 0) {
2176f7c631bcSMatt Jacob 			continue;
2177f7c631bcSMatt Jacob 		}
2178f7c631bcSMatt Jacob 		lp->new_reserved -= 1;
2179f7c631bcSMatt Jacob 		if (lp->new_reserved != 0) {
2180f7c631bcSMatt Jacob 			more_to_do++;
2181f7c631bcSMatt Jacob 			continue;
2182f7c631bcSMatt Jacob 		}
2183f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2184f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2185f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2186f7c631bcSMatt Jacob 		lp->state = FC_PORTDB_STATE_NIL;
2187f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2188f7c631bcSMatt Jacob 		    "Gone Device Timeout");
2189f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2190f7c631bcSMatt Jacob 	}
2191f7c631bcSMatt Jacob 	if (more_to_do) {
21920a70657fSMatt Jacob 		isp->isp_osinfo.gdt_running = 1;
21930a70657fSMatt Jacob 		callout_reset(&isp->isp_osinfo.gdt, hz, isp_gdt, isp);
2194f7c631bcSMatt Jacob 	} else {
2195f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2196f7c631bcSMatt Jacob 		    "stopping Gone Device Timer");
2197f7c631bcSMatt Jacob 		isp->isp_osinfo.gdt_running = 0;
2198f7c631bcSMatt Jacob 	}
2199f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2200f7c631bcSMatt Jacob }
2201f7c631bcSMatt Jacob 
2202f7c631bcSMatt Jacob /*
2203f7c631bcSMatt Jacob  * Loop Down Timer Function- when loop goes down, a timer is started and
2204f7c631bcSMatt Jacob  * and after it expires we come here and take all probational devices that
2205f7c631bcSMatt Jacob  * the OS knows about and the tell the OS that they've gone away.
2206f7c631bcSMatt Jacob  *
2207f7c631bcSMatt Jacob  * We don't clear the devices out of our port database because, when loop
2208f7c631bcSMatt Jacob  * come back up, we have to do some actual cleanup with the chip at that
2209f7c631bcSMatt Jacob  * point (implicit PLOGO, e.g., to get the chip's port database state right).
2210f7c631bcSMatt Jacob  */
2211f7c631bcSMatt Jacob static void
2212f7c631bcSMatt Jacob isp_ldt(void *arg)
2213f7c631bcSMatt Jacob {
2214f7c631bcSMatt Jacob 	ispsoftc_t *isp = arg;
2215f7c631bcSMatt Jacob 	fcportdb_t *lp;
2216f7c631bcSMatt Jacob 	int dbidx, tgt;
2217f7c631bcSMatt Jacob 
2218f7c631bcSMatt Jacob 	ISP_LOCK(isp);
2219f7c631bcSMatt Jacob 
22200a70657fSMatt Jacob 	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired");
22210a70657fSMatt Jacob 
2222f7c631bcSMatt Jacob 	/*
2223f7c631bcSMatt Jacob 	 * Notify to the OS all targets who we now consider have departed.
2224f7c631bcSMatt Jacob 	 */
2225f7c631bcSMatt Jacob 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
2226f7c631bcSMatt Jacob 		lp = &FCPARAM(isp)->portdb[dbidx];
2227f7c631bcSMatt Jacob 
2228f7c631bcSMatt Jacob 		if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
2229f7c631bcSMatt Jacob 			continue;
2230f7c631bcSMatt Jacob 		}
2231f7c631bcSMatt Jacob 		if (lp->ini_map_idx == 0) {
2232f7c631bcSMatt Jacob 			continue;
2233f7c631bcSMatt Jacob 		}
2234f7c631bcSMatt Jacob 
2235f7c631bcSMatt Jacob 		/*
2236f7c631bcSMatt Jacob 		 * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST!
2237f7c631bcSMatt Jacob 		 */
2238f7c631bcSMatt Jacob 
2239f7c631bcSMatt Jacob 		/*
2240f7c631bcSMatt Jacob 		 * Mark that we've announced that this device is gone....
2241f7c631bcSMatt Jacob 		 */
2242f7c631bcSMatt Jacob 		lp->reserved = 1;
2243f7c631bcSMatt Jacob 
2244f7c631bcSMatt Jacob 		/*
2245f7c631bcSMatt Jacob 		 * but *don't* change the state of the entry. Just clear
2246f7c631bcSMatt Jacob 		 * any target id stuff and announce to CAM that the
2247f7c631bcSMatt Jacob 		 * device is gone. This way any necessary PLOGO stuff
2248f7c631bcSMatt Jacob 		 * will happen when loop comes back up.
2249f7c631bcSMatt Jacob 		 */
2250f7c631bcSMatt Jacob 
2251f7c631bcSMatt Jacob 		tgt = lp->ini_map_idx - 1;
2252f7c631bcSMatt Jacob 		FCPARAM(isp)->isp_ini_map[tgt] = 0;
2253f7c631bcSMatt Jacob 		lp->ini_map_idx = 0;
2254f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGCONFIG, prom3, lp->portid, tgt,
2255f7c631bcSMatt Jacob 		    "Loop Down Timeout");
2256f7c631bcSMatt Jacob 		isp_make_gone(isp, tgt);
2257f7c631bcSMatt Jacob 	}
2258f7c631bcSMatt Jacob 
2259f7c631bcSMatt Jacob 	/*
2260f7c631bcSMatt Jacob 	 * The loop down timer has expired. Wake up the kthread
2261f7c631bcSMatt Jacob 	 * to notice that fact (or make it false).
2262f7c631bcSMatt Jacob 	 */
2263f7c631bcSMatt Jacob 	isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1;
22640a70657fSMatt Jacob 	wakeup(ISP_KT_WCHAN(isp));
2265f7c631bcSMatt Jacob 	ISP_UNLOCK(isp);
2266cc8df88bSMatt Jacob }
2267cc8df88bSMatt Jacob 
22685d571944SMatt Jacob static void
22695d571944SMatt Jacob isp_kthread(void *arg)
22705d571944SMatt Jacob {
22719cd7268eSMatt Jacob 	ispsoftc_t *isp = arg;
2272f7c631bcSMatt Jacob 	int slp = 0;
22739cd7268eSMatt Jacob #if __FreeBSD_version < 500000
22740a70657fSMatt Jacob         int s = splcam();
22750a70657fSMatt Jacob #elif __FreeBSD_version < 700037
2276ee76282eSMatt Jacob 	mtx_lock(&Giant);
22770a70657fSMatt Jacob #else
22780a70657fSMatt Jacob 	mtx_lock(&isp->isp_osinfo.lock);
22799cd7268eSMatt Jacob #endif
2280fdeb9f2fSMatt Jacob 	/*
2281fdeb9f2fSMatt Jacob 	 * The first loop is for our usage where we have yet to have
2282fdeb9f2fSMatt Jacob 	 * gotten good fibre channel state.
2283fdeb9f2fSMatt Jacob 	 */
22845d571944SMatt Jacob 	for (;;) {
2285f7c631bcSMatt Jacob 		int wasfrozen, lb, lim;
2286fdeb9f2fSMatt Jacob 
2287f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2288f7c631bcSMatt Jacob 		    "isp_kthread: checking FC state");
2289f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
229010365e5aSMatt Jacob 		lb = isp_fc_runstate(isp, 250000);
2291f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
229210365e5aSMatt Jacob 		if (lb) {
2293f7c631bcSMatt Jacob 			/*
2294f7c631bcSMatt Jacob 			 * Increment loop down time by the last sleep interval
2295f7c631bcSMatt Jacob 			 */
2296f7c631bcSMatt Jacob 			isp->isp_osinfo.loop_down_time += slp;
229710365e5aSMatt Jacob 
229810365e5aSMatt Jacob 			if (lb < 0) {
2299f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
230010365e5aSMatt Jacob 				    "kthread: FC loop not up (down count %d)",
230110365e5aSMatt Jacob 				    isp->isp_osinfo.loop_down_time);
230210365e5aSMatt Jacob 			} else {
2303f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
230410365e5aSMatt Jacob 				    "kthread: FC got to %d (down count %d)",
230510365e5aSMatt Jacob 				    lb, isp->isp_osinfo.loop_down_time);
2306f44257c2SMatt Jacob 			}
230710365e5aSMatt Jacob 
230810365e5aSMatt Jacob 
230910365e5aSMatt Jacob 			/*
231010365e5aSMatt Jacob 			 * If we've never seen loop up and we've waited longer
2311f7c631bcSMatt Jacob 			 * than quickboot time, or we've seen loop up but we've
2312f7c631bcSMatt Jacob 			 * waited longer than loop_down_limit, give up and go
2313f7c631bcSMatt Jacob 			 * to sleep until loop comes up.
231410365e5aSMatt Jacob 			 */
2315f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2316f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
231710365e5aSMatt Jacob 			} else {
2318f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2319f7c631bcSMatt Jacob 			}
2320f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2321f7c631bcSMatt Jacob 				isp_freeze_loopdown(isp, "loop limit hit");
2322f7c631bcSMatt Jacob 				slp = 0;
2323f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 10) {
232410365e5aSMatt Jacob 				slp = 1;
2325f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 30) {
2326f7c631bcSMatt Jacob 				slp = 5;
2327f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 60) {
2328f7c631bcSMatt Jacob 				slp = 10;
2329f7c631bcSMatt Jacob 			} else if (isp->isp_osinfo.loop_down_time < 120) {
2330f7c631bcSMatt Jacob 				slp = 20;
2331f7c631bcSMatt Jacob 			} else {
2332f7c631bcSMatt Jacob 				slp = 30;
2333f44257c2SMatt Jacob 			}
233410365e5aSMatt Jacob 
233510365e5aSMatt Jacob 		} else {
2336f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2337f7c631bcSMatt Jacob 			    "isp_kthread: FC state OK");
233810365e5aSMatt Jacob 			isp->isp_osinfo.loop_down_time = 0;
233910365e5aSMatt Jacob 			slp = 0;
23405d571944SMatt Jacob 		}
2341fdeb9f2fSMatt Jacob 
2342f44257c2SMatt Jacob 		/*
234310365e5aSMatt Jacob 		 * If we'd frozen the simq, unfreeze it now so that CAM
234410365e5aSMatt Jacob 		 * can start sending us commands. If the FC state isn't
234510365e5aSMatt Jacob 		 * okay yet, they'll hit that in isp_start which will
234610365e5aSMatt Jacob 		 * freeze the queue again.
2347f44257c2SMatt Jacob 		 */
23485d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
23495d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
23505d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
2351f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2352f7c631bcSMatt Jacob 			    "isp_kthread: releasing simq");
23535d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
23545d571944SMatt Jacob 		}
2355f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2356f7c631bcSMatt Jacob 		    "isp_kthread: sleep time %d", slp);
23570a70657fSMatt Jacob #if __FreeBSD_version < 700037
23580a70657fSMatt Jacob 		tsleep(ISP_KT_WCHAN(isp), PRIBIO, "ispf", slp * hz);
23599cd7268eSMatt Jacob #else
23600a70657fSMatt Jacob 		msleep(ISP_KT_WCHAN(isp), &isp->isp_osinfo.lock,
23610a70657fSMatt Jacob 		    PRIBIO, "ispf", slp * hz);
23629cd7268eSMatt Jacob #endif
236310365e5aSMatt Jacob 		/*
236410365e5aSMatt Jacob 		 * If slp is zero, we're waking up for the first time after
236510365e5aSMatt Jacob 		 * things have been okay. In this case, we set a deferral state
236610365e5aSMatt Jacob 		 * for all commands and delay hysteresis seconds before starting
236710365e5aSMatt Jacob 		 * the FC state evaluation. This gives the loop/fabric a chance
236810365e5aSMatt Jacob 		 * to settle.
236910365e5aSMatt Jacob 		 */
237010365e5aSMatt Jacob 		if (slp == 0 && isp->isp_osinfo.hysteresis) {
2371f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
2372f7c631bcSMatt Jacob 			    "isp_kthread: sleep hysteresis tick time %d",
2373f7c631bcSMatt Jacob 			    isp->isp_osinfo.hysteresis * hz);
23740a70657fSMatt Jacob #if __FreeBSD_version < 700037
237510365e5aSMatt Jacob 			(void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT",
237610365e5aSMatt Jacob 			    (isp->isp_osinfo.hysteresis * hz));
23770a70657fSMatt Jacob #else
23780a70657fSMatt Jacob 			(void) msleep(&isp_fabric_hysteresis,
23790a70657fSMatt Jacob 			    &isp->isp_osinfo.lock, PRIBIO, "ispT",
23800a70657fSMatt Jacob 			    (isp->isp_osinfo.hysteresis * hz));
23810a70657fSMatt Jacob #endif
238210365e5aSMatt Jacob 		}
23835d571944SMatt Jacob 	}
23840a70657fSMatt Jacob #if __FreeBSD_version < 500000
23850a70657fSMatt Jacob 	splx(s);
23860a70657fSMatt Jacob #elif __FreeBSD_version < 700037
23870a70657fSMatt Jacob 	mtx_unlock(&Giant);
23880a70657fSMatt Jacob #else
23890a70657fSMatt Jacob 	mtx_unlock(&isp->isp_osinfo.lock);
23900a70657fSMatt Jacob #endif
23915d571944SMatt Jacob }
23925d571944SMatt Jacob 
23930a70657fSMatt Jacob #if __FreeBSD_version < 500000
23940a70657fSMatt Jacob static void isp_action_wrk(struct cam_sim *, union ccb *);
23950a70657fSMatt Jacob static void
23960a70657fSMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
23970a70657fSMatt Jacob {
23980a70657fSMatt Jacob 	ispsoftc_t *isp = (ispsoftc_t *)cam_sim_softc(sim);
23990a70657fSMatt Jacob 	ISP_LOCK(isp);
24000a70657fSMatt Jacob 	isp_action_wrk(sim, ccb);
24010a70657fSMatt Jacob 	ISP_UNLOCK(isp);
24020a70657fSMatt Jacob }
24030a70657fSMatt Jacob #define	isp_action isp_action_wrk
24040a70657fSMatt Jacob #endif
24050a70657fSMatt Jacob 
2406cc8df88bSMatt Jacob static void
2407c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
2408478f8a96SJustin T. Gibbs {
24090a70657fSMatt Jacob 	int bus, tgt, ts, error, lim;
24109cd7268eSMatt Jacob 	ispsoftc_t *isp;
24114663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
2412478f8a96SJustin T. Gibbs 
2413478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
2414478f8a96SJustin T. Gibbs 
24159cd7268eSMatt Jacob 	isp = (ispsoftc_t *)cam_sim_softc(sim);
24160470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
24170470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
241857c801f5SMatt Jacob 		isp_init(isp);
241957c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
242057c801f5SMatt Jacob 			/*
242157c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
242257c801f5SMatt Jacob 			 */
2423b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
24240470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
242557c801f5SMatt Jacob 			xpt_done(ccb);
242657c801f5SMatt Jacob 			return;
242757c801f5SMatt Jacob 		}
242857c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
242957c801f5SMatt Jacob 	}
2430b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
24310a70657fSMatt Jacob 	ISP_PCMD(ccb) = NULL;
24325d571944SMatt Jacob 
2433478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
2434478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
2435478f8a96SJustin T. Gibbs 		/*
2436478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
2437478f8a96SJustin T. Gibbs 		 */
2438478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2439478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2440478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
2441478f8a96SJustin T. Gibbs 				xpt_done(ccb);
2442478f8a96SJustin T. Gibbs 				break;
2443478f8a96SJustin T. Gibbs 			}
2444478f8a96SJustin T. Gibbs 		}
24450470d791SMatt Jacob #ifdef	DIAGNOSTIC
24460470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
2447dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid target\n");
2448478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
24490470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
2450dd9fc7c3SMatt Jacob 			xpt_print(ccb->ccb_h.path, "invalid lun\n");
2451478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
2452478f8a96SJustin T. Gibbs 		}
2453478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
2454478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2455478f8a96SJustin T. Gibbs 			break;
2456478f8a96SJustin T. Gibbs 		}
24570470d791SMatt Jacob #endif
24580a70657fSMatt Jacob 		ccb->csio.scsi_status = SCSI_STATUS_OK;
24590a70657fSMatt Jacob 		if (isp_get_pcmd(isp, ccb)) {
24600a70657fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "out of PCMDs");
24610a70657fSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
24620a70657fSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
24630a70657fSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
24640a70657fSMatt Jacob 			xpt_done(ccb);
24650a70657fSMatt Jacob 			break;
24660a70657fSMatt Jacob 		}
2467b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
24680470d791SMatt Jacob 		switch (error) {
2469478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
2470f7c631bcSMatt Jacob 			XS_CMD_S_CLEAR(ccb);
2471478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
24720a70657fSMatt Jacob 			if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) {
24730a70657fSMatt Jacob 				break;
2474d69a5f7dSMatt Jacob 			}
24750a70657fSMatt Jacob 			ts = ccb->ccb_h.timeout;
24760a70657fSMatt Jacob 			if (ts == CAM_TIME_DEFAULT) {
24770a70657fSMatt Jacob 				ts = 60*1000;
2478cc8df88bSMatt Jacob 			}
24790a70657fSMatt Jacob 			ts = isp_mstohz(ts);
24800a70657fSMatt Jacob 			callout_reset(&PISP_PCMD(ccb)->wdog, ts,
24810a70657fSMatt Jacob 			    isp_watchdog, ccb);
2482478f8a96SJustin T. Gibbs 			break;
24830470d791SMatt Jacob 		case CMD_RQLATER:
2484f44257c2SMatt Jacob 			/*
2485f7c631bcSMatt Jacob 			 * Handle initial and subsequent loop down cases
248610365e5aSMatt Jacob 			 */
2487f7c631bcSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0) {
2488f7c631bcSMatt Jacob 				lim = isp_quickboot_time;
2489f7c631bcSMatt Jacob 			} else {
2490f7c631bcSMatt Jacob 				lim = isp->isp_osinfo.loop_down_limit;
2491f7c631bcSMatt Jacob 			}
2492f7c631bcSMatt Jacob 			if (isp->isp_osinfo.loop_down_time >= lim) {
2493f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
2494f7c631bcSMatt Jacob 				    "%d.%d downtime (%d) > lim (%d)",
2495f7c631bcSMatt Jacob 				    XS_TGT(ccb), XS_LUN(ccb),
2496f7c631bcSMatt Jacob 				    isp->isp_osinfo.loop_down_time, lim);
2497f7c631bcSMatt Jacob 				ccb->ccb_h.status =
2498f7c631bcSMatt Jacob 				    CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
2499f7c631bcSMatt Jacob 				xpt_freeze_devq(ccb->ccb_h.path, 1);
25000a70657fSMatt Jacob 				isp_free_pcmd(isp, ccb);
2501f44257c2SMatt Jacob 				xpt_done(ccb);
2502f44257c2SMatt Jacob 				break;
2503f44257c2SMatt Jacob 			}
2504f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2505f7c631bcSMatt Jacob 			    "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
2506f7c631bcSMatt Jacob 			/*
2507f7c631bcSMatt Jacob 			 * Otherwise, retry in a while.
2508f7c631bcSMatt Jacob 			 */
2509f7c631bcSMatt Jacob 			cam_freeze_devq(ccb->ccb_h.path);
2510f7c631bcSMatt Jacob 			cam_release_devq(ccb->ccb_h.path,
2511f7c631bcSMatt Jacob 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
2512f7c631bcSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
25130a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
2514478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2515478f8a96SJustin T. Gibbs 			break;
25160470d791SMatt Jacob 		case CMD_EAGAIN:
25170a70657fSMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
25180a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
2519478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2520478f8a96SJustin T. Gibbs 			break;
25210470d791SMatt Jacob 		case CMD_COMPLETE:
25220470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
25230470d791SMatt Jacob 			break;
25240470d791SMatt Jacob 		default:
2525bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2526bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
252791f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
2528b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
25290a70657fSMatt Jacob 			isp_free_pcmd(isp, ccb);
25300470d791SMatt Jacob 			xpt_done(ccb);
2531478f8a96SJustin T. Gibbs 		}
2532478f8a96SJustin T. Gibbs 		break;
2533478f8a96SJustin T. Gibbs 
2534d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2535478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
253664edff94SMatt Jacob 	{
253710365e5aSMatt Jacob 		int seq, i;
253867ff51f1SMatt Jacob 		seq = isp_en_lun(isp, ccb);
253967ff51f1SMatt Jacob 		if (seq < 0) {
2540478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2541478f8a96SJustin T. Gibbs 			break;
254264edff94SMatt Jacob 		}
254367ff51f1SMatt Jacob 		for (i = 0; isp->isp_osinfo.leact[seq] && i < 30 * 1000; i++) {
254410365e5aSMatt Jacob 			uint32_t isr;
254510365e5aSMatt Jacob 			uint16_t sema, mbox;
254667ff51f1SMatt Jacob 			if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
254767ff51f1SMatt Jacob 				isp_intr(isp, isr, sema, mbox);
254867ff51f1SMatt Jacob 			}
254967ff51f1SMatt Jacob 			DELAY(1000);
255067ff51f1SMatt Jacob 		}
255167ff51f1SMatt Jacob 		break;
255267ff51f1SMatt Jacob 	}
2553d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
2554d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
2555d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
2556d81ba9d5SMatt Jacob 	{
2557a1bc34c6SMatt Jacob 		tstate_t *tptr =
2558a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
2559d81ba9d5SMatt Jacob 		if (tptr == NULL) {
2560d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
2561d81ba9d5SMatt Jacob 			xpt_done(ccb);
2562d81ba9d5SMatt Jacob 			break;
2563d81ba9d5SMatt Jacob 		}
2564f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2565f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
2566570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
2567570c7a3fSMatt Jacob 
2568d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
2569570c7a3fSMatt Jacob 			/*
2570570c7a3fSMatt Jacob 			 * Note that the command itself may not be done-
2571570c7a3fSMatt Jacob 			 * it may not even have had the first CTIO sent.
2572570c7a3fSMatt Jacob 			 */
2573570c7a3fSMatt Jacob 			tptr->atio_count++;
2574570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2575746e9c85SMatt Jacob 			    "Put FREE ATIO, lun %d, count now %d",
2576570c7a3fSMatt Jacob 			    ccb->ccb_h.target_lun, tptr->atio_count);
2577570c7a3fSMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
2578570c7a3fSMatt Jacob 			    sim_links.sle);
2579570c7a3fSMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
2580746e9c85SMatt Jacob 			tptr->inot_count++;
2581746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2582746e9c85SMatt Jacob 			    "Put FREE INOT, lun %d, count now %d",
2583746e9c85SMatt Jacob 			    ccb->ccb_h.target_lun, tptr->inot_count);
2584d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
2585d81ba9d5SMatt Jacob 			    sim_links.sle);
2586570c7a3fSMatt Jacob 		} else {
2587746e9c85SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "Got Notify ACK");;
2588d81ba9d5SMatt Jacob 		}
2589d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
2590d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
2591d81ba9d5SMatt Jacob 		break;
2592d81ba9d5SMatt Jacob 	}
2593d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
2594d81ba9d5SMatt Jacob 	{
25959cd7268eSMatt Jacob 		isp_target_start_ctio(isp, ccb);
2596d81ba9d5SMatt Jacob 		break;
2597d81ba9d5SMatt Jacob 	}
2598d81ba9d5SMatt Jacob #endif
2599478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2600d81ba9d5SMatt Jacob 
2601d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2602d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2603d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2604d81ba9d5SMatt Jacob 
2605ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
2606478f8a96SJustin T. Gibbs 		if (error) {
2607478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2608478f8a96SJustin T. Gibbs 		} else {
2609478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2610478f8a96SJustin T. Gibbs 		}
2611478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2612478f8a96SJustin T. Gibbs 		break;
2613478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2614d81ba9d5SMatt Jacob 	{
2615d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
2616d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2617d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2618d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2619d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2620d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2621d81ba9d5SMatt Jacob 			break;
2622d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2623b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2624d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2625d81ba9d5SMatt Jacob 			break;
2626d81ba9d5SMatt Jacob #endif
2627d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2628478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2629478f8a96SJustin T. Gibbs 			if (error) {
2630d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2631478f8a96SJustin T. Gibbs 			} else {
2632478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2633478f8a96SJustin T. Gibbs 			}
2634d81ba9d5SMatt Jacob 			break;
2635d81ba9d5SMatt Jacob 		default:
2636d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2637d81ba9d5SMatt Jacob 			break;
2638d81ba9d5SMatt Jacob 		}
2639478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2640478f8a96SJustin T. Gibbs 		break;
2641d81ba9d5SMatt Jacob 	}
2642805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2643ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2644805e1f82SMatt Jacob #else
2645805e1f82SMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->flags & CCB_TRANS_CURRENT_SETTINGS)
2646805e1f82SMatt Jacob #endif
2647478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2648478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
26499ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
26509ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
26519ce9bdafSMatt Jacob 			xpt_done(ccb);
26529ce9bdafSMatt Jacob 			break;
26539ce9bdafSMatt Jacob 		}
2654478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2655ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2656805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2657805e1f82SMatt Jacob 			sdparam *sdp = isp->isp_param;
2658805e1f82SMatt Jacob 			uint16_t *dptr;
2659805e1f82SMatt Jacob 
2660805e1f82SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2661805e1f82SMatt Jacob 
2662805e1f82SMatt Jacob 			sdp += bus;
2663805e1f82SMatt Jacob 			/*
2664805e1f82SMatt Jacob 			 * We always update (internally) from goal_flags
2665805e1f82SMatt Jacob 			 * so any request to change settings just gets
2666805e1f82SMatt Jacob 			 * vectored to that location.
2667805e1f82SMatt Jacob 			 */
2668805e1f82SMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2669805e1f82SMatt Jacob 
2670805e1f82SMatt Jacob 			/*
2671805e1f82SMatt Jacob 			 * Note that these operations affect the
2672805e1f82SMatt Jacob 			 * the goal flags (goal_flags)- not
2673805e1f82SMatt Jacob 			 * the current state flags. Then we mark
2674805e1f82SMatt Jacob 			 * things so that the next operation to
2675805e1f82SMatt Jacob 			 * this HBA will cause the update to occur.
2676805e1f82SMatt Jacob 			 */
2677805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_DISC_VALID) {
2678805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
2679805e1f82SMatt Jacob 					*dptr |= DPARM_DISC;
2680805e1f82SMatt Jacob 				} else {
2681805e1f82SMatt Jacob 					*dptr &= ~DPARM_DISC;
2682805e1f82SMatt Jacob 				}
2683805e1f82SMatt Jacob 			}
2684805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_TQ_VALID) {
2685805e1f82SMatt Jacob 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
2686805e1f82SMatt Jacob 					*dptr |= DPARM_TQING;
2687805e1f82SMatt Jacob 				} else {
2688805e1f82SMatt Jacob 					*dptr &= ~DPARM_TQING;
2689805e1f82SMatt Jacob 				}
2690805e1f82SMatt Jacob 			}
2691805e1f82SMatt Jacob 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
2692805e1f82SMatt Jacob 				switch (cts->bus_width) {
2693805e1f82SMatt Jacob 				case MSG_EXT_WDTR_BUS_16_BIT:
2694805e1f82SMatt Jacob 					*dptr |= DPARM_WIDE;
2695805e1f82SMatt Jacob 					break;
2696805e1f82SMatt Jacob 				default:
2697805e1f82SMatt Jacob 					*dptr &= ~DPARM_WIDE;
2698805e1f82SMatt Jacob 				}
2699805e1f82SMatt Jacob 			}
2700805e1f82SMatt Jacob 			/*
2701805e1f82SMatt Jacob 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
2702805e1f82SMatt Jacob 			 * of nonzero will cause us to go to the
2703805e1f82SMatt Jacob 			 * selected (from NVRAM) maximum value for
2704805e1f82SMatt Jacob 			 * this device. At a later point, we'll
2705805e1f82SMatt Jacob 			 * allow finer control.
2706805e1f82SMatt Jacob 			 */
2707805e1f82SMatt Jacob 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
2708805e1f82SMatt Jacob 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
2709805e1f82SMatt Jacob 			    (cts->sync_offset > 0)) {
2710805e1f82SMatt Jacob 				*dptr |= DPARM_SYNC;
2711805e1f82SMatt Jacob 			} else {
2712805e1f82SMatt Jacob 				*dptr &= ~DPARM_SYNC;
2713805e1f82SMatt Jacob 			}
2714805e1f82SMatt Jacob 			*dptr |= DPARM_SAFE_DFLT;
2715805e1f82SMatt Jacob #else
2716ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2717ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2718ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2719ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2720ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
27211dae40ebSMatt Jacob 			uint16_t *dptr;
2722ab163f5fSMatt Jacob 
2723b61386a4SMatt Jacob 			if (spi->valid == 0 && scsi->valid == 0) {
2724b61386a4SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
2725b61386a4SMatt Jacob 				xpt_done(ccb);
2726b61386a4SMatt Jacob 				break;
2727b61386a4SMatt Jacob 			}
2728b61386a4SMatt Jacob 
2729ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2730ab163f5fSMatt Jacob 			sdp += bus;
2731ab163f5fSMatt Jacob 			/*
27329ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2733ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2734ab163f5fSMatt Jacob 			 * vectored to that location.
2735ab163f5fSMatt Jacob 			 */
27369ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2737ab163f5fSMatt Jacob 
2738ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2739ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2740ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2741ab163f5fSMatt Jacob 				else
2742ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2743ab163f5fSMatt Jacob 			}
2744ab163f5fSMatt Jacob 
2745ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2746ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2747ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2748ab163f5fSMatt Jacob 				else
2749ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2750ab163f5fSMatt Jacob 			}
2751ab163f5fSMatt Jacob 
2752ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2753ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2754ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2755ab163f5fSMatt Jacob 				else
2756ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2757ab163f5fSMatt Jacob 			}
2758ab163f5fSMatt Jacob 
2759ab163f5fSMatt Jacob 			/*
2760ab163f5fSMatt Jacob 			 * XXX: FIX ME
2761ab163f5fSMatt Jacob 			 */
2762ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
27639ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
27649ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2765ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
27669ce9bdafSMatt Jacob 				/*
27679ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
27689ce9bdafSMatt Jacob 				 */
27699ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
27709ce9bdafSMatt Jacob 				    spi->sync_period;
27719ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
27729ce9bdafSMatt Jacob 				    spi->sync_offset;
2773ab163f5fSMatt Jacob 			} else {
2774ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2775ab163f5fSMatt Jacob 			}
2776805e1f82SMatt Jacob #endif
2777bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2778b61386a4SMatt Jacob 			    "SET (%d.%d.%d) to flags %x off %x per %x",
2779b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun,
2780b61386a4SMatt Jacob 			    sdp->isp_devparam[tgt].goal_flags,
27819ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
27829ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2783478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2784ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2785478f8a96SJustin T. Gibbs 		}
2786478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2787478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2788478f8a96SJustin T. Gibbs 		break;
2789478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2790478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2791478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2792ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2793805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2794805e1f82SMatt Jacob 			/*
2795805e1f82SMatt Jacob 			 * a lot of normal SCSI things don't make sense.
2796805e1f82SMatt Jacob 			 */
2797805e1f82SMatt Jacob 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
2798805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2799805e1f82SMatt Jacob 			/*
2800805e1f82SMatt Jacob 			 * How do you measure the width of a high
2801805e1f82SMatt Jacob 			 * speed serial bus? Well, in bytes.
2802805e1f82SMatt Jacob 			 *
2803805e1f82SMatt Jacob 			 * Offset and period make no sense, though, so we set
2804805e1f82SMatt Jacob 			 * (above) a 'base' transfer speed to be gigabit.
2805805e1f82SMatt Jacob 			 */
2806805e1f82SMatt Jacob 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2807805e1f82SMatt Jacob #else
2808ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
28099b03492aSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
28109b03492aSMatt Jacob 			    &cts->proto_specific.scsi;
2811ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2812ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2813478f8a96SJustin T. Gibbs 
2814ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2815ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2816ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2817ab163f5fSMatt Jacob 			cts->transport_version = 0;
2818ab163f5fSMatt Jacob 
28199b03492aSMatt Jacob 			scsi->valid = CTS_SCSI_VALID_TQ;
28209b03492aSMatt Jacob 			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2821ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
28229b03492aSMatt Jacob 			if (fcp->isp_gbspeed == 2) {
282353036e92SMatt Jacob 				fc->bitrate = 200000;
28249b03492aSMatt Jacob 			} else {
2825ab163f5fSMatt Jacob 				fc->bitrate = 100000;
28269b03492aSMatt Jacob 			}
2827ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
282810365e5aSMatt Jacob 				fcportdb_t *lp = &fcp->portdb[tgt];
2829ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2830ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2831ab163f5fSMatt Jacob 				fc->port = lp->portid;
2832ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2833ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2834ab163f5fSMatt Jacob 			}
2835805e1f82SMatt Jacob #endif
2836ab163f5fSMatt Jacob 		} else {
2837805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2838ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2839ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2840ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2841ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2842805e1f82SMatt Jacob #endif
2843ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2844ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
28451dae40ebSMatt Jacob 			uint16_t dval, pval, oval;
2846ab163f5fSMatt Jacob 
2847ea6f23cdSMatt Jacob 			sdp += bus;
2848ab163f5fSMatt Jacob 
2849ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
285083ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
285183ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
285283ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
285383ae4407SMatt Jacob 				    NULL);
28549ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
28559ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
28569ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
28574394c92fSMatt Jacob 			} else {
28589ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
28599ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
28609ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
28614394c92fSMatt Jacob 			}
2862478f8a96SJustin T. Gibbs 
2863805e1f82SMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2864805e1f82SMatt Jacob 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
2865805e1f82SMatt Jacob 
2866805e1f82SMatt Jacob 			if (dval & DPARM_DISC) {
2867805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_DISC_ENB;
2868805e1f82SMatt Jacob 			}
2869805e1f82SMatt Jacob 			if (dval & DPARM_TQING) {
2870805e1f82SMatt Jacob 				cts->flags |= CCB_TRANS_TAG_ENB;
2871805e1f82SMatt Jacob 			}
2872805e1f82SMatt Jacob 			if (dval & DPARM_WIDE) {
2873805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2874805e1f82SMatt Jacob 			} else {
2875805e1f82SMatt Jacob 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2876805e1f82SMatt Jacob 			}
2877805e1f82SMatt Jacob 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
2878805e1f82SMatt Jacob 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2879805e1f82SMatt Jacob 
2880805e1f82SMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
2881805e1f82SMatt Jacob 				cts->sync_period = pval;
2882805e1f82SMatt Jacob 				cts->sync_offset = oval;
2883805e1f82SMatt Jacob 				cts->valid |=
2884805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_RATE_VALID |
2885805e1f82SMatt Jacob 				    CCB_TRANS_SYNC_OFFSET_VALID;
2886805e1f82SMatt Jacob 			}
2887805e1f82SMatt Jacob #else
2888ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2889ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2890ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2891ab163f5fSMatt Jacob 			cts->transport_version = 2;
2892ab163f5fSMatt Jacob 
2893b61386a4SMatt Jacob 			spi->valid = 0;
2894b61386a4SMatt Jacob 			scsi->valid = 0;
2895b61386a4SMatt Jacob 			spi->flags = 0;
2896b61386a4SMatt Jacob 			scsi->flags = 0;
2897ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2898ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2899ab163f5fSMatt Jacob 			}
29009ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2901ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2902ab163f5fSMatt Jacob 				spi->sync_period = pval;
2903b61386a4SMatt Jacob 			} else {
2904b61386a4SMatt Jacob 				spi->sync_offset = 0;
2905b61386a4SMatt Jacob 				spi->sync_period = 0;
2906b61386a4SMatt Jacob 			}
2907ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2908ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2909ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2910ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2911ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2912ab163f5fSMatt Jacob 			} else {
2913ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2914ab163f5fSMatt Jacob 			}
2915ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2916ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2917b61386a4SMatt Jacob 				if (dval & DPARM_TQING) {
2918b61386a4SMatt Jacob 					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2919b61386a4SMatt Jacob 				}
2920ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2921ab163f5fSMatt Jacob 			}
2922805e1f82SMatt Jacob #endif
2923bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2924b61386a4SMatt Jacob 			    "GET %s (%d.%d.%d) to flags %x off %x per %x",
29259ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
2926b61386a4SMatt Jacob 			    bus, tgt, cts->ccb_h.target_lun, dval, oval, pval);
2927478f8a96SJustin T. Gibbs 		}
2928478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2929478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2930478f8a96SJustin T. Gibbs 		break;
2931478f8a96SJustin T. Gibbs 
2932478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
29339cd7268eSMatt Jacob #if __FreeBSD_version < 500000
2934478f8a96SJustin T. Gibbs 	{
2935478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
29369cd7268eSMatt Jacob 		u_int32_t secs_per_cylinder;
29379cd7268eSMatt Jacob 		u_int32_t size_mb;
2938478f8a96SJustin T. Gibbs 
2939478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2940478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2941478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2942478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2943478f8a96SJustin T. Gibbs 			break;
2944478f8a96SJustin T. Gibbs 		}
29459cd7268eSMatt Jacob 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
29469cd7268eSMatt Jacob 		if (size_mb > 1024) {
29479cd7268eSMatt Jacob 			ccg->heads = 255;
29489cd7268eSMatt Jacob 			ccg->secs_per_track = 63;
29499cd7268eSMatt Jacob 		} else {
29509cd7268eSMatt Jacob 			ccg->heads = 64;
29519cd7268eSMatt Jacob 			ccg->secs_per_track = 32;
29529cd7268eSMatt Jacob 		}
29539cd7268eSMatt Jacob 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
29549cd7268eSMatt Jacob 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
29559cd7268eSMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
2956478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2957478f8a96SJustin T. Gibbs 		break;
2958478f8a96SJustin T. Gibbs 	}
29599cd7268eSMatt Jacob #else
29609cd7268eSMatt Jacob 	{
29619cd7268eSMatt Jacob 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
29629cd7268eSMatt Jacob 		xpt_done(ccb);
29639cd7268eSMatt Jacob 		break;
29649cd7268eSMatt Jacob 	}
29659cd7268eSMatt Jacob #endif
2966478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
2967ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
2968ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
2969478f8a96SJustin T. Gibbs 		if (error)
2970478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
29712b052931SMatt Jacob 		else {
29720a70657fSMatt Jacob 			if (bootverbose) {
29730a70657fSMatt Jacob 				xpt_print(ccb->ccb_h.path, "reset bus\n");
29740a70657fSMatt Jacob 			}
2975ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
2976ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
2977ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
29782b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
2979478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
29802b052931SMatt Jacob 		}
2981478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2982478f8a96SJustin T. Gibbs 		break;
2983478f8a96SJustin T. Gibbs 
2984478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
2985478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2986478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2987478f8a96SJustin T. Gibbs 		break;
2988478f8a96SJustin T. Gibbs 
2989478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
2990478f8a96SJustin T. Gibbs 	{
2991478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
2992478f8a96SJustin T. Gibbs 
2993478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
2994d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2995a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
2996d81ba9d5SMatt Jacob #else
2997478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
2998d81ba9d5SMatt Jacob #endif
2999478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
30000470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
30010470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
30020470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
30034394c92fSMatt Jacob 		if (IS_FC(isp)) {
30044394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
30050470d791SMatt Jacob 			/*
30060470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
30070470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
30080470d791SMatt Jacob 			 */
30090470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
30100470d791SMatt Jacob 
30119deea857SKenneth D. Merry 			/*
30129deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
30139deea857SKenneth D. Merry 			 * Technically not correct because we don't know
30149deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
30159deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
30169deea857SKenneth D. Merry 			 */
301753036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
301853036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
301953036e92SMatt Jacob 			else
30209deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
30210470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
3022805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3023ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
3024805e1f82SMatt Jacob 			cpi->transport_version = 0;
3025805e1f82SMatt Jacob #endif
3026478f8a96SJustin T. Gibbs 		} else {
3027ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
3028ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
30290470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
30304394c92fSMatt Jacob 			cpi->hba_misc = 0;
3031ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
30329deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
3033805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3034ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
3035805e1f82SMatt Jacob 			cpi->transport_version = 2;
3036805e1f82SMatt Jacob #endif
3037478f8a96SJustin T. Gibbs 		}
3038805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3039ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
3040ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
3041805e1f82SMatt Jacob #endif
3042478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
3043478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
3044478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
3045478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
3046478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
3047478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3048478f8a96SJustin T. Gibbs 		break;
3049478f8a96SJustin T. Gibbs 	}
3050478f8a96SJustin T. Gibbs 	default:
3051478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
3052478f8a96SJustin T. Gibbs 		xpt_done(ccb);
3053478f8a96SJustin T. Gibbs 		break;
3054478f8a96SJustin T. Gibbs 	}
3055478f8a96SJustin T. Gibbs }
3056d3a9eb2eSMatt Jacob 
3057d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
3058f7c631bcSMatt Jacob 
3059d3a9eb2eSMatt Jacob void
3060c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
3061d3a9eb2eSMatt Jacob {
30629cd7268eSMatt Jacob 	ispsoftc_t *isp = XS_ISP(sccb);
3063d3a9eb2eSMatt Jacob 
3064d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
3065d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
3066b85389e1SMatt Jacob 
3067d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
3068d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
3069d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
307092a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
307192a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
307292a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
307392a1e549SMatt Jacob 		} else {
3074d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
3075d3a9eb2eSMatt Jacob 		}
307692a1e549SMatt Jacob 	}
3077b85389e1SMatt Jacob 
30780470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
3079d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3080f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0,
3081f7c631bcSMatt Jacob 		    "target %d lun %d CAM status 0x%x SCSI status 0x%x",
3082f7c631bcSMatt Jacob 		    XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status,
3083f7c631bcSMatt Jacob 		    sccb->scsi_status);
3084d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
3085d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
30860470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
3087d3a9eb2eSMatt Jacob 		}
3088d3a9eb2eSMatt Jacob 	}
3089b85389e1SMatt Jacob 
3090b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
3091d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
3092dd9fc7c3SMatt Jacob 		xpt_print(sccb->ccb_h.path,
3093dd9fc7c3SMatt Jacob 		    "cam completion status 0x%x\n", sccb->ccb_h.status);
3094d3a9eb2eSMatt Jacob 	}
3095b85389e1SMatt Jacob 
3096b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
3097b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
3098f7c631bcSMatt Jacob 		untimeout(isp_watchdog, sccb, sccb->ccb_h.timeout_ch);
3099b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
3100b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
3101b09b0095SMatt Jacob 			    "finished command on borrowed time");
3102b85389e1SMatt Jacob 		}
3103b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
31040a70657fSMatt Jacob 		isp_free_pcmd(isp, (union ccb *) sccb);
3105d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
3106d3a9eb2eSMatt Jacob 	}
3107b85389e1SMatt Jacob }
3108d3a9eb2eSMatt Jacob 
3109cbf57b47SMatt Jacob int
31109cd7268eSMatt Jacob isp_async(ispsoftc_t *isp, ispasync_t cmd, void *arg)
3111cbf57b47SMatt Jacob {
3112ea6f23cdSMatt Jacob 	int bus, rv = 0;
311310365e5aSMatt Jacob 	static const char prom[] =
311410365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s\n"
311510365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
311610365e5aSMatt Jacob 	static const char prom2[] =
311710365e5aSMatt Jacob 	    "PortID 0x%06x handle 0x%x role %s %s tgt %u\n"
311810365e5aSMatt Jacob 	    "      WWNN 0x%08x%08x WWPN 0x%08x%08x";
3119f7c631bcSMatt Jacob 	char *msg = NULL;
312010365e5aSMatt Jacob 	target_id_t tgt;
312110365e5aSMatt Jacob 	fcportdb_t *lp;
312210365e5aSMatt Jacob 	struct cam_path *tmppath;
312310365e5aSMatt Jacob 
3124cbf57b47SMatt Jacob 	switch (cmd) {
3125cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
31260470d791SMatt Jacob 	{
3127805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3128ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
3129ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
3130805e1f82SMatt Jacob #endif
3131cbf57b47SMatt Jacob 		int flags, tgt;
3132cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
3133ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
3134cbf57b47SMatt Jacob 
313529f76675SMatt Jacob 		memset(&cts, 0, sizeof (struct ccb_trans_settings));
3136ab163f5fSMatt Jacob 
3137cbf57b47SMatt Jacob 		tgt = *((int *)arg);
3138ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
3139ea6f23cdSMatt Jacob 		tgt &= 0xffff;
3140ea6f23cdSMatt Jacob 		sdp += bus;
3141cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
3142ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
3143ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
3144bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3145bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
3146bfbab170SMatt Jacob 			    tgt, bus);
3147cbf57b47SMatt Jacob 			rv = -1;
3148cbf57b47SMatt Jacob 			break;
3149cbf57b47SMatt Jacob 		}
31509ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
3151805e1f82SMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
3152ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
3153ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
3154ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
3155ab163f5fSMatt Jacob 
3156ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
3157ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
3158ab163f5fSMatt Jacob 
3159ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
3160ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
3161ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
3162ab163f5fSMatt Jacob 		}
3163ab163f5fSMatt Jacob 
3164cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
3165ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
3166ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
3167ab163f5fSMatt Jacob 		}
3168ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
3169ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
3170ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
3171ab163f5fSMatt Jacob 		} else {
3172ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
3173ab163f5fSMatt Jacob 		}
3174ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
3175ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
3176ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
31779ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
31789ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
3179ab163f5fSMatt Jacob 		}
3180805e1f82SMatt Jacob #else
3181805e1f82SMatt Jacob 		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
3182805e1f82SMatt Jacob 		cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
3183805e1f82SMatt Jacob 		if (flags & DPARM_DISC) {
3184805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_DISC_ENB;
3185805e1f82SMatt Jacob 		}
3186805e1f82SMatt Jacob 		if (flags & DPARM_TQING) {
3187805e1f82SMatt Jacob 			cts.flags |= CCB_TRANS_TAG_ENB;
3188805e1f82SMatt Jacob 		}
3189805e1f82SMatt Jacob 		cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
3190805e1f82SMatt Jacob 		cts.bus_width = (flags & DPARM_WIDE)?
3191805e1f82SMatt Jacob 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
3192805e1f82SMatt Jacob 		cts.sync_period = sdp->isp_devparam[tgt].actv_period;
3193805e1f82SMatt Jacob 		cts.sync_offset = sdp->isp_devparam[tgt].actv_offset;
3194805e1f82SMatt Jacob 		if (flags & DPARM_SYNC) {
3195805e1f82SMatt Jacob 			cts.valid |=
3196805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_RATE_VALID |
3197805e1f82SMatt Jacob 			    CCB_TRANS_SYNC_OFFSET_VALID;
3198805e1f82SMatt Jacob 		}
3199805e1f82SMatt Jacob #endif
3200b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
3201b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
32029ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
32039ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
3204ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
3205ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
3206cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
3207cbf57b47SMatt Jacob 		break;
32080470d791SMatt Jacob 	}
320957c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
3210ea6f23cdSMatt Jacob 		bus = *((int *)arg);
3211b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
3212b09b0095SMatt Jacob 		    bus);
3213ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
3214ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
3215ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
321657c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
321757c801f5SMatt Jacob 		}
321857c801f5SMatt Jacob 		break;
32195d571944SMatt Jacob 	case ISPASYNC_LIP:
3220f7c631bcSMatt Jacob 		if (msg == NULL) {
3221f7c631bcSMatt Jacob 			msg = "LIP Received";
32225d571944SMatt Jacob 		}
3223f7c631bcSMatt Jacob 		/* FALLTHROUGH */
32245d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
3225f7c631bcSMatt Jacob 		if (msg == NULL) {
3226f7c631bcSMatt Jacob 			msg = "LOOP Reset";
32275d571944SMatt Jacob 		}
3228f7c631bcSMatt Jacob 		/* FALLTHROUGH */
322957c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
3230f7c631bcSMatt Jacob 		if (msg == NULL) {
3231f7c631bcSMatt Jacob 			msg = "LOOP Down";
323257c801f5SMatt Jacob 		}
3233f7c631bcSMatt Jacob 		if (isp->isp_path) {
3234f7c631bcSMatt Jacob 			isp_freeze_loopdown(isp, msg);
3235f7c631bcSMatt Jacob 		}
3236f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running == 0) {
3237f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 1;
32380a70657fSMatt Jacob 			callout_reset(&isp->isp_osinfo.ldt,
32390a70657fSMatt Jacob 			    isp->isp_osinfo.loop_down_limit * hz, isp_ldt, isp);
3240f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3241f7c631bcSMatt Jacob 			   "starting Loop Down Timer");
3242f7c631bcSMatt Jacob 		}
3243f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
324457c801f5SMatt Jacob 		break;
324557c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
32465d571944SMatt Jacob 		/*
32475d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
32485d571944SMatt Jacob 		 * actually do anything because we're waiting for a
32495d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
32505d571944SMatt Jacob 		 * thread to look at the state of the loop again.
32515d571944SMatt Jacob 		 */
3252b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
325357c801f5SMatt Jacob 		break;
325410365e5aSMatt Jacob 	case ISPASYNC_DEV_ARRIVED:
325510365e5aSMatt Jacob 		lp = arg;
3256f7c631bcSMatt Jacob 		lp->reserved = 0;
3257f7c631bcSMatt Jacob 		if ((isp->isp_role & ISP_ROLE_INITIATOR) &&
3258f7c631bcSMatt Jacob 		    (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
3259f7c631bcSMatt Jacob 			int dbidx = lp - FCPARAM(isp)->portdb;
3260f7c631bcSMatt Jacob 			int i;
326102ab3379SMatt Jacob 
3262f7c631bcSMatt Jacob 			for (i = 0; i < MAX_FC_TARG; i++) {
3263f7c631bcSMatt Jacob 				if (i >= FL_ID && i <= SNS_ID) {
3264f7c631bcSMatt Jacob 					continue;
3265f7c631bcSMatt Jacob 				}
3266f7c631bcSMatt Jacob 				if (FCPARAM(isp)->isp_ini_map[i] == 0) {
3267f7c631bcSMatt Jacob 					break;
3268f7c631bcSMatt Jacob 				}
3269f7c631bcSMatt Jacob 			}
3270f7c631bcSMatt Jacob 			if (i < MAX_FC_TARG) {
3271f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[i] = dbidx + 1;
3272f7c631bcSMatt Jacob 				lp->ini_map_idx = i + 1;
3273f7c631bcSMatt Jacob 			} else {
3274f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "out of target ids");
3275f7c631bcSMatt Jacob 				isp_dump_portdb(isp);
3276f7c631bcSMatt Jacob 			}
3277f7c631bcSMatt Jacob 		}
327810365e5aSMatt Jacob 		if (lp->ini_map_idx) {
327910365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
328010365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
328110365e5aSMatt Jacob 			    lp->portid, lp->handle,
3282f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived at", tgt,
32831dae40ebSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
328410365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
328510365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
328610365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3287f7c631bcSMatt Jacob 			isp_make_here(isp, tgt);
328810365e5aSMatt Jacob 		} else {
328910365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
329010365e5aSMatt Jacob 			    lp->portid, lp->handle,
3291f7c631bcSMatt Jacob 		            roles[lp->roles], "arrived",
329210365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
329310365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
329410365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
329510365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
329610365e5aSMatt Jacob 		}
329710365e5aSMatt Jacob 		break;
329810365e5aSMatt Jacob 	case ISPASYNC_DEV_CHANGED:
329910365e5aSMatt Jacob 		lp = arg;
3300f7c631bcSMatt Jacob 		if (isp_change_is_bad) {
3301f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_NIL;
330210365e5aSMatt Jacob 			if (lp->ini_map_idx) {
330310365e5aSMatt Jacob 				tgt = lp->ini_map_idx - 1;
3304f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[tgt] = 0;
3305f7c631bcSMatt Jacob 				lp->ini_map_idx = 0;
3306f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom3,
3307f7c631bcSMatt Jacob 				    lp->portid, tgt, "change is bad");
3308f7c631bcSMatt Jacob 				isp_make_gone(isp, tgt);
3309f7c631bcSMatt Jacob 			} else {
3310f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
3311f7c631bcSMatt Jacob 				    lp->portid, lp->handle,
3312f7c631bcSMatt Jacob 				    roles[lp->roles],
3313f7c631bcSMatt Jacob 				    "changed and departed",
3314f7c631bcSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
3315f7c631bcSMatt Jacob 				    (uint32_t) lp->node_wwn,
3316f7c631bcSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
3317f7c631bcSMatt Jacob 				    (uint32_t) lp->port_wwn);
3318f7c631bcSMatt Jacob 			}
3319f7c631bcSMatt Jacob 		} else {
3320f7c631bcSMatt Jacob 			lp->portid = lp->new_portid;
3321f7c631bcSMatt Jacob 			lp->roles = lp->new_roles;
3322f7c631bcSMatt Jacob 			if (lp->ini_map_idx) {
3323f7c631bcSMatt Jacob 				int t = lp->ini_map_idx - 1;
3324f7c631bcSMatt Jacob 				FCPARAM(isp)->isp_ini_map[t] =
3325f7c631bcSMatt Jacob 				    (lp - FCPARAM(isp)->portdb) + 1;
3326f7c631bcSMatt Jacob 				tgt = lp->ini_map_idx - 1;
332710365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom2,
332810365e5aSMatt Jacob 				    lp->portid, lp->handle,
3329f7c631bcSMatt Jacob 				    roles[lp->roles], "changed at", tgt,
333010365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
333110365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
333210365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
333310365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
333410365e5aSMatt Jacob 			} else {
333510365e5aSMatt Jacob 				isp_prt(isp, ISP_LOGCONFIG, prom,
333610365e5aSMatt Jacob 				    lp->portid, lp->handle,
3337f7c631bcSMatt Jacob 				    roles[lp->roles], "changed",
333810365e5aSMatt Jacob 				    (uint32_t) (lp->node_wwn >> 32),
333910365e5aSMatt Jacob 				    (uint32_t) lp->node_wwn,
334010365e5aSMatt Jacob 				    (uint32_t) (lp->port_wwn >> 32),
334110365e5aSMatt Jacob 				    (uint32_t) lp->port_wwn);
334210365e5aSMatt Jacob 			}
3343f7c631bcSMatt Jacob 		}
334410365e5aSMatt Jacob 		break;
334510365e5aSMatt Jacob 	case ISPASYNC_DEV_STAYED:
334610365e5aSMatt Jacob 		lp = arg;
334710365e5aSMatt Jacob 		if (lp->ini_map_idx) {
334810365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
334910365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
335010365e5aSMatt Jacob 			    lp->portid, lp->handle,
3351f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed at", tgt,
335210365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
335310365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
335410365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
335510365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
335610365e5aSMatt Jacob 		} else {
335710365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
335810365e5aSMatt Jacob 			    lp->portid, lp->handle,
3359f7c631bcSMatt Jacob 		    	    roles[lp->roles], "stayed",
336010365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
336110365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
336210365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
336310365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
336410365e5aSMatt Jacob 		}
336510365e5aSMatt Jacob 		break;
336610365e5aSMatt Jacob 	case ISPASYNC_DEV_GONE:
336710365e5aSMatt Jacob 		lp = arg;
3368f7c631bcSMatt Jacob 		/*
3369f7c631bcSMatt Jacob 		 * If this has a virtual target and we haven't marked it
3370f7c631bcSMatt Jacob 		 * that we're going to have isp_gdt tell the OS it's gone,
3371f7c631bcSMatt Jacob 		 * set the isp_gdt timer running on it.
3372f7c631bcSMatt Jacob 		 *
3373f7c631bcSMatt Jacob 		 * If it isn't marked that isp_gdt is going to get rid of it,
3374f7c631bcSMatt Jacob 		 * announce that it's gone.
3375f7c631bcSMatt Jacob 		 */
3376f7c631bcSMatt Jacob 		if (lp->ini_map_idx && lp->reserved == 0) {
3377f7c631bcSMatt Jacob 			lp->reserved = 1;
3378f7c631bcSMatt Jacob 			lp->new_reserved = isp->isp_osinfo.gone_device_time;
3379f7c631bcSMatt Jacob 			lp->state = FC_PORTDB_STATE_ZOMBIE;
3380f7c631bcSMatt Jacob 			if (isp->isp_osinfo.gdt_running == 0) {
3381f7c631bcSMatt Jacob 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3382f7c631bcSMatt Jacob 				    "starting Gone Device Timer");
3383f7c631bcSMatt Jacob 				isp->isp_osinfo.gdt_running = 1;
33840a70657fSMatt Jacob 				callout_reset(&isp->isp_osinfo.gdt, hz,
33850a70657fSMatt Jacob 				    isp_gdt, isp);
3386f7c631bcSMatt Jacob 			}
338710365e5aSMatt Jacob 			tgt = lp->ini_map_idx - 1;
338810365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom2,
338910365e5aSMatt Jacob 			    lp->portid, lp->handle,
3390f7c631bcSMatt Jacob 		            roles[lp->roles], "gone zombie at", tgt,
339110365e5aSMatt Jacob 		    	    (uint32_t) (lp->node_wwn >> 32),
339210365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
339310365e5aSMatt Jacob 		    	    (uint32_t) (lp->port_wwn >> 32),
339410365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
3395f7c631bcSMatt Jacob 		} else if (lp->reserved == 0) {
339610365e5aSMatt Jacob 			isp_prt(isp, ISP_LOGCONFIG, prom,
339710365e5aSMatt Jacob 			    lp->portid, lp->handle,
3398f7c631bcSMatt Jacob 			    roles[lp->roles], "departed",
339910365e5aSMatt Jacob 			    (uint32_t) (lp->node_wwn >> 32),
340010365e5aSMatt Jacob 			    (uint32_t) lp->node_wwn,
340110365e5aSMatt Jacob 			    (uint32_t) (lp->port_wwn >> 32),
340210365e5aSMatt Jacob 			    (uint32_t) lp->port_wwn);
34034b9d588eSMatt Jacob 		}
340410365e5aSMatt Jacob 		break;
340510365e5aSMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
340610365e5aSMatt Jacob 	{
340710365e5aSMatt Jacob 		char *msg;
340810365e5aSMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
340910365e5aSMatt Jacob 			msg = "Port Database Changed";
341010365e5aSMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
341110365e5aSMatt Jacob 			msg = "Name Server Database Changed";
341210365e5aSMatt Jacob 		} else {
341310365e5aSMatt Jacob 			msg = "Other Change Notify";
341410365e5aSMatt Jacob 		}
3415f7c631bcSMatt Jacob 		/*
3416f7c631bcSMatt Jacob 		 * If the loop down timer is running, cancel it.
3417f7c631bcSMatt Jacob 		 */
3418f7c631bcSMatt Jacob 		if (isp->isp_osinfo.ldt_running) {
3419f7c631bcSMatt Jacob 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
3420f7c631bcSMatt Jacob 			   "Stopping Loop Down Timer");
3421f7c631bcSMatt Jacob 			isp->isp_osinfo.ldt_running = 0;
34220a70657fSMatt Jacob 			callout_stop(&isp->isp_osinfo.ldt);
3423f7c631bcSMatt Jacob 		}
342410365e5aSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, msg);
342510365e5aSMatt Jacob 		isp_freeze_loopdown(isp, msg);
34260a70657fSMatt Jacob 		wakeup(ISP_KT_WCHAN(isp));
342757c801f5SMatt Jacob 		break;
342802ab3379SMatt Jacob 	}
3429d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3430e5265237SMatt Jacob 	case ISPASYNC_TARGET_NOTIFY:
3431d81ba9d5SMatt Jacob 	{
3432e5265237SMatt Jacob 		tmd_notify_t *nt = arg;
343364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3434e5265237SMatt Jacob 		    "target notify code 0x%x", nt->nt_ncode);
3435d81ba9d5SMatt Jacob 		break;
3436d81ba9d5SMatt Jacob 	}
3437d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
3438d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
3439cbf57b47SMatt Jacob 		default:
3440bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3441bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
3442bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
3443d81ba9d5SMatt Jacob 			break;
3444570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
3445570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
3446570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_scsi(isp,
3447570c7a3fSMatt Jacob 				    (in_entry_t *) arg);
3448570c7a3fSMatt Jacob 			} else {
3449570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_fc(isp,
3450570c7a3fSMatt Jacob 				    (in_fcentry_t *) arg);
3451570c7a3fSMatt Jacob 			}
3452570c7a3fSMatt Jacob 			break;
3453d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
3454d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
3455d81ba9d5SMatt Jacob 			break;
3456d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
3457d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
3458d81ba9d5SMatt Jacob 			break;
3459d4a6993aSMatt Jacob 		case RQSTYPE_CTIO3:
3460d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
3461d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
3462d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
3463d81ba9d5SMatt Jacob 			break;
3464d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
3465d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
346667ff51f1SMatt Jacob 			isp_ledone(isp, (lun_entry_t *) arg);
3467d81ba9d5SMatt Jacob 			break;
3468d81ba9d5SMatt Jacob 		}
3469d81ba9d5SMatt Jacob 		break;
3470d81ba9d5SMatt Jacob #endif
3471ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
3472ab163f5fSMatt Jacob 	{
34731dae40ebSMatt Jacob 		uint16_t mbox1, mbox6;
3474ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
3475ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
3476ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
3477ab163f5fSMatt Jacob 		} else {
3478ab163f5fSMatt Jacob 			mbox6 = 0;
3479ab163f5fSMatt Jacob 		}
3480ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
3481570c7a3fSMatt Jacob                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
3482ab163f5fSMatt Jacob                     mbox6, mbox1);
34838a5f89b9SMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
34840a70657fSMatt Jacob 		mbox1 = isp->isp_osinfo.mbox_sleep_ok;
34850a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
34868a5f89b9SMatt Jacob 		if (IS_FC(isp)) {
34878a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
34888a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_loopstate = LOOP_NIL;
34898a5f89b9SMatt Jacob 			isp_freeze_loopdown(isp, "f/w crash");
34908a5f89b9SMatt Jacob 			isp_fw_dump(isp);
34918a5f89b9SMatt Jacob 		}
3492ab163f5fSMatt Jacob 		isp_reinit(isp);
34930a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = mbox1;
34940a70657fSMatt Jacob #else
34950a70657fSMatt Jacob 		mbox1 = isp->isp_osinfo.mbox_sleep_ok;
34960a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
34970a70657fSMatt Jacob 		isp_reinit(isp);
34980a70657fSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = mbox1;
34998a5f89b9SMatt Jacob #endif
35000a70657fSMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
3501ab163f5fSMatt Jacob 		break;
3502ab163f5fSMatt Jacob 	}
3503be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
3504be534d5fSMatt Jacob 		break;
3505d81ba9d5SMatt Jacob 	default:
3506b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
3507cbf57b47SMatt Jacob 		break;
3508cbf57b47SMatt Jacob 	}
3509cbf57b47SMatt Jacob 	return (rv);
3510cbf57b47SMatt Jacob }
3511cbf57b47SMatt Jacob 
351292718a7fSMatt Jacob 
351392718a7fSMatt Jacob /*
351492718a7fSMatt Jacob  * Locks are held before coming here.
351592718a7fSMatt Jacob  */
351692718a7fSMatt Jacob void
35179cd7268eSMatt Jacob isp_uninit(ispsoftc_t *isp)
351892718a7fSMatt Jacob {
351910365e5aSMatt Jacob 	if (IS_24XX(isp)) {
352010365e5aSMatt Jacob 		ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET);
352110365e5aSMatt Jacob 	} else {
3522ea6f23cdSMatt Jacob 		ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
352310365e5aSMatt Jacob 	}
352410365e5aSMatt Jacob 	ISP_DISABLE_INTS(isp);
352592718a7fSMatt Jacob }
3526b09b0095SMatt Jacob 
3527b09b0095SMatt Jacob void
35289cd7268eSMatt Jacob isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...)
3529b09b0095SMatt Jacob {
3530b09b0095SMatt Jacob 	va_list ap;
3531b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
3532b09b0095SMatt Jacob 		return;
3533b09b0095SMatt Jacob 	}
35343c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
3535b09b0095SMatt Jacob 	va_start(ap, fmt);
3536b09b0095SMatt Jacob 	vprintf(fmt, ap);
3537b09b0095SMatt Jacob 	va_end(ap);
3538b09b0095SMatt Jacob 	printf("\n");
3539b09b0095SMatt Jacob }
3540f7c631bcSMatt Jacob 
3541f7c631bcSMatt Jacob uint64_t
3542f7c631bcSMatt Jacob isp_nanotime_sub(struct timespec *b, struct timespec *a)
3543f7c631bcSMatt Jacob {
3544f7c631bcSMatt Jacob 	uint64_t elapsed;
3545f7c631bcSMatt Jacob 	struct timespec x = *b;
3546f7c631bcSMatt Jacob 	timespecsub(&x, a);
3547f7c631bcSMatt Jacob 	elapsed = GET_NANOSEC(&x);
3548f7c631bcSMatt Jacob 	if (elapsed == 0)
3549f7c631bcSMatt Jacob 		elapsed++;
3550f7c631bcSMatt Jacob 	return (elapsed);
3551f7c631bcSMatt Jacob }
3552f7c631bcSMatt Jacob 
3553f7c631bcSMatt Jacob int
3554f7c631bcSMatt Jacob isp_mbox_acquire(ispsoftc_t *isp)
3555f7c631bcSMatt Jacob {
3556f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxbsy) {
3557f7c631bcSMatt Jacob 		return (1);
3558f7c631bcSMatt Jacob 	} else {
3559f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 0;
3560f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxbsy = 1;
3561f7c631bcSMatt Jacob 		return (0);
3562f7c631bcSMatt Jacob 	}
3563f7c631bcSMatt Jacob }
3564f7c631bcSMatt Jacob 
3565f7c631bcSMatt Jacob void
3566f7c631bcSMatt Jacob isp_mbox_wait_complete(ispsoftc_t *isp, mbreg_t *mbp)
3567f7c631bcSMatt Jacob {
3568a4f3a2beSMatt Jacob 	unsigned int usecs = mbp->timeout;
3569a4f3a2beSMatt Jacob 	unsigned int max, olim, ilim;
3570f7c631bcSMatt Jacob 
3571f7c631bcSMatt Jacob 	if (usecs == 0) {
3572f7c631bcSMatt Jacob 		usecs = MBCMD_DEFAULT_TIMEOUT;
3573f7c631bcSMatt Jacob 	}
3574a4f3a2beSMatt Jacob 	max = isp->isp_mbxwrk0 + 1;
3575a4f3a2beSMatt Jacob 
3576f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleep_ok) {
3577a4f3a2beSMatt Jacob 		unsigned int ms = (usecs + 999) / 1000;
3578a4f3a2beSMatt Jacob 
3579f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 0;
3580f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 1;
3581a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
35820a70657fSMatt Jacob #if __FreeBSD_version < 700037
3583f7c631bcSMatt Jacob 			tsleep(&isp->isp_mbxworkp, PRIBIO, "ispmbx_sleep",
3584f7c631bcSMatt Jacob 			    isp_mstohz(ms));
3585f7c631bcSMatt Jacob #else
35860a70657fSMatt Jacob 			msleep(&isp->isp_mbxworkp, &isp->isp_osinfo.lock,
35870a70657fSMatt Jacob 			    PRIBIO, "ispmbx_sleep", isp_mstohz(ms));
3588f7c631bcSMatt Jacob #endif
3589a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3590a4f3a2beSMatt Jacob 				break;
3591a4f3a2beSMatt Jacob 			}
3592a4f3a2beSMatt Jacob 		}
3593f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleep_ok = 1;
3594f7c631bcSMatt Jacob 		isp->isp_osinfo.mbox_sleeping = 0;
3595f7c631bcSMatt Jacob 	} else {
3596a4f3a2beSMatt Jacob 		for (olim = 0; olim < max; olim++) {
3597a4f3a2beSMatt Jacob 			for (ilim = 0; ilim < usecs; ilim += 100) {
3598f7c631bcSMatt Jacob 				uint32_t isr;
3599f7c631bcSMatt Jacob 				uint16_t sema, mbox;
3600f7c631bcSMatt Jacob 				if (isp->isp_osinfo.mboxcmd_done) {
3601f7c631bcSMatt Jacob 					break;
3602f7c631bcSMatt Jacob 				}
3603f7c631bcSMatt Jacob 				if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
3604f7c631bcSMatt Jacob 					isp_intr(isp, isr, sema, mbox);
3605f7c631bcSMatt Jacob 					if (isp->isp_osinfo.mboxcmd_done) {
3606f7c631bcSMatt Jacob 						break;
3607f7c631bcSMatt Jacob 					}
3608f7c631bcSMatt Jacob 				}
3609f7c631bcSMatt Jacob 				USEC_DELAY(100);
3610f7c631bcSMatt Jacob 			}
3611a4f3a2beSMatt Jacob 			if (isp->isp_osinfo.mboxcmd_done) {
3612a4f3a2beSMatt Jacob 				break;
3613a4f3a2beSMatt Jacob 			}
3614a4f3a2beSMatt Jacob 		}
3615f7c631bcSMatt Jacob 	}
3616f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mboxcmd_done == 0) {
3617f7c631bcSMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
3618ffcf6651SMatt Jacob 		    "%s Mailbox Command (0x%x) Timeout (%uus)",
3619f7c631bcSMatt Jacob 		    isp->isp_osinfo.mbox_sleep_ok? "Interrupting" : "Polled",
3620ffcf6651SMatt Jacob 		    isp->isp_lastmbxcmd, usecs);
3621f7c631bcSMatt Jacob 		mbp->param[0] = MBOX_TIMEOUT;
3622f7c631bcSMatt Jacob 		isp->isp_osinfo.mboxcmd_done = 1;
3623f7c631bcSMatt Jacob 	}
3624f7c631bcSMatt Jacob }
3625f7c631bcSMatt Jacob 
3626f7c631bcSMatt Jacob void
3627f7c631bcSMatt Jacob isp_mbox_notify_done(ispsoftc_t *isp)
3628f7c631bcSMatt Jacob {
3629f7c631bcSMatt Jacob 	if (isp->isp_osinfo.mbox_sleeping) {
3630f7c631bcSMatt Jacob 		wakeup(&isp->isp_mbxworkp);
3631f7c631bcSMatt Jacob 	}
3632f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxcmd_done = 1;
3633f7c631bcSMatt Jacob }
3634f7c631bcSMatt Jacob 
3635f7c631bcSMatt Jacob void
3636f7c631bcSMatt Jacob isp_mbox_release(ispsoftc_t *isp)
3637f7c631bcSMatt Jacob {
3638f7c631bcSMatt Jacob 	isp->isp_osinfo.mboxbsy = 0;
3639f7c631bcSMatt Jacob }
3640f7c631bcSMatt Jacob 
3641f7c631bcSMatt Jacob int
3642f7c631bcSMatt Jacob isp_mstohz(int ms)
3643f7c631bcSMatt Jacob {
3644a4f3a2beSMatt Jacob 	int hz;
3645f7c631bcSMatt Jacob 	struct timeval t;
3646f7c631bcSMatt Jacob 	t.tv_sec = ms / 1000;
3647f7c631bcSMatt Jacob 	t.tv_usec = (ms % 1000) * 1000;
3648a4f3a2beSMatt Jacob 	hz = tvtohz(&t);
3649a4f3a2beSMatt Jacob 	if (hz < 0) {
3650a4f3a2beSMatt Jacob 		hz = 0x7fffffff;
3651f7c631bcSMatt Jacob 	}
3652a4f3a2beSMatt Jacob 	if (hz == 0) {
3653a4f3a2beSMatt Jacob 		hz = 1;
3654a4f3a2beSMatt Jacob 	}
3655a4f3a2beSMatt Jacob 	return (hz);
3656f7c631bcSMatt Jacob }
36570a70657fSMatt Jacob 
36580a70657fSMatt Jacob void
36590a70657fSMatt Jacob isp_platform_intr(void *arg)
36600a70657fSMatt Jacob {
36610a70657fSMatt Jacob 	ispsoftc_t *isp = arg;
36620a70657fSMatt Jacob 	uint32_t isr;
36630a70657fSMatt Jacob 	uint16_t sema, mbox;
36640a70657fSMatt Jacob 
36650a70657fSMatt Jacob 	ISP_LOCK(isp);
36660a70657fSMatt Jacob 	isp->isp_intcnt++;
36670a70657fSMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
36680a70657fSMatt Jacob 		isp->isp_intbogus++;
36690a70657fSMatt Jacob 	} else {
36700a70657fSMatt Jacob 		isp_intr(isp, isr, sema, mbox);
36710a70657fSMatt Jacob 	}
36720a70657fSMatt Jacob 	ISP_UNLOCK(isp);
36730a70657fSMatt Jacob }
36740a70657fSMatt Jacob 
36750a70657fSMatt Jacob void
36760a70657fSMatt Jacob isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl)
36770a70657fSMatt Jacob {
36780a70657fSMatt Jacob 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
36790a70657fSMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat,
36800a70657fSMatt Jacob 		    PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTREAD);
36810a70657fSMatt Jacob 	} else {
36820a70657fSMatt Jacob 		bus_dmamap_sync(isp->isp_osinfo.dmat,
36830a70657fSMatt Jacob 		    PISP_PCMD(csio)->dmap, BUS_DMASYNC_POSTWRITE);
36840a70657fSMatt Jacob 	}
36850a70657fSMatt Jacob 	bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
36860a70657fSMatt Jacob }
3687