xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision aad970f1)
16054c3f6SMatt Jacob /*
26054c3f6SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
36054c3f6SMatt Jacob  *
45f5aafe1SMatt Jacob  * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob
56054c3f6SMatt Jacob  *
66054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
76054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
86054c3f6SMatt Jacob  * are met:
96054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
106054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
116054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
12aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
13aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
146054c3f6SMatt Jacob  *
156054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
196054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256054c3f6SMatt Jacob  * SUCH DAMAGE.
266054c3f6SMatt Jacob  */
27aad970f1SDavid E. O'Brien 
28aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
30aad970f1SDavid E. O'Brien 
316054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
325d571944SMatt Jacob #include <sys/unistd.h>
335d571944SMatt Jacob #include <sys/kthread.h>
343ea883b4SMatt Jacob #include <machine/stdarg.h>	/* for use by isp_prt below */
355d571944SMatt Jacob #include <sys/conf.h>
364eb49427SMatt Jacob #include <sys/module.h>
375d571944SMatt Jacob #include <sys/ioccom.h>
385d571944SMatt Jacob #include <dev/isp/isp_ioctl.h>
396054c3f6SMatt Jacob 
40a1bc34c6SMatt Jacob 
414eb49427SMatt Jacob MODULE_VERSION(isp, 1);
4273030e03SMatt Jacob int isp_announced = 0;
4373030e03SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL;
4473030e03SMatt Jacob 
455d571944SMatt Jacob static d_ioctl_t ispioctl;
46f6e75de2SMatt Jacob static void isp_intr_enable(void *);
470470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
480470d791SMatt Jacob static void isp_poll(struct cam_sim *);
49b85389e1SMatt Jacob static timeout_t isp_watchdog;
505d571944SMatt Jacob static void isp_kthread(void *);
51d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
520470d791SMatt Jacob 
53cc8df88bSMatt Jacob 
545d571944SMatt Jacob #define ISP_CDEV_MAJOR	248
555d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
567ac40f5fSPoul-Henning Kamp 	.d_open =	nullopen,
577ac40f5fSPoul-Henning Kamp 	.d_close =	nullclose,
587ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ispioctl,
597ac40f5fSPoul-Henning Kamp 	.d_name =	"isp",
607ac40f5fSPoul-Henning Kamp 	.d_maj =	ISP_CDEV_MAJOR,
617ac40f5fSPoul-Henning Kamp 	.d_flags =	D_TAPE,
625d571944SMatt Jacob };
635d571944SMatt Jacob 
64d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL;
65478f8a96SJustin T. Gibbs 
66478f8a96SJustin T. Gibbs void
67c3055363SMatt Jacob isp_attach(struct ispsoftc *isp)
68478f8a96SJustin T. Gibbs {
69ea6f23cdSMatt Jacob 	int primary, secondary;
70478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
71478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
72ea6f23cdSMatt Jacob 	struct cam_sim *sim;
73ea6f23cdSMatt Jacob 	struct cam_path *path;
74478f8a96SJustin T. Gibbs 
75478f8a96SJustin T. Gibbs 	/*
76ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
77ea6f23cdSMatt Jacob 	 */
78ea6f23cdSMatt Jacob 
79ea6f23cdSMatt Jacob 	primary = 0;
80ea6f23cdSMatt Jacob 	secondary = 1;
81ea6f23cdSMatt Jacob 
82ea6f23cdSMatt Jacob 	/*
83ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
84478f8a96SJustin T. Gibbs 	 */
85ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
86478f8a96SJustin T. Gibbs 	if (devq == NULL) {
87478f8a96SJustin T. Gibbs 		return;
88478f8a96SJustin T. Gibbs 	}
89478f8a96SJustin T. Gibbs 
90478f8a96SJustin T. Gibbs 	/*
91ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
92478f8a96SJustin T. Gibbs 	 */
9345c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
94ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
953c75bb14SMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
96ea6f23cdSMatt Jacob 	if (sim == NULL) {
97478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
9845c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
99478f8a96SJustin T. Gibbs 		return;
100478f8a96SJustin T. Gibbs 	}
10145c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
102f6e75de2SMatt Jacob 
103f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
104f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
10545c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
106f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
10745c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
10845c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
109bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
110bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
111f6e75de2SMatt Jacob 		return;
112f6e75de2SMatt Jacob 	}
113f6e75de2SMatt Jacob 
114ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
115ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
11645c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
117478f8a96SJustin T. Gibbs 		return;
118478f8a96SJustin T. Gibbs 	}
119478f8a96SJustin T. Gibbs 
120ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
121478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
122ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
123ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1245d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
12545c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
126478f8a96SJustin T. Gibbs 		return;
127478f8a96SJustin T. Gibbs 	}
128478f8a96SJustin T. Gibbs 
129ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
130478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
131478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
132cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
133ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
134478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
13545c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
136ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
137ea6f23cdSMatt Jacob 	isp->isp_path = path;
1385d571944SMatt Jacob 	/*
1395d571944SMatt Jacob 	 * Create a kernel thread for fibre channel instances. We
1405d571944SMatt Jacob 	 * don't have dual channel FC cards.
1415d571944SMatt Jacob 	 */
1425d571944SMatt Jacob 	if (IS_FC(isp)) {
14345c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
14445c9a36aSMatt Jacob 		/* XXX: LOCK VIOLATION */
1455d571944SMatt Jacob 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
1465d571944SMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
147316ec49aSScott Long 		    RFHIGHPID, 0, "%s: fc_thrd",
1485d571944SMatt Jacob 		    device_get_nameunit(isp->isp_dev))) {
1495d571944SMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
1505d571944SMatt Jacob 			cam_sim_free(sim, TRUE);
1515d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
15245c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
15345c9a36aSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
1545d571944SMatt Jacob 			return;
1555d571944SMatt Jacob 		}
1568e6a12fcSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
1575d571944SMatt Jacob 	}
1585d571944SMatt Jacob 
159478f8a96SJustin T. Gibbs 
160ea6f23cdSMatt Jacob 	/*
161ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
162ea6f23cdSMatt Jacob 	 */
16322e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
16445c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
165ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
1663c75bb14SMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
167ea6f23cdSMatt Jacob 		if (sim == NULL) {
168ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
169ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
170ea6f23cdSMatt Jacob 			cam_simq_free(devq);
1715d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
172ea6f23cdSMatt Jacob 			return;
173ea6f23cdSMatt Jacob 		}
174ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
175ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
176ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
177ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
1785d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
17945c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
180ea6f23cdSMatt Jacob 			return;
181ea6f23cdSMatt Jacob 		}
182ea6f23cdSMatt Jacob 
183ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
184ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
185ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
186ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
187ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
188ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
1895d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
19045c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
191ea6f23cdSMatt Jacob 			return;
192ea6f23cdSMatt Jacob 		}
193ea6f23cdSMatt Jacob 
194ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
195ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
196ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
197ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
198ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
199ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
20045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
201ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
202ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
203ea6f23cdSMatt Jacob 	}
2045d571944SMatt Jacob 
20564edff94SMatt Jacob #ifdef	ISP_TARGET_MODE
20664edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv0[0], "isp_tgcv0a");
20764edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv0[1], "isp_tgcv0b");
20864edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv1[0], "isp_tgcv1a");
20964edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv1[1], "isp_tgcv1b");
21064edff94SMatt Jacob #endif
2115d571944SMatt Jacob 	/*
2125d571944SMatt Jacob 	 * Create device nodes
2135d571944SMatt Jacob 	 */
2145d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2155d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2165d571944SMatt Jacob 
217d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
218478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
219b85389e1SMatt Jacob 		ENABLE_INTS(isp);
220d6e5500fSMatt Jacob 	}
221d81ba9d5SMatt Jacob 	if (isplist == NULL) {
222d81ba9d5SMatt Jacob 		isplist = isp;
223d81ba9d5SMatt Jacob 	} else {
224d81ba9d5SMatt Jacob 		struct ispsoftc *tmp = isplist;
225d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
226d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
227d81ba9d5SMatt Jacob 		}
228d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
229478f8a96SJustin T. Gibbs 	}
2305d571944SMatt Jacob 
2315d571944SMatt Jacob }
2325d571944SMatt Jacob 
233162e9893SMatt Jacob static INLINE void
234fdeb9f2fSMatt Jacob isp_freeze_loopdown(struct ispsoftc *isp, char *msg)
235fdeb9f2fSMatt Jacob {
236fdeb9f2fSMatt Jacob 	if (isp->isp_osinfo.simqfrozen == 0) {
237fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: freeze simq (loopdown)", msg);
238fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
239fdeb9f2fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
240fdeb9f2fSMatt Jacob 		xpt_freeze_simq(isp->isp_sim, 1);
241fdeb9f2fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
242fdeb9f2fSMatt Jacob 	} else {
243fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "%s: mark frozen (loopdown)", msg);
244fdeb9f2fSMatt Jacob 		isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
245fdeb9f2fSMatt Jacob 	}
246fdeb9f2fSMatt Jacob }
247fdeb9f2fSMatt Jacob 
2485d571944SMatt Jacob static int
249b40ce416SJulian Elischer ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
2505d571944SMatt Jacob {
2515d571944SMatt Jacob 	struct ispsoftc *isp;
2525d571944SMatt Jacob 	int retval = ENOTTY;
2535d571944SMatt Jacob 
2545d571944SMatt Jacob 	isp = isplist;
2555d571944SMatt Jacob 	while (isp) {
2565d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
2575d571944SMatt Jacob 			break;
2585d571944SMatt Jacob 		}
2595d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
2605d571944SMatt Jacob 	}
2615d571944SMatt Jacob 	if (isp == NULL)
2625d571944SMatt Jacob 		return (ENXIO);
2635d571944SMatt Jacob 
2645d571944SMatt Jacob 	switch (cmd) {
265d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
266d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
267d134aa0bSMatt Jacob 	{
268d134aa0bSMatt Jacob 		u_int16_t *ptr = FCPARAM(isp)->isp_dump_data;
269d134aa0bSMatt Jacob 		size_t sz;
270d134aa0bSMatt Jacob 
271d134aa0bSMatt Jacob 		retval = 0;
272d134aa0bSMatt Jacob 		if (IS_2200(isp))
273d134aa0bSMatt Jacob 			sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
274d134aa0bSMatt Jacob 		else
275d134aa0bSMatt Jacob 			sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
276d134aa0bSMatt Jacob 		ISP_LOCK(isp);
277d134aa0bSMatt Jacob 		if (ptr && *ptr) {
278d134aa0bSMatt Jacob 			void *uaddr = *((void **) addr);
279d134aa0bSMatt Jacob 			if (copyout(ptr, uaddr, sz)) {
280d134aa0bSMatt Jacob 				retval = EFAULT;
281d134aa0bSMatt Jacob 			} else {
282d134aa0bSMatt Jacob 				*ptr = 0;
283d134aa0bSMatt Jacob 			}
284d134aa0bSMatt Jacob 		} else {
285d134aa0bSMatt Jacob 			retval = ENXIO;
286d134aa0bSMatt Jacob 		}
287d134aa0bSMatt Jacob 		ISP_UNLOCK(isp);
288d134aa0bSMatt Jacob 		break;
289d134aa0bSMatt Jacob 	}
290d134aa0bSMatt Jacob 
291d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
292d134aa0bSMatt Jacob 		ISP_LOCK(isp);
293fdeb9f2fSMatt Jacob 		isp_freeze_loopdown(isp, "ispioctl(ISP_FORCE_CRASH_DUMP)");
294d134aa0bSMatt Jacob 		isp_fw_dump(isp);
295d134aa0bSMatt Jacob 		isp_reinit(isp);
296d134aa0bSMatt Jacob 		ISP_UNLOCK(isp);
297d134aa0bSMatt Jacob 		retval = 0;
298d134aa0bSMatt Jacob 		break;
299d134aa0bSMatt Jacob #endif
3005d571944SMatt Jacob 	case ISP_SDBLEV:
3015d571944SMatt Jacob 	{
3025d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
3035d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
3045d571944SMatt Jacob 		*(int *)addr = olddblev;
3055d571944SMatt Jacob 		retval = 0;
3065d571944SMatt Jacob 		break;
3075d571944SMatt Jacob 	}
3085d571944SMatt Jacob 	case ISP_RESETHBA:
3095d571944SMatt Jacob 		ISP_LOCK(isp);
3105d571944SMatt Jacob 		isp_reinit(isp);
3115d571944SMatt Jacob 		ISP_UNLOCK(isp);
3125d571944SMatt Jacob 		retval = 0;
3135d571944SMatt Jacob 		break;
314f553351eSMatt Jacob 	case ISP_RESCAN:
3155d571944SMatt Jacob 		if (IS_FC(isp)) {
3165d571944SMatt Jacob 			ISP_LOCK(isp);
3175d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
3185d571944SMatt Jacob 				retval = EIO;
3195d571944SMatt Jacob 			} else {
3205d571944SMatt Jacob 				retval = 0;
3215d571944SMatt Jacob 			}
3225d571944SMatt Jacob 			ISP_UNLOCK(isp);
3235d571944SMatt Jacob 		}
3245d571944SMatt Jacob 		break;
3255d571944SMatt Jacob 	case ISP_FC_LIP:
3265d571944SMatt Jacob 		if (IS_FC(isp)) {
3275d571944SMatt Jacob 			ISP_LOCK(isp);
3285d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
3295d571944SMatt Jacob 				retval = EIO;
3305d571944SMatt Jacob 			} else {
3315d571944SMatt Jacob 				retval = 0;
3325d571944SMatt Jacob 			}
3335d571944SMatt Jacob 			ISP_UNLOCK(isp);
3345d571944SMatt Jacob 		}
3355d571944SMatt Jacob 		break;
3365d571944SMatt Jacob 	case ISP_FC_GETDINFO:
3375d571944SMatt Jacob 	{
3385d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
3395d571944SMatt Jacob 		struct lportdb *lp;
3405d571944SMatt Jacob 
3415d571944SMatt Jacob 		if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
3425d571944SMatt Jacob 			retval = EINVAL;
3435d571944SMatt Jacob 			break;
3445d571944SMatt Jacob 		}
3455d571944SMatt Jacob 		ISP_LOCK(isp);
3465d571944SMatt Jacob 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
3475d571944SMatt Jacob 		if (lp->valid) {
3485d571944SMatt Jacob 			ifc->loopid = lp->loopid;
3495d571944SMatt Jacob 			ifc->portid = lp->portid;
3505d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
3515d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
3525d571944SMatt Jacob 			retval = 0;
3535d571944SMatt Jacob 		} else {
3545d571944SMatt Jacob 			retval = ENODEV;
3555d571944SMatt Jacob 		}
3565d571944SMatt Jacob 		ISP_UNLOCK(isp);
3575d571944SMatt Jacob 		break;
3585d571944SMatt Jacob 	}
3592903b272SMatt Jacob 	case ISP_GET_STATS:
3602903b272SMatt Jacob 	{
3612903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
3622903b272SMatt Jacob 
3632903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
3642903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
3652903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
3662903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
3672903b272SMatt Jacob 		ISP_LOCK(isp);
3682903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
3692903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
3702903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
3712903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
3722903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
3732903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
3742903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
3752903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
3762903b272SMatt Jacob 		ISP_UNLOCK(isp);
3772903b272SMatt Jacob 		retval = 0;
3782903b272SMatt Jacob 		break;
3792903b272SMatt Jacob 	}
3802903b272SMatt Jacob 	case ISP_CLR_STATS:
3812903b272SMatt Jacob 		ISP_LOCK(isp);
3822903b272SMatt Jacob 		isp->isp_intcnt = 0;
3832903b272SMatt Jacob 		isp->isp_intbogus = 0;
3842903b272SMatt Jacob 		isp->isp_intmboxc = 0;
3852903b272SMatt Jacob 		isp->isp_intoasync = 0;
3862903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
3872903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
3882903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
3892903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
3902903b272SMatt Jacob 		ISP_UNLOCK(isp);
3912903b272SMatt Jacob 		retval = 0;
3922903b272SMatt Jacob 		break;
393570c7a3fSMatt Jacob 	case ISP_FC_GETHINFO:
394570c7a3fSMatt Jacob 	{
395570c7a3fSMatt Jacob 		struct isp_hba_device *hba = (struct isp_hba_device *) addr;
396570c7a3fSMatt Jacob 		MEMZERO(hba, sizeof (*hba));
397570c7a3fSMatt Jacob 		ISP_LOCK(isp);
398570c7a3fSMatt Jacob 		hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
399570c7a3fSMatt Jacob 		hba->fc_scsi_supported = 1;
400570c7a3fSMatt Jacob 		hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
401570c7a3fSMatt Jacob 		hba->fc_loopid = FCPARAM(isp)->isp_loopid;
402570c7a3fSMatt Jacob 		hba->active_node_wwn = FCPARAM(isp)->isp_nodewwn;
403570c7a3fSMatt Jacob 		hba->active_port_wwn = FCPARAM(isp)->isp_portwwn;
404570c7a3fSMatt Jacob 		ISP_UNLOCK(isp);
405570c7a3fSMatt Jacob 		retval = 0;
406570c7a3fSMatt Jacob 		break;
407570c7a3fSMatt Jacob 	}
408fdeb9f2fSMatt Jacob 	case ISP_GET_FC_PARAM:
409fdeb9f2fSMatt Jacob 	{
410fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
411fdeb9f2fSMatt Jacob 
412fdeb9f2fSMatt Jacob 		if (!IS_FC(isp)) {
413fdeb9f2fSMatt Jacob 			retval = EINVAL;
414fdeb9f2fSMatt Jacob 			break;
415fdeb9f2fSMatt Jacob 		}
416fdeb9f2fSMatt Jacob 		f->parameter = 0;
417fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
418fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_maxfrmlen;
419fdeb9f2fSMatt Jacob 			retval = 0;
420fdeb9f2fSMatt Jacob 			break;
421fdeb9f2fSMatt Jacob 		}
422fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
423fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_execthrottle;
424fdeb9f2fSMatt Jacob 			retval = 0;
425fdeb9f2fSMatt Jacob 			break;
426fdeb9f2fSMatt Jacob 		}
427fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
428fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->isp_fwoptions & ICBOPT_FULL_DUPLEX)
429fdeb9f2fSMatt Jacob 				f->parameter = 1;
430fdeb9f2fSMatt Jacob 			retval = 0;
431fdeb9f2fSMatt Jacob 			break;
432fdeb9f2fSMatt Jacob 		}
433fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
434fdeb9f2fSMatt Jacob 			f->parameter = FCPARAM(isp)->isp_loopid;
435fdeb9f2fSMatt Jacob 			retval = 0;
436fdeb9f2fSMatt Jacob 			break;
437fdeb9f2fSMatt Jacob 		}
438fdeb9f2fSMatt Jacob 		retval = EINVAL;
439fdeb9f2fSMatt Jacob 		break;
440fdeb9f2fSMatt Jacob 	}
441fdeb9f2fSMatt Jacob 	case ISP_SET_FC_PARAM:
442fdeb9f2fSMatt Jacob 	{
443fdeb9f2fSMatt Jacob 		struct isp_fc_param *f = (struct isp_fc_param *) addr;
444fdeb9f2fSMatt Jacob 		u_int32_t param = f->parameter;
445fdeb9f2fSMatt Jacob 
446fdeb9f2fSMatt Jacob 		if (!IS_FC(isp)) {
447fdeb9f2fSMatt Jacob 			retval = EINVAL;
448fdeb9f2fSMatt Jacob 			break;
449fdeb9f2fSMatt Jacob 		}
450fdeb9f2fSMatt Jacob 		f->parameter = 0;
451fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "framelength") == 0) {
452fdeb9f2fSMatt Jacob 			if (param != 512 && param != 1024 && param != 1024) {
453fdeb9f2fSMatt Jacob 				retval = EINVAL;
454fdeb9f2fSMatt Jacob 				break;
455fdeb9f2fSMatt Jacob 			}
456fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_maxfrmlen = param;
457fdeb9f2fSMatt Jacob 			retval = 0;
458fdeb9f2fSMatt Jacob 			break;
459fdeb9f2fSMatt Jacob 		}
460fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "exec_throttle") == 0) {
461fdeb9f2fSMatt Jacob 			if (param < 16 || param > 255) {
462fdeb9f2fSMatt Jacob 				retval = EINVAL;
463fdeb9f2fSMatt Jacob 				break;
464fdeb9f2fSMatt Jacob 			}
465fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_execthrottle = param;
466fdeb9f2fSMatt Jacob 			retval = 0;
467fdeb9f2fSMatt Jacob 			break;
468fdeb9f2fSMatt Jacob 		}
469fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "fullduplex") == 0) {
470fdeb9f2fSMatt Jacob 			if (param != 0 && param != 1) {
471fdeb9f2fSMatt Jacob 				retval = EINVAL;
472fdeb9f2fSMatt Jacob 				break;
473fdeb9f2fSMatt Jacob 			}
474fdeb9f2fSMatt Jacob 			if (param) {
475fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions |=
476fdeb9f2fSMatt Jacob 				    ICBOPT_FULL_DUPLEX;
477fdeb9f2fSMatt Jacob 			} else {
478fdeb9f2fSMatt Jacob 				FCPARAM(isp)->isp_fwoptions &=
479fdeb9f2fSMatt Jacob 				    ~ICBOPT_FULL_DUPLEX;
480fdeb9f2fSMatt Jacob 			}
481fdeb9f2fSMatt Jacob 			retval = 0;
482fdeb9f2fSMatt Jacob 			break;
483fdeb9f2fSMatt Jacob 		}
484fdeb9f2fSMatt Jacob 		if (strcmp(f->param_name, "loopid") == 0) {
485fdeb9f2fSMatt Jacob 			if (param < 0 || param > 125) {
486fdeb9f2fSMatt Jacob 				retval = EINVAL;
487fdeb9f2fSMatt Jacob 				break;
488fdeb9f2fSMatt Jacob 			}
489fdeb9f2fSMatt Jacob 			FCPARAM(isp)->isp_loopid = param;
490fdeb9f2fSMatt Jacob 			retval = 0;
491fdeb9f2fSMatt Jacob 			break;
492fdeb9f2fSMatt Jacob 		}
493fdeb9f2fSMatt Jacob 		retval = EINVAL;
494fdeb9f2fSMatt Jacob 		break;
495fdeb9f2fSMatt Jacob 	}
4965d571944SMatt Jacob 	default:
4975d571944SMatt Jacob 		break;
4985d571944SMatt Jacob 	}
4995d571944SMatt Jacob 	return (retval);
5000470d791SMatt Jacob }
501478f8a96SJustin T. Gibbs 
502f6e75de2SMatt Jacob static void
503f6e75de2SMatt Jacob isp_intr_enable(void *arg)
504f6e75de2SMatt Jacob {
505f6e75de2SMatt Jacob 	struct ispsoftc *isp = arg;
506d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
507f6e75de2SMatt Jacob 		ENABLE_INTS(isp);
508f6e75de2SMatt Jacob 		isp->isp_osinfo.intsok = 1;
509d6e5500fSMatt Jacob 	}
510f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
511f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
512f6e75de2SMatt Jacob }
513d81ba9d5SMatt Jacob 
514d81ba9d5SMatt Jacob /*
515d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
516d81ba9d5SMatt Jacob  */
517d81ba9d5SMatt Jacob 
518d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
519d81ba9d5SMatt Jacob 
520162e9893SMatt Jacob static INLINE int is_lun_enabled(struct ispsoftc *, int, lun_id_t);
521162e9893SMatt Jacob static INLINE int are_any_luns_enabled(struct ispsoftc *, int);
522162e9893SMatt Jacob static INLINE tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t);
523162e9893SMatt Jacob static INLINE void rls_lun_statep(struct ispsoftc *, tstate_t *);
524162e9893SMatt Jacob static INLINE int isp_psema_sig_rqe(struct ispsoftc *, int);
525162e9893SMatt Jacob static INLINE int isp_cv_wait_timed_rqe(struct ispsoftc *, int, int);
526162e9893SMatt Jacob static INLINE void isp_cv_signal_rqe(struct ispsoftc *, int, int);
527162e9893SMatt Jacob static INLINE void isp_vsema_rqe(struct ispsoftc *, int);
528162e9893SMatt Jacob static INLINE atio_private_data_t *isp_get_atpd(struct ispsoftc *, int);
529d81ba9d5SMatt Jacob static cam_status
530a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **);
531d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *);
532d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *);
533d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *);
534f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
535a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
536a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
537a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *);
538d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *);
539d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *);
540d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *);
541570c7a3fSMatt Jacob static int isp_handle_platform_notify_scsi(struct ispsoftc *, in_entry_t *);
542570c7a3fSMatt Jacob static int isp_handle_platform_notify_fc(struct ispsoftc *, in_fcentry_t *);
543d81ba9d5SMatt Jacob 
544162e9893SMatt Jacob static INLINE int
545a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
546d81ba9d5SMatt Jacob {
547d81ba9d5SMatt Jacob 	tstate_t *tptr;
548a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
549a1bc34c6SMatt Jacob 	if (tptr == NULL) {
550d81ba9d5SMatt Jacob 		return (0);
551d81ba9d5SMatt Jacob 	}
552d81ba9d5SMatt Jacob 	do {
553a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
554d81ba9d5SMatt Jacob 			return (1);
555d81ba9d5SMatt Jacob 		}
556d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
557d81ba9d5SMatt Jacob 	return (0);
558d81ba9d5SMatt Jacob }
559d81ba9d5SMatt Jacob 
560162e9893SMatt Jacob static INLINE int
561a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port)
562d81ba9d5SMatt Jacob {
563a1bc34c6SMatt Jacob 	int lo, hi;
564a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
565a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
566a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
567a1bc34c6SMatt Jacob 	} else {
568a1bc34c6SMatt Jacob 		lo = 0;
569a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
570a1bc34c6SMatt Jacob 	}
571a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
572a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
573d81ba9d5SMatt Jacob 			return (1);
574d81ba9d5SMatt Jacob 		}
575d81ba9d5SMatt Jacob 	}
576d81ba9d5SMatt Jacob 	return (0);
577d81ba9d5SMatt Jacob }
578d81ba9d5SMatt Jacob 
579162e9893SMatt Jacob static INLINE tstate_t *
580a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun)
581d81ba9d5SMatt Jacob {
58264edff94SMatt Jacob 	tstate_t *tptr = NULL;
583d81ba9d5SMatt Jacob 
584d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
58564edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
586a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
587d81ba9d5SMatt Jacob 			tptr->hold++;
588d81ba9d5SMatt Jacob 			return (tptr);
589d81ba9d5SMatt Jacob 		}
590126ec864SMatt Jacob 	} else {
591126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
59264edff94SMatt Jacob 		if (tptr == NULL) {
59364edff94SMatt Jacob 			return (NULL);
59464edff94SMatt Jacob 		}
595126ec864SMatt Jacob 	}
596d81ba9d5SMatt Jacob 
597d81ba9d5SMatt Jacob 	do {
598a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
599d81ba9d5SMatt Jacob 			tptr->hold++;
600d81ba9d5SMatt Jacob 			return (tptr);
601d81ba9d5SMatt Jacob 		}
602d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
603d81ba9d5SMatt Jacob 	return (tptr);
604d81ba9d5SMatt Jacob }
605d81ba9d5SMatt Jacob 
606162e9893SMatt Jacob static INLINE void
607d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr)
608d81ba9d5SMatt Jacob {
609d81ba9d5SMatt Jacob 	if (tptr->hold)
610d81ba9d5SMatt Jacob 		tptr->hold--;
611d81ba9d5SMatt Jacob }
612d81ba9d5SMatt Jacob 
613162e9893SMatt Jacob static INLINE int
61464edff94SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp, int bus)
615d81ba9d5SMatt Jacob {
61664edff94SMatt Jacob 	while (isp->isp_osinfo.tmflags[bus] & TM_BUSY) {
61764edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_WANTED;
618162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
61964edff94SMatt Jacob 		if (cv_wait_sig(&isp->isp_osinfo.tgtcv0[bus], &isp->isp_lock)) {
620d81ba9d5SMatt Jacob 			return (-1);
621d81ba9d5SMatt Jacob 		}
622162e9893SMatt Jacob #else
623162e9893SMatt Jacob 		if (tsleep(&isp->isp_osinfo.tgtcv0[bus], PZERO, "cv_isp", 0)) {
624162e9893SMatt Jacob 			return (-1);
625162e9893SMatt Jacob 		}
626162e9893SMatt Jacob #endif
62764edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_BUSY;
628d81ba9d5SMatt Jacob 	}
629d81ba9d5SMatt Jacob 	return (0);
630d81ba9d5SMatt Jacob }
631d81ba9d5SMatt Jacob 
632162e9893SMatt Jacob static INLINE int
63364edff94SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int bus, int timo)
634d81ba9d5SMatt Jacob {
635162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
63664edff94SMatt Jacob 	if (cv_timedwait(&isp->isp_osinfo.tgtcv1[bus], &isp->isp_lock, timo)) {
637d81ba9d5SMatt Jacob 		return (-1);
638d81ba9d5SMatt Jacob 	}
639162e9893SMatt Jacob #else
640162e9893SMatt Jacob 	if (tsleep(&isp->isp_osinfo.tgtcv1[bus], PZERO, "cv_isp1", 0)) {
641162e9893SMatt Jacob 		return (-1);
642162e9893SMatt Jacob 	}
643162e9893SMatt Jacob #endif
644d81ba9d5SMatt Jacob 	return (0);
645d81ba9d5SMatt Jacob }
646d81ba9d5SMatt Jacob 
647162e9893SMatt Jacob static INLINE void
64864edff94SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int bus, int status)
649d81ba9d5SMatt Jacob {
65064edff94SMatt Jacob 	isp->isp_osinfo.rstatus[bus] = status;
651162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
65264edff94SMatt Jacob 	cv_signal(&isp->isp_osinfo.tgtcv1[bus]);
653162e9893SMatt Jacob #else
654162e9893SMatt Jacob 	wakeup(&isp->isp_osinfo.tgtcv1[bus]);
655162e9893SMatt Jacob #endif
656d81ba9d5SMatt Jacob }
657d81ba9d5SMatt Jacob 
658162e9893SMatt Jacob static INLINE void
65964edff94SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp, int bus)
660d81ba9d5SMatt Jacob {
66164edff94SMatt Jacob 	if (isp->isp_osinfo.tmflags[bus] & TM_WANTED) {
66264edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_WANTED;
663162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
66464edff94SMatt Jacob 		cv_signal(&isp->isp_osinfo.tgtcv0[bus]);
665162e9893SMatt Jacob #else
666162e9893SMatt Jacob 		cv_signal(&isp->isp_osinfo.tgtcv0[bus]);
667162e9893SMatt Jacob #endif
668d81ba9d5SMatt Jacob 	}
66964edff94SMatt Jacob 	isp->isp_osinfo.tmflags[bus] &= ~TM_BUSY;
670d81ba9d5SMatt Jacob }
671d81ba9d5SMatt Jacob 
672162e9893SMatt Jacob static INLINE atio_private_data_t *
67353036e92SMatt Jacob isp_get_atpd(struct ispsoftc *isp, int tag)
67453036e92SMatt Jacob {
67553036e92SMatt Jacob 	atio_private_data_t *atp;
67653036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
67753036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
67853036e92SMatt Jacob 		if (atp->tag == tag)
67953036e92SMatt Jacob 			return (atp);
68053036e92SMatt Jacob 	}
68153036e92SMatt Jacob 	return (NULL);
68253036e92SMatt Jacob }
68353036e92SMatt Jacob 
684d81ba9d5SMatt Jacob static cam_status
685a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus,
686a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
687d81ba9d5SMatt Jacob {
688d81ba9d5SMatt Jacob 	cam_status status;
689d81ba9d5SMatt Jacob 	lun_id_t lun;
690a1bc34c6SMatt Jacob 	int hfx;
691d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
692d81ba9d5SMatt Jacob 
693d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
694d81ba9d5SMatt Jacob 	if (lun < 0) {
695d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
696d81ba9d5SMatt Jacob 	}
697a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
698d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
699d81ba9d5SMatt Jacob 	}
700ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
701d81ba9d5SMatt Jacob 	if (new == NULL) {
702d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
703d81ba9d5SMatt Jacob 	}
704d81ba9d5SMatt Jacob 
705d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
706d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
707d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
708d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
709d81ba9d5SMatt Jacob 		return (status);
710d81ba9d5SMatt Jacob 	}
711a1bc34c6SMatt Jacob 	new->bus = bus;
712d81ba9d5SMatt Jacob 	new->lun = lun;
713d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
714d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
715d81ba9d5SMatt Jacob 	new->hold = 1;
716d81ba9d5SMatt Jacob 
717a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
718a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
719a1bc34c6SMatt Jacob 	if (tptr == NULL) {
720a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
721d81ba9d5SMatt Jacob 	} else {
722d81ba9d5SMatt Jacob 		while (tptr->next)
723d81ba9d5SMatt Jacob 			tptr = tptr->next;
724d81ba9d5SMatt Jacob 		tptr->next = new;
725d81ba9d5SMatt Jacob 	}
726d81ba9d5SMatt Jacob 	*rslt = new;
727d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
728d81ba9d5SMatt Jacob }
729d81ba9d5SMatt Jacob 
730162e9893SMatt Jacob static INLINE void
731d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
732d81ba9d5SMatt Jacob {
733a1bc34c6SMatt Jacob 	int hfx;
734d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
735d81ba9d5SMatt Jacob 
736a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
737d81ba9d5SMatt Jacob 	if (tptr->hold) {
738d81ba9d5SMatt Jacob 		return;
739d81ba9d5SMatt Jacob 	}
740a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
741d81ba9d5SMatt Jacob 	if (pw == NULL) {
742d81ba9d5SMatt Jacob 		return;
743a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
744a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
745d81ba9d5SMatt Jacob 	} else {
746d81ba9d5SMatt Jacob 		lw = pw;
747d81ba9d5SMatt Jacob 		pw = lw->next;
748d81ba9d5SMatt Jacob 		while (pw) {
749a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
750d81ba9d5SMatt Jacob 				lw->next = pw->next;
751d81ba9d5SMatt Jacob 				break;
752d81ba9d5SMatt Jacob 			}
753d81ba9d5SMatt Jacob 			lw = pw;
754d81ba9d5SMatt Jacob 			pw = pw->next;
755d81ba9d5SMatt Jacob 		}
756d81ba9d5SMatt Jacob 		if (pw == NULL) {
757d81ba9d5SMatt Jacob 			return;
758d81ba9d5SMatt Jacob 		}
759d81ba9d5SMatt Jacob 	}
760d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
761d81ba9d5SMatt Jacob }
762d81ba9d5SMatt Jacob 
7635d571944SMatt Jacob /*
7645d571944SMatt Jacob  * we enter with our locks held.
7655d571944SMatt Jacob  */
766d81ba9d5SMatt Jacob static void
767d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
768d81ba9d5SMatt Jacob {
769a1bc34c6SMatt Jacob 	const char lfmt[] = "Lun now %sabled for target mode on channel %d";
770d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
771d81ba9d5SMatt Jacob 	tstate_t *tptr;
772d81ba9d5SMatt Jacob 	u_int16_t rstat;
77364edff94SMatt Jacob 	int bus, cmd, av, wildcard;
774d81ba9d5SMatt Jacob 	lun_id_t lun;
775d81ba9d5SMatt Jacob 	target_id_t tgt;
776d81ba9d5SMatt Jacob 
777d81ba9d5SMatt Jacob 
778a1bc34c6SMatt Jacob 	bus = XS_CHANNEL(ccb) & 0x1;
779d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
780d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
781d81ba9d5SMatt Jacob 
782d81ba9d5SMatt Jacob 	/*
783d81ba9d5SMatt Jacob 	 * Do some sanity checking first.
784d81ba9d5SMatt Jacob 	 */
785d81ba9d5SMatt Jacob 
786d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
787d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
788d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
789d81ba9d5SMatt Jacob 		return;
790d81ba9d5SMatt Jacob 	}
79164edff94SMatt Jacob 
7922ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
793a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
794a1bc34c6SMatt Jacob 		sdp += bus;
795d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
796a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
797d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
798d81ba9d5SMatt Jacob 			return;
799d81ba9d5SMatt Jacob 		}
800d81ba9d5SMatt Jacob 	} else {
801d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
802d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
803d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
804d81ba9d5SMatt Jacob 			return;
805d81ba9d5SMatt Jacob 		}
80664edff94SMatt Jacob 		/*
80764edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
80864edff94SMatt Jacob 		 */
80964edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) {
81064edff94SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
81164edff94SMatt Jacob 			    "firmware does not support target mode");
81264edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
81364edff94SMatt Jacob 			return;
81464edff94SMatt Jacob 		}
81564edff94SMatt Jacob 		/*
81664edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
81764edff94SMatt Jacob 		 * XXX: dorks with our already fragile enable/disable code.
81864edff94SMatt Jacob 		 */
81964edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
82064edff94SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
82164edff94SMatt Jacob 			    "firmware not SCCLUN capable");
82264edff94SMatt Jacob 		}
823d81ba9d5SMatt Jacob 	}
824d81ba9d5SMatt Jacob 
825d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
82664edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
82764edff94SMatt Jacob 			wildcard = 1;
82864edff94SMatt Jacob 		} else {
829d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
830d6e5500fSMatt Jacob 			return;
831d6e5500fSMatt Jacob 		}
832126ec864SMatt Jacob 	} else {
833126ec864SMatt Jacob 		wildcard = 0;
834126ec864SMatt Jacob 	}
835b6b6ad2fSMatt Jacob 
836b6b6ad2fSMatt Jacob 	/*
837b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
83864edff94SMatt Jacob 	 *
83964edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
84064edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
84164edff94SMatt Jacob 	 * handle them locally (if we see them at all).
842b6b6ad2fSMatt Jacob 	 */
843126ec864SMatt Jacob 
844126ec864SMatt Jacob 	if (wildcard) {
845a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
846b6b6ad2fSMatt Jacob 		if (cel->enable) {
84764edff94SMatt Jacob 			if (isp->isp_osinfo.tmflags[bus] &
84864edff94SMatt Jacob 			    TM_WILDCARD_ENABLED) {
849b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
850b6b6ad2fSMatt Jacob 				return;
851b6b6ad2fSMatt Jacob 			}
852b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
853b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
854b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
855b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
856b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
857b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
858b6b6ad2fSMatt Jacob 				return;
859b6b6ad2fSMatt Jacob 			}
860b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
861b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
86264edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
863126ec864SMatt Jacob 		} else {
86464edff94SMatt Jacob 			if ((isp->isp_osinfo.tmflags[bus] &
86564edff94SMatt Jacob 			    TM_WILDCARD_ENABLED) == 0) {
866126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
867126ec864SMatt Jacob 				return;
868126ec864SMatt Jacob 			}
869126ec864SMatt Jacob 			if (tptr->hold) {
870126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
871126ec864SMatt Jacob 				return;
872126ec864SMatt Jacob 			}
873126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
87464edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
875126ec864SMatt Jacob 		}
876126ec864SMatt Jacob 	}
877126ec864SMatt Jacob 
878126ec864SMatt Jacob 	/*
879126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
880126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
881126ec864SMatt Jacob 	 */
882126ec864SMatt Jacob 	av = bus << 31;
88364edff94SMatt Jacob 	if (cel->enable && !(isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED)) {
884a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
885b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
886b6b6ad2fSMatt Jacob 		if (av) {
887b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
888126ec864SMatt Jacob 			if (wildcard) {
88964edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
89064edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
891b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
8925d571944SMatt Jacob 			}
893b6b6ad2fSMatt Jacob 			return;
894b6b6ad2fSMatt Jacob 		}
89564edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
896126ec864SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
897126ec864SMatt Jacob 		    "Target Mode enabled on channel %d", bus);
89864edff94SMatt Jacob 	} else if (cel->enable == 0 &&
89964edff94SMatt Jacob 	    (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) && wildcard) {
900a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
901b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
902b6b6ad2fSMatt Jacob 			return;
903b6b6ad2fSMatt Jacob 		}
904b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
905b6b6ad2fSMatt Jacob 		if (av) {
906b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
907b6b6ad2fSMatt Jacob 			return;
908b6b6ad2fSMatt Jacob 		}
90964edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
910126ec864SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
911126ec864SMatt Jacob 		    "Target Mode disabled on channel %d", bus);
912126ec864SMatt Jacob 	}
913126ec864SMatt Jacob 
914126ec864SMatt Jacob 	if (wildcard) {
91564edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
916b6b6ad2fSMatt Jacob 		return;
917b6b6ad2fSMatt Jacob 	}
918b6b6ad2fSMatt Jacob 
919d81ba9d5SMatt Jacob 	if (cel->enable) {
920d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
921a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
922d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
923d81ba9d5SMatt Jacob 			return;
924d81ba9d5SMatt Jacob 		}
925d81ba9d5SMatt Jacob 	} else {
926a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
927d81ba9d5SMatt Jacob 		if (tptr == NULL) {
928d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
929d81ba9d5SMatt Jacob 			return;
930d81ba9d5SMatt Jacob 		}
931d81ba9d5SMatt Jacob 	}
932d81ba9d5SMatt Jacob 
93364edff94SMatt Jacob 	if (isp_psema_sig_rqe(isp, bus)) {
934d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
935d81ba9d5SMatt Jacob 		if (cel->enable)
936d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
937d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
938d81ba9d5SMatt Jacob 		return;
939d81ba9d5SMatt Jacob 	}
940d81ba9d5SMatt Jacob 
941d81ba9d5SMatt Jacob 	if (cel->enable) {
942d81ba9d5SMatt Jacob 		u_int32_t seq = isp->isp_osinfo.rollinfo++;
9435d571944SMatt Jacob 		int c, n, ulun = lun;
9445d571944SMatt Jacob 
9455d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
9465d571944SMatt Jacob 		c = DFLT_CMND_CNT;
9475d571944SMatt Jacob 		n = DFLT_INOT_CNT;
9485d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
9495d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
9505d571944SMatt Jacob 			n = 0;
9515d571944SMatt Jacob 			/*
9525d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
9535d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
9545d571944SMatt Jacob 			 */
9555d571944SMatt Jacob 			ulun = 0;
9565d571944SMatt Jacob 		}
957d81ba9d5SMatt Jacob 		rstat = LUN_ERR;
9585d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) {
959d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
9603c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed");
961d81ba9d5SMatt Jacob 			goto out;
962d81ba9d5SMatt Jacob 		}
96364edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
964d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
9653c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
9665d571944SMatt Jacob 			    "wait for ENABLE/MODIFY LUN timed out");
967d81ba9d5SMatt Jacob 			goto out;
968d81ba9d5SMatt Jacob 		}
96964edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
970d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
971d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
9723c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
9735d571944SMatt Jacob 			    "ENABLE/MODIFY LUN returned 0x%x", rstat);
974d81ba9d5SMatt Jacob 			goto out;
975d81ba9d5SMatt Jacob 		}
976d81ba9d5SMatt Jacob 	} else {
9775d571944SMatt Jacob 		int c, n, ulun = lun;
978d81ba9d5SMatt Jacob 		u_int32_t seq;
979d81ba9d5SMatt Jacob 
980d81ba9d5SMatt Jacob 		rstat = LUN_ERR;
9815d571944SMatt Jacob 		seq = isp->isp_osinfo.rollinfo++;
9825d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
983d81ba9d5SMatt Jacob 
9845d571944SMatt Jacob 		c = DFLT_CMND_CNT;
9855d571944SMatt Jacob 		n = DFLT_INOT_CNT;
9865d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
9875d571944SMatt Jacob 			n = 0;
9885d571944SMatt Jacob 			/*
9895d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
9905d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
9915d571944SMatt Jacob 			 */
9925d571944SMatt Jacob 			ulun = 0;
9935d571944SMatt Jacob 		}
9945d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) {
995d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
9963c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed");
997d81ba9d5SMatt Jacob 			goto out;
998d81ba9d5SMatt Jacob 		}
99964edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
1000d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
10013c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
10023c75bb14SMatt Jacob 			    "wait for MODIFY LUN timed out");
1003d81ba9d5SMatt Jacob 			goto out;
1004d81ba9d5SMatt Jacob 		}
100564edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
1006d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
1007d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
10083c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
10093c75bb14SMatt Jacob 			    "MODIFY LUN returned 0x%x", rstat);
1010d81ba9d5SMatt Jacob 			goto out;
1011d81ba9d5SMatt Jacob 		}
10125d571944SMatt Jacob 		if (IS_FC(isp) && lun) {
10135d571944SMatt Jacob 			goto out;
10145d571944SMatt Jacob 		}
10155d571944SMatt Jacob 
1016d81ba9d5SMatt Jacob 		seq = isp->isp_osinfo.rollinfo++;
1017d81ba9d5SMatt Jacob 
10185d571944SMatt Jacob 		rstat = LUN_ERR;
10195d571944SMatt Jacob 		cmd = -RQSTYPE_ENABLE_LUN;
10205d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) {
1021d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
10223c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed");
1023d81ba9d5SMatt Jacob 			goto out;
1024d81ba9d5SMatt Jacob 		}
102564edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
1026d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
10273c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
10285d571944SMatt Jacob 			     "wait for DISABLE LUN timed out");
1029d81ba9d5SMatt Jacob 			goto out;
1030d81ba9d5SMatt Jacob 		}
103164edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
1032d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
1033d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
10343c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
10355d571944SMatt Jacob 			    "DISABLE LUN returned 0x%x", rstat);
1036d81ba9d5SMatt Jacob 			goto out;
1037d81ba9d5SMatt Jacob 		}
1038126ec864SMatt Jacob 		if (are_any_luns_enabled(isp, bus) == 0) {
1039126ec864SMatt Jacob 			av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
1040126ec864SMatt Jacob 			if (av) {
1041126ec864SMatt Jacob 				isp_prt(isp, ISP_LOGWARN,
1042126ec864SMatt Jacob 				    "disable target mode on channel %d failed",
1043126ec864SMatt Jacob 				    bus);
1044126ec864SMatt Jacob 				goto out;
1045d81ba9d5SMatt Jacob 			}
104664edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
1047126ec864SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
1048126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
1049126ec864SMatt Jacob 			    "Target Mode disabled on channel %d", bus);
1050126ec864SMatt Jacob 		}
1051126ec864SMatt Jacob 	}
1052126ec864SMatt Jacob 
1053d81ba9d5SMatt Jacob out:
105464edff94SMatt Jacob 	isp_vsema_rqe(isp, bus);
1055d81ba9d5SMatt Jacob 
1056d81ba9d5SMatt Jacob 	if (rstat != LUN_OK) {
1057d81ba9d5SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
10583c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
10593c75bb14SMatt Jacob 		    "lun %sable failed", (cel->enable) ? "en" : "dis");
1060d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1061d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1062d81ba9d5SMatt Jacob 		if (cel->enable)
1063d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
1064d81ba9d5SMatt Jacob 	} else {
1065d81ba9d5SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
1066a1bc34c6SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, lfmt,
1067a1bc34c6SMatt Jacob 		    (cel->enable) ? "en" : "dis", bus);
1068d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1069d81ba9d5SMatt Jacob 		if (cel->enable == 0) {
1070d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
1071d81ba9d5SMatt Jacob 		}
1072d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
1073d81ba9d5SMatt Jacob 	}
1074d81ba9d5SMatt Jacob }
1075d81ba9d5SMatt Jacob 
1076d81ba9d5SMatt Jacob static cam_status
1077d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb)
1078d81ba9d5SMatt Jacob {
1079d81ba9d5SMatt Jacob 	tstate_t *tptr;
1080d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
1081d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
1082d81ba9d5SMatt Jacob 	int found;
1083d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
1084d81ba9d5SMatt Jacob 
1085d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
1086d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
1087d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
1088d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1089d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
1090d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
1091d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
1092d81ba9d5SMatt Jacob 		}
1093d81ba9d5SMatt Jacob 	}
1094a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
1095d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1096d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
1097d81ba9d5SMatt Jacob 	}
1098d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1099d81ba9d5SMatt Jacob 		lp = &tptr->atios;
1100d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
1101d81ba9d5SMatt Jacob 		lp = &tptr->inots;
1102d81ba9d5SMatt Jacob 	} else {
1103d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1104d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
1105d81ba9d5SMatt Jacob 	}
1106d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
1107d81ba9d5SMatt Jacob 	found = 0;
1108d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
1109d81ba9d5SMatt Jacob 		found = 1;
1110d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
1111d81ba9d5SMatt Jacob 	} else {
1112d81ba9d5SMatt Jacob 		while(curelm != NULL) {
1113d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
1114d81ba9d5SMatt Jacob 
1115d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
1116d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
1117d81ba9d5SMatt Jacob 				found = 1;
1118d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
1119d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
1120d81ba9d5SMatt Jacob 				break;
1121d81ba9d5SMatt Jacob 			}
1122d81ba9d5SMatt Jacob 			curelm = nextelm;
1123d81ba9d5SMatt Jacob 		}
1124d81ba9d5SMatt Jacob 	}
1125d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1126d81ba9d5SMatt Jacob 	if (found) {
1127d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
1128d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
1129d81ba9d5SMatt Jacob 	}
1130d81ba9d5SMatt Jacob 	return(CAM_PATH_INVALID);
1131d81ba9d5SMatt Jacob }
1132d81ba9d5SMatt Jacob 
1133d81ba9d5SMatt Jacob static cam_status
1134d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
1135d81ba9d5SMatt Jacob {
1136d81ba9d5SMatt Jacob 	void *qe;
113700a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
11385f5aafe1SMatt Jacob 	u_int16_t *hp, save_handle;
11394fd13c1bSMatt Jacob 	u_int16_t nxti, optr;
11404fd13c1bSMatt Jacob 	u_int8_t local[QENTRY_LEN];
1141d81ba9d5SMatt Jacob 
1142f48ce188SMatt Jacob 
11434fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
114492a1e549SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
114592a1e549SMatt Jacob 		printf("Request Queue Overflow in isp_target_start_ctio\n");
1146d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1147d81ba9d5SMatt Jacob 	}
11484fd13c1bSMatt Jacob 	bzero(local, QENTRY_LEN);
1149d81ba9d5SMatt Jacob 
1150d81ba9d5SMatt Jacob 	/*
1151d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1152d81ba9d5SMatt Jacob 	 */
1153d81ba9d5SMatt Jacob 
1154d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
115553036e92SMatt Jacob 		atio_private_data_t *atp;
11564fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
115700a8e174SMatt Jacob 
1158d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1159d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
116000a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
116164edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
1162d81ba9d5SMatt Jacob 			cto->ct_lun = ccb->ccb_h.target_lun;
11632ad50ca5SMatt Jacob 		}
116453036e92SMatt Jacob 
116553036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
116653036e92SMatt Jacob 		if (atp == NULL) {
1167570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1168570c7a3fSMatt Jacob 			    "cannot find private data adjunct for tag %x",
116953036e92SMatt Jacob 			    cso->tag_id);
1170570c7a3fSMatt Jacob 			return (-1);
117153036e92SMatt Jacob 		}
1172f48ce188SMatt Jacob 
117300a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
117400a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
117500a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1176f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
117700a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1178f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
117953036e92SMatt Jacob 				cto->ct_resid =
118053036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1181570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1182570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1183570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1184570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1185570c7a3fSMatt Jacob 					cto->rsp.m1.ct_scsi_status |=
1186570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1187570c7a3fSMatt Jacob 				}
1188f48ce188SMatt Jacob 			}
118900a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
119000a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
119100a8e174SMatt Jacob 				bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m);
119200a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
119300a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
119400a8e174SMatt Jacob 			}
119500a8e174SMatt Jacob 		} else {
119600a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
119700a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
119800a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
119900a8e174SMatt Jacob 			} else {
120000a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1201d81ba9d5SMatt Jacob 			}
1202570c7a3fSMatt Jacob 			cto->ct_reloff = atp->bytes_xfered;
1203d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1204d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
120500a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
120653036e92SMatt Jacob 				cto->ct_resid =
120753036e92SMatt Jacob 				    atp->orig_datalen -
120853036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
1209570c7a3fSMatt Jacob 				if (cto->ct_resid < 0) {
1210570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1211570c7a3fSMatt Jacob 					    CT2_DATA_OVER;
1212570c7a3fSMatt Jacob 				} else if (cto->ct_resid > 0) {
1213570c7a3fSMatt Jacob 					cto->rsp.m0.ct_scsi_status |=
1214570c7a3fSMatt Jacob 					    CT2_DATA_UNDER;
1215570c7a3fSMatt Jacob 				}
121653036e92SMatt Jacob 			} else {
121753036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1218d81ba9d5SMatt Jacob 			}
1219f48ce188SMatt Jacob 			/*
1220f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1221f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1222f48ce188SMatt Jacob 			 */
122300a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
122400a8e174SMatt Jacob 		}
122553036e92SMatt Jacob 
1226290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
122764edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
122853036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
122953036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
123053036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1231a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
1232570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_LAST_CTIO;
1233570c7a3fSMatt Jacob 		} else
1234570c7a3fSMatt Jacob 			atp->state = ATPD_STATE_CTIO;
1235a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
12365f5aafe1SMatt Jacob 		hp = &cto->ct_syshandle;
1237d81ba9d5SMatt Jacob 	} else {
12384fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
123900a8e174SMatt Jacob 
1240d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1241d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
124200a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1243a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1244d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1245d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1246a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1247a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
1248a1bc34c6SMatt Jacob 			cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id);
1249f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1250f48ce188SMatt Jacob 		}
1251f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1252f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1253f48ce188SMatt Jacob 		}
1254f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1255d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
125600a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
125700a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
125800a8e174SMatt Jacob 		} else {
125900a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1260d81ba9d5SMatt Jacob 		}
1261f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
126253036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
126300a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
126400a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
126564edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1266a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1267a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1268a1bc34c6SMatt Jacob 			    cso->tag_id);
126992a1e549SMatt Jacob 		}
127064edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1271a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
12725f5aafe1SMatt Jacob 		hp = &cto->ct_syshandle;
1273d81ba9d5SMatt Jacob 	}
1274d81ba9d5SMatt Jacob 
1275b09b0095SMatt Jacob 	if (isp_save_xs(isp, (XS_T *)ccb, hp)) {
127692a1e549SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
127792a1e549SMatt Jacob 		printf("No XFLIST pointers for isp_target_start_ctio\n");
1278d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1279d81ba9d5SMatt Jacob 	}
1280d81ba9d5SMatt Jacob 
1281d81ba9d5SMatt Jacob 
1282d81ba9d5SMatt Jacob 	/*
1283d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1284d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1285b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1286d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1287d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1288d81ba9d5SMatt Jacob 	 * format.
1289d81ba9d5SMatt Jacob 	 */
1290d81ba9d5SMatt Jacob 
1291d81ba9d5SMatt Jacob 	save_handle = *hp;
1292a1bc34c6SMatt Jacob 
12934fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1294d81ba9d5SMatt Jacob 	case CMD_QUEUED:
12954fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
1296d81ba9d5SMatt Jacob 		return (CAM_REQ_INPROG);
1297d81ba9d5SMatt Jacob 
1298d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
1299d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1300d81ba9d5SMatt Jacob 		isp_destroy_handle(isp, save_handle);
1301d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1302d81ba9d5SMatt Jacob 
1303d81ba9d5SMatt Jacob 	default:
1304d81ba9d5SMatt Jacob 		isp_destroy_handle(isp, save_handle);
1305b85389e1SMatt Jacob 		return (XS_ERR(ccb));
1306d81ba9d5SMatt Jacob 	}
1307d81ba9d5SMatt Jacob }
1308d81ba9d5SMatt Jacob 
1309a1bc34c6SMatt Jacob static void
1310a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1311f48ce188SMatt Jacob {
1312a1bc34c6SMatt Jacob 	int s = splcam();
1313a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1314a1bc34c6SMatt Jacob 	splx(s);
1315a1bc34c6SMatt Jacob }
1316a1bc34c6SMatt Jacob 
1317a1bc34c6SMatt Jacob static void
1318a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1319a1bc34c6SMatt Jacob {
1320a1bc34c6SMatt Jacob 	struct ispsoftc *isp;
1321a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
13224fd13c1bSMatt Jacob 	u_int16_t nxti, optr;
1323a1bc34c6SMatt Jacob 	void *qe;
1324a1bc34c6SMatt Jacob 
1325a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1326f48ce188SMatt Jacob 
13274fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1328a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1329a1bc34c6SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
1330a1bc34c6SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow");
1331a1bc34c6SMatt Jacob 		return;
1332f48ce188SMatt Jacob 	}
1333f48ce188SMatt Jacob 	bzero(qe, QENTRY_LEN);
1334a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1335f48ce188SMatt Jacob 	if (IS_FC(isp)) {
13364fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
13374fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1338f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1339f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
134064edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) {
1341a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1342f48ce188SMatt Jacob 		} else {
1343a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1344f48ce188SMatt Jacob 		}
1345f48ce188SMatt Jacob 		at->at_status = CT_OK;
1346a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
1347570c7a3fSMatt Jacob 		at->at_iid = cso->ccb_h.target_id;
13484fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1349f48ce188SMatt Jacob 	} else {
13504fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
13514fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1352f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1353f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1354a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1355a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1356a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1357a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1358f48ce188SMatt Jacob 		at->at_status = CT_OK;
1359a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1360a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
13614fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1362f48ce188SMatt Jacob 	}
1363f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
13644fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1365a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1366f48ce188SMatt Jacob }
1367f48ce188SMatt Jacob 
1368f48ce188SMatt Jacob static void
1369a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1370f48ce188SMatt Jacob {
1371a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1372a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1373f48ce188SMatt Jacob 	}
1374a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1375a1bc34c6SMatt Jacob 	xpt_done(ccb);
1376f48ce188SMatt Jacob }
1377f48ce188SMatt Jacob 
1378d81ba9d5SMatt Jacob /*
1379d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1380d81ba9d5SMatt Jacob  * This means handling CDBs.
1381d81ba9d5SMatt Jacob  */
1382d81ba9d5SMatt Jacob 
1383d81ba9d5SMatt Jacob static int
1384d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
1385d81ba9d5SMatt Jacob {
1386d81ba9d5SMatt Jacob 	tstate_t *tptr;
138764edff94SMatt Jacob 	int status, bus, iswildcard;
1388d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1389d81ba9d5SMatt Jacob 
1390d81ba9d5SMatt Jacob 	/*
1391d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1392d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1393d81ba9d5SMatt Jacob 	 *
1394d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1395d81ba9d5SMatt Jacob 	 *
1396d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
13975d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1398d81ba9d5SMatt Jacob 	 */
1399d81ba9d5SMatt Jacob 	status = aep->at_status;
1400d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1401d81ba9d5SMatt Jacob 		/*
1402d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1403d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1404d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1405d81ba9d5SMatt Jacob 		 */
14063c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1407d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1408d81ba9d5SMatt Jacob 		return (0);
1409d81ba9d5SMatt Jacob 	}
1410d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
14115d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
14123c75bb14SMatt Jacob 		    status);
1413d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1414d81ba9d5SMatt Jacob 		return (0);
1415d81ba9d5SMatt Jacob 	}
1416d81ba9d5SMatt Jacob 
14175d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1418a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1419d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1420a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
142164edff94SMatt Jacob 		iswildcard = 1;
142264edff94SMatt Jacob 	} else {
142364edff94SMatt Jacob 		iswildcard = 0;
1424d81ba9d5SMatt Jacob 	}
1425d81ba9d5SMatt Jacob 
1426d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1427d81ba9d5SMatt Jacob 		/*
1428d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1429d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1430d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a BUSY status
1431d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only
1432d81ba9d5SMatt Jacob 		 * time we should, in fact, get this, is in the
1433d81ba9d5SMatt Jacob 		 * case that somebody configured us without the
1434d81ba9d5SMatt Jacob 		 * blackhole driver, so they get what they deserve.
1435d81ba9d5SMatt Jacob 		 */
1436d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1437d81ba9d5SMatt Jacob 		return (0);
1438d81ba9d5SMatt Jacob 	}
1439d81ba9d5SMatt Jacob 
1440d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1441d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1442d81ba9d5SMatt Jacob 		/*
1443d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1444d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1445d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1446d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1447d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1448d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1449d81ba9d5SMatt Jacob 		 */
1450d81ba9d5SMatt Jacob 		xpt_print_path(tptr->owner);
14513c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
1452a1bc34c6SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d",
14535d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1454d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1455d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1456d81ba9d5SMatt Jacob 		else
1457d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
145864edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1459d81ba9d5SMatt Jacob 		return (0);
1460d81ba9d5SMatt Jacob 	}
1461d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
146264edff94SMatt Jacob 	if (iswildcard) {
1463d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1464d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1465d81ba9d5SMatt Jacob 	}
1466d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1467f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1468f48ce188SMatt Jacob 	} else {
1469f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1470d81ba9d5SMatt Jacob 	}
1471d81ba9d5SMatt Jacob 
1472f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1473f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1474f48ce188SMatt Jacob 		atiop->sense_len = amt;
1475f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1476f48ce188SMatt Jacob 	} else {
1477f48ce188SMatt Jacob 		atiop->sense_len = 0;
1478f48ce188SMatt Jacob 	}
1479d81ba9d5SMatt Jacob 
14805d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1481d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1482d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1483d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1484a1bc34c6SMatt Jacob 	/*
1485a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1486a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1487a1bc34c6SMatt Jacob 	 */
1488a1bc34c6SMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id, aep);
1489a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1490a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1491d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1492d81ba9d5SMatt Jacob 	}
1493d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
149464edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
14955d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
14965d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
14975d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
14985d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
14995d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1500d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1501d81ba9d5SMatt Jacob 	return (0);
1502d81ba9d5SMatt Jacob }
1503d81ba9d5SMatt Jacob 
1504d81ba9d5SMatt Jacob static int
1505d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
1506d81ba9d5SMatt Jacob {
150792a1e549SMatt Jacob 	lun_id_t lun;
1508d81ba9d5SMatt Jacob 	tstate_t *tptr;
1509d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
151053036e92SMatt Jacob 	atio_private_data_t *atp;
1511d81ba9d5SMatt Jacob 
1512d81ba9d5SMatt Jacob 	/*
1513d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1514d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1515d81ba9d5SMatt Jacob 	 *
1516d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1517d81ba9d5SMatt Jacob 	 */
1518d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
15193c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
15203c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1521d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1522d81ba9d5SMatt Jacob 		return (0);
1523d81ba9d5SMatt Jacob 	}
1524d81ba9d5SMatt Jacob 
152564edff94SMatt Jacob 	if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) {
152692a1e549SMatt Jacob 		lun = aep->at_scclun;
15272ad50ca5SMatt Jacob 	} else {
152892a1e549SMatt Jacob 		lun = aep->at_lun;
15292ad50ca5SMatt Jacob 	}
1530a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1531d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1532570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "no state pointer for lun %d", lun);
1533a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1534d81ba9d5SMatt Jacob 	}
1535d81ba9d5SMatt Jacob 
1536d81ba9d5SMatt Jacob 	if (tptr == NULL) {
153752df5dfdSMatt Jacob 		/*
153852df5dfdSMatt Jacob 		 * What we'd like to know is whether or not we have a listener
153952df5dfdSMatt Jacob 		 * upstream that really hasn't configured yet. If we do, then
154052df5dfdSMatt Jacob 		 * we can give a more sensible reply here. If not, then we can
154152df5dfdSMatt Jacob 		 * reject this out of hand.
154252df5dfdSMatt Jacob 		 *
154352df5dfdSMatt Jacob 		 * Choices for what to send were
154452df5dfdSMatt Jacob 		 *
154552df5dfdSMatt Jacob                  *	Not Ready, Unit Not Self-Configured Yet
154652df5dfdSMatt Jacob 		 *	(0x2,0x3e,0x00)
154752df5dfdSMatt Jacob 		 *
154852df5dfdSMatt Jacob 		 * for the former and
154952df5dfdSMatt Jacob 		 *
155052df5dfdSMatt Jacob 		 *	Illegal Request, Logical Unit Not Supported
155152df5dfdSMatt Jacob 		 *	(0x5,0x25,0x00)
155252df5dfdSMatt Jacob 		 *
155352df5dfdSMatt Jacob 		 * for the latter.
155452df5dfdSMatt Jacob 		 *
155552df5dfdSMatt Jacob 		 * We used to decide whether there was at least one listener
155652df5dfdSMatt Jacob 		 * based upon whether the black hole driver was configured.
155752df5dfdSMatt Jacob 		 * However, recent config(8) changes have made this hard to do
155852df5dfdSMatt Jacob 		 * at this time.
155952df5dfdSMatt Jacob 		 *
156052df5dfdSMatt Jacob 		 */
1561570c7a3fSMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1562d81ba9d5SMatt Jacob 		return (0);
1563d81ba9d5SMatt Jacob 	}
1564d81ba9d5SMatt Jacob 
156553036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1566d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
156753036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1568d81ba9d5SMatt Jacob 		/*
1569d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1570d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1571d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1572d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1573d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1574d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1575d81ba9d5SMatt Jacob 		 */
1576d81ba9d5SMatt Jacob 		xpt_print_path(tptr->owner);
15773c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
1578570c7a3fSMatt Jacob 		    "no %s for lun %d from initiator %d",
1579570c7a3fSMatt Jacob 		    (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
1580570c7a3fSMatt Jacob 		    ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
1581d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1582d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1583d81ba9d5SMatt Jacob 		return (0);
1584d81ba9d5SMatt Jacob 	}
1585570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_ATIO;
1586d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1587570c7a3fSMatt Jacob 	tptr->atio_count--;
1588570c7a3fSMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO2 lun %d, count now %d",
1589570c7a3fSMatt Jacob 	    lun, tptr->atio_count);
1590f48ce188SMatt Jacob 
1591a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
1592d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id =
1593d81ba9d5SMatt Jacob 		    ((fcparam *)isp->isp_param)->isp_loopid;
159492a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1595d81ba9d5SMatt Jacob 	}
1596b0a3ba7eSMatt Jacob 	/*
1597b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1598b0a3ba7eSMatt Jacob 	 */
1599f48ce188SMatt Jacob 	atiop->sense_len = 0;
1600f48ce188SMatt Jacob 
1601d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1602d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1603d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1604d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1605d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1606d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1607d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1608d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1609d81ba9d5SMatt Jacob 		break;
1610d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1611d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1612d81ba9d5SMatt Jacob 		break;
1613d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1614d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1615d81ba9d5SMatt Jacob 		break;
1616d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1617d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1618d81ba9d5SMatt Jacob 	default:
1619d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1620d81ba9d5SMatt Jacob 		break;
1621d81ba9d5SMatt Jacob 	}
1622570c7a3fSMatt Jacob 	atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
1623f48ce188SMatt Jacob 
162453036e92SMatt Jacob 	atp->tag = atiop->tag_id;
1625570c7a3fSMatt Jacob 	atp->lun = lun;
162653036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
162753036e92SMatt Jacob 	atp->last_xframt = 0;
162853036e92SMatt Jacob 	atp->bytes_xfered = 0;
1629570c7a3fSMatt Jacob 	atp->state = ATPD_STATE_CAM;
1630d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
1631570c7a3fSMatt Jacob 
163264edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
16335f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
16345f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1635b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1636d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1637d81ba9d5SMatt Jacob 	return (0);
1638d81ba9d5SMatt Jacob }
1639d81ba9d5SMatt Jacob 
1640d81ba9d5SMatt Jacob static int
1641d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
1642d81ba9d5SMatt Jacob {
1643d81ba9d5SMatt Jacob 	union ccb *ccb;
1644a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
164564edff94SMatt Jacob 	u_int16_t tval;
1646d81ba9d5SMatt Jacob 
1647d81ba9d5SMatt Jacob 	/*
1648d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1649d81ba9d5SMatt Jacob 	 */
1650d81ba9d5SMatt Jacob 
16515f5aafe1SMatt Jacob 	ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle);
1652d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
16535f5aafe1SMatt Jacob 	isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1654d81ba9d5SMatt Jacob 
1655d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1656d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1657570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
1658570c7a3fSMatt Jacob 		if (atp == NULL) {
1659570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1660570c7a3fSMatt Jacob 			    "cannot find adjunct for %x after I/O",
1661570c7a3fSMatt Jacob 			    ct->ct_rxid);
1662570c7a3fSMatt Jacob 			return (0);
1663570c7a3fSMatt Jacob 		}
1664d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1665d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1666a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
166700a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
166800a8e174SMatt Jacob 		}
1669a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
16705d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
1671a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
167253036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
167353036e92SMatt Jacob 			atp->last_xframt = 0;
1674570c7a3fSMatt Jacob 		}
1675570c7a3fSMatt Jacob 		if (sentstatus || !ok) {
167653036e92SMatt Jacob 			atp->tag = 0;
167753036e92SMatt Jacob 		}
1678570c7a3fSMatt Jacob 		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
167964edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
168064edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
168164edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
168264edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
168364edff94SMatt Jacob 		tval = ct->ct_rxid;
1684570c7a3fSMatt Jacob 
1685570c7a3fSMatt Jacob 		/* XXX: should really come after isp_complete_ctio */
1686570c7a3fSMatt Jacob 		atp->state = ATPD_STATE_PDON;
1687d81ba9d5SMatt Jacob 	} else {
1688d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1689d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1690d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1691d81ba9d5SMatt Jacob 		/*
1692a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1693a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1694a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1695a1bc34c6SMatt Jacob 		 * private data.
1696a1bc34c6SMatt Jacob 		 *
1697a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1698a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1699a1bc34c6SMatt Jacob 		 */
1700a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1701a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1702a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1703a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1704a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1705a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1706a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1707a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1708a1bc34c6SMatt Jacob 		}
17095d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1710a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1711a1bc34c6SMatt Jacob 		}
171264edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
171364edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
171464edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
171564edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
171664edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
171764edff94SMatt Jacob 		tval = ct->ct_fwhandle;
17185d571944SMatt Jacob 	}
1719a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1720a1bc34c6SMatt Jacob 
1721a1bc34c6SMatt Jacob 	/*
1722a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1723a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1724a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1725d81ba9d5SMatt Jacob 	 *
1726d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1727d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1728a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1729a1bc34c6SMatt Jacob 	 * freed.
1730d81ba9d5SMatt Jacob 	 */
1731f48ce188SMatt Jacob 	if (notify_cam == 0) {
173264edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1733f48ce188SMatt Jacob 		return (0);
1734f48ce188SMatt Jacob 	}
1735d81ba9d5SMatt Jacob 
173653036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
173753036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1738a1bc34c6SMatt Jacob 
1739a1bc34c6SMatt Jacob 	if (!ok) {
1740a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1741d81ba9d5SMatt Jacob 	} else {
1742a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1743a1bc34c6SMatt Jacob 
1744d81ba9d5SMatt Jacob 	}
1745a1bc34c6SMatt Jacob 	return (0);
1746d81ba9d5SMatt Jacob }
1747570c7a3fSMatt Jacob 
1748570c7a3fSMatt Jacob static int
1749570c7a3fSMatt Jacob isp_handle_platform_notify_scsi(struct ispsoftc *isp, in_entry_t *inp)
1750570c7a3fSMatt Jacob {
1751570c7a3fSMatt Jacob 	return (0);	/* XXXX */
1752570c7a3fSMatt Jacob }
1753570c7a3fSMatt Jacob 
1754570c7a3fSMatt Jacob static int
1755570c7a3fSMatt Jacob isp_handle_platform_notify_fc(struct ispsoftc *isp, in_fcentry_t *inp)
1756570c7a3fSMatt Jacob {
1757570c7a3fSMatt Jacob 
1758570c7a3fSMatt Jacob 	switch (inp->in_status) {
1759570c7a3fSMatt Jacob 	case IN_PORT_LOGOUT:
1760570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
1761570c7a3fSMatt Jacob 		   inp->in_iid);
1762570c7a3fSMatt Jacob 		break;
1763570c7a3fSMatt Jacob 	case IN_PORT_CHANGED:
1764570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
1765570c7a3fSMatt Jacob 		   inp->in_iid);
1766570c7a3fSMatt Jacob 		break;
1767570c7a3fSMatt Jacob 	case IN_GLOBAL_LOGO:
1768570c7a3fSMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "all ports logged out");
1769570c7a3fSMatt Jacob 		break;
1770570c7a3fSMatt Jacob 	case IN_ABORT_TASK:
1771570c7a3fSMatt Jacob 	{
1772570c7a3fSMatt Jacob 		atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
1773570c7a3fSMatt Jacob 		struct ccb_immed_notify *inot = NULL;
1774570c7a3fSMatt Jacob 
1775570c7a3fSMatt Jacob 		if (atp) {
1776570c7a3fSMatt Jacob 			tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
1777570c7a3fSMatt Jacob 			if (tptr) {
1778570c7a3fSMatt Jacob 				inot = (struct ccb_immed_notify *)
1779570c7a3fSMatt Jacob 				    SLIST_FIRST(&tptr->inots);
1780570c7a3fSMatt Jacob 				if (inot) {
1781570c7a3fSMatt Jacob 					SLIST_REMOVE_HEAD(&tptr->inots,
1782570c7a3fSMatt Jacob 					    sim_links.sle);
1783570c7a3fSMatt Jacob 				}
1784570c7a3fSMatt Jacob 			}
1785570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1786570c7a3fSMatt Jacob 			   "abort task RX_ID %x IID %d state %d",
1787570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid, atp->state);
1788570c7a3fSMatt Jacob 		} else {
1789570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1790570c7a3fSMatt Jacob 			   "abort task RX_ID %x from iid %d, state unknown",
1791570c7a3fSMatt Jacob 			   inp->in_seqid, inp->in_iid);
1792570c7a3fSMatt Jacob 		}
1793570c7a3fSMatt Jacob 		if (inot) {
1794570c7a3fSMatt Jacob 			inot->initiator_id = inp->in_iid;
1795570c7a3fSMatt Jacob 			inot->sense_len = 0;
1796570c7a3fSMatt Jacob 			inot->message_args[0] = MSG_ABORT_TAG;
1797570c7a3fSMatt Jacob 			inot->message_args[1] = inp->in_seqid & 0xff;
1798570c7a3fSMatt Jacob 			inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
1799570c7a3fSMatt Jacob 			inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
1800570c7a3fSMatt Jacob 			xpt_done((union ccb *)inot);
1801570c7a3fSMatt Jacob 		}
1802570c7a3fSMatt Jacob 		break;
1803570c7a3fSMatt Jacob 	}
1804570c7a3fSMatt Jacob 	default:
1805570c7a3fSMatt Jacob 		break;
1806570c7a3fSMatt Jacob 	}
1807570c7a3fSMatt Jacob 	return (0);
1808570c7a3fSMatt Jacob }
1809d81ba9d5SMatt Jacob #endif
1810d81ba9d5SMatt Jacob 
1811478f8a96SJustin T. Gibbs static void
1812cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
1813478f8a96SJustin T. Gibbs {
1814478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
1815478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
1816478f8a96SJustin T. Gibbs 
1817478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
1818478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *) cam_sim_softc(sim);
1819478f8a96SJustin T. Gibbs 	switch (code) {
1820478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1821ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
1822478f8a96SJustin T. Gibbs 			u_int16_t oflags, nflags;
1823478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1824a1bc34c6SMatt Jacob 			int tgt;
1825478f8a96SJustin T. Gibbs 
1826f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
182741ed683eSMatt Jacob 			if (tgt >= 0) {
1828ea6f23cdSMatt Jacob 				sdp += cam_sim_bus(sim);
182941ed683eSMatt Jacob 				ISP_LOCK(isp);
18309ce9bdafSMatt Jacob 				nflags = sdp->isp_devparam[tgt].nvrm_flags;
1831a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
18329ce9bdafSMatt Jacob 				nflags &= DPARM_SAFE_DFLT;
1833a1bc34c6SMatt Jacob 				if (isp->isp_loaded_fw) {
1834478f8a96SJustin T. Gibbs 					nflags |= DPARM_NARROW | DPARM_ASYNC;
1835478f8a96SJustin T. Gibbs 				}
1836a1bc34c6SMatt Jacob #else
1837a1bc34c6SMatt Jacob 				nflags = DPARM_DEFAULT;
1838a1bc34c6SMatt Jacob #endif
18399ce9bdafSMatt Jacob 				oflags = sdp->isp_devparam[tgt].goal_flags;
18409ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = nflags;
1841478f8a96SJustin T. Gibbs 				sdp->isp_devparam[tgt].dev_update = 1;
1842a1bc34c6SMatt Jacob 				isp->isp_update |= (1 << cam_sim_bus(sim));
184341ed683eSMatt Jacob 				(void) isp_control(isp,
184441ed683eSMatt Jacob 				    ISPCTL_UPDATE_PARAMS, NULL);
18459ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_flags = oflags;
1846f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
1847478f8a96SJustin T. Gibbs 			}
184841ed683eSMatt Jacob 		}
1849478f8a96SJustin T. Gibbs 		break;
1850478f8a96SJustin T. Gibbs 	default:
18513c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
1852478f8a96SJustin T. Gibbs 		break;
1853478f8a96SJustin T. Gibbs 	}
1854478f8a96SJustin T. Gibbs }
1855478f8a96SJustin T. Gibbs 
1856478f8a96SJustin T. Gibbs static void
1857c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
1858478f8a96SJustin T. Gibbs {
1859c40e096eSMatt Jacob 	struct ispsoftc *isp = cam_sim_softc(sim);
1860126ec864SMatt Jacob 	u_int16_t isr, sema, mbox;
1861126ec864SMatt Jacob 
1862c40e096eSMatt Jacob 	ISP_LOCK(isp);
1863126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
1864126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
1865126ec864SMatt Jacob 	}
1866c40e096eSMatt Jacob 	ISP_UNLOCK(isp);
1867478f8a96SJustin T. Gibbs }
1868478f8a96SJustin T. Gibbs 
1869ab6c4b31SMatt Jacob 
1870478f8a96SJustin T. Gibbs static void
1871b85389e1SMatt Jacob isp_watchdog(void *arg)
1872cc8df88bSMatt Jacob {
1873b09b0095SMatt Jacob 	XS_T *xs = arg;
1874cc8df88bSMatt Jacob 	struct ispsoftc *isp = XS_ISP(xs);
1875cc8df88bSMatt Jacob 	u_int32_t handle;
1876fdeb9f2fSMatt Jacob 	int iok;
1877b85389e1SMatt Jacob 
1878cc8df88bSMatt Jacob 	/*
1879b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
1880b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
1881b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
1882cc8df88bSMatt Jacob 	 */
1883f6e75de2SMatt Jacob 	ISP_LOCK(isp);
1884fdeb9f2fSMatt Jacob 	iok = isp->isp_osinfo.intsok;
1885fdeb9f2fSMatt Jacob 	isp->isp_osinfo.intsok = 0;
1886cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
1887cc8df88bSMatt Jacob 	if (handle) {
1888126ec864SMatt Jacob 		u_int16_t isr, sema, mbox;
1889126ec864SMatt Jacob 
1890b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
1891b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
1892b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
1893f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
1894b85389e1SMatt Jacob 			return;
1895b85389e1SMatt Jacob 		}
1896b85389e1SMatt Jacob 
1897b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
1898b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
1899b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
1900f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
1901b85389e1SMatt Jacob 			return;
1902b85389e1SMatt Jacob 		}
1903b85389e1SMatt Jacob 
1904b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
1905126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
1906126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
1907126ec864SMatt Jacob 		}
1908126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
1909b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
1910126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
1911b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
1912b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
19131fcf5debSMatt Jacob 			/*
19141fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
19151fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
19161fcf5debSMatt Jacob 			 */
19171fcf5debSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, arg);
19181fcf5debSMatt Jacob 
19191fcf5debSMatt Jacob 			/*
19201fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
19211fcf5debSMatt Jacob 			 */
1922f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
1923f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
1924f6e75de2SMatt Jacob                 	}
1925cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
1926cc8df88bSMatt Jacob 			xpt_print_path(xs->ccb_h.path);
19273c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
19282903b272SMatt Jacob 			    "watchdog timeout for handle 0x%x", handle);
1929cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
1930b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
1931cc8df88bSMatt Jacob 			isp_done(xs);
1932b85389e1SMatt Jacob 		} else {
19334fd13c1bSMatt Jacob 			u_int16_t nxti, optr;
19344fd13c1bSMatt Jacob 			ispreq_t local, *mp= &local, *qe;
1935b85389e1SMatt Jacob 
1936b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
1937b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
19384fd13c1bSMatt Jacob 			if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) {
1939f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
1940b85389e1SMatt Jacob 				return;
1941b85389e1SMatt Jacob 			}
1942b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
1943b85389e1SMatt Jacob 			MEMZERO((void *) mp, sizeof (*mp));
1944b85389e1SMatt Jacob 			mp->req_header.rqs_entry_count = 1;
1945b85389e1SMatt Jacob 			mp->req_header.rqs_entry_type = RQSTYPE_MARKER;
1946b85389e1SMatt Jacob 			mp->req_modifier = SYNC_ALL;
1947b85389e1SMatt Jacob 			mp->req_target = XS_CHANNEL(xs) << 7;
19484fd13c1bSMatt Jacob 			isp_put_request(isp, mp, qe);
19494fd13c1bSMatt Jacob 			ISP_ADD_REQUEST(isp, nxti);
1950b85389e1SMatt Jacob 		}
1951b85389e1SMatt Jacob 	} else {
1952b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command");
1953cc8df88bSMatt Jacob 	}
1954fdeb9f2fSMatt Jacob 	isp->isp_osinfo.intsok = iok;
1955f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
1956cc8df88bSMatt Jacob }
1957cc8df88bSMatt Jacob 
19585d571944SMatt Jacob static void
19595d571944SMatt Jacob isp_kthread(void *arg)
19605d571944SMatt Jacob {
19615d571944SMatt Jacob 	struct ispsoftc *isp = arg;
19625d571944SMatt Jacob 
1963162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
19645d571944SMatt Jacob 	mtx_lock(&isp->isp_lock);
1965ee76282eSMatt Jacob #else
1966ee76282eSMatt Jacob 	mtx_lock(&Giant);
1967162e9893SMatt Jacob #endif
1968fdeb9f2fSMatt Jacob 	/*
1969fdeb9f2fSMatt Jacob 	 * The first loop is for our usage where we have yet to have
1970fdeb9f2fSMatt Jacob 	 * gotten good fibre channel state.
1971fdeb9f2fSMatt Jacob 	 */
19725d571944SMatt Jacob 	for (;;) {
1973fdeb9f2fSMatt Jacob 		int wasfrozen;
1974fdeb9f2fSMatt Jacob 
1975fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state");
19765d571944SMatt Jacob 		while (isp_fc_runstate(isp, 2 * 1000000) != 0) {
1977fdeb9f2fSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state ungood");
1978f44257c2SMatt Jacob 			if (FCPARAM(isp)->isp_fwstate != FW_READY ||
1979f44257c2SMatt Jacob 			    FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) {
1980f44257c2SMatt Jacob 				if (FCPARAM(isp)->loop_seen_once == 0 ||
1981fdeb9f2fSMatt Jacob 				    isp->isp_osinfo.ktmature == 0) {
1982f44257c2SMatt Jacob 					break;
1983f44257c2SMatt Jacob 				}
1984f44257c2SMatt Jacob 			}
1985162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
19865d571944SMatt Jacob 			msleep(isp_kthread, &isp->isp_lock,
19875d571944SMatt Jacob 			    PRIBIO, "isp_fcthrd", hz);
1988162e9893SMatt Jacob #else
1989162e9893SMatt Jacob 			(void) tsleep(isp_kthread, PRIBIO, "isp_fcthrd", hz);
1990162e9893SMatt Jacob #endif
19915d571944SMatt Jacob 		}
1992fdeb9f2fSMatt Jacob 
1993f44257c2SMatt Jacob 		/*
1994f44257c2SMatt Jacob 		 * Even if we didn't get good loop state we may be
1995f44257c2SMatt Jacob 		 * unfreezing the SIMQ so that we can kill off
1996fdeb9f2fSMatt Jacob 		 * commands (if we've never seen loop before, for example).
1997f44257c2SMatt Jacob 		 */
1998fdeb9f2fSMatt Jacob 		isp->isp_osinfo.ktmature = 1;
19995d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
20005d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
20015d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
2002fdeb9f2fSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq");
20035d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
20045d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
20055d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
20065d571944SMatt Jacob 		}
2007fdeb9f2fSMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "kthread: waiting until called");
2008162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
20095d571944SMatt Jacob 		cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock);
2010162e9893SMatt Jacob #else
2011162e9893SMatt Jacob 		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "fc_cv", 0);
2012162e9893SMatt Jacob #endif
20135d571944SMatt Jacob 	}
20145d571944SMatt Jacob }
20155d571944SMatt Jacob 
2016cc8df88bSMatt Jacob static void
2017c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
2018478f8a96SJustin T. Gibbs {
2019f6e75de2SMatt Jacob 	int bus, tgt, error;
2020478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
20214663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
2022478f8a96SJustin T. Gibbs 
2023478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
2024478f8a96SJustin T. Gibbs 
2025478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *)cam_sim_softc(sim);
2026478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
2027478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
20280470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
20290470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
20305d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
203157c801f5SMatt Jacob 		isp_init(isp);
203257c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
2033f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
203457c801f5SMatt Jacob 			/*
203557c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
203657c801f5SMatt Jacob 			 */
2037b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
20380470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
203957c801f5SMatt Jacob 			xpt_done(ccb);
204057c801f5SMatt Jacob 			return;
204157c801f5SMatt Jacob 		}
204257c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
20435d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
204457c801f5SMatt Jacob 	}
2045b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
2046478f8a96SJustin T. Gibbs 
20475d571944SMatt Jacob 
2048478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
2049478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
2050478f8a96SJustin T. Gibbs 		/*
2051478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
2052478f8a96SJustin T. Gibbs 		 */
2053478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2054478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2055478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
2056478f8a96SJustin T. Gibbs 				xpt_done(ccb);
2057478f8a96SJustin T. Gibbs 				break;
2058478f8a96SJustin T. Gibbs 			}
2059478f8a96SJustin T. Gibbs 		}
20600470d791SMatt Jacob #ifdef	DIAGNOSTIC
20610470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
2062478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
20630470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
2064478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
2065478f8a96SJustin T. Gibbs 		}
2066478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
2067bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2068bfbab170SMatt Jacob 			    "invalid tgt/lun (%d.%d) in XPT_SCSI_IO",
2069bfbab170SMatt Jacob 			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
2070478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2071478f8a96SJustin T. Gibbs 			break;
2072478f8a96SJustin T. Gibbs 		}
20730470d791SMatt Jacob #endif
20740470d791SMatt Jacob 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
20755d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2076b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
20770470d791SMatt Jacob 		switch (error) {
2078478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
2079478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2080cc8df88bSMatt Jacob 			if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
2081d69a5f7dSMatt Jacob 				u_int64_t ticks = (u_int64_t) hz;
2082cc8df88bSMatt Jacob 				if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
2083d69a5f7dSMatt Jacob 					ticks = 60 * 1000 * ticks;
2084b85389e1SMatt Jacob 				else
2085b85389e1SMatt Jacob 					ticks = ccb->ccb_h.timeout * hz;
2086b85389e1SMatt Jacob 				ticks = ((ticks + 999) / 1000) + hz + hz;
2087d69a5f7dSMatt Jacob 				if (ticks >= 0x80000000) {
2088d69a5f7dSMatt Jacob 					isp_prt(isp, ISP_LOGERR,
2089d69a5f7dSMatt Jacob 					    "timeout overflow");
2090fdeb9f2fSMatt Jacob 					ticks = 0x7fffffff;
2091d69a5f7dSMatt Jacob 				}
2092d69a5f7dSMatt Jacob 				ccb->ccb_h.timeout_ch = timeout(isp_watchdog,
2093d69a5f7dSMatt Jacob 				    (caddr_t)ccb, (int)ticks);
2094b85389e1SMatt Jacob 			} else {
2095b85389e1SMatt Jacob 				callout_handle_init(&ccb->ccb_h.timeout_ch);
2096cc8df88bSMatt Jacob 			}
20975d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2098478f8a96SJustin T. Gibbs 			break;
20990470d791SMatt Jacob 		case CMD_RQLATER:
2100f44257c2SMatt Jacob 			/*
2101f44257c2SMatt Jacob 			 * This can only happen for Fibre Channel
2102f44257c2SMatt Jacob 			 */
2103f44257c2SMatt Jacob 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
2104fdeb9f2fSMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0 &&
2105fdeb9f2fSMatt Jacob 			    isp->isp_osinfo.ktmature) {
2106f44257c2SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
2107f44257c2SMatt Jacob 				XS_SETERR(ccb, CAM_SEL_TIMEOUT);
2108f44257c2SMatt Jacob 				xpt_done(ccb);
2109f44257c2SMatt Jacob 				break;
2110f44257c2SMatt Jacob 			}
2111162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
21125d571944SMatt Jacob 			cv_signal(&isp->isp_osinfo.kthread_cv);
2113162e9893SMatt Jacob #else
2114162e9893SMatt Jacob 			wakeup(&isp->isp_osinfo.kthread_cv);
2115162e9893SMatt Jacob #endif
2116fdeb9f2fSMatt Jacob 			isp_freeze_loopdown(isp, "isp_action(RQLATER)");
2117b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
2118fdeb9f2fSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2119478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2120478f8a96SJustin T. Gibbs 			break;
21210470d791SMatt Jacob 		case CMD_EAGAIN:
2122b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
21235d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2124478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2125478f8a96SJustin T. Gibbs 			break;
21260470d791SMatt Jacob 		case CMD_COMPLETE:
21270470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
21285d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
21290470d791SMatt Jacob 			break;
21300470d791SMatt Jacob 		default:
2131bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2132bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
213391f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
2134b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
21350470d791SMatt Jacob 			xpt_done(ccb);
21365d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2137478f8a96SJustin T. Gibbs 		}
2138478f8a96SJustin T. Gibbs 		break;
2139478f8a96SJustin T. Gibbs 
2140d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2141478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
214264edff94SMatt Jacob 	{
214364edff94SMatt Jacob 		int iok;
21445d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
214564edff94SMatt Jacob 		iok = isp->isp_osinfo.intsok;
214664edff94SMatt Jacob 		isp->isp_osinfo.intsok = 0;
2147d81ba9d5SMatt Jacob 		isp_en_lun(isp, ccb);
214864edff94SMatt Jacob 		isp->isp_osinfo.intsok = iok;
21495d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2150478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2151478f8a96SJustin T. Gibbs 		break;
215264edff94SMatt Jacob 	}
2153d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
2154d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
2155d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
2156d81ba9d5SMatt Jacob 	{
2157a1bc34c6SMatt Jacob 		tstate_t *tptr =
2158a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
2159d81ba9d5SMatt Jacob 		if (tptr == NULL) {
2160d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
2161d81ba9d5SMatt Jacob 			xpt_done(ccb);
2162d81ba9d5SMatt Jacob 			break;
2163d81ba9d5SMatt Jacob 		}
2164f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2165f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
2166570c7a3fSMatt Jacob 		ccb->ccb_h.flags = 0;
2167570c7a3fSMatt Jacob 
21685d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2169d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
2170570c7a3fSMatt Jacob 			/*
2171570c7a3fSMatt Jacob 			 * Note that the command itself may not be done-
2172570c7a3fSMatt Jacob 			 * it may not even have had the first CTIO sent.
2173570c7a3fSMatt Jacob 			 */
2174570c7a3fSMatt Jacob 			tptr->atio_count++;
2175570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
2176570c7a3fSMatt Jacob 			    "Put FREE ATIO2, lun %d, count now %d",
2177570c7a3fSMatt Jacob 			    ccb->ccb_h.target_lun, tptr->atio_count);
2178570c7a3fSMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
2179570c7a3fSMatt Jacob 			    sim_links.sle);
2180570c7a3fSMatt Jacob 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
2181d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
2182d81ba9d5SMatt Jacob 			    sim_links.sle);
2183570c7a3fSMatt Jacob 		} else {
2184570c7a3fSMatt Jacob 			;
2185d81ba9d5SMatt Jacob 		}
2186d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
2187d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
21885d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2189d81ba9d5SMatt Jacob 		break;
2190d81ba9d5SMatt Jacob 	}
2191d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
2192d81ba9d5SMatt Jacob 	{
21935d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2194d81ba9d5SMatt Jacob 		ccb->ccb_h.status = isp_target_start_ctio(isp, ccb);
2195d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_INPROG) {
2196570c7a3fSMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2197570c7a3fSMatt Jacob 			    "XPT_CONT_TARGET_IO: status 0x%x",
2198570c7a3fSMatt Jacob 			    ccb->ccb_h.status);
2199b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
22005d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2201d81ba9d5SMatt Jacob 			xpt_done(ccb);
2202d81ba9d5SMatt Jacob 		} else {
22035d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2204d81ba9d5SMatt Jacob 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2205d81ba9d5SMatt Jacob 		}
2206d81ba9d5SMatt Jacob 		break;
2207d81ba9d5SMatt Jacob 	}
2208d81ba9d5SMatt Jacob #endif
2209478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2210d81ba9d5SMatt Jacob 
2211d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2212d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2213d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2214d81ba9d5SMatt Jacob 
22155d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2216ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
22175d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2218478f8a96SJustin T. Gibbs 		if (error) {
2219478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2220478f8a96SJustin T. Gibbs 		} else {
2221478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2222478f8a96SJustin T. Gibbs 		}
2223478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2224478f8a96SJustin T. Gibbs 		break;
2225478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2226d81ba9d5SMatt Jacob 	{
2227d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
22285d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2229d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2230d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2231d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2232d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2233d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2234d81ba9d5SMatt Jacob 			break;
2235d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2236b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2237d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2238d81ba9d5SMatt Jacob 			break;
2239d81ba9d5SMatt Jacob #endif
2240d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2241478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2242478f8a96SJustin T. Gibbs 			if (error) {
2243d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2244478f8a96SJustin T. Gibbs 			} else {
2245478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2246478f8a96SJustin T. Gibbs 			}
2247d81ba9d5SMatt Jacob 			break;
2248d81ba9d5SMatt Jacob 		default:
2249d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2250d81ba9d5SMatt Jacob 			break;
2251d81ba9d5SMatt Jacob 		}
22525d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2253478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2254478f8a96SJustin T. Gibbs 		break;
2255d81ba9d5SMatt Jacob 	}
2256ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2257ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2258ab163f5fSMatt Jacob #else
2259ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->flags & CCB_TRANS_CURRENT_SETTINGS)
2260ab163f5fSMatt Jacob #endif
2261478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2262478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
22639ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
22649ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
22659ce9bdafSMatt Jacob 			xpt_done(ccb);
22669ce9bdafSMatt Jacob 			break;
22679ce9bdafSMatt Jacob 		}
2268478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
22695d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2270ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2271ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2272478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
2273478f8a96SJustin T. Gibbs 			u_int16_t *dptr;
2274d81ba9d5SMatt Jacob 
2275d81ba9d5SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2276478f8a96SJustin T. Gibbs 
2277ea6f23cdSMatt Jacob 			sdp += bus;
2278478f8a96SJustin T. Gibbs 			/*
22799ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2280478f8a96SJustin T. Gibbs 			 * so any request to change settings just gets
2281478f8a96SJustin T. Gibbs 			 * vectored to that location.
2282478f8a96SJustin T. Gibbs 			 */
22839ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2284478f8a96SJustin T. Gibbs 
2285478f8a96SJustin T. Gibbs 			/*
2286478f8a96SJustin T. Gibbs 			 * Note that these operations affect the
22879ce9bdafSMatt Jacob 			 * the goal flags (goal_flags)- not
2288478f8a96SJustin T. Gibbs 			 * the current state flags. Then we mark
2289478f8a96SJustin T. Gibbs 			 * things so that the next operation to
2290478f8a96SJustin T. Gibbs 			 * this HBA will cause the update to occur.
2291478f8a96SJustin T. Gibbs 			 */
2292478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_DISC_VALID) {
2293478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
2294478f8a96SJustin T. Gibbs 					*dptr |= DPARM_DISC;
2295478f8a96SJustin T. Gibbs 				} else {
2296478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_DISC;
2297478f8a96SJustin T. Gibbs 				}
2298478f8a96SJustin T. Gibbs 			}
2299478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_TQ_VALID) {
2300478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
2301478f8a96SJustin T. Gibbs 					*dptr |= DPARM_TQING;
2302478f8a96SJustin T. Gibbs 				} else {
2303478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_TQING;
2304478f8a96SJustin T. Gibbs 				}
2305478f8a96SJustin T. Gibbs 			}
2306478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
2307478f8a96SJustin T. Gibbs 				switch (cts->bus_width) {
2308478f8a96SJustin T. Gibbs 				case MSG_EXT_WDTR_BUS_16_BIT:
2309478f8a96SJustin T. Gibbs 					*dptr |= DPARM_WIDE;
2310478f8a96SJustin T. Gibbs 					break;
2311478f8a96SJustin T. Gibbs 				default:
2312478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_WIDE;
2313478f8a96SJustin T. Gibbs 				}
2314478f8a96SJustin T. Gibbs 			}
2315478f8a96SJustin T. Gibbs 			/*
2316478f8a96SJustin T. Gibbs 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
2317478f8a96SJustin T. Gibbs 			 * of nonzero will cause us to go to the
2318478f8a96SJustin T. Gibbs 			 * selected (from NVRAM) maximum value for
2319478f8a96SJustin T. Gibbs 			 * this device. At a later point, we'll
2320478f8a96SJustin T. Gibbs 			 * allow finer control.
2321478f8a96SJustin T. Gibbs 			 */
2322478f8a96SJustin T. Gibbs 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
2323478f8a96SJustin T. Gibbs 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
2324478f8a96SJustin T. Gibbs 			    (cts->sync_offset > 0)) {
2325478f8a96SJustin T. Gibbs 				*dptr |= DPARM_SYNC;
2326478f8a96SJustin T. Gibbs 			} else {
2327478f8a96SJustin T. Gibbs 				*dptr &= ~DPARM_SYNC;
2328478f8a96SJustin T. Gibbs 			}
2329ab6c4b31SMatt Jacob 			*dptr |= DPARM_SAFE_DFLT;
2330ab163f5fSMatt Jacob #else
2331ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2332ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2333ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2334ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2335ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2336ab163f5fSMatt Jacob 			u_int16_t *dptr;
2337ab163f5fSMatt Jacob 
2338ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2339ab163f5fSMatt Jacob 			sdp += bus;
2340ab163f5fSMatt Jacob 			/*
23419ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2342ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2343ab163f5fSMatt Jacob 			 * vectored to that location.
2344ab163f5fSMatt Jacob 			 */
23459ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2346ab163f5fSMatt Jacob 
2347ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2348ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2349ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2350ab163f5fSMatt Jacob 				else
2351ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2352ab163f5fSMatt Jacob 			}
2353ab163f5fSMatt Jacob 
2354ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2355ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2356ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2357ab163f5fSMatt Jacob 				else
2358ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2359ab163f5fSMatt Jacob 			}
2360ab163f5fSMatt Jacob 
2361ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2362ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2363ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2364ab163f5fSMatt Jacob 				else
2365ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2366ab163f5fSMatt Jacob 			}
2367ab163f5fSMatt Jacob 
2368ab163f5fSMatt Jacob 			/*
2369ab163f5fSMatt Jacob 			 * XXX: FIX ME
2370ab163f5fSMatt Jacob 			 */
2371ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
23729ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
23739ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2374ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
23759ce9bdafSMatt Jacob 				/*
23769ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
23779ce9bdafSMatt Jacob 				 */
23789ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
23799ce9bdafSMatt Jacob 				    spi->sync_period;
23809ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
23819ce9bdafSMatt Jacob 				    spi->sync_offset;
2382ab163f5fSMatt Jacob 			} else {
2383ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2384ab163f5fSMatt Jacob 			}
2385ab163f5fSMatt Jacob #endif
2386bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
23879ce9bdafSMatt Jacob 			    "SET bus %d targ %d to flags %x off %x per %x",
23889ce9bdafSMatt Jacob 			    bus, tgt, sdp->isp_devparam[tgt].goal_flags,
23899ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
23909ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2391478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2392ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2393478f8a96SJustin T. Gibbs 		}
23945d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2395478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2396478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2397478f8a96SJustin T. Gibbs 		break;
2398478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2399478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2400478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2401ab163f5fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2402ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2403ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2404478f8a96SJustin T. Gibbs 			/*
2405478f8a96SJustin T. Gibbs 			 * a lot of normal SCSI things don't make sense.
2406478f8a96SJustin T. Gibbs 			 */
2407478f8a96SJustin T. Gibbs 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
2408478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2409478f8a96SJustin T. Gibbs 			/*
2410478f8a96SJustin T. Gibbs 			 * How do you measure the width of a high
2411478f8a96SJustin T. Gibbs 			 * speed serial bus? Well, in bytes.
2412478f8a96SJustin T. Gibbs 			 *
2413478f8a96SJustin T. Gibbs 			 * Offset and period make no sense, though, so we set
2414478f8a96SJustin T. Gibbs 			 * (above) a 'base' transfer speed to be gigabit.
2415478f8a96SJustin T. Gibbs 			 */
2416478f8a96SJustin T. Gibbs 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2417ab163f5fSMatt Jacob #else
2418ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
2419ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2420ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2421478f8a96SJustin T. Gibbs 
2422ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2423ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2424ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2425ab163f5fSMatt Jacob 			cts->transport_version = 0;
2426ab163f5fSMatt Jacob 
2427ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
242853036e92SMatt Jacob 			if (fcp->isp_gbspeed == 2)
242953036e92SMatt Jacob 				fc->bitrate = 200000;
243053036e92SMatt Jacob 			else
2431ab163f5fSMatt Jacob 				fc->bitrate = 100000;
2432ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
2433ab163f5fSMatt Jacob 				struct lportdb *lp = &fcp->portdb[tgt];
2434ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2435ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2436ab163f5fSMatt Jacob 				fc->port = lp->portid;
2437ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2438ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2439ab163f5fSMatt Jacob 			}
2440ab163f5fSMatt Jacob #endif
2441ab163f5fSMatt Jacob 		} else {
2442ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2443ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2444ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2445ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2446ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2447ab163f5fSMatt Jacob #endif
2448ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2449ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2450ab163f5fSMatt Jacob 			u_int16_t dval, pval, oval;
2451ab163f5fSMatt Jacob 
2452ea6f23cdSMatt Jacob 			sdp += bus;
2453ab163f5fSMatt Jacob 
2454ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
245583ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
245683ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
245783ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
245883ae4407SMatt Jacob 				    NULL);
24599ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
24609ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
24619ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
24624394c92fSMatt Jacob 			} else {
24639ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
24649ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
24659ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
24664394c92fSMatt Jacob 			}
2467478f8a96SJustin T. Gibbs 
2468ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2469478f8a96SJustin T. Gibbs 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
2470478f8a96SJustin T. Gibbs 
2471478f8a96SJustin T. Gibbs 			if (dval & DPARM_DISC) {
2472478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_DISC_ENB;
2473478f8a96SJustin T. Gibbs 			}
2474478f8a96SJustin T. Gibbs 			if (dval & DPARM_TQING) {
2475478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_TAG_ENB;
2476478f8a96SJustin T. Gibbs 			}
2477478f8a96SJustin T. Gibbs 			if (dval & DPARM_WIDE) {
2478478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2479478f8a96SJustin T. Gibbs 			} else {
2480478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2481478f8a96SJustin T. Gibbs 			}
2482478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
2483478f8a96SJustin T. Gibbs 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2484478f8a96SJustin T. Gibbs 
24854394c92fSMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
24864394c92fSMatt Jacob 				cts->sync_period = pval;
24874394c92fSMatt Jacob 				cts->sync_offset = oval;
2488478f8a96SJustin T. Gibbs 				cts->valid |=
2489478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_RATE_VALID |
2490478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_OFFSET_VALID;
2491478f8a96SJustin T. Gibbs 			}
2492ab163f5fSMatt Jacob #else
2493ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2494ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2495ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2496ab163f5fSMatt Jacob 			cts->transport_version = 2;
2497ab163f5fSMatt Jacob 
2498ab163f5fSMatt Jacob 			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2499ab163f5fSMatt Jacob 			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
2500ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2501ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2502ab163f5fSMatt Jacob 			}
2503ab163f5fSMatt Jacob 			if (dval & DPARM_TQING) {
2504ab163f5fSMatt Jacob 				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2505ab163f5fSMatt Jacob 			}
25069ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2507ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2508ab163f5fSMatt Jacob 				spi->sync_period = pval;
2509ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2510ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2511ab163f5fSMatt Jacob 			}
2512ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2513ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2514ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2515ab163f5fSMatt Jacob 			} else {
2516ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2517ab163f5fSMatt Jacob 			}
2518ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2519ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2520ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2521ab163f5fSMatt Jacob 			} else {
2522ab163f5fSMatt Jacob 				scsi->valid = 0;
2523ab163f5fSMatt Jacob 			}
2524ab163f5fSMatt Jacob #endif
2525bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
25269ce9bdafSMatt Jacob 			    "GET %s bus %d targ %d to flags %x off %x per %x",
25279ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
25289ce9bdafSMatt Jacob 			    bus, tgt, dval, oval, pval);
2529478f8a96SJustin T. Gibbs 		}
2530ab163f5fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2531478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2532478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2533478f8a96SJustin T. Gibbs 		break;
2534478f8a96SJustin T. Gibbs 
2535478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
2536478f8a96SJustin T. Gibbs 	{
2537478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
2538478f8a96SJustin T. Gibbs 
2539478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2540478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2541bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2542bfbab170SMatt Jacob 			    "%d.%d XPT_CALC_GEOMETRY block size 0?",
2543bfbab170SMatt Jacob 			    ccg->ccb_h.target_id, ccg->ccb_h.target_lun);
2544478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2545478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2546478f8a96SJustin T. Gibbs 			break;
2547478f8a96SJustin T. Gibbs 		}
25482813692cSNate Lawson 		cam_calc_geometry(ccg, /*extended*/1);
2549478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2550478f8a96SJustin T. Gibbs 		break;
2551478f8a96SJustin T. Gibbs 	}
2552478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
2553ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
25545d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2555ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
25565d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2557478f8a96SJustin T. Gibbs 		if (error)
2558478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
25592b052931SMatt Jacob 		else {
2560ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
2561ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
2562ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
25632b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
2564478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
25652b052931SMatt Jacob 		}
2566478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2567478f8a96SJustin T. Gibbs 		break;
2568478f8a96SJustin T. Gibbs 
2569478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
2570478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2571478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2572478f8a96SJustin T. Gibbs 		break;
2573478f8a96SJustin T. Gibbs 
2574478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
2575478f8a96SJustin T. Gibbs 	{
2576478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
2577478f8a96SJustin T. Gibbs 
2578478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
2579d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2580a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
2581d81ba9d5SMatt Jacob #else
2582478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
2583d81ba9d5SMatt Jacob #endif
2584478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
25850470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
25860470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
25870470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
25884394c92fSMatt Jacob 		if (IS_FC(isp)) {
25894394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
25900470d791SMatt Jacob 			/*
25910470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
25920470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
25930470d791SMatt Jacob 			 */
25940470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
25950470d791SMatt Jacob 
25969deea857SKenneth D. Merry 			/*
25979deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
25989deea857SKenneth D. Merry 			 * Technically not correct because we don't know
25999deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
26009deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
26019deea857SKenneth D. Merry 			 */
260253036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
260353036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
260453036e92SMatt Jacob 			else
26059deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
26060470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
2607ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2608ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
2609ab163f5fSMatt Jacob 			cpi->transport_version = 0;	/* WHAT'S THIS FOR? */
2610ab163f5fSMatt Jacob #endif
2611478f8a96SJustin T. Gibbs 		} else {
2612ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
2613ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
26140470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
26154394c92fSMatt Jacob 			cpi->hba_misc = 0;
2616ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
26179deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
2618ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2619ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
2620ab163f5fSMatt Jacob 			cpi->transport_version = 2;	/* WHAT'S THIS FOR? */
2621ab163f5fSMatt Jacob #endif
2622478f8a96SJustin T. Gibbs 		}
2623ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2624ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
2625ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
2626ab163f5fSMatt Jacob #endif
2627478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2628478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
2629478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2630478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
2631478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
2632478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2633478f8a96SJustin T. Gibbs 		break;
2634478f8a96SJustin T. Gibbs 	}
2635478f8a96SJustin T. Gibbs 	default:
2636478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2637478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2638478f8a96SJustin T. Gibbs 		break;
2639478f8a96SJustin T. Gibbs 	}
2640478f8a96SJustin T. Gibbs }
2641d3a9eb2eSMatt Jacob 
2642d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
2643d3a9eb2eSMatt Jacob void
2644c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
2645d3a9eb2eSMatt Jacob {
2646d3a9eb2eSMatt Jacob 	struct ispsoftc *isp = XS_ISP(sccb);
2647d3a9eb2eSMatt Jacob 
2648d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
2649d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
2650b85389e1SMatt Jacob 
2651d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
2652d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
2653d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
265492a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
265592a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
265692a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
265792a1e549SMatt Jacob 		} else {
2658d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
2659d3a9eb2eSMatt Jacob 		}
266092a1e549SMatt Jacob 	}
2661b85389e1SMatt Jacob 
26620470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
2663d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2664d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2665d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
26660470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
2667fdeb9f2fSMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
2668fdeb9f2fSMatt Jacob 			    "freeze devq %d.%d cam sts %x scsi sts %x",
2669fdeb9f2fSMatt Jacob 			    sccb->ccb_h.target_id, sccb->ccb_h.target_lun,
2670fdeb9f2fSMatt Jacob 			    sccb->ccb_h.status, sccb->scsi_status);
2671d3a9eb2eSMatt Jacob 		}
2672d3a9eb2eSMatt Jacob 	}
2673b85389e1SMatt Jacob 
2674b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
2675d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2676d3a9eb2eSMatt Jacob 		xpt_print_path(sccb->ccb_h.path);
26773c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
26783c75bb14SMatt Jacob 		    "cam completion status 0x%x", sccb->ccb_h.status);
2679d3a9eb2eSMatt Jacob 	}
2680b85389e1SMatt Jacob 
2681b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
2682b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
2683b85389e1SMatt Jacob 		untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch);
2684b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
2685b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2686b09b0095SMatt Jacob 			    "finished command on borrowed time");
2687b85389e1SMatt Jacob 		}
2688b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
26895d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2690d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
26915d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2692d3a9eb2eSMatt Jacob 	}
2693b85389e1SMatt Jacob }
2694d3a9eb2eSMatt Jacob 
2695cbf57b47SMatt Jacob int
26960470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
2697cbf57b47SMatt Jacob {
2698ea6f23cdSMatt Jacob 	int bus, rv = 0;
2699cbf57b47SMatt Jacob 	switch (cmd) {
2700cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
27010470d791SMatt Jacob 	{
2702ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2703ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
2704ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
2705ab163f5fSMatt Jacob #endif
2706cbf57b47SMatt Jacob 		int flags, tgt;
2707cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
2708ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
2709cbf57b47SMatt Jacob 		struct cam_path *tmppath;
2710cbf57b47SMatt Jacob 
2711ab163f5fSMatt Jacob 		bzero(&cts, sizeof (struct ccb_trans_settings));
2712ab163f5fSMatt Jacob 
2713cbf57b47SMatt Jacob 		tgt = *((int *)arg);
2714ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
2715ea6f23cdSMatt Jacob 		tgt &= 0xffff;
2716ea6f23cdSMatt Jacob 		sdp += bus;
271745c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2718cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
2719ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
2720ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
272145c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2722bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2723bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
2724bfbab170SMatt Jacob 			    tgt, bus);
2725cbf57b47SMatt Jacob 			rv = -1;
2726cbf57b47SMatt Jacob 			break;
2727cbf57b47SMatt Jacob 		}
272845c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
27299ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
2730ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2731ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
2732ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
2733ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
2734ab163f5fSMatt Jacob 
2735ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
2736ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
2737ab163f5fSMatt Jacob 
2738ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
2739ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
2740ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2741ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_TAG_ENB;
2742ab163f5fSMatt Jacob 		}
2743ab163f5fSMatt Jacob 
2744cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
2745ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
2746ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2747ab163f5fSMatt Jacob 		}
2748ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
2749ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
2750ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2751ab163f5fSMatt Jacob 		} else {
2752ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2753ab163f5fSMatt Jacob 		}
2754ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
2755ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2756ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
27579ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
27589ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
2759ab163f5fSMatt Jacob 		}
2760ab163f5fSMatt Jacob #else
2761ab163f5fSMatt Jacob 		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
2762ab163f5fSMatt Jacob 		cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2763ab163f5fSMatt Jacob 		if (flags & DPARM_DISC) {
2764ab163f5fSMatt Jacob 			cts.flags |= CCB_TRANS_DISC_ENB;
2765cbf57b47SMatt Jacob 		}
2766cbf57b47SMatt Jacob 		if (flags & DPARM_TQING) {
2767ab163f5fSMatt Jacob 			cts.flags |= CCB_TRANS_TAG_ENB;
2768cbf57b47SMatt Jacob 		}
2769ab163f5fSMatt Jacob 		cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
2770ab163f5fSMatt Jacob 		cts.bus_width = (flags & DPARM_WIDE)?
2771cbf57b47SMatt Jacob 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
27729ce9bdafSMatt Jacob 		cts.sync_period = sdp->isp_devparam[tgt].actv_period;
27739ce9bdafSMatt Jacob 		cts.sync_offset = sdp->isp_devparam[tgt].actv_offset;
2774cbf57b47SMatt Jacob 		if (flags & DPARM_SYNC) {
2775ab163f5fSMatt Jacob 			cts.valid |=
27764394c92fSMatt Jacob 			    CCB_TRANS_SYNC_RATE_VALID |
2777cbf57b47SMatt Jacob 			    CCB_TRANS_SYNC_OFFSET_VALID;
2778cbf57b47SMatt Jacob 		}
2779ab163f5fSMatt Jacob #endif
2780b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
2781b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
27829ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
27839ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
2784ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
27855d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2786ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
2787cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
2788f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2789cbf57b47SMatt Jacob 		break;
27900470d791SMatt Jacob 	}
279157c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
2792ea6f23cdSMatt Jacob 		bus = *((int *)arg);
2793b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
2794b09b0095SMatt Jacob 		    bus);
2795ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
27965d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2797ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
27985d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2799ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
28005d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
280157c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
28025d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
280357c801f5SMatt Jacob 		}
280457c801f5SMatt Jacob 		break;
28055d571944SMatt Jacob 	case ISPASYNC_LIP:
28065d571944SMatt Jacob 		if (isp->isp_path) {
2807fdeb9f2fSMatt Jacob 			isp_freeze_loopdown(isp, "ISPASYNC_LIP");
28085d571944SMatt Jacob 		}
28095d571944SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "LIP Received");
28105d571944SMatt Jacob 		break;
28115d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
28125d571944SMatt Jacob 		if (isp->isp_path) {
2813fdeb9f2fSMatt Jacob 			isp_freeze_loopdown(isp, "ISPASYNC_LOOP_RESET");
28145d571944SMatt Jacob 		}
28155d571944SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop Reset Received");
28165d571944SMatt Jacob 		break;
281757c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
281857c801f5SMatt Jacob 		if (isp->isp_path) {
2819fdeb9f2fSMatt Jacob 			isp_freeze_loopdown(isp, "ISPASYNC_LOOP_DOWN");
282057c801f5SMatt Jacob 		}
2821b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
282257c801f5SMatt Jacob 		break;
282357c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
28245d571944SMatt Jacob 		/*
28255d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
28265d571944SMatt Jacob 		 * actually do anything because we're waiting for a
28275d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
28285d571944SMatt Jacob 		 * thread to look at the state of the loop again.
28295d571944SMatt Jacob 		 */
2830b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
283157c801f5SMatt Jacob 		break;
2832d6e5500fSMatt Jacob 	case ISPASYNC_PROMENADE:
28330470d791SMatt Jacob 	{
2834ab163f5fSMatt Jacob 		struct cam_path *tmppath;
2835b09b0095SMatt Jacob 		const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x "
2836d6e5500fSMatt Jacob 		    "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x";
2837d6e5500fSMatt Jacob 		static const char *roles[4] = {
28380470d791SMatt Jacob 		    "(none)", "Target", "Initiator", "Target/Initiator"
283957c801f5SMatt Jacob 		};
284002ab3379SMatt Jacob 		fcparam *fcp = isp->isp_param;
284102ab3379SMatt Jacob 		int tgt = *((int *) arg);
2842f44257c2SMatt Jacob 		int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT);
284302ab3379SMatt Jacob 		struct lportdb *lp = &fcp->portdb[tgt];
284402ab3379SMatt Jacob 
2845b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid,
2846d6e5500fSMatt Jacob 		    roles[lp->roles & 0x3],
2847d6e5500fSMatt Jacob 		    (lp->valid)? "Arrived" : "Departed",
284802ab3379SMatt Jacob 		    (u_int32_t) (lp->port_wwn >> 32),
284902ab3379SMatt Jacob 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
285002ab3379SMatt Jacob 		    (u_int32_t) (lp->node_wwn >> 32),
285102ab3379SMatt Jacob 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
2852ab163f5fSMatt Jacob 
285345c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2854ab163f5fSMatt Jacob 		if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim),
2855ab163f5fSMatt Jacob 		    (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
285645c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2857ab163f5fSMatt Jacob                         break;
2858ab163f5fSMatt Jacob                 }
2859f44257c2SMatt Jacob 		/*
2860f44257c2SMatt Jacob 		 * Policy: only announce targets.
2861f44257c2SMatt Jacob 		 */
2862f44257c2SMatt Jacob 		if (lp->roles & is_tgt_mask) {
2863f44257c2SMatt Jacob 			if (lp->valid) {
2864ab163f5fSMatt Jacob 				xpt_async(AC_FOUND_DEVICE, tmppath, NULL);
2865ab163f5fSMatt Jacob 			} else {
2866ab163f5fSMatt Jacob 				xpt_async(AC_LOST_DEVICE, tmppath, NULL);
2867ab163f5fSMatt Jacob 			}
2868f44257c2SMatt Jacob 		}
2869ab163f5fSMatt Jacob 		xpt_free_path(tmppath);
2870f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
28714394c92fSMatt Jacob 		break;
28724394c92fSMatt Jacob 	}
287357c801f5SMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
2874f44257c2SMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
28754b9d588eSMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
2876f44257c2SMatt Jacob 			    "Port Database Changed");
2877f44257c2SMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
28784b9d588eSMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
28794b9d588eSMatt Jacob 			    "Name Server Database Changed");
28804b9d588eSMatt Jacob 		}
2881162e9893SMatt Jacob #ifdef	ISP_SMPLOCK
28825d571944SMatt Jacob 		cv_signal(&isp->isp_osinfo.kthread_cv);
2883162e9893SMatt Jacob #else
2884162e9893SMatt Jacob 		wakeup(&isp->isp_osinfo.kthread_cv);
2885162e9893SMatt Jacob #endif
288657c801f5SMatt Jacob 		break;
288702ab3379SMatt Jacob 	case ISPASYNC_FABRIC_DEV:
288802ab3379SMatt Jacob 	{
2889029f13c6SMatt Jacob 		int target, base, lim;
289002ab3379SMatt Jacob 		fcparam *fcp = isp->isp_param;
2891029f13c6SMatt Jacob 		struct lportdb *lp = NULL;
2892029f13c6SMatt Jacob 		struct lportdb *clp = (struct lportdb *) arg;
2893029f13c6SMatt Jacob 		char *pt;
289402ab3379SMatt Jacob 
2895029f13c6SMatt Jacob 		switch (clp->port_type) {
289640cfc8feSMatt Jacob 		case 1:
289740cfc8feSMatt Jacob 			pt = "   N_Port";
289840cfc8feSMatt Jacob 			break;
289940cfc8feSMatt Jacob 		case 2:
290040cfc8feSMatt Jacob 			pt = "  NL_Port";
290140cfc8feSMatt Jacob 			break;
290240cfc8feSMatt Jacob 		case 3:
290340cfc8feSMatt Jacob 			pt = "F/NL_Port";
290440cfc8feSMatt Jacob 			break;
290540cfc8feSMatt Jacob 		case 0x7f:
290640cfc8feSMatt Jacob 			pt = "  Nx_Port";
290740cfc8feSMatt Jacob 			break;
290840cfc8feSMatt Jacob 		case 0x81:
290940cfc8feSMatt Jacob 			pt = "  F_port";
291040cfc8feSMatt Jacob 			break;
291140cfc8feSMatt Jacob 		case 0x82:
291240cfc8feSMatt Jacob 			pt = "  FL_Port";
291340cfc8feSMatt Jacob 			break;
291440cfc8feSMatt Jacob 		case 0x84:
291540cfc8feSMatt Jacob 			pt = "   E_port";
291640cfc8feSMatt Jacob 			break;
291740cfc8feSMatt Jacob 		default:
2918029f13c6SMatt Jacob 			pt = " ";
291940cfc8feSMatt Jacob 			break;
292040cfc8feSMatt Jacob 		}
2921029f13c6SMatt Jacob 
2922b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
2923029f13c6SMatt Jacob 		    "%s Fabric Device @ PortID 0x%x", pt, clp->portid);
2924029f13c6SMatt Jacob 
292570d2ccceSMatt Jacob 		/*
2926029f13c6SMatt Jacob 		 * If we don't have an initiator role we bail.
2927029f13c6SMatt Jacob 		 *
2928029f13c6SMatt Jacob 		 * We just use ISPASYNC_FABRIC_DEV for announcement purposes.
292970d2ccceSMatt Jacob 		 */
2930029f13c6SMatt Jacob 
2931029f13c6SMatt Jacob 		if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) {
293202ab3379SMatt Jacob 			break;
293302ab3379SMatt Jacob 		}
2934029f13c6SMatt Jacob 
2935029f13c6SMatt Jacob 		/*
2936029f13c6SMatt Jacob 		 * Is this entry for us? If so, we bail.
2937029f13c6SMatt Jacob 		 */
2938029f13c6SMatt Jacob 
2939029f13c6SMatt Jacob 		if (fcp->isp_portid == clp->portid) {
2940029f13c6SMatt Jacob 			break;
2941029f13c6SMatt Jacob 		}
2942029f13c6SMatt Jacob 
2943029f13c6SMatt Jacob 		/*
2944029f13c6SMatt Jacob 		 * Else, the default policy is to find room for it in
2945029f13c6SMatt Jacob 		 * our local port database. Later, when we execute
2946029f13c6SMatt Jacob 		 * the call to isp_pdb_sync either this newly arrived
2947029f13c6SMatt Jacob 		 * or already logged in device will be (re)announced.
2948029f13c6SMatt Jacob 		 */
2949029f13c6SMatt Jacob 
2950029f13c6SMatt Jacob 		if (fcp->isp_topo == TOPO_FL_PORT)
2951029f13c6SMatt Jacob 			base = FC_SNS_ID+1;
295270d2ccceSMatt Jacob 		else
2953029f13c6SMatt Jacob 			base = 0;
2954029f13c6SMatt Jacob 
2955029f13c6SMatt Jacob 		if (fcp->isp_topo == TOPO_N_PORT)
2956029f13c6SMatt Jacob 			lim = 1;
2957029f13c6SMatt Jacob 		else
2958029f13c6SMatt Jacob 			lim = MAX_FC_TARG;
2959029f13c6SMatt Jacob 
296070d2ccceSMatt Jacob 		/*
296170d2ccceSMatt Jacob 		 * Is it already in our list?
296270d2ccceSMatt Jacob 		 */
2963029f13c6SMatt Jacob 		for (target = base; target < lim; target++) {
296470d2ccceSMatt Jacob 			if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
296570d2ccceSMatt Jacob 				continue;
296670d2ccceSMatt Jacob 			}
296770d2ccceSMatt Jacob 			lp = &fcp->portdb[target];
2968029f13c6SMatt Jacob 			if (lp->port_wwn == clp->port_wwn &&
2969029f13c6SMatt Jacob 			    lp->node_wwn == clp->node_wwn) {
297070d2ccceSMatt Jacob 				lp->fabric_dev = 1;
297170d2ccceSMatt Jacob 				break;
297270d2ccceSMatt Jacob 			}
297370d2ccceSMatt Jacob 		}
2974029f13c6SMatt Jacob 		if (target < lim) {
297502ab3379SMatt Jacob 			break;
297602ab3379SMatt Jacob 		}
2977029f13c6SMatt Jacob 		for (target = base; target < lim; target++) {
297870d2ccceSMatt Jacob 			if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
297970d2ccceSMatt Jacob 				continue;
298070d2ccceSMatt Jacob 			}
298102ab3379SMatt Jacob 			lp = &fcp->portdb[target];
298270d2ccceSMatt Jacob 			if (lp->port_wwn == 0) {
298302ab3379SMatt Jacob 				break;
298402ab3379SMatt Jacob 			}
298570d2ccceSMatt Jacob 		}
2986029f13c6SMatt Jacob 		if (target == lim) {
2987bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2988029f13c6SMatt Jacob 			    "out of space for fabric devices");
298902ab3379SMatt Jacob 			break;
299002ab3379SMatt Jacob 		}
2991029f13c6SMatt Jacob 		lp->port_type = clp->port_type;
2992029f13c6SMatt Jacob 		lp->fc4_type = clp->fc4_type;
2993029f13c6SMatt Jacob 		lp->node_wwn = clp->node_wwn;
2994029f13c6SMatt Jacob 		lp->port_wwn = clp->port_wwn;
2995029f13c6SMatt Jacob 		lp->portid = clp->portid;
299670d2ccceSMatt Jacob 		lp->fabric_dev = 1;
299702ab3379SMatt Jacob 		break;
299802ab3379SMatt Jacob 	}
2999d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
3000d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_MESSAGE:
3001d81ba9d5SMatt Jacob 	{
3002d81ba9d5SMatt Jacob 		tmd_msg_t *mp = arg;
300364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3004b09b0095SMatt Jacob 		    "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x",
3005b09b0095SMatt Jacob 		    mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt,
3006b09b0095SMatt Jacob 		    (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval,
3007b09b0095SMatt Jacob 		    mp->nt_msg[0]);
3008d81ba9d5SMatt Jacob 		break;
3009d81ba9d5SMatt Jacob 	}
3010d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_EVENT:
3011d81ba9d5SMatt Jacob 	{
3012d81ba9d5SMatt Jacob 		tmd_event_t *ep = arg;
301364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
3014b09b0095SMatt Jacob 		    "bus %d event code 0x%x", ep->ev_bus, ep->ev_event);
3015d81ba9d5SMatt Jacob 		break;
3016d81ba9d5SMatt Jacob 	}
3017d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
3018d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
3019cbf57b47SMatt Jacob 		default:
3020bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
3021bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
3022bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
3023d81ba9d5SMatt Jacob 			break;
3024570c7a3fSMatt Jacob 		case RQSTYPE_NOTIFY:
3025570c7a3fSMatt Jacob 			if (IS_SCSI(isp)) {
3026570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_scsi(isp,
3027570c7a3fSMatt Jacob 				    (in_entry_t *) arg);
3028570c7a3fSMatt Jacob 			} else {
3029570c7a3fSMatt Jacob 				rv = isp_handle_platform_notify_fc(isp,
3030570c7a3fSMatt Jacob 				    (in_fcentry_t *) arg);
3031570c7a3fSMatt Jacob 			}
3032570c7a3fSMatt Jacob 			break;
3033d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
3034d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
3035d81ba9d5SMatt Jacob 			break;
3036d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
3037d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
3038d81ba9d5SMatt Jacob 			break;
3039d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
3040d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
3041d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
3042d81ba9d5SMatt Jacob 			break;
3043d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
3044d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
304564edff94SMatt Jacob 			if (IS_DUALBUS(isp)) {
304664edff94SMatt Jacob 				bus =
304764edff94SMatt Jacob 				    GET_BUS_VAL(((lun_entry_t *)arg)->le_rsvd);
304864edff94SMatt Jacob 			} else {
304964edff94SMatt Jacob 				bus = 0;
305064edff94SMatt Jacob 			}
305164edff94SMatt Jacob 			isp_cv_signal_rqe(isp, bus,
305264edff94SMatt Jacob 			    ((lun_entry_t *)arg)->le_status);
3053d81ba9d5SMatt Jacob 			break;
3054d81ba9d5SMatt Jacob 		}
3055d81ba9d5SMatt Jacob 		break;
3056d81ba9d5SMatt Jacob #endif
3057ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
3058ab163f5fSMatt Jacob 	{
3059ab163f5fSMatt Jacob 		u_int16_t mbox1, mbox6;
3060ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
3061ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
3062ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
3063ab163f5fSMatt Jacob 		} else {
3064ab163f5fSMatt Jacob 			mbox6 = 0;
3065ab163f5fSMatt Jacob 		}
3066ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
3067570c7a3fSMatt Jacob                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
3068ab163f5fSMatt Jacob                     mbox6, mbox1);
30698a5f89b9SMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
30708a5f89b9SMatt Jacob 		/*
30718a5f89b9SMatt Jacob 		 * XXX: really need a thread to do this right.
30728a5f89b9SMatt Jacob 		 */
30738a5f89b9SMatt Jacob 		if (IS_FC(isp)) {
30748a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
30758a5f89b9SMatt Jacob 			FCPARAM(isp)->isp_loopstate = LOOP_NIL;
30768a5f89b9SMatt Jacob 			isp_freeze_loopdown(isp, "f/w crash");
30778a5f89b9SMatt Jacob 			isp_fw_dump(isp);
30788a5f89b9SMatt Jacob 		}
3079ab163f5fSMatt Jacob 		isp_reinit(isp);
30808a5f89b9SMatt Jacob 		isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
30818a5f89b9SMatt Jacob #endif
3082ab163f5fSMatt Jacob 		break;
3083ab163f5fSMatt Jacob 	}
3084be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
3085be534d5fSMatt Jacob 		break;
3086d81ba9d5SMatt Jacob 	default:
3087b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
3088cbf57b47SMatt Jacob 		break;
3089cbf57b47SMatt Jacob 	}
3090cbf57b47SMatt Jacob 	return (rv);
3091cbf57b47SMatt Jacob }
3092cbf57b47SMatt Jacob 
309392718a7fSMatt Jacob 
309492718a7fSMatt Jacob /*
309592718a7fSMatt Jacob  * Locks are held before coming here.
309692718a7fSMatt Jacob  */
309792718a7fSMatt Jacob void
309892718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp)
309992718a7fSMatt Jacob {
3100ea6f23cdSMatt Jacob 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
310192718a7fSMatt Jacob 	DISABLE_INTS(isp);
310292718a7fSMatt Jacob }
3103b09b0095SMatt Jacob 
3104b09b0095SMatt Jacob void
3105b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...)
3106b09b0095SMatt Jacob {
3107b09b0095SMatt Jacob 	va_list ap;
3108b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
3109b09b0095SMatt Jacob 		return;
3110b09b0095SMatt Jacob 	}
31113c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
3112b09b0095SMatt Jacob 	va_start(ap, fmt);
3113b09b0095SMatt Jacob 	vprintf(fmt, ap);
3114b09b0095SMatt Jacob 	va_end(ap);
3115b09b0095SMatt Jacob 	printf("\n");
3116b09b0095SMatt Jacob }
3117