xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision d134aa0b204e8cb7ecac243d68053017b4f2b6ab)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
26054c3f6SMatt Jacob /*
36054c3f6SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
46054c3f6SMatt Jacob  *
55f5aafe1SMatt Jacob  * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob
66054c3f6SMatt Jacob  *
76054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
86054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
96054c3f6SMatt Jacob  * are met:
106054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
116054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
126054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
13aa57fd6fSMatt Jacob  * 2. The name of the author may not be used to endorse or promote products
14aa57fd6fSMatt Jacob  *    derived from this software without specific prior written permission.
156054c3f6SMatt Jacob  *
166054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
176054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
186054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
196054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
206054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
216054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
226054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
236054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
246054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
256054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
266054c3f6SMatt Jacob  * SUCH DAMAGE.
276054c3f6SMatt Jacob  */
286054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
295d571944SMatt Jacob #include <sys/unistd.h>
305d571944SMatt Jacob #include <sys/kthread.h>
313ea883b4SMatt Jacob #include <machine/stdarg.h>	/* for use by isp_prt below */
325d571944SMatt Jacob #include <sys/conf.h>
335d571944SMatt Jacob #include <sys/ioccom.h>
345d571944SMatt Jacob #include <dev/isp/isp_ioctl.h>
356054c3f6SMatt Jacob 
36a1bc34c6SMatt Jacob 
375d571944SMatt Jacob static d_ioctl_t ispioctl;
38f6e75de2SMatt Jacob static void isp_intr_enable(void *);
390470d791SMatt Jacob static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
400470d791SMatt Jacob static void isp_poll(struct cam_sim *);
415d571944SMatt Jacob #if	0
420470d791SMatt Jacob static void isp_relsim(void *);
435d571944SMatt Jacob #endif
44b85389e1SMatt Jacob static timeout_t isp_watchdog;
455d571944SMatt Jacob static void isp_kthread(void *);
46d81ba9d5SMatt Jacob static void isp_action(struct cam_sim *, union ccb *);
470470d791SMatt Jacob 
48cc8df88bSMatt Jacob 
495d571944SMatt Jacob #define ISP_CDEV_MAJOR	248
505d571944SMatt Jacob static struct cdevsw isp_cdevsw = {
515d571944SMatt Jacob 	/* open */	nullopen,
525d571944SMatt Jacob 	/* close */	nullclose,
535d571944SMatt Jacob 	/* read */	noread,
545d571944SMatt Jacob 	/* write */	nowrite,
555d571944SMatt Jacob 	/* ioctl */	ispioctl,
565d571944SMatt Jacob 	/* poll */	nopoll,
575d571944SMatt Jacob 	/* mmap */	nommap,
585d571944SMatt Jacob 	/* strategy */	nostrategy,
595d571944SMatt Jacob 	/* name */	"isp",
605d571944SMatt Jacob 	/* maj */	ISP_CDEV_MAJOR,
615d571944SMatt Jacob 	/* dump */	nodump,
625d571944SMatt Jacob 	/* psize */	nopsize,
635d571944SMatt Jacob 	/* flags */	D_TAPE,
645d571944SMatt Jacob };
655d571944SMatt Jacob 
66d81ba9d5SMatt Jacob static struct ispsoftc *isplist = NULL;
67478f8a96SJustin T. Gibbs 
68478f8a96SJustin T. Gibbs void
69c3055363SMatt Jacob isp_attach(struct ispsoftc *isp)
70478f8a96SJustin T. Gibbs {
71ea6f23cdSMatt Jacob 	int primary, secondary;
72478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
73478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
74ea6f23cdSMatt Jacob 	struct cam_sim *sim;
75ea6f23cdSMatt Jacob 	struct cam_path *path;
76478f8a96SJustin T. Gibbs 
77478f8a96SJustin T. Gibbs 	/*
78ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
79ea6f23cdSMatt Jacob 	 */
80ea6f23cdSMatt Jacob 
81ea6f23cdSMatt Jacob 	primary = 0;
82ea6f23cdSMatt Jacob 	secondary = 1;
83ea6f23cdSMatt Jacob 
84ea6f23cdSMatt Jacob 	/*
85ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
86478f8a96SJustin T. Gibbs 	 */
87ab6c4b31SMatt Jacob 	devq = cam_simq_alloc(isp->isp_maxcmds);
88478f8a96SJustin T. Gibbs 	if (devq == NULL) {
89478f8a96SJustin T. Gibbs 		return;
90478f8a96SJustin T. Gibbs 	}
91478f8a96SJustin T. Gibbs 
92478f8a96SJustin T. Gibbs 	/*
93ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
94478f8a96SJustin T. Gibbs 	 */
9545c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
96ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
973c75bb14SMatt Jacob 	    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
98ea6f23cdSMatt Jacob 	if (sim == NULL) {
99478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
10045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
101478f8a96SJustin T. Gibbs 		return;
102478f8a96SJustin T. Gibbs 	}
10345c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
104f6e75de2SMatt Jacob 
105f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_func = isp_intr_enable;
106f6e75de2SMatt Jacob 	isp->isp_osinfo.ehook.ich_arg = isp;
10745c9a36aSMatt Jacob 	ISPLOCK_2_CAMLOCK(isp);
108f6e75de2SMatt Jacob 	if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) {
10945c9a36aSMatt Jacob 		cam_sim_free(sim, TRUE);
11045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
111bfbab170SMatt Jacob 		isp_prt(isp, ISP_LOGERR,
112bfbab170SMatt Jacob 		    "could not establish interrupt enable hook");
113f6e75de2SMatt Jacob 		return;
114f6e75de2SMatt Jacob 	}
115f6e75de2SMatt Jacob 
116ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
117ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
11845c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
119478f8a96SJustin T. Gibbs 		return;
120478f8a96SJustin T. Gibbs 	}
121478f8a96SJustin T. Gibbs 
122ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
123478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
124ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
125ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
1265d571944SMatt Jacob 		config_intrhook_disestablish(&isp->isp_osinfo.ehook);
12745c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
128478f8a96SJustin T. Gibbs 		return;
129478f8a96SJustin T. Gibbs 	}
130478f8a96SJustin T. Gibbs 
131ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
132478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
133478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
134cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
135ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
136478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
13745c9a36aSMatt Jacob 	CAMLOCK_2_ISPLOCK(isp);
138ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
139ea6f23cdSMatt Jacob 	isp->isp_path = path;
1405d571944SMatt Jacob 	/*
1415d571944SMatt Jacob 	 * Create a kernel thread for fibre channel instances. We
1425d571944SMatt Jacob 	 * don't have dual channel FC cards.
1435d571944SMatt Jacob 	 */
1445d571944SMatt Jacob 	if (IS_FC(isp)) {
14545c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
14645c9a36aSMatt Jacob 		/* XXX: LOCK VIOLATION */
1475d571944SMatt Jacob 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
1485d571944SMatt Jacob 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
1495d571944SMatt Jacob 		    RFHIGHPID, "%s: fc_thrd",
1505d571944SMatt Jacob 		    device_get_nameunit(isp->isp_dev))) {
1515d571944SMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
1525d571944SMatt Jacob 			cam_sim_free(sim, TRUE);
1535d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
15445c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
15545c9a36aSMatt Jacob 			isp_prt(isp, ISP_LOGERR, "could not create kthread");
1565d571944SMatt Jacob 			return;
1575d571944SMatt Jacob 		}
1588e6a12fcSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
1595d571944SMatt Jacob 	}
1605d571944SMatt Jacob 
161478f8a96SJustin T. Gibbs 
162ea6f23cdSMatt Jacob 	/*
163ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
164ea6f23cdSMatt Jacob 	 */
16522e1dc85SMatt Jacob 	if (IS_DUALBUS(isp)) {
16645c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
167ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
1683c75bb14SMatt Jacob 		    device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq);
169ea6f23cdSMatt Jacob 		if (sim == NULL) {
170ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
171ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
172ea6f23cdSMatt Jacob 			cam_simq_free(devq);
1735d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
174ea6f23cdSMatt Jacob 			return;
175ea6f23cdSMatt Jacob 		}
176ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
177ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
178ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
179ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
1805d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
18145c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
182ea6f23cdSMatt Jacob 			return;
183ea6f23cdSMatt Jacob 		}
184ea6f23cdSMatt Jacob 
185ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
186ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
187ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
188ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
189ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
190ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
1915d571944SMatt Jacob 			config_intrhook_disestablish(&isp->isp_osinfo.ehook);
19245c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
193ea6f23cdSMatt Jacob 			return;
194ea6f23cdSMatt Jacob 		}
195ea6f23cdSMatt Jacob 
196ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
197ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
198ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
199ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
200ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
201ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
20245c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
203ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
204ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
205ea6f23cdSMatt Jacob 	}
2065d571944SMatt Jacob 
20764edff94SMatt Jacob #ifdef	ISP_TARGET_MODE
20864edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv0[0], "isp_tgcv0a");
20964edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv0[1], "isp_tgcv0b");
21064edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv1[0], "isp_tgcv1a");
21164edff94SMatt Jacob 	cv_init(&isp->isp_osinfo.tgtcv1[1], "isp_tgcv1b");
21264edff94SMatt Jacob #endif
2135d571944SMatt Jacob 	/*
2145d571944SMatt Jacob 	 * Create device nodes
2155d571944SMatt Jacob 	 */
2165d571944SMatt Jacob 	(void) make_dev(&isp_cdevsw, device_get_unit(isp->isp_dev), UID_ROOT,
2175d571944SMatt Jacob 	    GID_OPERATOR, 0600, "%s", device_get_nameunit(isp->isp_dev));
2185d571944SMatt Jacob 
219d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
220478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
221b85389e1SMatt Jacob 		ENABLE_INTS(isp);
222d6e5500fSMatt Jacob 	}
223d81ba9d5SMatt Jacob 	if (isplist == NULL) {
224d81ba9d5SMatt Jacob 		isplist = isp;
225d81ba9d5SMatt Jacob 	} else {
226d81ba9d5SMatt Jacob 		struct ispsoftc *tmp = isplist;
227d81ba9d5SMatt Jacob 		while (tmp->isp_osinfo.next) {
228d81ba9d5SMatt Jacob 			tmp = tmp->isp_osinfo.next;
229d81ba9d5SMatt Jacob 		}
230d81ba9d5SMatt Jacob 		tmp->isp_osinfo.next = isp;
231478f8a96SJustin T. Gibbs 	}
2325d571944SMatt Jacob 
2335d571944SMatt Jacob }
2345d571944SMatt Jacob 
2355d571944SMatt Jacob static int
236b40ce416SJulian Elischer ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
2375d571944SMatt Jacob {
2385d571944SMatt Jacob 	struct ispsoftc *isp;
2395d571944SMatt Jacob 	int retval = ENOTTY;
2405d571944SMatt Jacob 
2415d571944SMatt Jacob 	isp = isplist;
2425d571944SMatt Jacob 	while (isp) {
2435d571944SMatt Jacob 		if (minor(dev) == device_get_unit(isp->isp_dev)) {
2445d571944SMatt Jacob 			break;
2455d571944SMatt Jacob 		}
2465d571944SMatt Jacob 		isp = isp->isp_osinfo.next;
2475d571944SMatt Jacob 	}
2485d571944SMatt Jacob 	if (isp == NULL)
2495d571944SMatt Jacob 		return (ENXIO);
2505d571944SMatt Jacob 
2515d571944SMatt Jacob 	switch (cmd) {
252d134aa0bSMatt Jacob #ifdef	ISP_FW_CRASH_DUMP
253d134aa0bSMatt Jacob 	case ISP_GET_FW_CRASH_DUMP:
254d134aa0bSMatt Jacob 	{
255d134aa0bSMatt Jacob 		u_int16_t *ptr = FCPARAM(isp)->isp_dump_data;
256d134aa0bSMatt Jacob 		size_t sz;
257d134aa0bSMatt Jacob 
258d134aa0bSMatt Jacob 		retval = 0;
259d134aa0bSMatt Jacob 		if (IS_2200(isp))
260d134aa0bSMatt Jacob 			sz = QLA2200_RISC_IMAGE_DUMP_SIZE;
261d134aa0bSMatt Jacob 		else
262d134aa0bSMatt Jacob 			sz = QLA2300_RISC_IMAGE_DUMP_SIZE;
263d134aa0bSMatt Jacob 		ISP_LOCK(isp);
264d134aa0bSMatt Jacob 		if (ptr && *ptr) {
265d134aa0bSMatt Jacob 			void *uaddr = *((void **) addr);
266d134aa0bSMatt Jacob 			if (copyout(ptr, uaddr, sz)) {
267d134aa0bSMatt Jacob 				retval = EFAULT;
268d134aa0bSMatt Jacob 			} else {
269d134aa0bSMatt Jacob 				*ptr = 0;
270d134aa0bSMatt Jacob 			}
271d134aa0bSMatt Jacob 		} else {
272d134aa0bSMatt Jacob 			retval = ENXIO;
273d134aa0bSMatt Jacob 		}
274d134aa0bSMatt Jacob 		ISP_UNLOCK(isp);
275d134aa0bSMatt Jacob 		break;
276d134aa0bSMatt Jacob 	}
277d134aa0bSMatt Jacob 
278d134aa0bSMatt Jacob 	case ISP_FORCE_CRASH_DUMP:
279d134aa0bSMatt Jacob 		ISP_LOCK(isp);
280d134aa0bSMatt Jacob 		if ((isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) == 0) {
281d134aa0bSMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
282d134aa0bSMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
283d134aa0bSMatt Jacob 			xpt_freeze_simq(isp->isp_sim, 1);
284d134aa0bSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
285d134aa0bSMatt Jacob 		}
286d134aa0bSMatt Jacob 		isp_fw_dump(isp);
287d134aa0bSMatt Jacob 		isp_reinit(isp);
288d134aa0bSMatt Jacob 		ISP_UNLOCK(isp);
289d134aa0bSMatt Jacob 		retval = 0;
290d134aa0bSMatt Jacob 		break;
291d134aa0bSMatt Jacob #endif
2925d571944SMatt Jacob 	case ISP_SDBLEV:
2935d571944SMatt Jacob 	{
2945d571944SMatt Jacob 		int olddblev = isp->isp_dblev;
2955d571944SMatt Jacob 		isp->isp_dblev = *(int *)addr;
2965d571944SMatt Jacob 		*(int *)addr = olddblev;
2975d571944SMatt Jacob 		retval = 0;
2985d571944SMatt Jacob 		break;
2995d571944SMatt Jacob 	}
3005d571944SMatt Jacob 	case ISP_RESETHBA:
3015d571944SMatt Jacob 		ISP_LOCK(isp);
3025d571944SMatt Jacob 		isp_reinit(isp);
3035d571944SMatt Jacob 		ISP_UNLOCK(isp);
3045d571944SMatt Jacob 		retval = 0;
3055d571944SMatt Jacob 		break;
3065d571944SMatt Jacob 	case ISP_FC_RESCAN:
3075d571944SMatt Jacob 		if (IS_FC(isp)) {
3085d571944SMatt Jacob 			ISP_LOCK(isp);
3095d571944SMatt Jacob 			if (isp_fc_runstate(isp, 5 * 1000000)) {
3105d571944SMatt Jacob 				retval = EIO;
3115d571944SMatt Jacob 			} else {
3125d571944SMatt Jacob 				retval = 0;
3135d571944SMatt Jacob 			}
3145d571944SMatt Jacob 			ISP_UNLOCK(isp);
3155d571944SMatt Jacob 		}
3165d571944SMatt Jacob 		break;
3175d571944SMatt Jacob 	case ISP_FC_LIP:
3185d571944SMatt Jacob 		if (IS_FC(isp)) {
3195d571944SMatt Jacob 			ISP_LOCK(isp);
3205d571944SMatt Jacob 			if (isp_control(isp, ISPCTL_SEND_LIP, 0)) {
3215d571944SMatt Jacob 				retval = EIO;
3225d571944SMatt Jacob 			} else {
3235d571944SMatt Jacob 				retval = 0;
3245d571944SMatt Jacob 			}
3255d571944SMatt Jacob 			ISP_UNLOCK(isp);
3265d571944SMatt Jacob 		}
3275d571944SMatt Jacob 		break;
3285d571944SMatt Jacob 	case ISP_FC_GETDINFO:
3295d571944SMatt Jacob 	{
3305d571944SMatt Jacob 		struct isp_fc_device *ifc = (struct isp_fc_device *) addr;
3315d571944SMatt Jacob 		struct lportdb *lp;
3325d571944SMatt Jacob 
3335d571944SMatt Jacob 		if (ifc->loopid < 0 || ifc->loopid >= MAX_FC_TARG) {
3345d571944SMatt Jacob 			retval = EINVAL;
3355d571944SMatt Jacob 			break;
3365d571944SMatt Jacob 		}
3375d571944SMatt Jacob 		ISP_LOCK(isp);
3385d571944SMatt Jacob 		lp = &FCPARAM(isp)->portdb[ifc->loopid];
3395d571944SMatt Jacob 		if (lp->valid) {
3405d571944SMatt Jacob 			ifc->loopid = lp->loopid;
3415d571944SMatt Jacob 			ifc->portid = lp->portid;
3425d571944SMatt Jacob 			ifc->node_wwn = lp->node_wwn;
3435d571944SMatt Jacob 			ifc->port_wwn = lp->port_wwn;
3445d571944SMatt Jacob 			retval = 0;
3455d571944SMatt Jacob 		} else {
3465d571944SMatt Jacob 			retval = ENODEV;
3475d571944SMatt Jacob 		}
3485d571944SMatt Jacob 		ISP_UNLOCK(isp);
3495d571944SMatt Jacob 		break;
3505d571944SMatt Jacob 	}
3512903b272SMatt Jacob 	case ISP_GET_STATS:
3522903b272SMatt Jacob 	{
3532903b272SMatt Jacob 		isp_stats_t *sp = (isp_stats_t *) addr;
3542903b272SMatt Jacob 
3552903b272SMatt Jacob 		MEMZERO(sp, sizeof (*sp));
3562903b272SMatt Jacob 		sp->isp_stat_version = ISP_STATS_VERSION;
3572903b272SMatt Jacob 		sp->isp_type = isp->isp_type;
3582903b272SMatt Jacob 		sp->isp_revision = isp->isp_revision;
3592903b272SMatt Jacob 		ISP_LOCK(isp);
3602903b272SMatt Jacob 		sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt;
3612903b272SMatt Jacob 		sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus;
3622903b272SMatt Jacob 		sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc;
3632903b272SMatt Jacob 		sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync;
3642903b272SMatt Jacob 		sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt;
3652903b272SMatt Jacob 		sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt;
3662903b272SMatt Jacob 		sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater;
3672903b272SMatt Jacob 		sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater;
3682903b272SMatt Jacob 		ISP_UNLOCK(isp);
3692903b272SMatt Jacob 		retval = 0;
3702903b272SMatt Jacob 		break;
3712903b272SMatt Jacob 	}
3722903b272SMatt Jacob 	case ISP_CLR_STATS:
3732903b272SMatt Jacob 		ISP_LOCK(isp);
3742903b272SMatt Jacob 		isp->isp_intcnt = 0;
3752903b272SMatt Jacob 		isp->isp_intbogus = 0;
3762903b272SMatt Jacob 		isp->isp_intmboxc = 0;
3772903b272SMatt Jacob 		isp->isp_intoasync = 0;
3782903b272SMatt Jacob 		isp->isp_rsltccmplt = 0;
3792903b272SMatt Jacob 		isp->isp_fphccmplt = 0;
3802903b272SMatt Jacob 		isp->isp_rscchiwater = 0;
3812903b272SMatt Jacob 		isp->isp_fpcchiwater = 0;
3822903b272SMatt Jacob 		ISP_UNLOCK(isp);
3832903b272SMatt Jacob 		retval = 0;
3842903b272SMatt Jacob 		break;
3852903b272SMatt Jacob 
3865d571944SMatt Jacob 	default:
3875d571944SMatt Jacob 		break;
3885d571944SMatt Jacob 	}
3895d571944SMatt Jacob 	return (retval);
3900470d791SMatt Jacob }
391478f8a96SJustin T. Gibbs 
392f6e75de2SMatt Jacob static void
393f6e75de2SMatt Jacob isp_intr_enable(void *arg)
394f6e75de2SMatt Jacob {
395f6e75de2SMatt Jacob 	struct ispsoftc *isp = arg;
396d6e5500fSMatt Jacob 	if (isp->isp_role != ISP_ROLE_NONE) {
397f6e75de2SMatt Jacob 		ENABLE_INTS(isp);
398f6e75de2SMatt Jacob 		isp->isp_osinfo.intsok = 1;
399d6e5500fSMatt Jacob 	}
400f6e75de2SMatt Jacob 	/* Release our hook so that the boot can continue. */
401f6e75de2SMatt Jacob 	config_intrhook_disestablish(&isp->isp_osinfo.ehook);
402f6e75de2SMatt Jacob }
403d81ba9d5SMatt Jacob 
404d81ba9d5SMatt Jacob /*
405d81ba9d5SMatt Jacob  * Put the target mode functions here, because some are inlines
406d81ba9d5SMatt Jacob  */
407d81ba9d5SMatt Jacob 
408d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
409d81ba9d5SMatt Jacob 
410a1bc34c6SMatt Jacob static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t);
411a1bc34c6SMatt Jacob static __inline int are_any_luns_enabled(struct ispsoftc *, int);
412a1bc34c6SMatt Jacob static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t);
413d81ba9d5SMatt Jacob static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *);
41464edff94SMatt Jacob static __inline int isp_psema_sig_rqe(struct ispsoftc *, int);
41564edff94SMatt Jacob static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int, int);
41664edff94SMatt Jacob static __inline void isp_cv_signal_rqe(struct ispsoftc *, int, int);
41764edff94SMatt Jacob static __inline void isp_vsema_rqe(struct ispsoftc *, int);
41853036e92SMatt Jacob static __inline atio_private_data_t *isp_get_atpd(struct ispsoftc *, int);
419d81ba9d5SMatt Jacob static cam_status
420a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **);
421d81ba9d5SMatt Jacob static void destroy_lun_state(struct ispsoftc *, tstate_t *);
422d81ba9d5SMatt Jacob static void isp_en_lun(struct ispsoftc *, union ccb *);
423d81ba9d5SMatt Jacob static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *);
424f48ce188SMatt Jacob static timeout_t isp_refire_putback_atio;
425a1bc34c6SMatt Jacob static void isp_complete_ctio(union ccb *);
426a1bc34c6SMatt Jacob static void isp_target_putback_atio(union ccb *);
427a1bc34c6SMatt Jacob static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *);
428d81ba9d5SMatt Jacob static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *);
429d81ba9d5SMatt Jacob static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *);
430d81ba9d5SMatt Jacob static int isp_handle_platform_ctio(struct ispsoftc *, void *);
431d81ba9d5SMatt Jacob 
432d81ba9d5SMatt Jacob static __inline int
433a1bc34c6SMatt Jacob is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
434d81ba9d5SMatt Jacob {
435d81ba9d5SMatt Jacob 	tstate_t *tptr;
436a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
437a1bc34c6SMatt Jacob 	if (tptr == NULL) {
438d81ba9d5SMatt Jacob 		return (0);
439d81ba9d5SMatt Jacob 	}
440d81ba9d5SMatt Jacob 	do {
441a1bc34c6SMatt Jacob 		if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
442d81ba9d5SMatt Jacob 			return (1);
443d81ba9d5SMatt Jacob 		}
444d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
445d81ba9d5SMatt Jacob 	return (0);
446d81ba9d5SMatt Jacob }
447d81ba9d5SMatt Jacob 
448d81ba9d5SMatt Jacob static __inline int
449a1bc34c6SMatt Jacob are_any_luns_enabled(struct ispsoftc *isp, int port)
450d81ba9d5SMatt Jacob {
451a1bc34c6SMatt Jacob 	int lo, hi;
452a1bc34c6SMatt Jacob 	if (IS_DUALBUS(isp)) {
453a1bc34c6SMatt Jacob 		lo = (port * (LUN_HASH_SIZE >> 1));
454a1bc34c6SMatt Jacob 		hi = lo + (LUN_HASH_SIZE >> 1);
455a1bc34c6SMatt Jacob 	} else {
456a1bc34c6SMatt Jacob 		lo = 0;
457a1bc34c6SMatt Jacob 		hi = LUN_HASH_SIZE;
458a1bc34c6SMatt Jacob 	}
459a1bc34c6SMatt Jacob 	for (lo = 0; lo < hi; lo++) {
460a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.lun_hash[lo]) {
461d81ba9d5SMatt Jacob 			return (1);
462d81ba9d5SMatt Jacob 		}
463d81ba9d5SMatt Jacob 	}
464d81ba9d5SMatt Jacob 	return (0);
465d81ba9d5SMatt Jacob }
466d81ba9d5SMatt Jacob 
467d81ba9d5SMatt Jacob static __inline tstate_t *
468a1bc34c6SMatt Jacob get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun)
469d81ba9d5SMatt Jacob {
47064edff94SMatt Jacob 	tstate_t *tptr = NULL;
471d81ba9d5SMatt Jacob 
472d81ba9d5SMatt Jacob 	if (lun == CAM_LUN_WILDCARD) {
47364edff94SMatt Jacob 		if (isp->isp_osinfo.tmflags[bus] & TM_WILDCARD_ENABLED) {
474a1bc34c6SMatt Jacob 			tptr = &isp->isp_osinfo.tsdflt[bus];
475d81ba9d5SMatt Jacob 			tptr->hold++;
476d81ba9d5SMatt Jacob 			return (tptr);
477d81ba9d5SMatt Jacob 		}
478126ec864SMatt Jacob 	} else {
479126ec864SMatt Jacob 		tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
48064edff94SMatt Jacob 		if (tptr == NULL) {
48164edff94SMatt Jacob 			return (NULL);
48264edff94SMatt Jacob 		}
483126ec864SMatt Jacob 	}
484d81ba9d5SMatt Jacob 
485d81ba9d5SMatt Jacob 	do {
486a1bc34c6SMatt Jacob 		if (tptr->lun == lun && tptr->bus == bus) {
487d81ba9d5SMatt Jacob 			tptr->hold++;
488d81ba9d5SMatt Jacob 			return (tptr);
489d81ba9d5SMatt Jacob 		}
490d81ba9d5SMatt Jacob 	} while ((tptr = tptr->next) != NULL);
491d81ba9d5SMatt Jacob 	return (tptr);
492d81ba9d5SMatt Jacob }
493d81ba9d5SMatt Jacob 
494d81ba9d5SMatt Jacob static __inline void
495d81ba9d5SMatt Jacob rls_lun_statep(struct ispsoftc *isp, tstate_t *tptr)
496d81ba9d5SMatt Jacob {
497d81ba9d5SMatt Jacob 	if (tptr->hold)
498d81ba9d5SMatt Jacob 		tptr->hold--;
499d81ba9d5SMatt Jacob }
500d81ba9d5SMatt Jacob 
501d81ba9d5SMatt Jacob static __inline int
50264edff94SMatt Jacob isp_psema_sig_rqe(struct ispsoftc *isp, int bus)
503d81ba9d5SMatt Jacob {
50464edff94SMatt Jacob 	while (isp->isp_osinfo.tmflags[bus] & TM_BUSY) {
50564edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_WANTED;
50664edff94SMatt Jacob 		if (cv_wait_sig(&isp->isp_osinfo.tgtcv0[bus], &isp->isp_lock)) {
507d81ba9d5SMatt Jacob 			return (-1);
508d81ba9d5SMatt Jacob 		}
50964edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_BUSY;
510d81ba9d5SMatt Jacob 	}
511d81ba9d5SMatt Jacob 	return (0);
512d81ba9d5SMatt Jacob }
513d81ba9d5SMatt Jacob 
514d81ba9d5SMatt Jacob static __inline int
51564edff94SMatt Jacob isp_cv_wait_timed_rqe(struct ispsoftc *isp, int bus, int timo)
516d81ba9d5SMatt Jacob {
51764edff94SMatt Jacob 	if (cv_timedwait(&isp->isp_osinfo.tgtcv1[bus], &isp->isp_lock, timo)) {
518d81ba9d5SMatt Jacob 		return (-1);
519d81ba9d5SMatt Jacob 	}
520d81ba9d5SMatt Jacob 	return (0);
521d81ba9d5SMatt Jacob }
522d81ba9d5SMatt Jacob 
523d81ba9d5SMatt Jacob static __inline void
52464edff94SMatt Jacob isp_cv_signal_rqe(struct ispsoftc *isp, int bus, int status)
525d81ba9d5SMatt Jacob {
52664edff94SMatt Jacob 	isp->isp_osinfo.rstatus[bus] = status;
52764edff94SMatt Jacob 	cv_signal(&isp->isp_osinfo.tgtcv1[bus]);
528d81ba9d5SMatt Jacob }
529d81ba9d5SMatt Jacob 
530d81ba9d5SMatt Jacob static __inline void
53164edff94SMatt Jacob isp_vsema_rqe(struct ispsoftc *isp, int bus)
532d81ba9d5SMatt Jacob {
53364edff94SMatt Jacob 	if (isp->isp_osinfo.tmflags[bus] & TM_WANTED) {
53464edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_WANTED;
53564edff94SMatt Jacob 		cv_signal(&isp->isp_osinfo.tgtcv0[bus]);
536d81ba9d5SMatt Jacob 	}
53764edff94SMatt Jacob 	isp->isp_osinfo.tmflags[bus] &= ~TM_BUSY;
538d81ba9d5SMatt Jacob }
539d81ba9d5SMatt Jacob 
54053036e92SMatt Jacob static __inline atio_private_data_t *
54153036e92SMatt Jacob isp_get_atpd(struct ispsoftc *isp, int tag)
54253036e92SMatt Jacob {
54353036e92SMatt Jacob 	atio_private_data_t *atp;
54453036e92SMatt Jacob 	for (atp = isp->isp_osinfo.atpdp;
54553036e92SMatt Jacob 	    atp < &isp->isp_osinfo.atpdp[ATPDPSIZE]; atp++) {
54653036e92SMatt Jacob 		if (atp->tag == tag)
54753036e92SMatt Jacob 			return (atp);
54853036e92SMatt Jacob 	}
54953036e92SMatt Jacob 	return (NULL);
55053036e92SMatt Jacob }
55153036e92SMatt Jacob 
552d81ba9d5SMatt Jacob static cam_status
553a1bc34c6SMatt Jacob create_lun_state(struct ispsoftc *isp, int bus,
554a1bc34c6SMatt Jacob     struct cam_path *path, tstate_t **rslt)
555d81ba9d5SMatt Jacob {
556d81ba9d5SMatt Jacob 	cam_status status;
557d81ba9d5SMatt Jacob 	lun_id_t lun;
558a1bc34c6SMatt Jacob 	int hfx;
559d81ba9d5SMatt Jacob 	tstate_t *tptr, *new;
560d81ba9d5SMatt Jacob 
561d81ba9d5SMatt Jacob 	lun = xpt_path_lun_id(path);
562d81ba9d5SMatt Jacob 	if (lun < 0) {
563d81ba9d5SMatt Jacob 		return (CAM_LUN_INVALID);
564d81ba9d5SMatt Jacob 	}
565a1bc34c6SMatt Jacob 	if (is_lun_enabled(isp, bus, lun)) {
566d81ba9d5SMatt Jacob 		return (CAM_LUN_ALRDY_ENA);
567d81ba9d5SMatt Jacob 	}
568ea8b5a9aSDavid Malone 	new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
569d81ba9d5SMatt Jacob 	if (new == NULL) {
570d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
571d81ba9d5SMatt Jacob 	}
572d81ba9d5SMatt Jacob 
573d81ba9d5SMatt Jacob 	status = xpt_create_path(&new->owner, NULL, xpt_path_path_id(path),
574d81ba9d5SMatt Jacob 	    xpt_path_target_id(path), xpt_path_lun_id(path));
575d81ba9d5SMatt Jacob 	if (status != CAM_REQ_CMP) {
576d81ba9d5SMatt Jacob 		free(new, M_DEVBUF);
577d81ba9d5SMatt Jacob 		return (status);
578d81ba9d5SMatt Jacob 	}
579a1bc34c6SMatt Jacob 	new->bus = bus;
580d81ba9d5SMatt Jacob 	new->lun = lun;
581d81ba9d5SMatt Jacob 	SLIST_INIT(&new->atios);
582d81ba9d5SMatt Jacob 	SLIST_INIT(&new->inots);
583d81ba9d5SMatt Jacob 	new->hold = 1;
584d81ba9d5SMatt Jacob 
585a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
586a1bc34c6SMatt Jacob 	tptr = isp->isp_osinfo.lun_hash[hfx];
587a1bc34c6SMatt Jacob 	if (tptr == NULL) {
588a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = new;
589d81ba9d5SMatt Jacob 	} else {
590d81ba9d5SMatt Jacob 		while (tptr->next)
591d81ba9d5SMatt Jacob 			tptr = tptr->next;
592d81ba9d5SMatt Jacob 		tptr->next = new;
593d81ba9d5SMatt Jacob 	}
594d81ba9d5SMatt Jacob 	*rslt = new;
595d81ba9d5SMatt Jacob 	return (CAM_REQ_CMP);
596d81ba9d5SMatt Jacob }
597d81ba9d5SMatt Jacob 
598d81ba9d5SMatt Jacob static __inline void
599d81ba9d5SMatt Jacob destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
600d81ba9d5SMatt Jacob {
601a1bc34c6SMatt Jacob 	int hfx;
602d81ba9d5SMatt Jacob 	tstate_t *lw, *pw;
603d81ba9d5SMatt Jacob 
604a1bc34c6SMatt Jacob 	hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
605d81ba9d5SMatt Jacob 	if (tptr->hold) {
606d81ba9d5SMatt Jacob 		return;
607d81ba9d5SMatt Jacob 	}
608a1bc34c6SMatt Jacob 	pw = isp->isp_osinfo.lun_hash[hfx];
609d81ba9d5SMatt Jacob 	if (pw == NULL) {
610d81ba9d5SMatt Jacob 		return;
611a1bc34c6SMatt Jacob 	} else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
612a1bc34c6SMatt Jacob 		isp->isp_osinfo.lun_hash[hfx] = pw->next;
613d81ba9d5SMatt Jacob 	} else {
614d81ba9d5SMatt Jacob 		lw = pw;
615d81ba9d5SMatt Jacob 		pw = lw->next;
616d81ba9d5SMatt Jacob 		while (pw) {
617a1bc34c6SMatt Jacob 			if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
618d81ba9d5SMatt Jacob 				lw->next = pw->next;
619d81ba9d5SMatt Jacob 				break;
620d81ba9d5SMatt Jacob 			}
621d81ba9d5SMatt Jacob 			lw = pw;
622d81ba9d5SMatt Jacob 			pw = pw->next;
623d81ba9d5SMatt Jacob 		}
624d81ba9d5SMatt Jacob 		if (pw == NULL) {
625d81ba9d5SMatt Jacob 			return;
626d81ba9d5SMatt Jacob 		}
627d81ba9d5SMatt Jacob 	}
628d81ba9d5SMatt Jacob 	free(tptr, M_DEVBUF);
629d81ba9d5SMatt Jacob }
630d81ba9d5SMatt Jacob 
6315d571944SMatt Jacob /*
6325d571944SMatt Jacob  * we enter with our locks held.
6335d571944SMatt Jacob  */
634d81ba9d5SMatt Jacob static void
635d81ba9d5SMatt Jacob isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
636d81ba9d5SMatt Jacob {
637a1bc34c6SMatt Jacob 	const char lfmt[] = "Lun now %sabled for target mode on channel %d";
638d81ba9d5SMatt Jacob 	struct ccb_en_lun *cel = &ccb->cel;
639d81ba9d5SMatt Jacob 	tstate_t *tptr;
640d81ba9d5SMatt Jacob 	u_int16_t rstat;
64164edff94SMatt Jacob 	int bus, cmd, av, wildcard;
642d81ba9d5SMatt Jacob 	lun_id_t lun;
643d81ba9d5SMatt Jacob 	target_id_t tgt;
644d81ba9d5SMatt Jacob 
645d81ba9d5SMatt Jacob 
646a1bc34c6SMatt Jacob 	bus = XS_CHANNEL(ccb) & 0x1;
647d81ba9d5SMatt Jacob 	tgt = ccb->ccb_h.target_id;
648d81ba9d5SMatt Jacob 	lun = ccb->ccb_h.target_lun;
649d81ba9d5SMatt Jacob 
650d81ba9d5SMatt Jacob 	/*
651d81ba9d5SMatt Jacob 	 * Do some sanity checking first.
652d81ba9d5SMatt Jacob 	 */
653d81ba9d5SMatt Jacob 
654d6e5500fSMatt Jacob 	if ((lun != CAM_LUN_WILDCARD) &&
655d6e5500fSMatt Jacob 	    (lun < 0 || lun >= (lun_id_t) isp->isp_maxluns)) {
656d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_LUN_INVALID;
657d81ba9d5SMatt Jacob 		return;
658d81ba9d5SMatt Jacob 	}
65964edff94SMatt Jacob 
6602ad50ca5SMatt Jacob 	if (IS_SCSI(isp)) {
661a1bc34c6SMatt Jacob 		sdparam *sdp = isp->isp_param;
662a1bc34c6SMatt Jacob 		sdp += bus;
663d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
664a1bc34c6SMatt Jacob 		    tgt != sdp->isp_initiator_id) {
665d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
666d81ba9d5SMatt Jacob 			return;
667d81ba9d5SMatt Jacob 		}
668d81ba9d5SMatt Jacob 	} else {
669d81ba9d5SMatt Jacob 		if (tgt != CAM_TARGET_WILDCARD &&
670d6e5500fSMatt Jacob 		    tgt != FCPARAM(isp)->isp_iid) {
671d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_TID_INVALID;
672d81ba9d5SMatt Jacob 			return;
673d81ba9d5SMatt Jacob 		}
67464edff94SMatt Jacob 		/*
67564edff94SMatt Jacob 		 * This is as a good a place as any to check f/w capabilities.
67664edff94SMatt Jacob 		 */
67764edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) == 0) {
67864edff94SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
67964edff94SMatt Jacob 			    "firmware does not support target mode");
68064edff94SMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
68164edff94SMatt Jacob 			return;
68264edff94SMatt Jacob 		}
68364edff94SMatt Jacob 		/*
68464edff94SMatt Jacob 		 * XXX: We *could* handle non-SCCLUN f/w, but we'd have to
68564edff94SMatt Jacob 		 * XXX: dorks with our already fragile enable/disable code.
68664edff94SMatt Jacob 		 */
68764edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
68864edff94SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
68964edff94SMatt Jacob 			    "firmware not SCCLUN capable");
69064edff94SMatt Jacob 		}
691d81ba9d5SMatt Jacob 	}
692d81ba9d5SMatt Jacob 
693d6e5500fSMatt Jacob 	if (tgt == CAM_TARGET_WILDCARD) {
69464edff94SMatt Jacob 		if (lun == CAM_LUN_WILDCARD) {
69564edff94SMatt Jacob 			wildcard = 1;
69664edff94SMatt Jacob 		} else {
697d6e5500fSMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
698d6e5500fSMatt Jacob 			return;
699d6e5500fSMatt Jacob 		}
700126ec864SMatt Jacob 	} else {
701126ec864SMatt Jacob 		wildcard = 0;
702126ec864SMatt Jacob 	}
703b6b6ad2fSMatt Jacob 
704b6b6ad2fSMatt Jacob 	/*
705b6b6ad2fSMatt Jacob 	 * Next check to see whether this is a target/lun wildcard action.
70664edff94SMatt Jacob 	 *
70764edff94SMatt Jacob 	 * If so, we know that we can accept commands for luns that haven't
70864edff94SMatt Jacob 	 * been enabled yet and send them upstream. Otherwise, we have to
70964edff94SMatt Jacob 	 * handle them locally (if we see them at all).
710b6b6ad2fSMatt Jacob 	 */
711126ec864SMatt Jacob 
712126ec864SMatt Jacob 	if (wildcard) {
713a1bc34c6SMatt Jacob 		tptr = &isp->isp_osinfo.tsdflt[bus];
714b6b6ad2fSMatt Jacob 		if (cel->enable) {
71564edff94SMatt Jacob 			if (isp->isp_osinfo.tmflags[bus] &
71664edff94SMatt Jacob 			    TM_WILDCARD_ENABLED) {
717b6b6ad2fSMatt Jacob 				ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
718b6b6ad2fSMatt Jacob 				return;
719b6b6ad2fSMatt Jacob 			}
720b6b6ad2fSMatt Jacob 			ccb->ccb_h.status =
721b6b6ad2fSMatt Jacob 			    xpt_create_path(&tptr->owner, NULL,
722b6b6ad2fSMatt Jacob 			    xpt_path_path_id(ccb->ccb_h.path),
723b6b6ad2fSMatt Jacob 			    xpt_path_target_id(ccb->ccb_h.path),
724b6b6ad2fSMatt Jacob 			    xpt_path_lun_id(ccb->ccb_h.path));
725b6b6ad2fSMatt Jacob 			if (ccb->ccb_h.status != CAM_REQ_CMP) {
726b6b6ad2fSMatt Jacob 				return;
727b6b6ad2fSMatt Jacob 			}
728b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->atios);
729b6b6ad2fSMatt Jacob 			SLIST_INIT(&tptr->inots);
73064edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] |= TM_WILDCARD_ENABLED;
731126ec864SMatt Jacob 		} else {
73264edff94SMatt Jacob 			if ((isp->isp_osinfo.tmflags[bus] &
73364edff94SMatt Jacob 			    TM_WILDCARD_ENABLED) == 0) {
734126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_REQ_CMP;
735126ec864SMatt Jacob 				return;
736126ec864SMatt Jacob 			}
737126ec864SMatt Jacob 			if (tptr->hold) {
738126ec864SMatt Jacob 				ccb->ccb_h.status = CAM_SCSI_BUSY;
739126ec864SMatt Jacob 				return;
740126ec864SMatt Jacob 			}
741126ec864SMatt Jacob 			xpt_free_path(tptr->owner);
74264edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_WILDCARD_ENABLED;
743126ec864SMatt Jacob 		}
744126ec864SMatt Jacob 	}
745126ec864SMatt Jacob 
746126ec864SMatt Jacob 	/*
747126ec864SMatt Jacob 	 * Now check to see whether this bus needs to be
748126ec864SMatt Jacob 	 * enabled/disabled with respect to target mode.
749126ec864SMatt Jacob 	 */
750126ec864SMatt Jacob 	av = bus << 31;
75164edff94SMatt Jacob 	if (cel->enable && !(isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED)) {
752a1bc34c6SMatt Jacob 		av |= ENABLE_TARGET_FLAG;
753b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
754b6b6ad2fSMatt Jacob 		if (av) {
755b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
756126ec864SMatt Jacob 			if (wildcard) {
75764edff94SMatt Jacob 				isp->isp_osinfo.tmflags[bus] &=
75864edff94SMatt Jacob 				    ~TM_WILDCARD_ENABLED;
759b6b6ad2fSMatt Jacob 				xpt_free_path(tptr->owner);
7605d571944SMatt Jacob 			}
761b6b6ad2fSMatt Jacob 			return;
762b6b6ad2fSMatt Jacob 		}
76364edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] |= TM_TMODE_ENABLED;
764126ec864SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
765126ec864SMatt Jacob 		    "Target Mode enabled on channel %d", bus);
76664edff94SMatt Jacob 	} else if (cel->enable == 0 &&
76764edff94SMatt Jacob 	    (isp->isp_osinfo.tmflags[bus] & TM_TMODE_ENABLED) && wildcard) {
768a1bc34c6SMatt Jacob 		if (are_any_luns_enabled(isp, bus)) {
769b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_SCSI_BUSY;
770b6b6ad2fSMatt Jacob 			return;
771b6b6ad2fSMatt Jacob 		}
772b6b6ad2fSMatt Jacob 		av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
773b6b6ad2fSMatt Jacob 		if (av) {
774b6b6ad2fSMatt Jacob 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
775b6b6ad2fSMatt Jacob 			return;
776b6b6ad2fSMatt Jacob 		}
77764edff94SMatt Jacob 		isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
778126ec864SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
779126ec864SMatt Jacob 		    "Target Mode disabled on channel %d", bus);
780126ec864SMatt Jacob 	}
781126ec864SMatt Jacob 
782126ec864SMatt Jacob 	if (wildcard) {
78364edff94SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
784b6b6ad2fSMatt Jacob 		return;
785b6b6ad2fSMatt Jacob 	}
786b6b6ad2fSMatt Jacob 
787d81ba9d5SMatt Jacob 	if (cel->enable) {
788d81ba9d5SMatt Jacob 		ccb->ccb_h.status =
789a1bc34c6SMatt Jacob 		    create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
790d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
791d81ba9d5SMatt Jacob 			return;
792d81ba9d5SMatt Jacob 		}
793d81ba9d5SMatt Jacob 	} else {
794a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, lun);
795d81ba9d5SMatt Jacob 		if (tptr == NULL) {
796d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
797d81ba9d5SMatt Jacob 			return;
798d81ba9d5SMatt Jacob 		}
799d81ba9d5SMatt Jacob 	}
800d81ba9d5SMatt Jacob 
80164edff94SMatt Jacob 	if (isp_psema_sig_rqe(isp, bus)) {
802d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
803d81ba9d5SMatt Jacob 		if (cel->enable)
804d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
805d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
806d81ba9d5SMatt Jacob 		return;
807d81ba9d5SMatt Jacob 	}
808d81ba9d5SMatt Jacob 
809d81ba9d5SMatt Jacob 	if (cel->enable) {
810d81ba9d5SMatt Jacob 		u_int32_t seq = isp->isp_osinfo.rollinfo++;
8115d571944SMatt Jacob 		int c, n, ulun = lun;
8125d571944SMatt Jacob 
8135d571944SMatt Jacob 		cmd = RQSTYPE_ENABLE_LUN;
8145d571944SMatt Jacob 		c = DFLT_CMND_CNT;
8155d571944SMatt Jacob 		n = DFLT_INOT_CNT;
8165d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
8175d571944SMatt Jacob 			cmd = RQSTYPE_MODIFY_LUN;
8185d571944SMatt Jacob 			n = 0;
8195d571944SMatt Jacob 			/*
8205d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
8215d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
8225d571944SMatt Jacob 			 */
8235d571944SMatt Jacob 			ulun = 0;
8245d571944SMatt Jacob 		}
825d81ba9d5SMatt Jacob 		rstat = LUN_ERR;
8265d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) {
827d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8283c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN, "isp_lun_cmd failed");
829d81ba9d5SMatt Jacob 			goto out;
830d81ba9d5SMatt Jacob 		}
83164edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
832d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8333c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
8345d571944SMatt Jacob 			    "wait for ENABLE/MODIFY LUN timed out");
835d81ba9d5SMatt Jacob 			goto out;
836d81ba9d5SMatt Jacob 		}
83764edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
838d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
839d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8403c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
8415d571944SMatt Jacob 			    "ENABLE/MODIFY LUN returned 0x%x", rstat);
842d81ba9d5SMatt Jacob 			goto out;
843d81ba9d5SMatt Jacob 		}
844d81ba9d5SMatt Jacob 	} else {
8455d571944SMatt Jacob 		int c, n, ulun = lun;
846d81ba9d5SMatt Jacob 		u_int32_t seq;
847d81ba9d5SMatt Jacob 
848d81ba9d5SMatt Jacob 		rstat = LUN_ERR;
8495d571944SMatt Jacob 		seq = isp->isp_osinfo.rollinfo++;
8505d571944SMatt Jacob 		cmd = -RQSTYPE_MODIFY_LUN;
851d81ba9d5SMatt Jacob 
8525d571944SMatt Jacob 		c = DFLT_CMND_CNT;
8535d571944SMatt Jacob 		n = DFLT_INOT_CNT;
8545d571944SMatt Jacob 		if (IS_FC(isp) && lun != 0) {
8555d571944SMatt Jacob 			n = 0;
8565d571944SMatt Jacob 			/*
8575d571944SMatt Jacob 		 	 * For SCC firmware, we only deal with setting
8585d571944SMatt Jacob 			 * (enabling or modifying) lun 0.
8595d571944SMatt Jacob 			 */
8605d571944SMatt Jacob 			ulun = 0;
8615d571944SMatt Jacob 		}
8625d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, c, n, seq)) {
863d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8643c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed");
865d81ba9d5SMatt Jacob 			goto out;
866d81ba9d5SMatt Jacob 		}
86764edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
868d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8693c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
8703c75bb14SMatt Jacob 			    "wait for MODIFY LUN timed out");
871d81ba9d5SMatt Jacob 			goto out;
872d81ba9d5SMatt Jacob 		}
87364edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
874d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
875d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8763c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
8773c75bb14SMatt Jacob 			    "MODIFY LUN returned 0x%x", rstat);
878d81ba9d5SMatt Jacob 			goto out;
879d81ba9d5SMatt Jacob 		}
8805d571944SMatt Jacob 		if (IS_FC(isp) && lun) {
8815d571944SMatt Jacob 			goto out;
8825d571944SMatt Jacob 		}
8835d571944SMatt Jacob 
884d81ba9d5SMatt Jacob 		seq = isp->isp_osinfo.rollinfo++;
885d81ba9d5SMatt Jacob 
8865d571944SMatt Jacob 		rstat = LUN_ERR;
8875d571944SMatt Jacob 		cmd = -RQSTYPE_ENABLE_LUN;
8885d571944SMatt Jacob 		if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) {
889d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8903c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed");
891d81ba9d5SMatt Jacob 			goto out;
892d81ba9d5SMatt Jacob 		}
89364edff94SMatt Jacob 		if (isp_cv_wait_timed_rqe(isp, bus, 30 * hz)) {
894d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
8953c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
8965d571944SMatt Jacob 			     "wait for DISABLE LUN timed out");
897d81ba9d5SMatt Jacob 			goto out;
898d81ba9d5SMatt Jacob 		}
89964edff94SMatt Jacob 		rstat = isp->isp_osinfo.rstatus[bus];
900d81ba9d5SMatt Jacob 		if (rstat != LUN_OK) {
901d81ba9d5SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
9023c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
9035d571944SMatt Jacob 			    "DISABLE LUN returned 0x%x", rstat);
904d81ba9d5SMatt Jacob 			goto out;
905d81ba9d5SMatt Jacob 		}
906126ec864SMatt Jacob 		if (are_any_luns_enabled(isp, bus) == 0) {
907126ec864SMatt Jacob 			av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
908126ec864SMatt Jacob 			if (av) {
909126ec864SMatt Jacob 				isp_prt(isp, ISP_LOGWARN,
910126ec864SMatt Jacob 				    "disable target mode on channel %d failed",
911126ec864SMatt Jacob 				    bus);
912126ec864SMatt Jacob 				goto out;
913d81ba9d5SMatt Jacob 			}
91464edff94SMatt Jacob 			isp->isp_osinfo.tmflags[bus] &= ~TM_TMODE_ENABLED;
915126ec864SMatt Jacob 			xpt_print_path(ccb->ccb_h.path);
916126ec864SMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
917126ec864SMatt Jacob 			    "Target Mode disabled on channel %d", bus);
918126ec864SMatt Jacob 		}
919126ec864SMatt Jacob 	}
920126ec864SMatt Jacob 
921d81ba9d5SMatt Jacob out:
92264edff94SMatt Jacob 	isp_vsema_rqe(isp, bus);
923d81ba9d5SMatt Jacob 
924d81ba9d5SMatt Jacob 	if (rstat != LUN_OK) {
925d81ba9d5SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
9263c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
9273c75bb14SMatt Jacob 		    "lun %sable failed", (cel->enable) ? "en" : "dis");
928d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
929d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
930d81ba9d5SMatt Jacob 		if (cel->enable)
931d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
932d81ba9d5SMatt Jacob 	} else {
933d81ba9d5SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
934a1bc34c6SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, lfmt,
935a1bc34c6SMatt Jacob 		    (cel->enable) ? "en" : "dis", bus);
936d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
937d81ba9d5SMatt Jacob 		if (cel->enable == 0) {
938d81ba9d5SMatt Jacob 			destroy_lun_state(isp, tptr);
939d81ba9d5SMatt Jacob 		}
940d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_CMP;
941d81ba9d5SMatt Jacob 	}
942d81ba9d5SMatt Jacob }
943d81ba9d5SMatt Jacob 
944d81ba9d5SMatt Jacob static cam_status
945d81ba9d5SMatt Jacob isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb)
946d81ba9d5SMatt Jacob {
947d81ba9d5SMatt Jacob 	tstate_t *tptr;
948d81ba9d5SMatt Jacob 	struct ccb_hdr_slist *lp;
949d81ba9d5SMatt Jacob 	struct ccb_hdr *curelm;
950d81ba9d5SMatt Jacob 	int found;
951d81ba9d5SMatt Jacob 	union ccb *accb = ccb->cab.abort_ccb;
952d81ba9d5SMatt Jacob 
953d81ba9d5SMatt Jacob 	if (accb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
954d81ba9d5SMatt Jacob 		if (IS_FC(isp) && (accb->ccb_h.target_id !=
955d81ba9d5SMatt Jacob 		    ((fcparam *) isp->isp_param)->isp_loopid)) {
956d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
957d81ba9d5SMatt Jacob 		} else if (IS_SCSI(isp) && (accb->ccb_h.target_id !=
958d81ba9d5SMatt Jacob 		    ((sdparam *) isp->isp_param)->isp_initiator_id)) {
959d81ba9d5SMatt Jacob 			return (CAM_PATH_INVALID);
960d81ba9d5SMatt Jacob 		}
961d81ba9d5SMatt Jacob 	}
962a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
963d81ba9d5SMatt Jacob 	if (tptr == NULL) {
964d81ba9d5SMatt Jacob 		return (CAM_PATH_INVALID);
965d81ba9d5SMatt Jacob 	}
966d81ba9d5SMatt Jacob 	if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
967d81ba9d5SMatt Jacob 		lp = &tptr->atios;
968d81ba9d5SMatt Jacob 	} else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
969d81ba9d5SMatt Jacob 		lp = &tptr->inots;
970d81ba9d5SMatt Jacob 	} else {
971d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
972d81ba9d5SMatt Jacob 		return (CAM_UA_ABORT);
973d81ba9d5SMatt Jacob 	}
974d81ba9d5SMatt Jacob 	curelm = SLIST_FIRST(lp);
975d81ba9d5SMatt Jacob 	found = 0;
976d81ba9d5SMatt Jacob 	if (curelm == &accb->ccb_h) {
977d81ba9d5SMatt Jacob 		found = 1;
978d81ba9d5SMatt Jacob 		SLIST_REMOVE_HEAD(lp, sim_links.sle);
979d81ba9d5SMatt Jacob 	} else {
980d81ba9d5SMatt Jacob 		while(curelm != NULL) {
981d81ba9d5SMatt Jacob 			struct ccb_hdr *nextelm;
982d81ba9d5SMatt Jacob 
983d81ba9d5SMatt Jacob 			nextelm = SLIST_NEXT(curelm, sim_links.sle);
984d81ba9d5SMatt Jacob 			if (nextelm == &accb->ccb_h) {
985d81ba9d5SMatt Jacob 				found = 1;
986d81ba9d5SMatt Jacob 				SLIST_NEXT(curelm, sim_links.sle) =
987d81ba9d5SMatt Jacob 				    SLIST_NEXT(nextelm, sim_links.sle);
988d81ba9d5SMatt Jacob 				break;
989d81ba9d5SMatt Jacob 			}
990d81ba9d5SMatt Jacob 			curelm = nextelm;
991d81ba9d5SMatt Jacob 		}
992d81ba9d5SMatt Jacob 	}
993d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
994d81ba9d5SMatt Jacob 	if (found) {
995d81ba9d5SMatt Jacob 		accb->ccb_h.status = CAM_REQ_ABORTED;
996d81ba9d5SMatt Jacob 		return (CAM_REQ_CMP);
997d81ba9d5SMatt Jacob 	}
998d81ba9d5SMatt Jacob 	return(CAM_PATH_INVALID);
999d81ba9d5SMatt Jacob }
1000d81ba9d5SMatt Jacob 
1001d81ba9d5SMatt Jacob static cam_status
1002d81ba9d5SMatt Jacob isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
1003d81ba9d5SMatt Jacob {
1004d81ba9d5SMatt Jacob 	void *qe;
100500a8e174SMatt Jacob 	struct ccb_scsiio *cso = &ccb->csio;
10065f5aafe1SMatt Jacob 	u_int16_t *hp, save_handle;
10074fd13c1bSMatt Jacob 	u_int16_t nxti, optr;
10084fd13c1bSMatt Jacob 	u_int8_t local[QENTRY_LEN];
1009d81ba9d5SMatt Jacob 
1010f48ce188SMatt Jacob 
10114fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
101292a1e549SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
101392a1e549SMatt Jacob 		printf("Request Queue Overflow in isp_target_start_ctio\n");
1014d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1015d81ba9d5SMatt Jacob 	}
10164fd13c1bSMatt Jacob 	bzero(local, QENTRY_LEN);
1017d81ba9d5SMatt Jacob 
1018d81ba9d5SMatt Jacob 	/*
1019d81ba9d5SMatt Jacob 	 * We're either moving data or completing a command here.
1020d81ba9d5SMatt Jacob 	 */
1021d81ba9d5SMatt Jacob 
1022d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
102353036e92SMatt Jacob 		atio_private_data_t *atp;
10244fd13c1bSMatt Jacob 		ct2_entry_t *cto = (ct2_entry_t *) local;
102500a8e174SMatt Jacob 
1026d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
1027d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
102800a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
102964edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
1030d81ba9d5SMatt Jacob 			cto->ct_lun = ccb->ccb_h.target_lun;
10312ad50ca5SMatt Jacob 		}
103253036e92SMatt Jacob 
103353036e92SMatt Jacob 		atp = isp_get_atpd(isp, cso->tag_id);
103453036e92SMatt Jacob 		if (atp == NULL) {
103553036e92SMatt Jacob 			panic("cannot find private data adjunct for tag %x",
103653036e92SMatt Jacob 			    cso->tag_id);
103753036e92SMatt Jacob 		}
1038f48ce188SMatt Jacob 
103900a8e174SMatt Jacob 		cto->ct_rxid = cso->tag_id;
104000a8e174SMatt Jacob 		if (cso->dxfer_len == 0) {
104100a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
1042f48ce188SMatt Jacob 			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
104300a8e174SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
1044f48ce188SMatt Jacob 				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
104553036e92SMatt Jacob 				cto->ct_resid =
104653036e92SMatt Jacob 				    atp->orig_datalen - atp->bytes_xfered;
1047f48ce188SMatt Jacob 			}
104800a8e174SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
104900a8e174SMatt Jacob 				int m = min(cso->sense_len, MAXRESPLEN);
105000a8e174SMatt Jacob 				bcopy(&cso->sense_data, cto->rsp.m1.ct_resp, m);
105100a8e174SMatt Jacob 				cto->rsp.m1.ct_senselen = m;
105200a8e174SMatt Jacob 				cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
105300a8e174SMatt Jacob 			}
105400a8e174SMatt Jacob 		} else {
105500a8e174SMatt Jacob 			cto->ct_flags |= CT2_FLAG_MODE0;
105600a8e174SMatt Jacob 			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
105700a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_IN;
105800a8e174SMatt Jacob 			} else {
105900a8e174SMatt Jacob 				cto->ct_flags |= CT2_DATA_OUT;
1060d81ba9d5SMatt Jacob 			}
1061d81ba9d5SMatt Jacob 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
1062d81ba9d5SMatt Jacob 				cto->ct_flags |= CT2_SENDSTATUS;
106300a8e174SMatt Jacob 				cto->rsp.m0.ct_scsi_status = cso->scsi_status;
106453036e92SMatt Jacob 				cto->ct_resid =
106553036e92SMatt Jacob 				    atp->orig_datalen -
106653036e92SMatt Jacob 				    (atp->bytes_xfered + cso->dxfer_len);
106753036e92SMatt Jacob 			} else {
106853036e92SMatt Jacob 				atp->last_xframt = cso->dxfer_len;
1069d81ba9d5SMatt Jacob 			}
1070f48ce188SMatt Jacob 			/*
1071f48ce188SMatt Jacob 			 * If we're sending data and status back together,
1072f48ce188SMatt Jacob 			 * we can't also send back sense data as well.
1073f48ce188SMatt Jacob 			 */
107400a8e174SMatt Jacob 			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
107500a8e174SMatt Jacob 		}
107653036e92SMatt Jacob 
1077290dc24bSMatt Jacob 		if (cto->ct_flags & CT2_SENDSTATUS) {
107864edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
107953036e92SMatt Jacob 			    "CTIO2[%x] STATUS %x origd %u curd %u resid %u",
108053036e92SMatt Jacob 			    cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
108153036e92SMatt Jacob 			    cso->dxfer_len, cto->ct_resid);
1082a1bc34c6SMatt Jacob 			cto->ct_flags |= CT2_CCINCR;
108364edff94SMatt Jacob 		}
1084a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
10855f5aafe1SMatt Jacob 		hp = &cto->ct_syshandle;
1086d81ba9d5SMatt Jacob 	} else {
10874fd13c1bSMatt Jacob 		ct_entry_t *cto = (ct_entry_t *) local;
108800a8e174SMatt Jacob 
1089d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
1090d81ba9d5SMatt Jacob 		cto->ct_header.rqs_entry_count = 1;
109100a8e174SMatt Jacob 		cto->ct_iid = cso->init_id;
1092a1bc34c6SMatt Jacob 		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
1093d81ba9d5SMatt Jacob 		cto->ct_tgt = ccb->ccb_h.target_id;
1094d81ba9d5SMatt Jacob 		cto->ct_lun = ccb->ccb_h.target_lun;
1095a1bc34c6SMatt Jacob 		cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
1096a1bc34c6SMatt Jacob 		if (AT_HAS_TAG(cso->tag_id)) {
1097a1bc34c6SMatt Jacob 			cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id);
1098f48ce188SMatt Jacob 			cto->ct_flags |= CT_TQAE;
1099f48ce188SMatt Jacob 		}
1100f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
1101f48ce188SMatt Jacob 			cto->ct_flags |= CT_NODISC;
1102f48ce188SMatt Jacob 		}
1103f48ce188SMatt Jacob 		if (cso->dxfer_len == 0) {
1104d81ba9d5SMatt Jacob 			cto->ct_flags |= CT_NO_DATA;
110500a8e174SMatt Jacob 		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
110600a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_IN;
110700a8e174SMatt Jacob 		} else {
110800a8e174SMatt Jacob 			cto->ct_flags |= CT_DATA_OUT;
1109d81ba9d5SMatt Jacob 		}
1110f48ce188SMatt Jacob 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
111153036e92SMatt Jacob 			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
111200a8e174SMatt Jacob 			cto->ct_scsi_status = cso->scsi_status;
111300a8e174SMatt Jacob 			cto->ct_resid = cso->resid;
111464edff94SMatt Jacob 			isp_prt(isp, ISP_LOGTDEBUG0,
1115a1bc34c6SMatt Jacob 			    "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
1116a1bc34c6SMatt Jacob 			    cto->ct_fwhandle, cso->scsi_status, cso->resid,
1117a1bc34c6SMatt Jacob 			    cso->tag_id);
111892a1e549SMatt Jacob 		}
111964edff94SMatt Jacob 		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
1120a1bc34c6SMatt Jacob 		cto->ct_timeout = 10;
11215f5aafe1SMatt Jacob 		hp = &cto->ct_syshandle;
1122d81ba9d5SMatt Jacob 	}
1123d81ba9d5SMatt Jacob 
1124b09b0095SMatt Jacob 	if (isp_save_xs(isp, (XS_T *)ccb, hp)) {
112592a1e549SMatt Jacob 		xpt_print_path(ccb->ccb_h.path);
112692a1e549SMatt Jacob 		printf("No XFLIST pointers for isp_target_start_ctio\n");
1127d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1128d81ba9d5SMatt Jacob 	}
1129d81ba9d5SMatt Jacob 
1130d81ba9d5SMatt Jacob 
1131d81ba9d5SMatt Jacob 	/*
1132d81ba9d5SMatt Jacob 	 * Call the dma setup routines for this entry (and any subsequent
1133d81ba9d5SMatt Jacob 	 * CTIOs) if there's data to move, and then tell the f/w it's got
1134b09b0095SMatt Jacob 	 * new things to play with. As with isp_start's usage of DMA setup,
1135d81ba9d5SMatt Jacob 	 * any swizzling is done in the machine dependent layer. Because
1136d81ba9d5SMatt Jacob 	 * of this, we put the request onto the queue area first in native
1137d81ba9d5SMatt Jacob 	 * format.
1138d81ba9d5SMatt Jacob 	 */
1139d81ba9d5SMatt Jacob 
1140d81ba9d5SMatt Jacob 	save_handle = *hp;
1141a1bc34c6SMatt Jacob 
11424fd13c1bSMatt Jacob 	switch (ISP_DMASETUP(isp, cso, (ispreq_t *) local, &nxti, optr)) {
1143d81ba9d5SMatt Jacob 	case CMD_QUEUED:
11444fd13c1bSMatt Jacob 		ISP_ADD_REQUEST(isp, nxti);
1145d81ba9d5SMatt Jacob 		return (CAM_REQ_INPROG);
1146d81ba9d5SMatt Jacob 
1147d81ba9d5SMatt Jacob 	case CMD_EAGAIN:
1148d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1149d81ba9d5SMatt Jacob 		isp_destroy_handle(isp, save_handle);
1150d81ba9d5SMatt Jacob 		return (CAM_RESRC_UNAVAIL);
1151d81ba9d5SMatt Jacob 
1152d81ba9d5SMatt Jacob 	default:
1153d81ba9d5SMatt Jacob 		isp_destroy_handle(isp, save_handle);
1154b85389e1SMatt Jacob 		return (XS_ERR(ccb));
1155d81ba9d5SMatt Jacob 	}
1156d81ba9d5SMatt Jacob }
1157d81ba9d5SMatt Jacob 
1158a1bc34c6SMatt Jacob static void
1159a1bc34c6SMatt Jacob isp_refire_putback_atio(void *arg)
1160f48ce188SMatt Jacob {
1161a1bc34c6SMatt Jacob 	int s = splcam();
1162a1bc34c6SMatt Jacob 	isp_target_putback_atio(arg);
1163a1bc34c6SMatt Jacob 	splx(s);
1164a1bc34c6SMatt Jacob }
1165a1bc34c6SMatt Jacob 
1166a1bc34c6SMatt Jacob static void
1167a1bc34c6SMatt Jacob isp_target_putback_atio(union ccb *ccb)
1168a1bc34c6SMatt Jacob {
1169a1bc34c6SMatt Jacob 	struct ispsoftc *isp;
1170a1bc34c6SMatt Jacob 	struct ccb_scsiio *cso;
11714fd13c1bSMatt Jacob 	u_int16_t nxti, optr;
1172a1bc34c6SMatt Jacob 	void *qe;
1173a1bc34c6SMatt Jacob 
1174a1bc34c6SMatt Jacob 	isp = XS_ISP(ccb);
1175f48ce188SMatt Jacob 
11764fd13c1bSMatt Jacob 	if (isp_getrqentry(isp, &nxti, &optr, &qe)) {
1177a1bc34c6SMatt Jacob 		(void) timeout(isp_refire_putback_atio, ccb, 10);
1178a1bc34c6SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
1179a1bc34c6SMatt Jacob 		    "isp_target_putback_atio: Request Queue Overflow");
1180a1bc34c6SMatt Jacob 		return;
1181f48ce188SMatt Jacob 	}
1182f48ce188SMatt Jacob 	bzero(qe, QENTRY_LEN);
1183a1bc34c6SMatt Jacob 	cso = &ccb->csio;
1184f48ce188SMatt Jacob 	if (IS_FC(isp)) {
11854fd13c1bSMatt Jacob 		at2_entry_t local, *at = &local;
11864fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at2_entry_t));
1187f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
1188f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
118964edff94SMatt Jacob 		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) {
1190a1bc34c6SMatt Jacob 			at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
1191f48ce188SMatt Jacob 		} else {
1192a1bc34c6SMatt Jacob 			at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
1193f48ce188SMatt Jacob 		}
1194f48ce188SMatt Jacob 		at->at_status = CT_OK;
1195a1bc34c6SMatt Jacob 		at->at_rxid = cso->tag_id;
11964fd13c1bSMatt Jacob 		isp_put_atio2(isp, at, qe);
1197f48ce188SMatt Jacob 	} else {
11984fd13c1bSMatt Jacob 		at_entry_t local, *at = &local;
11994fd13c1bSMatt Jacob 		MEMZERO(at, sizeof (at_entry_t));
1200f48ce188SMatt Jacob 		at->at_header.rqs_entry_type = RQSTYPE_ATIO;
1201f48ce188SMatt Jacob 		at->at_header.rqs_entry_count = 1;
1202a1bc34c6SMatt Jacob 		at->at_iid = cso->init_id;
1203a1bc34c6SMatt Jacob 		at->at_iid |= XS_CHANNEL(ccb) << 7;
1204a1bc34c6SMatt Jacob 		at->at_tgt = cso->ccb_h.target_id;
1205a1bc34c6SMatt Jacob 		at->at_lun = cso->ccb_h.target_lun;
1206f48ce188SMatt Jacob 		at->at_status = CT_OK;
1207a1bc34c6SMatt Jacob 		at->at_tag_val = AT_GET_TAG(cso->tag_id);
1208a1bc34c6SMatt Jacob 		at->at_handle = AT_GET_HANDLE(cso->tag_id);
12094fd13c1bSMatt Jacob 		isp_put_atio(isp, at, qe);
1210f48ce188SMatt Jacob 	}
1211f48ce188SMatt Jacob 	ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
12124fd13c1bSMatt Jacob 	ISP_ADD_REQUEST(isp, nxti);
1213a1bc34c6SMatt Jacob 	isp_complete_ctio(ccb);
1214f48ce188SMatt Jacob }
1215f48ce188SMatt Jacob 
1216f48ce188SMatt Jacob static void
1217a1bc34c6SMatt Jacob isp_complete_ctio(union ccb *ccb)
1218f48ce188SMatt Jacob {
1219a1bc34c6SMatt Jacob 	struct ispsoftc *isp = XS_ISP(ccb);
1220a1bc34c6SMatt Jacob 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
1221a1bc34c6SMatt Jacob 		ccb->ccb_h.status |= CAM_REQ_CMP;
1222f48ce188SMatt Jacob 	}
1223a1bc34c6SMatt Jacob 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1224a1bc34c6SMatt Jacob 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
1225a1bc34c6SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
1226a1bc34c6SMatt Jacob 		if (isp->isp_osinfo.simqfrozen == 0) {
1227a1bc34c6SMatt Jacob 			if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
1228a1bc34c6SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq");
1229a1bc34c6SMatt Jacob 				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
1230a1bc34c6SMatt Jacob 			} else {
1231a1bc34c6SMatt Jacob 				isp_prt(isp, ISP_LOGWARN, "ctio->devqfrozen");
1232a1bc34c6SMatt Jacob 			}
1233a1bc34c6SMatt Jacob 		} else {
1234a1bc34c6SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
1235a1bc34c6SMatt Jacob 			    "ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen);
1236a1bc34c6SMatt Jacob 		}
1237a1bc34c6SMatt Jacob 	}
1238a1bc34c6SMatt Jacob 	xpt_done(ccb);
1239f48ce188SMatt Jacob }
1240f48ce188SMatt Jacob 
1241d81ba9d5SMatt Jacob /*
1242d81ba9d5SMatt Jacob  * Handle ATIO stuff that the generic code can't.
1243d81ba9d5SMatt Jacob  * This means handling CDBs.
1244d81ba9d5SMatt Jacob  */
1245d81ba9d5SMatt Jacob 
1246d81ba9d5SMatt Jacob static int
1247d81ba9d5SMatt Jacob isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
1248d81ba9d5SMatt Jacob {
1249d81ba9d5SMatt Jacob 	tstate_t *tptr;
125064edff94SMatt Jacob 	int status, bus, iswildcard;
1251d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
1252d81ba9d5SMatt Jacob 
1253d81ba9d5SMatt Jacob 	/*
1254d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1255d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1256d81ba9d5SMatt Jacob 	 *
1257d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1258d81ba9d5SMatt Jacob 	 *
1259d81ba9d5SMatt Jacob 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
12605d571944SMatt Jacob 	 * we're still connected on the SCSI bus.
1261d81ba9d5SMatt Jacob 	 */
1262d81ba9d5SMatt Jacob 	status = aep->at_status;
1263d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) {
1264d81ba9d5SMatt Jacob 		/*
1265d81ba9d5SMatt Jacob 		 * Bus Phase Sequence error. We should have sense data
1266d81ba9d5SMatt Jacob 		 * suggested by the f/w. I'm not sure quite yet what
1267d81ba9d5SMatt Jacob 		 * to do about this for CAM.
1268d81ba9d5SMatt Jacob 		 */
12693c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "PHASE ERROR");
1270d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1271d81ba9d5SMatt Jacob 		return (0);
1272d81ba9d5SMatt Jacob 	}
1273d81ba9d5SMatt Jacob 	if ((status & ~QLTM_SVALID) != AT_CDB) {
12745d571944SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "bad atio (0x%x) leaked to platform",
12753c75bb14SMatt Jacob 		    status);
1276d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1277d81ba9d5SMatt Jacob 		return (0);
1278d81ba9d5SMatt Jacob 	}
1279d81ba9d5SMatt Jacob 
12805d571944SMatt Jacob 	bus = GET_BUS_VAL(aep->at_iid);
1281a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, bus, aep->at_lun);
1282d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1283a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
128464edff94SMatt Jacob 		iswildcard = 1;
128564edff94SMatt Jacob 	} else {
128664edff94SMatt Jacob 		iswildcard = 0;
1287d81ba9d5SMatt Jacob 	}
1288d81ba9d5SMatt Jacob 
1289d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1290d81ba9d5SMatt Jacob 		/*
1291d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1292d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1293d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a BUSY status
1294d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only
1295d81ba9d5SMatt Jacob 		 * time we should, in fact, get this, is in the
1296d81ba9d5SMatt Jacob 		 * case that somebody configured us without the
1297d81ba9d5SMatt Jacob 		 * blackhole driver, so they get what they deserve.
1298d81ba9d5SMatt Jacob 		 */
1299d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1300d81ba9d5SMatt Jacob 		return (0);
1301d81ba9d5SMatt Jacob 	}
1302d81ba9d5SMatt Jacob 
1303d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
1304d81ba9d5SMatt Jacob 	if (atiop == NULL) {
1305d81ba9d5SMatt Jacob 		/*
1306d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1307d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1308d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1309d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1310d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1311d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1312d81ba9d5SMatt Jacob 		 */
1313d81ba9d5SMatt Jacob 		xpt_print_path(tptr->owner);
13143c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
1315a1bc34c6SMatt Jacob 		    "no ATIOS for lun %d from initiator %d on channel %d",
13165d571944SMatt Jacob 		    aep->at_lun, GET_IID_VAL(aep->at_iid), bus);
1317d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1318d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1319d81ba9d5SMatt Jacob 		else
1320d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
132164edff94SMatt Jacob 		rls_lun_statep(isp, tptr);
1322d81ba9d5SMatt Jacob 		return (0);
1323d81ba9d5SMatt Jacob 	}
1324d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
132564edff94SMatt Jacob 	if (iswildcard) {
1326d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id = aep->at_tgt;
1327d81ba9d5SMatt Jacob 		atiop->ccb_h.target_lun = aep->at_lun;
1328d81ba9d5SMatt Jacob 	}
1329d81ba9d5SMatt Jacob 	if (aep->at_flags & AT_NODISC) {
1330f48ce188SMatt Jacob 		atiop->ccb_h.flags = CAM_DIS_DISCONNECT;
1331f48ce188SMatt Jacob 	} else {
1332f48ce188SMatt Jacob 		atiop->ccb_h.flags = 0;
1333d81ba9d5SMatt Jacob 	}
1334d81ba9d5SMatt Jacob 
1335f48ce188SMatt Jacob 	if (status & QLTM_SVALID) {
1336f48ce188SMatt Jacob 		size_t amt = imin(QLTM_SENSELEN, sizeof (atiop->sense_data));
1337f48ce188SMatt Jacob 		atiop->sense_len = amt;
1338f48ce188SMatt Jacob 		MEMCPY(&atiop->sense_data, aep->at_sense, amt);
1339f48ce188SMatt Jacob 	} else {
1340f48ce188SMatt Jacob 		atiop->sense_len = 0;
1341f48ce188SMatt Jacob 	}
1342d81ba9d5SMatt Jacob 
13435d571944SMatt Jacob 	atiop->init_id = GET_IID_VAL(aep->at_iid);
1344d81ba9d5SMatt Jacob 	atiop->cdb_len = aep->at_cdblen;
1345d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
1346d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1347a1bc34c6SMatt Jacob 	/*
1348a1bc34c6SMatt Jacob 	 * Construct a tag 'id' based upon tag value (which may be 0..255)
1349a1bc34c6SMatt Jacob 	 * and the handle (which we have to preserve).
1350a1bc34c6SMatt Jacob 	 */
1351a1bc34c6SMatt Jacob 	AT_MAKE_TAGID(atiop->tag_id, aep);
1352a1bc34c6SMatt Jacob 	if (aep->at_flags & AT_TQAE) {
1353a1bc34c6SMatt Jacob 		atiop->tag_action = aep->at_tag_type;
1354d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1355d81ba9d5SMatt Jacob 	}
1356d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
135764edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
13585d571944SMatt Jacob 	    "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s",
13595d571944SMatt Jacob 	    aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid),
13605d571944SMatt Jacob 	    GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff,
13615d571944SMatt Jacob 	    aep->at_tag_type, (aep->at_flags & AT_NODISC)?
13625d571944SMatt Jacob 	    "nondisc" : "disconnecting");
1363d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1364d81ba9d5SMatt Jacob 	return (0);
1365d81ba9d5SMatt Jacob }
1366d81ba9d5SMatt Jacob 
1367d81ba9d5SMatt Jacob static int
1368d81ba9d5SMatt Jacob isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
1369d81ba9d5SMatt Jacob {
137092a1e549SMatt Jacob 	lun_id_t lun;
1371d81ba9d5SMatt Jacob 	tstate_t *tptr;
1372d81ba9d5SMatt Jacob 	struct ccb_accept_tio *atiop;
137353036e92SMatt Jacob 	atio_private_data_t *atp;
1374d81ba9d5SMatt Jacob 
1375d81ba9d5SMatt Jacob 	/*
1376d81ba9d5SMatt Jacob 	 * The firmware status (except for the QLTM_SVALID bit)
1377d81ba9d5SMatt Jacob 	 * indicates why this ATIO was sent to us.
1378d81ba9d5SMatt Jacob 	 *
1379d81ba9d5SMatt Jacob 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
1380d81ba9d5SMatt Jacob 	 */
1381d81ba9d5SMatt Jacob 	if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) {
13823c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
13833c75bb14SMatt Jacob 		    "bogus atio (0x%x) leaked to platform", aep->at_status);
1384d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1385d81ba9d5SMatt Jacob 		return (0);
1386d81ba9d5SMatt Jacob 	}
1387d81ba9d5SMatt Jacob 
138864edff94SMatt Jacob 	if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) != 0) {
138992a1e549SMatt Jacob 		lun = aep->at_scclun;
13902ad50ca5SMatt Jacob 	} else {
139192a1e549SMatt Jacob 		lun = aep->at_lun;
13922ad50ca5SMatt Jacob 	}
1393a1bc34c6SMatt Jacob 	tptr = get_lun_statep(isp, 0, lun);
1394d81ba9d5SMatt Jacob 	if (tptr == NULL) {
1395a1bc34c6SMatt Jacob 		tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
1396d81ba9d5SMatt Jacob 	}
1397d81ba9d5SMatt Jacob 
1398d81ba9d5SMatt Jacob 	if (tptr == NULL) {
139952df5dfdSMatt Jacob 		/*
140052df5dfdSMatt Jacob 		 * What we'd like to know is whether or not we have a listener
140152df5dfdSMatt Jacob 		 * upstream that really hasn't configured yet. If we do, then
140252df5dfdSMatt Jacob 		 * we can give a more sensible reply here. If not, then we can
140352df5dfdSMatt Jacob 		 * reject this out of hand.
140452df5dfdSMatt Jacob 		 *
140552df5dfdSMatt Jacob 		 * Choices for what to send were
140652df5dfdSMatt Jacob 		 *
140752df5dfdSMatt Jacob                  *	Not Ready, Unit Not Self-Configured Yet
140852df5dfdSMatt Jacob 		 *	(0x2,0x3e,0x00)
140952df5dfdSMatt Jacob 		 *
141052df5dfdSMatt Jacob 		 * for the former and
141152df5dfdSMatt Jacob 		 *
141252df5dfdSMatt Jacob 		 *	Illegal Request, Logical Unit Not Supported
141352df5dfdSMatt Jacob 		 *	(0x5,0x25,0x00)
141452df5dfdSMatt Jacob 		 *
141552df5dfdSMatt Jacob 		 * for the latter.
141652df5dfdSMatt Jacob 		 *
141752df5dfdSMatt Jacob 		 * We used to decide whether there was at least one listener
141852df5dfdSMatt Jacob 		 * based upon whether the black hole driver was configured.
141952df5dfdSMatt Jacob 		 * However, recent config(8) changes have made this hard to do
142052df5dfdSMatt Jacob 		 * at this time.
142152df5dfdSMatt Jacob 		 *
142252df5dfdSMatt Jacob 		 */
1423d81ba9d5SMatt Jacob 		u_int32_t ccode = SCSI_STATUS_BUSY;
1424d81ba9d5SMatt Jacob 
1425d81ba9d5SMatt Jacob 		/*
1426d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1427d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1428d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a BUSY status
1429d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only
1430d81ba9d5SMatt Jacob 		 * time we should, in fact, get this, is in the
1431d81ba9d5SMatt Jacob 		 * case that somebody configured us without the
1432d81ba9d5SMatt Jacob 		 * blackhole driver, so they get what they deserve.
1433d81ba9d5SMatt Jacob 		 */
1434d81ba9d5SMatt Jacob 		isp_endcmd(isp, aep, ccode, 0);
1435d81ba9d5SMatt Jacob 		return (0);
1436d81ba9d5SMatt Jacob 	}
1437d81ba9d5SMatt Jacob 
143853036e92SMatt Jacob 	atp = isp_get_atpd(isp, 0);
1439d81ba9d5SMatt Jacob 	atiop = (struct ccb_accept_tio *) SLIST_FIRST(&tptr->atios);
144053036e92SMatt Jacob 	if (atiop == NULL || atp == NULL) {
1441d81ba9d5SMatt Jacob 		/*
1442d81ba9d5SMatt Jacob 		 * Because we can't autofeed sense data back with
1443d81ba9d5SMatt Jacob 		 * a command for parallel SCSI, we can't give back
1444d81ba9d5SMatt Jacob 		 * a CHECK CONDITION. We'll give back a QUEUE FULL status
1445d81ba9d5SMatt Jacob 		 * instead. This works out okay because the only time we
1446d81ba9d5SMatt Jacob 		 * should, in fact, get this, is in the case that we've
1447d81ba9d5SMatt Jacob 		 * run out of ATIOS.
1448d81ba9d5SMatt Jacob 		 */
1449d81ba9d5SMatt Jacob 		xpt_print_path(tptr->owner);
14503c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN,
14513c75bb14SMatt Jacob 		    "no ATIOS for lun %d from initiator %d", lun, aep->at_iid);
1452d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1453d81ba9d5SMatt Jacob 		if (aep->at_flags & AT_TQAE)
1454d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
1455d81ba9d5SMatt Jacob 		else
1456d81ba9d5SMatt Jacob 			isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
1457d81ba9d5SMatt Jacob 		return (0);
1458d81ba9d5SMatt Jacob 	}
1459d81ba9d5SMatt Jacob 	SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
1460f48ce188SMatt Jacob 
1461a1bc34c6SMatt Jacob 	if (tptr == &isp->isp_osinfo.tsdflt[0]) {
1462d81ba9d5SMatt Jacob 		atiop->ccb_h.target_id =
1463d81ba9d5SMatt Jacob 			((fcparam *)isp->isp_param)->isp_loopid;
146492a1e549SMatt Jacob 		atiop->ccb_h.target_lun = lun;
1465d81ba9d5SMatt Jacob 	}
1466b0a3ba7eSMatt Jacob 	/*
1467b0a3ba7eSMatt Jacob 	 * We don't get 'suggested' sense data as we do with SCSI cards.
1468b0a3ba7eSMatt Jacob 	 */
1469f48ce188SMatt Jacob 	atiop->sense_len = 0;
1470f48ce188SMatt Jacob 
1471d81ba9d5SMatt Jacob 	atiop->init_id = aep->at_iid;
1472d81ba9d5SMatt Jacob 	atiop->cdb_len = ATIO2_CDBLEN;
1473d81ba9d5SMatt Jacob 	MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, ATIO2_CDBLEN);
1474d81ba9d5SMatt Jacob 	atiop->ccb_h.status = CAM_CDB_RECVD;
1475d81ba9d5SMatt Jacob 	atiop->tag_id = aep->at_rxid;
1476d81ba9d5SMatt Jacob 	switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) {
1477d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_SIMPLEQ:
1478d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_SIMPLE_Q_TAG;
1479d81ba9d5SMatt Jacob 		break;
1480d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_HEADOFQ:
1481d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_HEAD_OF_Q_TAG;
1482d81ba9d5SMatt Jacob 		break;
1483d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ORDERED:
1484d81ba9d5SMatt Jacob 		atiop->tag_action = MSG_ORDERED_Q_TAG;
1485d81ba9d5SMatt Jacob 		break;
1486d81ba9d5SMatt Jacob         case ATIO2_TC_ATTR_ACAQ:		/* ?? */
1487d81ba9d5SMatt Jacob 	case ATIO2_TC_ATTR_UNTAGGED:
1488d81ba9d5SMatt Jacob 	default:
1489d81ba9d5SMatt Jacob 		atiop->tag_action = 0;
1490d81ba9d5SMatt Jacob 		break;
1491d81ba9d5SMatt Jacob 	}
1492d81ba9d5SMatt Jacob 	if (atiop->tag_action != 0) {
1493d81ba9d5SMatt Jacob 		atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
1494d81ba9d5SMatt Jacob 	}
1495f48ce188SMatt Jacob 
149653036e92SMatt Jacob 	atp->tag = atiop->tag_id;
149753036e92SMatt Jacob 	atp->orig_datalen = aep->at_datalen;
149853036e92SMatt Jacob 	atp->last_xframt = 0;
149953036e92SMatt Jacob 	atp->bytes_xfered = 0;
1500f48ce188SMatt Jacob 
1501d81ba9d5SMatt Jacob 	xpt_done((union ccb*)atiop);
150264edff94SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0,
15035f5aafe1SMatt Jacob 	    "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
15045f5aafe1SMatt Jacob 	    aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
1505b09b0095SMatt Jacob 	    lun, aep->at_taskflags, aep->at_datalen);
1506d81ba9d5SMatt Jacob 	rls_lun_statep(isp, tptr);
1507d81ba9d5SMatt Jacob 	return (0);
1508d81ba9d5SMatt Jacob }
1509d81ba9d5SMatt Jacob 
1510d81ba9d5SMatt Jacob static int
1511d81ba9d5SMatt Jacob isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
1512d81ba9d5SMatt Jacob {
1513d81ba9d5SMatt Jacob 	union ccb *ccb;
1514a1bc34c6SMatt Jacob 	int sentstatus, ok, notify_cam, resid = 0;
151564edff94SMatt Jacob 	u_int16_t tval;
1516d81ba9d5SMatt Jacob 
1517d81ba9d5SMatt Jacob 	/*
1518d81ba9d5SMatt Jacob 	 * CTIO and CTIO2 are close enough....
1519d81ba9d5SMatt Jacob 	 */
1520d81ba9d5SMatt Jacob 
15215f5aafe1SMatt Jacob 	ccb = (union ccb *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle);
1522d81ba9d5SMatt Jacob 	KASSERT((ccb != NULL), ("null ccb in isp_handle_platform_ctio"));
15235f5aafe1SMatt Jacob 	isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle);
1524d81ba9d5SMatt Jacob 
1525d81ba9d5SMatt Jacob 	if (IS_FC(isp)) {
1526d81ba9d5SMatt Jacob 		ct2_entry_t *ct = arg;
1527d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT2_SENDSTATUS;
1528d81ba9d5SMatt Jacob 		ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
1529a1bc34c6SMatt Jacob 		if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
153000a8e174SMatt Jacob 			ccb->ccb_h.status |= CAM_SENT_SENSE;
153100a8e174SMatt Jacob 		}
1532a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
15335d571944SMatt Jacob 		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
153453036e92SMatt Jacob 			atio_private_data_t *atp =
153553036e92SMatt Jacob 			    isp_get_atpd(isp, ct->ct_rxid);
153653036e92SMatt Jacob 			if (atp == NULL) {
153753036e92SMatt Jacob 				panic("cannot find adjunct after I/O");
153853036e92SMatt Jacob 			}
1539a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
154053036e92SMatt Jacob 			atp->bytes_xfered += (atp->last_xframt - resid);
154153036e92SMatt Jacob 			atp->last_xframt = 0;
154253036e92SMatt Jacob 			if (sentstatus) {
154353036e92SMatt Jacob 				atp->tag = 0;
154453036e92SMatt Jacob 			}
15455d571944SMatt Jacob 		}
154664edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
154764edff94SMatt Jacob 		    "CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
154864edff94SMatt Jacob 		    ct->ct_rxid, ct->ct_status, ct->ct_flags,
154964edff94SMatt Jacob 		    (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
155064edff94SMatt Jacob 		    resid, sentstatus? "FIN" : "MID");
155164edff94SMatt Jacob 		tval = ct->ct_rxid;
1552d81ba9d5SMatt Jacob 	} else {
1553d81ba9d5SMatt Jacob 		ct_entry_t *ct = arg;
1554d81ba9d5SMatt Jacob 		sentstatus = ct->ct_flags & CT_SENDSTATUS;
1555d81ba9d5SMatt Jacob 		ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
1556d81ba9d5SMatt Jacob 		/*
1557a1bc34c6SMatt Jacob 		 * We *ought* to be able to get back to the original ATIO
1558a1bc34c6SMatt Jacob 		 * here, but for some reason this gets lost. It's just as
1559a1bc34c6SMatt Jacob 		 * well because it's squirrelled away as part of periph
1560a1bc34c6SMatt Jacob 		 * private data.
1561a1bc34c6SMatt Jacob 		 *
1562a1bc34c6SMatt Jacob 		 * We can live without it as long as we continue to use
1563a1bc34c6SMatt Jacob 		 * the auto-replenish feature for CTIOs.
1564a1bc34c6SMatt Jacob 		 */
1565a1bc34c6SMatt Jacob 		notify_cam = ct->ct_header.rqs_seqno & 0x1;
1566a1bc34c6SMatt Jacob 		if (ct->ct_status & QLTM_SVALID) {
1567a1bc34c6SMatt Jacob 			char *sp = (char *)ct;
1568a1bc34c6SMatt Jacob 			sp += CTIO_SENSE_OFFSET;
1569a1bc34c6SMatt Jacob 			ccb->csio.sense_len =
1570a1bc34c6SMatt Jacob 			    min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
1571a1bc34c6SMatt Jacob 			MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
1572a1bc34c6SMatt Jacob 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1573a1bc34c6SMatt Jacob 		}
15745d571944SMatt Jacob 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
1575a1bc34c6SMatt Jacob 			resid = ct->ct_resid;
1576a1bc34c6SMatt Jacob 		}
157764edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0,
157864edff94SMatt Jacob 		    "CTIO[%x] tag %x iid %d lun %d sts %x flg %x resid %d %s",
157964edff94SMatt Jacob 		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun,
158064edff94SMatt Jacob 		    ct->ct_status, ct->ct_flags, resid,
158164edff94SMatt Jacob 		    sentstatus? "FIN" : "MID");
158264edff94SMatt Jacob 		tval = ct->ct_fwhandle;
15835d571944SMatt Jacob 	}
1584a1bc34c6SMatt Jacob 	ccb->csio.resid += resid;
1585a1bc34c6SMatt Jacob 
1586a1bc34c6SMatt Jacob 	/*
1587a1bc34c6SMatt Jacob 	 * We're here either because intermediate data transfers are done
1588a1bc34c6SMatt Jacob 	 * and/or the final status CTIO (which may have joined with a
1589a1bc34c6SMatt Jacob 	 * Data Transfer) is done.
1590d81ba9d5SMatt Jacob 	 *
1591d81ba9d5SMatt Jacob 	 * In any case, for this platform, the upper layers figure out
1592d81ba9d5SMatt Jacob 	 * what to do next, so all we do here is collect status and
1593a1bc34c6SMatt Jacob 	 * pass information along. Any DMA handles have already been
1594a1bc34c6SMatt Jacob 	 * freed.
1595d81ba9d5SMatt Jacob 	 */
1596f48ce188SMatt Jacob 	if (notify_cam == 0) {
159764edff94SMatt Jacob 		isp_prt(isp, ISP_LOGTDEBUG0, "  INTER CTIO[0x%x] done", tval);
1598f48ce188SMatt Jacob 		return (0);
1599f48ce188SMatt Jacob 	}
1600d81ba9d5SMatt Jacob 
160153036e92SMatt Jacob 	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done",
160253036e92SMatt Jacob 	    (sentstatus)? "  FINAL " : "MIDTERM ", tval);
1603a1bc34c6SMatt Jacob 
1604a1bc34c6SMatt Jacob 	if (!ok) {
1605a1bc34c6SMatt Jacob 		isp_target_putback_atio(ccb);
1606d81ba9d5SMatt Jacob 	} else {
1607a1bc34c6SMatt Jacob 		isp_complete_ctio(ccb);
1608a1bc34c6SMatt Jacob 
1609d81ba9d5SMatt Jacob 	}
1610a1bc34c6SMatt Jacob 	return (0);
1611d81ba9d5SMatt Jacob }
1612d81ba9d5SMatt Jacob #endif
1613d81ba9d5SMatt Jacob 
1614478f8a96SJustin T. Gibbs static void
1615cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
1616478f8a96SJustin T. Gibbs {
1617478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
1618478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
1619478f8a96SJustin T. Gibbs 
1620478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
1621478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *) cam_sim_softc(sim);
1622478f8a96SJustin T. Gibbs 	switch (code) {
1623478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
1624ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
1625478f8a96SJustin T. Gibbs 			u_int16_t oflags, nflags;
1626478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
1627a1bc34c6SMatt Jacob 			int tgt;
1628478f8a96SJustin T. Gibbs 
1629f9e908dcSMatt Jacob 			tgt = xpt_path_target_id(path);
1630f6e75de2SMatt Jacob 			ISP_LOCK(isp);
1631ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(sim);
16329ce9bdafSMatt Jacob 			nflags = sdp->isp_devparam[tgt].nvrm_flags;
1633a1bc34c6SMatt Jacob #ifndef	ISP_TARGET_MODE
16349ce9bdafSMatt Jacob 			nflags &= DPARM_SAFE_DFLT;
1635a1bc34c6SMatt Jacob 			if (isp->isp_loaded_fw) {
1636478f8a96SJustin T. Gibbs 				nflags |= DPARM_NARROW | DPARM_ASYNC;
1637478f8a96SJustin T. Gibbs 			}
1638a1bc34c6SMatt Jacob #else
1639a1bc34c6SMatt Jacob 			nflags = DPARM_DEFAULT;
1640a1bc34c6SMatt Jacob #endif
16419ce9bdafSMatt Jacob 			oflags = sdp->isp_devparam[tgt].goal_flags;
16429ce9bdafSMatt Jacob 			sdp->isp_devparam[tgt].goal_flags = nflags;
1643478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
1644a1bc34c6SMatt Jacob 			isp->isp_update |= (1 << cam_sim_bus(sim));
1645478f8a96SJustin T. Gibbs 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
16469ce9bdafSMatt Jacob 			sdp->isp_devparam[tgt].goal_flags = oflags;
1647f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
1648478f8a96SJustin T. Gibbs 		}
1649478f8a96SJustin T. Gibbs 		break;
1650478f8a96SJustin T. Gibbs 	default:
16513c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGWARN, "isp_cam_async: Code 0x%x", code);
1652478f8a96SJustin T. Gibbs 		break;
1653478f8a96SJustin T. Gibbs 	}
1654478f8a96SJustin T. Gibbs }
1655478f8a96SJustin T. Gibbs 
1656478f8a96SJustin T. Gibbs static void
1657c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
1658478f8a96SJustin T. Gibbs {
1659c40e096eSMatt Jacob 	struct ispsoftc *isp = cam_sim_softc(sim);
1660126ec864SMatt Jacob 	u_int16_t isr, sema, mbox;
1661126ec864SMatt Jacob 
1662c40e096eSMatt Jacob 	ISP_LOCK(isp);
1663126ec864SMatt Jacob 	if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
1664126ec864SMatt Jacob 		isp_intr(isp, isr, sema, mbox);
1665126ec864SMatt Jacob 	}
1666c40e096eSMatt Jacob 	ISP_UNLOCK(isp);
1667478f8a96SJustin T. Gibbs }
1668478f8a96SJustin T. Gibbs 
16695d571944SMatt Jacob #if	0
16700470d791SMatt Jacob static void
16710470d791SMatt Jacob isp_relsim(void *arg)
16720470d791SMatt Jacob {
16730470d791SMatt Jacob 	struct ispsoftc *isp = arg;
1674f6e75de2SMatt Jacob 	ISP_LOCK(isp);
16750470d791SMatt Jacob 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED) {
16760470d791SMatt Jacob 		int wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED;
16770470d791SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_TIMED;
16780470d791SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
16790470d791SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
1680b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2, "timed relsimq");
16810470d791SMatt Jacob 		}
16820470d791SMatt Jacob 	}
1683f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
16840470d791SMatt Jacob }
16855d571944SMatt Jacob #endif
1686ab6c4b31SMatt Jacob 
1687478f8a96SJustin T. Gibbs static void
1688b85389e1SMatt Jacob isp_watchdog(void *arg)
1689cc8df88bSMatt Jacob {
1690b09b0095SMatt Jacob 	XS_T *xs = arg;
1691cc8df88bSMatt Jacob 	struct ispsoftc *isp = XS_ISP(xs);
1692cc8df88bSMatt Jacob 	u_int32_t handle;
1693b85389e1SMatt Jacob 
1694cc8df88bSMatt Jacob 	/*
1695b85389e1SMatt Jacob 	 * We've decided this command is dead. Make sure we're not trying
1696b85389e1SMatt Jacob 	 * to kill a command that's already dead by getting it's handle and
1697b85389e1SMatt Jacob 	 * and seeing whether it's still alive.
1698cc8df88bSMatt Jacob 	 */
1699f6e75de2SMatt Jacob 	ISP_LOCK(isp);
1700cc8df88bSMatt Jacob 	handle = isp_find_handle(isp, xs);
1701cc8df88bSMatt Jacob 	if (handle) {
1702126ec864SMatt Jacob 		u_int16_t isr, sema, mbox;
1703126ec864SMatt Jacob 
1704b85389e1SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
1705b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG1,
1706b09b0095SMatt Jacob 			    "watchdog found done cmd (handle 0x%x)", handle);
1707f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
1708b85389e1SMatt Jacob 			return;
1709b85389e1SMatt Jacob 		}
1710b85389e1SMatt Jacob 
1711b85389e1SMatt Jacob 		if (XS_CMD_WDOG_P(xs)) {
1712b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
1713b09b0095SMatt Jacob 			    "recursive watchdog (handle 0x%x)", handle);
1714f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
1715b85389e1SMatt Jacob 			return;
1716b85389e1SMatt Jacob 		}
1717b85389e1SMatt Jacob 
1718b85389e1SMatt Jacob 		XS_CMD_S_WDOG(xs);
1719126ec864SMatt Jacob 		if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
1720126ec864SMatt Jacob 			isp_intr(isp, isr, sema, mbox);
1721126ec864SMatt Jacob 		}
1722126ec864SMatt Jacob 		if (XS_CMD_DONE_P(xs)) {
1723b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
1724126ec864SMatt Jacob 			    "watchdog cleanup for handle 0x%x", handle);
1725b85389e1SMatt Jacob 			xpt_done((union ccb *) xs);
1726b85389e1SMatt Jacob 		} else if (XS_CMD_GRACE_P(xs)) {
17271fcf5debSMatt Jacob 			/*
17281fcf5debSMatt Jacob 			 * Make sure the command is *really* dead before we
17291fcf5debSMatt Jacob 			 * release the handle (and DMA resources) for reuse.
17301fcf5debSMatt Jacob 			 */
17311fcf5debSMatt Jacob 			(void) isp_control(isp, ISPCTL_ABORT_CMD, arg);
17321fcf5debSMatt Jacob 
17331fcf5debSMatt Jacob 			/*
17341fcf5debSMatt Jacob 			 * After this point, the comamnd is really dead.
17351fcf5debSMatt Jacob 			 */
1736f6e75de2SMatt Jacob 			if (XS_XFRLEN(xs)) {
1737f6e75de2SMatt Jacob 				ISP_DMAFREE(isp, xs, handle);
1738f6e75de2SMatt Jacob                 	}
1739cc8df88bSMatt Jacob 			isp_destroy_handle(isp, handle);
1740cc8df88bSMatt Jacob 			xpt_print_path(xs->ccb_h.path);
17413c75bb14SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
17422903b272SMatt Jacob 			    "watchdog timeout for handle 0x%x", handle);
1743cc8df88bSMatt Jacob 			XS_SETERR(xs, CAM_CMD_TIMEOUT);
1744b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
1745cc8df88bSMatt Jacob 			isp_done(xs);
1746b85389e1SMatt Jacob 		} else {
17474fd13c1bSMatt Jacob 			u_int16_t nxti, optr;
17484fd13c1bSMatt Jacob 			ispreq_t local, *mp= &local, *qe;
1749b85389e1SMatt Jacob 
1750b85389e1SMatt Jacob 			XS_CMD_C_WDOG(xs);
1751b85389e1SMatt Jacob 			xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
17524fd13c1bSMatt Jacob 			if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) {
1753f6e75de2SMatt Jacob 				ISP_UNLOCK(isp);
1754b85389e1SMatt Jacob 				return;
1755b85389e1SMatt Jacob 			}
1756b85389e1SMatt Jacob 			XS_CMD_S_GRACE(xs);
1757b85389e1SMatt Jacob 			MEMZERO((void *) mp, sizeof (*mp));
1758b85389e1SMatt Jacob 			mp->req_header.rqs_entry_count = 1;
1759b85389e1SMatt Jacob 			mp->req_header.rqs_entry_type = RQSTYPE_MARKER;
1760b85389e1SMatt Jacob 			mp->req_modifier = SYNC_ALL;
1761b85389e1SMatt Jacob 			mp->req_target = XS_CHANNEL(xs) << 7;
17624fd13c1bSMatt Jacob 			isp_put_request(isp, mp, qe);
17634fd13c1bSMatt Jacob 			ISP_ADD_REQUEST(isp, nxti);
1764b85389e1SMatt Jacob 		}
1765b85389e1SMatt Jacob 	} else {
1766b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command");
1767cc8df88bSMatt Jacob 	}
1768f6e75de2SMatt Jacob 	ISP_UNLOCK(isp);
1769cc8df88bSMatt Jacob }
1770cc8df88bSMatt Jacob 
1771f44257c2SMatt Jacob static int isp_ktmature = 0;
1772f44257c2SMatt Jacob 
17735d571944SMatt Jacob static void
17745d571944SMatt Jacob isp_kthread(void *arg)
17755d571944SMatt Jacob {
17765d571944SMatt Jacob 	int wasfrozen;
17775d571944SMatt Jacob 	struct ispsoftc *isp = arg;
17785d571944SMatt Jacob 
17795d571944SMatt Jacob 	mtx_lock(&isp->isp_lock);
17805d571944SMatt Jacob 	for (;;) {
17815d571944SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG0, "kthread checking FC state");
17825d571944SMatt Jacob 		while (isp_fc_runstate(isp, 2 * 1000000) != 0) {
1783f44257c2SMatt Jacob 			if (FCPARAM(isp)->isp_fwstate != FW_READY ||
1784f44257c2SMatt Jacob 			    FCPARAM(isp)->isp_loopstate < LOOP_PDB_RCVD) {
1785f44257c2SMatt Jacob 				if (FCPARAM(isp)->loop_seen_once == 0 ||
1786f44257c2SMatt Jacob 				    isp_ktmature == 0) {
1787f44257c2SMatt Jacob 					break;
1788f44257c2SMatt Jacob 				}
1789f44257c2SMatt Jacob 			}
17905d571944SMatt Jacob 			msleep(isp_kthread, &isp->isp_lock,
17915d571944SMatt Jacob 			    PRIBIO, "isp_fcthrd", hz);
17925d571944SMatt Jacob 		}
1793f44257c2SMatt Jacob 		/*
1794f44257c2SMatt Jacob 		 * Even if we didn't get good loop state we may be
1795f44257c2SMatt Jacob 		 * unfreezing the SIMQ so that we can kill off
1796f44257c2SMatt Jacob 		 * commands (if we've never seen loop before, e.g.)
1797f44257c2SMatt Jacob 		 */
1798f44257c2SMatt Jacob 		isp_ktmature = 1;
17995d571944SMatt Jacob 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
18005d571944SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
18015d571944SMatt Jacob 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
18025d571944SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0, "kthread up release simq");
18035d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
18045d571944SMatt Jacob 			xpt_release_simq(isp->isp_sim, 1);
18055d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
18065d571944SMatt Jacob 		}
18075d571944SMatt Jacob 		cv_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock);
18085d571944SMatt Jacob 	}
18095d571944SMatt Jacob }
18105d571944SMatt Jacob 
1811cc8df88bSMatt Jacob static void
1812c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
1813478f8a96SJustin T. Gibbs {
1814f6e75de2SMatt Jacob 	int bus, tgt, error;
1815478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
18164663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
1817478f8a96SJustin T. Gibbs 
1818478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
1819478f8a96SJustin T. Gibbs 
1820478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *)cam_sim_softc(sim);
1821478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
1822478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
18230470d791SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE &&
18240470d791SMatt Jacob 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
18255d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
182657c801f5SMatt Jacob 		isp_init(isp);
182757c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
1828f6e75de2SMatt Jacob 			ISP_UNLOCK(isp);
182957c801f5SMatt Jacob 			/*
183057c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
183157c801f5SMatt Jacob 			 */
1832b85389e1SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
18330470d791SMatt Jacob 			xpt_freeze_devq(ccb->ccb_h.path, 1);
183457c801f5SMatt Jacob 			xpt_done(ccb);
183557c801f5SMatt Jacob 			return;
183657c801f5SMatt Jacob 		}
183757c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
18385d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
183957c801f5SMatt Jacob 	}
1840b09b0095SMatt Jacob 	isp_prt(isp, ISP_LOGDEBUG2, "isp_action code %x", ccb->ccb_h.func_code);
1841478f8a96SJustin T. Gibbs 
18425d571944SMatt Jacob 
1843478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
1844478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
1845478f8a96SJustin T. Gibbs 		/*
1846478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
1847478f8a96SJustin T. Gibbs 		 */
1848478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1849478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
1850478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
1851478f8a96SJustin T. Gibbs 				xpt_done(ccb);
1852478f8a96SJustin T. Gibbs 				break;
1853478f8a96SJustin T. Gibbs 			}
1854478f8a96SJustin T. Gibbs 		}
18550470d791SMatt Jacob #ifdef	DIAGNOSTIC
18560470d791SMatt Jacob 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
1857478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
18580470d791SMatt Jacob 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
1859478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PATH_INVALID;
1860478f8a96SJustin T. Gibbs 		}
1861478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
1862bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1863bfbab170SMatt Jacob 			    "invalid tgt/lun (%d.%d) in XPT_SCSI_IO",
1864bfbab170SMatt Jacob 			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
1865478f8a96SJustin T. Gibbs 			xpt_done(ccb);
1866478f8a96SJustin T. Gibbs 			break;
1867478f8a96SJustin T. Gibbs 		}
18680470d791SMatt Jacob #endif
18690470d791SMatt Jacob 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
18705d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
1871b09b0095SMatt Jacob 		error = isp_start((XS_T *) ccb);
18720470d791SMatt Jacob 		switch (error) {
1873478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
1874478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
1875cc8df88bSMatt Jacob 			if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
1876d69a5f7dSMatt Jacob 				u_int64_t ticks = (u_int64_t) hz;
1877cc8df88bSMatt Jacob 				if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
1878d69a5f7dSMatt Jacob 					ticks = 60 * 1000 * ticks;
1879b85389e1SMatt Jacob 				else
1880b85389e1SMatt Jacob 					ticks = ccb->ccb_h.timeout * hz;
1881b85389e1SMatt Jacob 				ticks = ((ticks + 999) / 1000) + hz + hz;
1882d69a5f7dSMatt Jacob 				if (ticks >= 0x80000000) {
1883d69a5f7dSMatt Jacob 					isp_prt(isp, ISP_LOGERR,
1884d69a5f7dSMatt Jacob 					    "timeout overflow");
1885d69a5f7dSMatt Jacob 					ticks = 0x80000000;
1886d69a5f7dSMatt Jacob 				}
1887d69a5f7dSMatt Jacob 				ccb->ccb_h.timeout_ch = timeout(isp_watchdog,
1888d69a5f7dSMatt Jacob 				    (caddr_t)ccb, (int)ticks);
1889b85389e1SMatt Jacob 			} else {
1890b85389e1SMatt Jacob 				callout_handle_init(&ccb->ccb_h.timeout_ch);
1891cc8df88bSMatt Jacob 			}
18925d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
1893478f8a96SJustin T. Gibbs 			break;
18940470d791SMatt Jacob 		case CMD_RQLATER:
1895f44257c2SMatt Jacob 			/*
1896f44257c2SMatt Jacob 			 * This can only happen for Fibre Channel
1897f44257c2SMatt Jacob 			 */
1898f44257c2SMatt Jacob 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
1899f44257c2SMatt Jacob 			if (FCPARAM(isp)->loop_seen_once == 0 && isp_ktmature) {
1900f44257c2SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
1901f44257c2SMatt Jacob 				XS_SETERR(ccb, CAM_SEL_TIMEOUT);
1902f44257c2SMatt Jacob 				xpt_done(ccb);
1903f44257c2SMatt Jacob 				break;
1904f44257c2SMatt Jacob 			}
19055d571944SMatt Jacob 			cv_signal(&isp->isp_osinfo.kthread_cv);
19060470d791SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
1907b09b0095SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2,
1908b09b0095SMatt Jacob 				    "RQLATER freeze simq");
19095d571944SMatt Jacob 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
19105d571944SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
1911478f8a96SJustin T. Gibbs 				xpt_freeze_simq(sim, 1);
19125d571944SMatt Jacob 			} else {
19135d571944SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
191400f50ce8SMatt Jacob 			}
1915b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
1916478f8a96SJustin T. Gibbs 			xpt_done(ccb);
1917478f8a96SJustin T. Gibbs 			break;
19180470d791SMatt Jacob 		case CMD_EAGAIN:
19190470d791SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
19200470d791SMatt Jacob 				xpt_freeze_simq(sim, 1);
1921b09b0095SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2,
1922b09b0095SMatt Jacob 				    "EAGAIN freeze simq");
1923478f8a96SJustin T. Gibbs 			}
19240470d791SMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
1925b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
19265d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
1927478f8a96SJustin T. Gibbs 			xpt_done(ccb);
1928478f8a96SJustin T. Gibbs 			break;
19290470d791SMatt Jacob 		case CMD_COMPLETE:
19300470d791SMatt Jacob 			isp_done((struct ccb_scsiio *) ccb);
19315d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
19320470d791SMatt Jacob 			break;
19330470d791SMatt Jacob 		default:
1934bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
1935bfbab170SMatt Jacob 			    "What's this? 0x%x at %d in file %s",
193691f1caa2SMatt Jacob 			    error, __LINE__, __FILE__);
1937b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQ_CMP_ERR);
19380470d791SMatt Jacob 			xpt_done(ccb);
19395d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
1940478f8a96SJustin T. Gibbs 		}
1941478f8a96SJustin T. Gibbs 		break;
1942478f8a96SJustin T. Gibbs 
1943d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
1944478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
194564edff94SMatt Jacob 	{
194664edff94SMatt Jacob 		int iok;
19475d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
194864edff94SMatt Jacob 		iok = isp->isp_osinfo.intsok;
194964edff94SMatt Jacob 		isp->isp_osinfo.intsok = 0;
1950d81ba9d5SMatt Jacob 		isp_en_lun(isp, ccb);
195164edff94SMatt Jacob 		isp->isp_osinfo.intsok = iok;
19525d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
1953478f8a96SJustin T. Gibbs 		xpt_done(ccb);
1954478f8a96SJustin T. Gibbs 		break;
195564edff94SMatt Jacob 	}
1956d81ba9d5SMatt Jacob 	case XPT_NOTIFY_ACK:		/* recycle notify ack */
1957d81ba9d5SMatt Jacob 	case XPT_IMMED_NOTIFY:		/* Add Immediate Notify Resource */
1958d81ba9d5SMatt Jacob 	case XPT_ACCEPT_TARGET_IO:	/* Add Accept Target IO Resource */
1959d81ba9d5SMatt Jacob 	{
1960a1bc34c6SMatt Jacob 		tstate_t *tptr =
1961a1bc34c6SMatt Jacob 		    get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
1962d81ba9d5SMatt Jacob 		if (tptr == NULL) {
1963d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_LUN_INVALID;
1964d81ba9d5SMatt Jacob 			xpt_done(ccb);
1965d81ba9d5SMatt Jacob 			break;
1966d81ba9d5SMatt Jacob 		}
1967f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[0].field = 0;
1968f48ce188SMatt Jacob 		ccb->ccb_h.sim_priv.entries[1].ptr = isp;
19695d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
1970d81ba9d5SMatt Jacob 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
1971d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->atios,
1972d81ba9d5SMatt Jacob 			    &ccb->ccb_h, sim_links.sle);
1973d81ba9d5SMatt Jacob 		} else {
1974d81ba9d5SMatt Jacob 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
1975d81ba9d5SMatt Jacob 			    sim_links.sle);
1976d81ba9d5SMatt Jacob 		}
1977d81ba9d5SMatt Jacob 		rls_lun_statep(isp, tptr);
1978d81ba9d5SMatt Jacob 		ccb->ccb_h.status = CAM_REQ_INPROG;
19795d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
1980d81ba9d5SMatt Jacob 		break;
1981d81ba9d5SMatt Jacob 	}
1982d81ba9d5SMatt Jacob 	case XPT_CONT_TARGET_IO:
1983d81ba9d5SMatt Jacob 	{
19845d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
1985d81ba9d5SMatt Jacob 		ccb->ccb_h.status = isp_target_start_ctio(isp, ccb);
1986d81ba9d5SMatt Jacob 		if (ccb->ccb_h.status != CAM_REQ_INPROG) {
1987d81ba9d5SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
1988d81ba9d5SMatt Jacob 				xpt_freeze_simq(sim, 1);
1989d81ba9d5SMatt Jacob 				xpt_print_path(ccb->ccb_h.path);
19903c75bb14SMatt Jacob 				isp_prt(isp, ISP_LOGINFO,
19913c75bb14SMatt Jacob 				    "XPT_CONT_TARGET_IO freeze simq");
1992d81ba9d5SMatt Jacob 			}
1993d81ba9d5SMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
1994b85389e1SMatt Jacob 			XS_SETERR(ccb, CAM_REQUEUE_REQ);
19955d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
1996d81ba9d5SMatt Jacob 			xpt_done(ccb);
1997d81ba9d5SMatt Jacob 		} else {
19985d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
1999d81ba9d5SMatt Jacob 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
2000d81ba9d5SMatt Jacob 		}
2001d81ba9d5SMatt Jacob 		break;
2002d81ba9d5SMatt Jacob 	}
2003d81ba9d5SMatt Jacob #endif
2004478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
2005d81ba9d5SMatt Jacob 
2006d81ba9d5SMatt Jacob 		bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
2007d81ba9d5SMatt Jacob 		tgt = ccb->ccb_h.target_id;
2008d81ba9d5SMatt Jacob 		tgt |= (bus << 16);
2009d81ba9d5SMatt Jacob 
20105d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2011ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
20125d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2013478f8a96SJustin T. Gibbs 		if (error) {
2014478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2015478f8a96SJustin T. Gibbs 		} else {
2016478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
2017478f8a96SJustin T. Gibbs 		}
2018478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2019478f8a96SJustin T. Gibbs 		break;
2020478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
2021d81ba9d5SMatt Jacob 	{
2022d81ba9d5SMatt Jacob 		union ccb *accb = ccb->cab.abort_ccb;
20235d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2024d81ba9d5SMatt Jacob 		switch (accb->ccb_h.func_code) {
2025d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2026d81ba9d5SMatt Jacob 		case XPT_ACCEPT_TARGET_IO:
2027d81ba9d5SMatt Jacob 		case XPT_IMMED_NOTIFY:
2028d81ba9d5SMatt Jacob         		ccb->ccb_h.status = isp_abort_tgt_ccb(isp, ccb);
2029d81ba9d5SMatt Jacob 			break;
2030d81ba9d5SMatt Jacob 		case XPT_CONT_TARGET_IO:
2031b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGERR, "cannot abort CTIOs yet");
2032d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_UA_ABORT;
2033d81ba9d5SMatt Jacob 			break;
2034d81ba9d5SMatt Jacob #endif
2035d81ba9d5SMatt Jacob 		case XPT_SCSI_IO:
2036478f8a96SJustin T. Gibbs 			error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
2037478f8a96SJustin T. Gibbs 			if (error) {
2038d81ba9d5SMatt Jacob 				ccb->ccb_h.status = CAM_UA_ABORT;
2039478f8a96SJustin T. Gibbs 			} else {
2040478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
2041478f8a96SJustin T. Gibbs 			}
2042d81ba9d5SMatt Jacob 			break;
2043d81ba9d5SMatt Jacob 		default:
2044d81ba9d5SMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
2045d81ba9d5SMatt Jacob 			break;
2046d81ba9d5SMatt Jacob 		}
20475d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2048478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2049478f8a96SJustin T. Gibbs 		break;
2050d81ba9d5SMatt Jacob 	}
2051ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2052ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
2053ab163f5fSMatt Jacob #else
2054ab163f5fSMatt Jacob #define	IS_CURRENT_SETTINGS(c)	(c->flags & CCB_TRANS_CURRENT_SETTINGS)
2055ab163f5fSMatt Jacob #endif
2056478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
2057478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
20589ce9bdafSMatt Jacob 		if (!IS_CURRENT_SETTINGS(cts)) {
20599ce9bdafSMatt Jacob 			ccb->ccb_h.status = CAM_REQ_INVALID;
20609ce9bdafSMatt Jacob 			xpt_done(ccb);
20619ce9bdafSMatt Jacob 			break;
20629ce9bdafSMatt Jacob 		}
2063478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
20645d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2065ab6c4b31SMatt Jacob 		if (IS_SCSI(isp)) {
2066ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2067478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
2068478f8a96SJustin T. Gibbs 			u_int16_t *dptr;
2069d81ba9d5SMatt Jacob 
2070d81ba9d5SMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2071478f8a96SJustin T. Gibbs 
2072ea6f23cdSMatt Jacob 			sdp += bus;
2073478f8a96SJustin T. Gibbs 			/*
20749ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2075478f8a96SJustin T. Gibbs 			 * so any request to change settings just gets
2076478f8a96SJustin T. Gibbs 			 * vectored to that location.
2077478f8a96SJustin T. Gibbs 			 */
20789ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2079478f8a96SJustin T. Gibbs 
2080478f8a96SJustin T. Gibbs 			/*
2081478f8a96SJustin T. Gibbs 			 * Note that these operations affect the
20829ce9bdafSMatt Jacob 			 * the goal flags (goal_flags)- not
2083478f8a96SJustin T. Gibbs 			 * the current state flags. Then we mark
2084478f8a96SJustin T. Gibbs 			 * things so that the next operation to
2085478f8a96SJustin T. Gibbs 			 * this HBA will cause the update to occur.
2086478f8a96SJustin T. Gibbs 			 */
2087478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_DISC_VALID) {
2088478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
2089478f8a96SJustin T. Gibbs 					*dptr |= DPARM_DISC;
2090478f8a96SJustin T. Gibbs 				} else {
2091478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_DISC;
2092478f8a96SJustin T. Gibbs 				}
2093478f8a96SJustin T. Gibbs 			}
2094478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_TQ_VALID) {
2095478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
2096478f8a96SJustin T. Gibbs 					*dptr |= DPARM_TQING;
2097478f8a96SJustin T. Gibbs 				} else {
2098478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_TQING;
2099478f8a96SJustin T. Gibbs 				}
2100478f8a96SJustin T. Gibbs 			}
2101478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
2102478f8a96SJustin T. Gibbs 				switch (cts->bus_width) {
2103478f8a96SJustin T. Gibbs 				case MSG_EXT_WDTR_BUS_16_BIT:
2104478f8a96SJustin T. Gibbs 					*dptr |= DPARM_WIDE;
2105478f8a96SJustin T. Gibbs 					break;
2106478f8a96SJustin T. Gibbs 				default:
2107478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_WIDE;
2108478f8a96SJustin T. Gibbs 				}
2109478f8a96SJustin T. Gibbs 			}
2110478f8a96SJustin T. Gibbs 			/*
2111478f8a96SJustin T. Gibbs 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
2112478f8a96SJustin T. Gibbs 			 * of nonzero will cause us to go to the
2113478f8a96SJustin T. Gibbs 			 * selected (from NVRAM) maximum value for
2114478f8a96SJustin T. Gibbs 			 * this device. At a later point, we'll
2115478f8a96SJustin T. Gibbs 			 * allow finer control.
2116478f8a96SJustin T. Gibbs 			 */
2117478f8a96SJustin T. Gibbs 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
2118478f8a96SJustin T. Gibbs 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
2119478f8a96SJustin T. Gibbs 			    (cts->sync_offset > 0)) {
2120478f8a96SJustin T. Gibbs 				*dptr |= DPARM_SYNC;
2121478f8a96SJustin T. Gibbs 			} else {
2122478f8a96SJustin T. Gibbs 				*dptr &= ~DPARM_SYNC;
2123478f8a96SJustin T. Gibbs 			}
2124ab6c4b31SMatt Jacob 			*dptr |= DPARM_SAFE_DFLT;
2125ab163f5fSMatt Jacob #else
2126ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2127ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2128ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2129ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2130ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2131ab163f5fSMatt Jacob 			u_int16_t *dptr;
2132ab163f5fSMatt Jacob 
2133ab163f5fSMatt Jacob 			bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2134ab163f5fSMatt Jacob 			sdp += bus;
2135ab163f5fSMatt Jacob 			/*
21369ce9bdafSMatt Jacob 			 * We always update (internally) from goal_flags
2137ab163f5fSMatt Jacob 			 * so any request to change settings just gets
2138ab163f5fSMatt Jacob 			 * vectored to that location.
2139ab163f5fSMatt Jacob 			 */
21409ce9bdafSMatt Jacob 			dptr = &sdp->isp_devparam[tgt].goal_flags;
2141ab163f5fSMatt Jacob 
2142ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
2143ab163f5fSMatt Jacob 				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
2144ab163f5fSMatt Jacob 					*dptr |= DPARM_DISC;
2145ab163f5fSMatt Jacob 				else
2146ab163f5fSMatt Jacob 					*dptr &= ~DPARM_DISC;
2147ab163f5fSMatt Jacob 			}
2148ab163f5fSMatt Jacob 
2149ab163f5fSMatt Jacob 			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2150ab163f5fSMatt Jacob 				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
2151ab163f5fSMatt Jacob 					*dptr |= DPARM_TQING;
2152ab163f5fSMatt Jacob 				else
2153ab163f5fSMatt Jacob 					*dptr &= ~DPARM_TQING;
2154ab163f5fSMatt Jacob 			}
2155ab163f5fSMatt Jacob 
2156ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
2157ab163f5fSMatt Jacob 				if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
2158ab163f5fSMatt Jacob 					*dptr |= DPARM_WIDE;
2159ab163f5fSMatt Jacob 				else
2160ab163f5fSMatt Jacob 					*dptr &= ~DPARM_WIDE;
2161ab163f5fSMatt Jacob 			}
2162ab163f5fSMatt Jacob 
2163ab163f5fSMatt Jacob 			/*
2164ab163f5fSMatt Jacob 			 * XXX: FIX ME
2165ab163f5fSMatt Jacob 			 */
2166ab163f5fSMatt Jacob 			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
21679ce9bdafSMatt Jacob 			    (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
21689ce9bdafSMatt Jacob 			    (spi->sync_period && spi->sync_offset)) {
2169ab163f5fSMatt Jacob 				*dptr |= DPARM_SYNC;
21709ce9bdafSMatt Jacob 				/*
21719ce9bdafSMatt Jacob 				 * XXX: CHECK FOR LEGALITY
21729ce9bdafSMatt Jacob 				 */
21739ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_period =
21749ce9bdafSMatt Jacob 				    spi->sync_period;
21759ce9bdafSMatt Jacob 				sdp->isp_devparam[tgt].goal_offset =
21769ce9bdafSMatt Jacob 				    spi->sync_offset;
2177ab163f5fSMatt Jacob 			} else {
2178ab163f5fSMatt Jacob 				*dptr &= ~DPARM_SYNC;
2179ab163f5fSMatt Jacob 			}
2180ab163f5fSMatt Jacob #endif
2181bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
21829ce9bdafSMatt Jacob 			    "SET bus %d targ %d to flags %x off %x per %x",
21839ce9bdafSMatt Jacob 			    bus, tgt, sdp->isp_devparam[tgt].goal_flags,
21849ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_offset,
21859ce9bdafSMatt Jacob 			    sdp->isp_devparam[tgt].goal_period);
2186478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
2187ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
2188478f8a96SJustin T. Gibbs 		}
21895d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2190478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2191478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2192478f8a96SJustin T. Gibbs 		break;
2193478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
2194478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
2195478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
2196ab163f5fSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2197ab6c4b31SMatt Jacob 		if (IS_FC(isp)) {
2198ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2199478f8a96SJustin T. Gibbs 			/*
2200478f8a96SJustin T. Gibbs 			 * a lot of normal SCSI things don't make sense.
2201478f8a96SJustin T. Gibbs 			 */
2202478f8a96SJustin T. Gibbs 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
2203478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2204478f8a96SJustin T. Gibbs 			/*
2205478f8a96SJustin T. Gibbs 			 * How do you measure the width of a high
2206478f8a96SJustin T. Gibbs 			 * speed serial bus? Well, in bytes.
2207478f8a96SJustin T. Gibbs 			 *
2208478f8a96SJustin T. Gibbs 			 * Offset and period make no sense, though, so we set
2209478f8a96SJustin T. Gibbs 			 * (above) a 'base' transfer speed to be gigabit.
2210478f8a96SJustin T. Gibbs 			 */
2211478f8a96SJustin T. Gibbs 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2212ab163f5fSMatt Jacob #else
2213ab163f5fSMatt Jacob 			fcparam *fcp = isp->isp_param;
2214ab163f5fSMatt Jacob 			struct ccb_trans_settings_fc *fc =
2215ab163f5fSMatt Jacob 			    &cts->xport_specific.fc;
2216478f8a96SJustin T. Gibbs 
2217ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2218ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2219ab163f5fSMatt Jacob 			cts->transport = XPORT_FC;
2220ab163f5fSMatt Jacob 			cts->transport_version = 0;
2221ab163f5fSMatt Jacob 
2222ab163f5fSMatt Jacob 			fc->valid = CTS_FC_VALID_SPEED;
222353036e92SMatt Jacob 			if (fcp->isp_gbspeed == 2)
222453036e92SMatt Jacob 				fc->bitrate = 200000;
222553036e92SMatt Jacob 			else
2226ab163f5fSMatt Jacob 				fc->bitrate = 100000;
2227ab163f5fSMatt Jacob 			if (tgt > 0 && tgt < MAX_FC_TARG) {
2228ab163f5fSMatt Jacob 				struct lportdb *lp = &fcp->portdb[tgt];
2229ab163f5fSMatt Jacob 				fc->wwnn = lp->node_wwn;
2230ab163f5fSMatt Jacob 				fc->wwpn = lp->port_wwn;
2231ab163f5fSMatt Jacob 				fc->port = lp->portid;
2232ab163f5fSMatt Jacob 				fc->valid |= CTS_FC_VALID_WWNN |
2233ab163f5fSMatt Jacob 				    CTS_FC_VALID_WWPN | CTS_FC_VALID_PORT;
2234ab163f5fSMatt Jacob 			}
2235ab163f5fSMatt Jacob #endif
2236ab163f5fSMatt Jacob 		} else {
2237ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2238ab163f5fSMatt Jacob 			struct ccb_trans_settings_scsi *scsi =
2239ab163f5fSMatt Jacob 			    &cts->proto_specific.scsi;
2240ab163f5fSMatt Jacob 			struct ccb_trans_settings_spi *spi =
2241ab163f5fSMatt Jacob 			    &cts->xport_specific.spi;
2242ab163f5fSMatt Jacob #endif
2243ab163f5fSMatt Jacob 			sdparam *sdp = isp->isp_param;
2244ab163f5fSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
2245ab163f5fSMatt Jacob 			u_int16_t dval, pval, oval;
2246ab163f5fSMatt Jacob 
2247ea6f23cdSMatt Jacob 			sdp += bus;
2248ab163f5fSMatt Jacob 
2249ab163f5fSMatt Jacob 			if (IS_CURRENT_SETTINGS(cts)) {
225083ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
225183ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
225283ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
225383ae4407SMatt Jacob 				    NULL);
22549ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].actv_flags;
22559ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].actv_offset;
22569ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].actv_period;
22574394c92fSMatt Jacob 			} else {
22589ce9bdafSMatt Jacob 				dval = sdp->isp_devparam[tgt].nvrm_flags;
22599ce9bdafSMatt Jacob 				oval = sdp->isp_devparam[tgt].nvrm_offset;
22609ce9bdafSMatt Jacob 				pval = sdp->isp_devparam[tgt].nvrm_period;
22614394c92fSMatt Jacob 			}
2262478f8a96SJustin T. Gibbs 
2263ab163f5fSMatt Jacob #ifndef	CAM_NEW_TRAN_CODE
2264478f8a96SJustin T. Gibbs 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
2265478f8a96SJustin T. Gibbs 
2266478f8a96SJustin T. Gibbs 			if (dval & DPARM_DISC) {
2267478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_DISC_ENB;
2268478f8a96SJustin T. Gibbs 			}
2269478f8a96SJustin T. Gibbs 			if (dval & DPARM_TQING) {
2270478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_TAG_ENB;
2271478f8a96SJustin T. Gibbs 			}
2272478f8a96SJustin T. Gibbs 			if (dval & DPARM_WIDE) {
2273478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2274478f8a96SJustin T. Gibbs 			} else {
2275478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2276478f8a96SJustin T. Gibbs 			}
2277478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
2278478f8a96SJustin T. Gibbs 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2279478f8a96SJustin T. Gibbs 
22804394c92fSMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
22814394c92fSMatt Jacob 				cts->sync_period = pval;
22824394c92fSMatt Jacob 				cts->sync_offset = oval;
2283478f8a96SJustin T. Gibbs 				cts->valid |=
2284478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_RATE_VALID |
2285478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_OFFSET_VALID;
2286478f8a96SJustin T. Gibbs 			}
2287ab163f5fSMatt Jacob #else
2288ab163f5fSMatt Jacob 			cts->protocol = PROTO_SCSI;
2289ab163f5fSMatt Jacob 			cts->protocol_version = SCSI_REV_2;
2290ab163f5fSMatt Jacob 			cts->transport = XPORT_SPI;
2291ab163f5fSMatt Jacob 			cts->transport_version = 2;
2292ab163f5fSMatt Jacob 
2293ab163f5fSMatt Jacob 			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2294ab163f5fSMatt Jacob 			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
2295ab163f5fSMatt Jacob 			if (dval & DPARM_DISC) {
2296ab163f5fSMatt Jacob 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2297ab163f5fSMatt Jacob 			}
2298ab163f5fSMatt Jacob 			if (dval & DPARM_TQING) {
2299ab163f5fSMatt Jacob 				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2300ab163f5fSMatt Jacob 			}
23019ce9bdafSMatt Jacob 			if ((dval & DPARM_SYNC) && oval && pval) {
2302ab163f5fSMatt Jacob 				spi->sync_offset = oval;
2303ab163f5fSMatt Jacob 				spi->sync_period = pval;
2304ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
2305ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2306ab163f5fSMatt Jacob 			}
2307ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
2308ab163f5fSMatt Jacob 			if (dval & DPARM_WIDE) {
2309ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2310ab163f5fSMatt Jacob 			} else {
2311ab163f5fSMatt Jacob 				spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2312ab163f5fSMatt Jacob 			}
2313ab163f5fSMatt Jacob 			if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
2314ab163f5fSMatt Jacob 				scsi->valid = CTS_SCSI_VALID_TQ;
2315ab163f5fSMatt Jacob 				spi->valid |= CTS_SPI_VALID_DISC;
2316ab163f5fSMatt Jacob 			} else {
2317ab163f5fSMatt Jacob 				scsi->valid = 0;
2318ab163f5fSMatt Jacob 			}
2319ab163f5fSMatt Jacob #endif
2320bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG0,
23219ce9bdafSMatt Jacob 			    "GET %s bus %d targ %d to flags %x off %x per %x",
23229ce9bdafSMatt Jacob 			    IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM",
23239ce9bdafSMatt Jacob 			    bus, tgt, dval, oval, pval);
2324478f8a96SJustin T. Gibbs 		}
2325ab163f5fSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2326478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2327478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2328478f8a96SJustin T. Gibbs 		break;
2329478f8a96SJustin T. Gibbs 
2330478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
2331478f8a96SJustin T. Gibbs 	{
2332478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
2333478f8a96SJustin T. Gibbs 		u_int32_t secs_per_cylinder;
2334478f8a96SJustin T. Gibbs 		u_int32_t size_mb;
2335478f8a96SJustin T. Gibbs 
2336478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
2337478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
2338bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGERR,
2339bfbab170SMatt Jacob 			    "%d.%d XPT_CALC_GEOMETRY block size 0?",
2340bfbab170SMatt Jacob 			    ccg->ccb_h.target_id, ccg->ccb_h.target_lun);
2341478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
2342478f8a96SJustin T. Gibbs 			xpt_done(ccb);
2343478f8a96SJustin T. Gibbs 			break;
2344478f8a96SJustin T. Gibbs 		}
2345478f8a96SJustin T. Gibbs 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
2346478f8a96SJustin T. Gibbs 		if (size_mb > 1024) {
2347478f8a96SJustin T. Gibbs 			ccg->heads = 255;
2348478f8a96SJustin T. Gibbs 			ccg->secs_per_track = 63;
2349478f8a96SJustin T. Gibbs 		} else {
2350478f8a96SJustin T. Gibbs 			ccg->heads = 64;
2351478f8a96SJustin T. Gibbs 			ccg->secs_per_track = 32;
2352478f8a96SJustin T. Gibbs 		}
2353478f8a96SJustin T. Gibbs 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
2354478f8a96SJustin T. Gibbs 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
2355478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
2356478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2357478f8a96SJustin T. Gibbs 		break;
2358478f8a96SJustin T. Gibbs 	}
2359478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
2360ab6c4b31SMatt Jacob 		bus = cam_sim_bus(sim);
23615d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2362ab6c4b31SMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
23635d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2364478f8a96SJustin T. Gibbs 		if (error)
2365478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
23662b052931SMatt Jacob 		else {
2367ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
2368ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
2369ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
23702b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
2371478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
23722b052931SMatt Jacob 		}
2373478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2374478f8a96SJustin T. Gibbs 		break;
2375478f8a96SJustin T. Gibbs 
2376478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
2377478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2378478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2379478f8a96SJustin T. Gibbs 		break;
2380478f8a96SJustin T. Gibbs 
2381478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
2382478f8a96SJustin T. Gibbs 	{
2383478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
2384478f8a96SJustin T. Gibbs 
2385478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
2386d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2387a1bc34c6SMatt Jacob 		cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
2388d81ba9d5SMatt Jacob #else
2389478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
2390d81ba9d5SMatt Jacob #endif
2391478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
23920470d791SMatt Jacob 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
23930470d791SMatt Jacob 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
23940470d791SMatt Jacob 		cpi->bus_id = cam_sim_bus(sim);
23954394c92fSMatt Jacob 		if (IS_FC(isp)) {
23964394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
23970470d791SMatt Jacob 			/*
23980470d791SMatt Jacob 			 * Because our loop ID can shift from time to time,
23990470d791SMatt Jacob 			 * make our initiator ID out of range of our bus.
24000470d791SMatt Jacob 			 */
24010470d791SMatt Jacob 			cpi->initiator_id = cpi->max_target + 1;
24020470d791SMatt Jacob 
24039deea857SKenneth D. Merry 			/*
24049deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
24059deea857SKenneth D. Merry 			 * Technically not correct because we don't know
24069deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
24079deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
24089deea857SKenneth D. Merry 			 */
240953036e92SMatt Jacob 			if (FCPARAM(isp)->isp_gbspeed == 2)
241053036e92SMatt Jacob 				cpi->base_transfer_speed = 200000;
241153036e92SMatt Jacob 			else
24129deea857SKenneth D. Merry 				cpi->base_transfer_speed = 100000;
24130470d791SMatt Jacob 			cpi->hba_inquiry = PI_TAG_ABLE;
2414ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2415ab163f5fSMatt Jacob 			cpi->transport = XPORT_FC;
2416ab163f5fSMatt Jacob 			cpi->transport_version = 0;	/* WHAT'S THIS FOR? */
2417ab163f5fSMatt Jacob #endif
2418478f8a96SJustin T. Gibbs 		} else {
2419ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
2420ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
24210470d791SMatt Jacob 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
24224394c92fSMatt Jacob 			cpi->hba_misc = 0;
2423ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
24249deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
2425ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2426ab163f5fSMatt Jacob 			cpi->transport = XPORT_SPI;
2427ab163f5fSMatt Jacob 			cpi->transport_version = 2;	/* WHAT'S THIS FOR? */
2428ab163f5fSMatt Jacob #endif
2429478f8a96SJustin T. Gibbs 		}
2430ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2431ab163f5fSMatt Jacob 		cpi->protocol = PROTO_SCSI;
2432ab163f5fSMatt Jacob 		cpi->protocol_version = SCSI_REV_2;
2433ab163f5fSMatt Jacob #endif
2434478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2435478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
2436478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2437478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
2438478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
2439478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2440478f8a96SJustin T. Gibbs 		break;
2441478f8a96SJustin T. Gibbs 	}
2442478f8a96SJustin T. Gibbs 	default:
2443478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
2444478f8a96SJustin T. Gibbs 		xpt_done(ccb);
2445478f8a96SJustin T. Gibbs 		break;
2446478f8a96SJustin T. Gibbs 	}
2447478f8a96SJustin T. Gibbs }
2448d3a9eb2eSMatt Jacob 
2449d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
2450d3a9eb2eSMatt Jacob void
2451c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
2452d3a9eb2eSMatt Jacob {
2453d3a9eb2eSMatt Jacob 	struct ispsoftc *isp = XS_ISP(sccb);
2454d3a9eb2eSMatt Jacob 
2455d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
2456d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
2457b85389e1SMatt Jacob 
2458d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
2459d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
2460d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
246192a1e549SMatt Jacob 		if ((sccb->scsi_status == SCSI_STATUS_CHECK_COND) &&
246292a1e549SMatt Jacob 		    (sccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0) {
246392a1e549SMatt Jacob 			sccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
246492a1e549SMatt Jacob 		} else {
2465d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
2466d3a9eb2eSMatt Jacob 		}
246792a1e549SMatt Jacob 	}
2468b85389e1SMatt Jacob 
24690470d791SMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
2470d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2471d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2472d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
24730470d791SMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
24740470d791SMatt Jacob 			if (sccb->scsi_status != SCSI_STATUS_OK)
2475b09b0095SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2,
2476b09b0095SMatt Jacob 				    "freeze devq %d.%d %x %x",
2477b09b0095SMatt Jacob 				    sccb->ccb_h.target_id,
24780470d791SMatt Jacob 				    sccb->ccb_h.target_lun, sccb->ccb_h.status,
2479b09b0095SMatt Jacob 				    sccb->scsi_status);
2480d3a9eb2eSMatt Jacob 		}
2481d3a9eb2eSMatt Jacob 	}
2482b85389e1SMatt Jacob 
24830470d791SMatt Jacob 	/*
24840470d791SMatt Jacob 	 * If we were frozen waiting resources, clear that we were frozen
24850470d791SMatt Jacob 	 * waiting for resources. If we are no longer frozen, and the devq
24860470d791SMatt Jacob 	 * isn't frozen, mark the completing CCB to have the XPT layer
24870470d791SMatt Jacob 	 * release the simq.
24880470d791SMatt Jacob 	 */
248957c801f5SMatt Jacob 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
249057c801f5SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
24910470d791SMatt Jacob 		if (isp->isp_osinfo.simqfrozen == 0) {
24920470d791SMatt Jacob 			if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
2493b09b0095SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2,
2494b09b0095SMatt Jacob 				    "isp_done->relsimq");
2495d3a9eb2eSMatt Jacob 				sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
24960470d791SMatt Jacob 			} else {
2497b09b0095SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG2,
2498b09b0095SMatt Jacob 				    "isp_done->devq frozen");
2499d3a9eb2eSMatt Jacob 			}
25000470d791SMatt Jacob 		} else {
2501b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2502b09b0095SMatt Jacob 			    "isp_done -> simqfrozen = %x",
2503b09b0095SMatt Jacob 			    isp->isp_osinfo.simqfrozen);
25040470d791SMatt Jacob 		}
25050470d791SMatt Jacob 	}
2506b85389e1SMatt Jacob 	if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
2507d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2508d3a9eb2eSMatt Jacob 		xpt_print_path(sccb->ccb_h.path);
25093c75bb14SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
25103c75bb14SMatt Jacob 		    "cam completion status 0x%x", sccb->ccb_h.status);
2511d3a9eb2eSMatt Jacob 	}
2512b85389e1SMatt Jacob 
2513b85389e1SMatt Jacob 	XS_CMD_S_DONE(sccb);
2514b85389e1SMatt Jacob 	if (XS_CMD_WDOG_P(sccb) == 0) {
2515b85389e1SMatt Jacob 		untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch);
2516b85389e1SMatt Jacob 		if (XS_CMD_GRACE_P(sccb)) {
2517b09b0095SMatt Jacob 			isp_prt(isp, ISP_LOGDEBUG2,
2518b09b0095SMatt Jacob 			    "finished command on borrowed time");
2519b85389e1SMatt Jacob 		}
2520b85389e1SMatt Jacob 		XS_CMD_S_CLEAR(sccb);
25215d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2522d3a9eb2eSMatt Jacob 		xpt_done((union ccb *) sccb);
25235d571944SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2524d3a9eb2eSMatt Jacob 	}
2525b85389e1SMatt Jacob }
2526d3a9eb2eSMatt Jacob 
2527cbf57b47SMatt Jacob int
25280470d791SMatt Jacob isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
2529cbf57b47SMatt Jacob {
2530ea6f23cdSMatt Jacob 	int bus, rv = 0;
2531cbf57b47SMatt Jacob 	switch (cmd) {
2532cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
25330470d791SMatt Jacob 	{
2534ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2535ab163f5fSMatt Jacob 		struct ccb_trans_settings_scsi *scsi;
2536ab163f5fSMatt Jacob 		struct ccb_trans_settings_spi *spi;
2537ab163f5fSMatt Jacob #endif
2538cbf57b47SMatt Jacob 		int flags, tgt;
2539cbf57b47SMatt Jacob 		sdparam *sdp = isp->isp_param;
2540ab163f5fSMatt Jacob 		struct ccb_trans_settings cts;
2541cbf57b47SMatt Jacob 		struct cam_path *tmppath;
2542cbf57b47SMatt Jacob 
2543ab163f5fSMatt Jacob 		bzero(&cts, sizeof (struct ccb_trans_settings));
2544ab163f5fSMatt Jacob 
2545cbf57b47SMatt Jacob 		tgt = *((int *)arg);
2546ea6f23cdSMatt Jacob 		bus = (tgt >> 16) & 0xffff;
2547ea6f23cdSMatt Jacob 		tgt &= 0xffff;
2548ea6f23cdSMatt Jacob 		sdp += bus;
254945c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2550cbf57b47SMatt Jacob 		if (xpt_create_path(&tmppath, NULL,
2551ea6f23cdSMatt Jacob 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
2552ea6f23cdSMatt Jacob 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
255345c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2554bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2555bfbab170SMatt Jacob 			    "isp_async cannot make temp path for %d.%d",
2556bfbab170SMatt Jacob 			    tgt, bus);
2557cbf57b47SMatt Jacob 			rv = -1;
2558cbf57b47SMatt Jacob 			break;
2559cbf57b47SMatt Jacob 		}
256045c9a36aSMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
25619ce9bdafSMatt Jacob 		flags = sdp->isp_devparam[tgt].actv_flags;
2562ab163f5fSMatt Jacob #ifdef	CAM_NEW_TRAN_CODE
2563ab163f5fSMatt Jacob 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
2564ab163f5fSMatt Jacob 		cts.protocol = PROTO_SCSI;
2565ab163f5fSMatt Jacob 		cts.transport = XPORT_SPI;
2566ab163f5fSMatt Jacob 
2567ab163f5fSMatt Jacob 		scsi = &cts.proto_specific.scsi;
2568ab163f5fSMatt Jacob 		spi = &cts.xport_specific.spi;
2569ab163f5fSMatt Jacob 
2570ab163f5fSMatt Jacob 		if (flags & DPARM_TQING) {
2571ab163f5fSMatt Jacob 			scsi->valid |= CTS_SCSI_VALID_TQ;
2572ab163f5fSMatt Jacob 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
2573ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_TAG_ENB;
2574ab163f5fSMatt Jacob 		}
2575ab163f5fSMatt Jacob 
2576cbf57b47SMatt Jacob 		if (flags & DPARM_DISC) {
2577ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_DISC;
2578ab163f5fSMatt Jacob 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
2579ab163f5fSMatt Jacob 		}
2580ab163f5fSMatt Jacob 		spi->flags |= CTS_SPI_VALID_BUS_WIDTH;
2581ab163f5fSMatt Jacob 		if (flags & DPARM_WIDE) {
2582ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2583ab163f5fSMatt Jacob 		} else {
2584ab163f5fSMatt Jacob 			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2585ab163f5fSMatt Jacob 		}
2586ab163f5fSMatt Jacob 		if (flags & DPARM_SYNC) {
2587ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
2588ab163f5fSMatt Jacob 			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
25899ce9bdafSMatt Jacob 			spi->sync_period = sdp->isp_devparam[tgt].actv_period;
25909ce9bdafSMatt Jacob 			spi->sync_offset = sdp->isp_devparam[tgt].actv_offset;
2591ab163f5fSMatt Jacob 		}
2592ab163f5fSMatt Jacob #else
2593ab163f5fSMatt Jacob 		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
2594ab163f5fSMatt Jacob 		cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
2595ab163f5fSMatt Jacob 		if (flags & DPARM_DISC) {
2596ab163f5fSMatt Jacob 			cts.flags |= CCB_TRANS_DISC_ENB;
2597cbf57b47SMatt Jacob 		}
2598cbf57b47SMatt Jacob 		if (flags & DPARM_TQING) {
2599ab163f5fSMatt Jacob 			cts.flags |= CCB_TRANS_TAG_ENB;
2600cbf57b47SMatt Jacob 		}
2601ab163f5fSMatt Jacob 		cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
2602ab163f5fSMatt Jacob 		cts.bus_width = (flags & DPARM_WIDE)?
2603cbf57b47SMatt Jacob 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
26049ce9bdafSMatt Jacob 		cts.sync_period = sdp->isp_devparam[tgt].actv_period;
26059ce9bdafSMatt Jacob 		cts.sync_offset = sdp->isp_devparam[tgt].actv_offset;
2606cbf57b47SMatt Jacob 		if (flags & DPARM_SYNC) {
2607ab163f5fSMatt Jacob 			cts.valid |=
26084394c92fSMatt Jacob 			    CCB_TRANS_SYNC_RATE_VALID |
2609cbf57b47SMatt Jacob 			    CCB_TRANS_SYNC_OFFSET_VALID;
2610cbf57b47SMatt Jacob 		}
2611ab163f5fSMatt Jacob #endif
2612b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGDEBUG2,
2613b09b0095SMatt Jacob 		    "NEW_TGT_PARAMS bus %d tgt %d period %x offset %x flags %x",
26149ce9bdafSMatt Jacob 		    bus, tgt, sdp->isp_devparam[tgt].actv_period,
26159ce9bdafSMatt Jacob 		    sdp->isp_devparam[tgt].actv_offset, flags);
2616ab163f5fSMatt Jacob 		xpt_setup_ccb(&cts.ccb_h, tmppath, 1);
26175d571944SMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2618ab163f5fSMatt Jacob 		xpt_async(AC_TRANSFER_NEG, tmppath, &cts);
2619cbf57b47SMatt Jacob 		xpt_free_path(tmppath);
2620f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
2621cbf57b47SMatt Jacob 		break;
26220470d791SMatt Jacob 	}
262357c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
2624ea6f23cdSMatt Jacob 		bus = *((int *)arg);
2625b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "SCSI bus reset on bus %d detected",
2626b09b0095SMatt Jacob 		    bus);
2627ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
26285d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
2629ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
26305d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2631ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
26325d571944SMatt Jacob 			ISPLOCK_2_CAMLOCK(isp);
263357c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
26345d571944SMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
263557c801f5SMatt Jacob 		}
263657c801f5SMatt Jacob 		break;
26375d571944SMatt Jacob 	case ISPASYNC_LIP:
26385d571944SMatt Jacob 		if (isp->isp_path) {
26395d571944SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
26405d571944SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0, "LIP freeze simq");
26415d571944SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
26425d571944SMatt Jacob 				xpt_freeze_simq(isp->isp_sim, 1);
26435d571944SMatt Jacob 				CAMLOCK_2_ISPLOCK(isp);
26445d571944SMatt Jacob 			}
26455d571944SMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
26465d571944SMatt Jacob 		}
26475d571944SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "LIP Received");
26485d571944SMatt Jacob 		break;
26495d571944SMatt Jacob 	case ISPASYNC_LOOP_RESET:
26505d571944SMatt Jacob 		if (isp->isp_path) {
26515d571944SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
26525d571944SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
26535d571944SMatt Jacob 				    "Loop Reset freeze simq");
26545d571944SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
26555d571944SMatt Jacob 				xpt_freeze_simq(isp->isp_sim, 1);
26565d571944SMatt Jacob 				CAMLOCK_2_ISPLOCK(isp);
26575d571944SMatt Jacob 			}
26585d571944SMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
26595d571944SMatt Jacob 		}
26605d571944SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop Reset Received");
26615d571944SMatt Jacob 		break;
266257c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
266357c801f5SMatt Jacob 		if (isp->isp_path) {
26640470d791SMatt Jacob 			if (isp->isp_osinfo.simqfrozen == 0) {
26655d571944SMatt Jacob 				isp_prt(isp, ISP_LOGDEBUG0,
2666b09b0095SMatt Jacob 				    "loop down freeze simq");
26675d571944SMatt Jacob 				ISPLOCK_2_CAMLOCK(isp);
266857c801f5SMatt Jacob 				xpt_freeze_simq(isp->isp_sim, 1);
26695d571944SMatt Jacob 				CAMLOCK_2_ISPLOCK(isp);
26700470d791SMatt Jacob 			}
267157c801f5SMatt Jacob 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
267257c801f5SMatt Jacob 		}
2673b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
267457c801f5SMatt Jacob 		break;
267557c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
26765d571944SMatt Jacob 		/*
26775d571944SMatt Jacob 		 * Now we just note that Loop has come up. We don't
26785d571944SMatt Jacob 		 * actually do anything because we're waiting for a
26795d571944SMatt Jacob 		 * Change Notify before activating the FC cleanup
26805d571944SMatt Jacob 		 * thread to look at the state of the loop again.
26815d571944SMatt Jacob 		 */
2682b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, "Loop UP");
268357c801f5SMatt Jacob 		break;
2684d6e5500fSMatt Jacob 	case ISPASYNC_PROMENADE:
26850470d791SMatt Jacob 	{
2686ab163f5fSMatt Jacob 		struct cam_path *tmppath;
2687b09b0095SMatt Jacob 		const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x "
2688d6e5500fSMatt Jacob 		    "(role %s) %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x";
2689d6e5500fSMatt Jacob 		static const char *roles[4] = {
26900470d791SMatt Jacob 		    "(none)", "Target", "Initiator", "Target/Initiator"
269157c801f5SMatt Jacob 		};
269202ab3379SMatt Jacob 		fcparam *fcp = isp->isp_param;
269302ab3379SMatt Jacob 		int tgt = *((int *) arg);
2694f44257c2SMatt Jacob 		int is_tgt_mask = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT);
269502ab3379SMatt Jacob 		struct lportdb *lp = &fcp->portdb[tgt];
269602ab3379SMatt Jacob 
2697b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid,
2698d6e5500fSMatt Jacob 		    roles[lp->roles & 0x3],
2699d6e5500fSMatt Jacob 		    (lp->valid)? "Arrived" : "Departed",
270002ab3379SMatt Jacob 		    (u_int32_t) (lp->port_wwn >> 32),
270102ab3379SMatt Jacob 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
270202ab3379SMatt Jacob 		    (u_int32_t) (lp->node_wwn >> 32),
270302ab3379SMatt Jacob 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
2704ab163f5fSMatt Jacob 
270545c9a36aSMatt Jacob 		ISPLOCK_2_CAMLOCK(isp);
2706ab163f5fSMatt Jacob 		if (xpt_create_path(&tmppath, NULL, cam_sim_path(isp->isp_sim),
2707ab163f5fSMatt Jacob 		    (target_id_t)tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
270845c9a36aSMatt Jacob 			CAMLOCK_2_ISPLOCK(isp);
2709ab163f5fSMatt Jacob                         break;
2710ab163f5fSMatt Jacob                 }
2711f44257c2SMatt Jacob 		/*
2712f44257c2SMatt Jacob 		 * Policy: only announce targets.
2713f44257c2SMatt Jacob 		 */
2714f44257c2SMatt Jacob 		if (lp->roles & is_tgt_mask) {
2715f44257c2SMatt Jacob 			if (lp->valid) {
2716ab163f5fSMatt Jacob 				xpt_async(AC_FOUND_DEVICE, tmppath, NULL);
2717ab163f5fSMatt Jacob 			} else {
2718ab163f5fSMatt Jacob 				xpt_async(AC_LOST_DEVICE, tmppath, NULL);
2719ab163f5fSMatt Jacob 			}
2720f44257c2SMatt Jacob 		}
2721ab163f5fSMatt Jacob 		xpt_free_path(tmppath);
2722f44257c2SMatt Jacob 		CAMLOCK_2_ISPLOCK(isp);
27234394c92fSMatt Jacob 		break;
27244394c92fSMatt Jacob 	}
272557c801f5SMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
2726f44257c2SMatt Jacob 		if (arg == ISPASYNC_CHANGE_PDB) {
27274b9d588eSMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
2728f44257c2SMatt Jacob 			    "Port Database Changed");
2729f44257c2SMatt Jacob 		} else if (arg == ISPASYNC_CHANGE_SNS) {
27304b9d588eSMatt Jacob 			isp_prt(isp, ISP_LOGINFO,
27314b9d588eSMatt Jacob 			    "Name Server Database Changed");
27324b9d588eSMatt Jacob 		}
27335d571944SMatt Jacob 		cv_signal(&isp->isp_osinfo.kthread_cv);
273457c801f5SMatt Jacob 		break;
273502ab3379SMatt Jacob 	case ISPASYNC_FABRIC_DEV:
273602ab3379SMatt Jacob 	{
273770d2ccceSMatt Jacob 		int target, lrange;
273870d2ccceSMatt Jacob 		struct lportdb *lp = NULL;
273940cfc8feSMatt Jacob 		char *pt;
274040cfc8feSMatt Jacob 		sns_ganrsp_t *resp = (sns_ganrsp_t *) arg;
274102ab3379SMatt Jacob 		u_int32_t portid;
274240cfc8feSMatt Jacob 		u_int64_t wwpn, wwnn;
274302ab3379SMatt Jacob 		fcparam *fcp = isp->isp_param;
274402ab3379SMatt Jacob 
274502ab3379SMatt Jacob 		portid =
274602ab3379SMatt Jacob 		    (((u_int32_t) resp->snscb_port_id[0]) << 16) |
274702ab3379SMatt Jacob 		    (((u_int32_t) resp->snscb_port_id[1]) << 8) |
274802ab3379SMatt Jacob 		    (((u_int32_t) resp->snscb_port_id[2]));
274940cfc8feSMatt Jacob 
275040cfc8feSMatt Jacob 		wwpn =
275102ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[0]) << 56) |
275202ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[1]) << 48) |
275302ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[2]) << 40) |
275402ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[3]) << 32) |
275502ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[4]) << 24) |
275602ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[5]) << 16) |
275702ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[6]) <<  8) |
275802ab3379SMatt Jacob 		    (((u_int64_t)resp->snscb_portname[7]));
275940cfc8feSMatt Jacob 
276040cfc8feSMatt Jacob 		wwnn =
276140cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[0]) << 56) |
276240cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[1]) << 48) |
276340cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[2]) << 40) |
276440cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[3]) << 32) |
276540cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[4]) << 24) |
276640cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[5]) << 16) |
276740cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[6]) <<  8) |
276840cfc8feSMatt Jacob 		    (((u_int64_t)resp->snscb_nodename[7]));
276940cfc8feSMatt Jacob 		if (portid == 0 || wwpn == 0) {
277002ab3379SMatt Jacob 			break;
277102ab3379SMatt Jacob 		}
277240cfc8feSMatt Jacob 
277340cfc8feSMatt Jacob 		switch (resp->snscb_port_type) {
277440cfc8feSMatt Jacob 		case 1:
277540cfc8feSMatt Jacob 			pt = "   N_Port";
277640cfc8feSMatt Jacob 			break;
277740cfc8feSMatt Jacob 		case 2:
277840cfc8feSMatt Jacob 			pt = "  NL_Port";
277940cfc8feSMatt Jacob 			break;
278040cfc8feSMatt Jacob 		case 3:
278140cfc8feSMatt Jacob 			pt = "F/NL_Port";
278240cfc8feSMatt Jacob 			break;
278340cfc8feSMatt Jacob 		case 0x7f:
278440cfc8feSMatt Jacob 			pt = "  Nx_Port";
278540cfc8feSMatt Jacob 			break;
278640cfc8feSMatt Jacob 		case 0x81:
278740cfc8feSMatt Jacob 			pt = "  F_port";
278840cfc8feSMatt Jacob 			break;
278940cfc8feSMatt Jacob 		case 0x82:
279040cfc8feSMatt Jacob 			pt = "  FL_Port";
279140cfc8feSMatt Jacob 			break;
279240cfc8feSMatt Jacob 		case 0x84:
279340cfc8feSMatt Jacob 			pt = "   E_port";
279440cfc8feSMatt Jacob 			break;
279540cfc8feSMatt Jacob 		default:
279640cfc8feSMatt Jacob 			pt = "?";
279740cfc8feSMatt Jacob 			break;
279840cfc8feSMatt Jacob 		}
2799b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGINFO,
2800b09b0095SMatt Jacob 		    "%s @ 0x%x, Node 0x%08x%08x Port %08x%08x",
2801b09b0095SMatt Jacob 		    pt, portid, ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn),
280240cfc8feSMatt Jacob 		    ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn));
280370d2ccceSMatt Jacob 		/*
280470d2ccceSMatt Jacob 		 * We're only interested in SCSI_FCP types (for now)
280570d2ccceSMatt Jacob 		 */
280670d2ccceSMatt Jacob 		if ((resp->snscb_fc4_types[2] & 1) == 0) {
280702ab3379SMatt Jacob 			break;
280802ab3379SMatt Jacob 		}
280970d2ccceSMatt Jacob 		if (fcp->isp_topo != TOPO_F_PORT)
281070d2ccceSMatt Jacob 			lrange = FC_SNS_ID+1;
281170d2ccceSMatt Jacob 		else
281270d2ccceSMatt Jacob 			lrange = 0;
281370d2ccceSMatt Jacob 		/*
281470d2ccceSMatt Jacob 		 * Is it already in our list?
281570d2ccceSMatt Jacob 		 */
281670d2ccceSMatt Jacob 		for (target = lrange; target < MAX_FC_TARG; target++) {
281770d2ccceSMatt Jacob 			if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
281870d2ccceSMatt Jacob 				continue;
281970d2ccceSMatt Jacob 			}
282070d2ccceSMatt Jacob 			lp = &fcp->portdb[target];
282170d2ccceSMatt Jacob 			if (lp->port_wwn == wwpn && lp->node_wwn == wwnn) {
282270d2ccceSMatt Jacob 				lp->fabric_dev = 1;
282370d2ccceSMatt Jacob 				break;
282470d2ccceSMatt Jacob 			}
282570d2ccceSMatt Jacob 		}
282602ab3379SMatt Jacob 		if (target < MAX_FC_TARG) {
282702ab3379SMatt Jacob 			break;
282802ab3379SMatt Jacob 		}
282970d2ccceSMatt Jacob 		for (target = lrange; target < MAX_FC_TARG; target++) {
283070d2ccceSMatt Jacob 			if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
283170d2ccceSMatt Jacob 				continue;
283270d2ccceSMatt Jacob 			}
283302ab3379SMatt Jacob 			lp = &fcp->portdb[target];
283470d2ccceSMatt Jacob 			if (lp->port_wwn == 0) {
283502ab3379SMatt Jacob 				break;
283602ab3379SMatt Jacob 			}
283770d2ccceSMatt Jacob 		}
283802ab3379SMatt Jacob 		if (target == MAX_FC_TARG) {
2839bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2840bfbab170SMatt Jacob 			    "no more space for fabric devices");
284102ab3379SMatt Jacob 			break;
284202ab3379SMatt Jacob 		}
284340cfc8feSMatt Jacob 		lp->node_wwn = wwnn;
284440cfc8feSMatt Jacob 		lp->port_wwn = wwpn;
284502ab3379SMatt Jacob 		lp->portid = portid;
284670d2ccceSMatt Jacob 		lp->fabric_dev = 1;
284702ab3379SMatt Jacob 		break;
284802ab3379SMatt Jacob 	}
2849d81ba9d5SMatt Jacob #ifdef	ISP_TARGET_MODE
2850d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_MESSAGE:
2851d81ba9d5SMatt Jacob 	{
2852d81ba9d5SMatt Jacob 		tmd_msg_t *mp = arg;
285364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
2854b09b0095SMatt Jacob 		    "bus %d iid %d tgt %d lun %d ttype %x tval %x msg[0]=%x",
2855b09b0095SMatt Jacob 		    mp->nt_bus, (int) mp->nt_iid, (int) mp->nt_tgt,
2856b09b0095SMatt Jacob 		    (int) mp->nt_lun, mp->nt_tagtype, mp->nt_tagval,
2857b09b0095SMatt Jacob 		    mp->nt_msg[0]);
2858d81ba9d5SMatt Jacob 		break;
2859d81ba9d5SMatt Jacob 	}
2860d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_EVENT:
2861d81ba9d5SMatt Jacob 	{
2862d81ba9d5SMatt Jacob 		tmd_event_t *ep = arg;
286364edff94SMatt Jacob 		isp_prt(isp, ISP_LOGALL,
2864b09b0095SMatt Jacob 		    "bus %d event code 0x%x", ep->ev_bus, ep->ev_event);
2865d81ba9d5SMatt Jacob 		break;
2866d81ba9d5SMatt Jacob 	}
2867d81ba9d5SMatt Jacob 	case ISPASYNC_TARGET_ACTION:
2868d81ba9d5SMatt Jacob 		switch (((isphdr_t *)arg)->rqs_entry_type) {
2869cbf57b47SMatt Jacob 		default:
2870bfbab170SMatt Jacob 			isp_prt(isp, ISP_LOGWARN,
2871bfbab170SMatt Jacob 			   "event 0x%x for unhandled target action",
2872bfbab170SMatt Jacob 			    ((isphdr_t *)arg)->rqs_entry_type);
2873d81ba9d5SMatt Jacob 			break;
2874d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO:
2875d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
2876d81ba9d5SMatt Jacob 			break;
2877d81ba9d5SMatt Jacob 		case RQSTYPE_ATIO2:
2878d81ba9d5SMatt Jacob 			rv = isp_handle_platform_atio2(isp, (at2_entry_t *)arg);
2879d81ba9d5SMatt Jacob 			break;
2880d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO2:
2881d81ba9d5SMatt Jacob 		case RQSTYPE_CTIO:
2882d81ba9d5SMatt Jacob 			rv = isp_handle_platform_ctio(isp, arg);
2883d81ba9d5SMatt Jacob 			break;
2884d81ba9d5SMatt Jacob 		case RQSTYPE_ENABLE_LUN:
2885d81ba9d5SMatt Jacob 		case RQSTYPE_MODIFY_LUN:
288664edff94SMatt Jacob 			if (IS_DUALBUS(isp)) {
288764edff94SMatt Jacob 				bus =
288864edff94SMatt Jacob 				    GET_BUS_VAL(((lun_entry_t *)arg)->le_rsvd);
288964edff94SMatt Jacob 			} else {
289064edff94SMatt Jacob 				bus = 0;
289164edff94SMatt Jacob 			}
289264edff94SMatt Jacob 			isp_cv_signal_rqe(isp, bus,
289364edff94SMatt Jacob 			    ((lun_entry_t *)arg)->le_status);
2894d81ba9d5SMatt Jacob 			break;
2895d81ba9d5SMatt Jacob 		}
2896d81ba9d5SMatt Jacob 		break;
2897d81ba9d5SMatt Jacob #endif
2898ab163f5fSMatt Jacob 	case ISPASYNC_FW_CRASH:
2899ab163f5fSMatt Jacob 	{
2900ab163f5fSMatt Jacob 		u_int16_t mbox1, mbox6;
2901ab163f5fSMatt Jacob 		mbox1 = ISP_READ(isp, OUTMAILBOX1);
2902ab163f5fSMatt Jacob 		if (IS_DUALBUS(isp)) {
2903ab163f5fSMatt Jacob 			mbox6 = ISP_READ(isp, OUTMAILBOX6);
2904ab163f5fSMatt Jacob 		} else {
2905ab163f5fSMatt Jacob 			mbox6 = 0;
2906ab163f5fSMatt Jacob 		}
2907ab163f5fSMatt Jacob                 isp_prt(isp, ISP_LOGERR,
2908ab163f5fSMatt Jacob                     "Internal Firmware on bus %d Error @ RISC Address 0x%x",
2909ab163f5fSMatt Jacob                     mbox6, mbox1);
2910ab163f5fSMatt Jacob 		isp_reinit(isp);
2911ab163f5fSMatt Jacob 		break;
2912ab163f5fSMatt Jacob 	}
2913be534d5fSMatt Jacob 	case ISPASYNC_UNHANDLED_RESPONSE:
2914be534d5fSMatt Jacob 		break;
2915d81ba9d5SMatt Jacob 	default:
2916b09b0095SMatt Jacob 		isp_prt(isp, ISP_LOGERR, "unknown isp_async event %d", cmd);
2917cbf57b47SMatt Jacob 		break;
2918cbf57b47SMatt Jacob 	}
2919cbf57b47SMatt Jacob 	return (rv);
2920cbf57b47SMatt Jacob }
2921cbf57b47SMatt Jacob 
292292718a7fSMatt Jacob 
292392718a7fSMatt Jacob /*
292492718a7fSMatt Jacob  * Locks are held before coming here.
292592718a7fSMatt Jacob  */
292692718a7fSMatt Jacob void
292792718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp)
292892718a7fSMatt Jacob {
2929ea6f23cdSMatt Jacob 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
293092718a7fSMatt Jacob 	DISABLE_INTS(isp);
293192718a7fSMatt Jacob }
2932b09b0095SMatt Jacob 
2933b09b0095SMatt Jacob void
2934b09b0095SMatt Jacob isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...)
2935b09b0095SMatt Jacob {
2936b09b0095SMatt Jacob 	va_list ap;
2937b09b0095SMatt Jacob 	if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
2938b09b0095SMatt Jacob 		return;
2939b09b0095SMatt Jacob 	}
29403c75bb14SMatt Jacob 	printf("%s: ", device_get_nameunit(isp->isp_dev));
2941b09b0095SMatt Jacob 	va_start(ap, fmt);
2942b09b0095SMatt Jacob 	vprintf(fmt, ap);
2943b09b0095SMatt Jacob 	va_end(ap);
2944b09b0095SMatt Jacob 	printf("\n");
2945b09b0095SMatt Jacob }
2946