xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 83ae4407f5bdeafee4ea2f8883632f7cd6b14e94)
183ae4407SMatt Jacob /* $Id: isp_freebsd.c,v 1.18 1999/05/11 05:10:06 mjacob Exp $ */
2ea6f23cdSMatt Jacob /* release_5_11_99 */
36054c3f6SMatt Jacob /*
46054c3f6SMatt Jacob  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
56054c3f6SMatt Jacob  *
66054c3f6SMatt Jacob  *---------------------------------------
76054c3f6SMatt Jacob  * Copyright (c) 1997, 1998 by Matthew Jacob
86054c3f6SMatt Jacob  * NASA/Ames Research Center
96054c3f6SMatt Jacob  * All rights reserved.
106054c3f6SMatt Jacob  *---------------------------------------
116054c3f6SMatt Jacob  *
126054c3f6SMatt Jacob  * Redistribution and use in source and binary forms, with or without
136054c3f6SMatt Jacob  * modification, are permitted provided that the following conditions
146054c3f6SMatt Jacob  * are met:
156054c3f6SMatt Jacob  * 1. Redistributions of source code must retain the above copyright
166054c3f6SMatt Jacob  *    notice immediately at the beginning of the file, without modification,
176054c3f6SMatt Jacob  *    this list of conditions, and the following disclaimer.
186054c3f6SMatt Jacob  * 2. Redistributions in binary form must reproduce the above copyright
196054c3f6SMatt Jacob  *    notice, this list of conditions and the following disclaimer in the
206054c3f6SMatt Jacob  *    documentation and/or other materials provided with the distribution.
216054c3f6SMatt Jacob  * 3. The name of the author may not be used to endorse or promote products
226054c3f6SMatt Jacob  *    derived from this software without specific prior written permission.
236054c3f6SMatt Jacob  *
246054c3f6SMatt Jacob  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
256054c3f6SMatt Jacob  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
266054c3f6SMatt Jacob  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
276054c3f6SMatt Jacob  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
286054c3f6SMatt Jacob  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
296054c3f6SMatt Jacob  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
306054c3f6SMatt Jacob  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
316054c3f6SMatt Jacob  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
326054c3f6SMatt Jacob  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
336054c3f6SMatt Jacob  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
346054c3f6SMatt Jacob  * SUCH DAMAGE.
356054c3f6SMatt Jacob  */
366054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h>
376054c3f6SMatt Jacob 
383dd37e43SMatt Jacob #if	__FreeBSD_version >= 300004
393dd37e43SMatt Jacob 
40cbf57b47SMatt Jacob static void isp_cam_async __P((void *, u_int32_t, struct cam_path *, void *));
41478f8a96SJustin T. Gibbs static void isp_poll __P((struct cam_sim *));
42478f8a96SJustin T. Gibbs static void isp_action __P((struct cam_sim *, union ccb *));
43478f8a96SJustin T. Gibbs 
44478f8a96SJustin T. Gibbs void
45c3055363SMatt Jacob isp_attach(struct ispsoftc *isp)
46478f8a96SJustin T. Gibbs {
47ea6f23cdSMatt Jacob 	int primary, secondary;
48478f8a96SJustin T. Gibbs 	struct ccb_setasync csa;
49478f8a96SJustin T. Gibbs 	struct cam_devq *devq;
50ea6f23cdSMatt Jacob 	struct cam_sim *sim;
51ea6f23cdSMatt Jacob 	struct cam_path *path;
52478f8a96SJustin T. Gibbs 
53478f8a96SJustin T. Gibbs 	/*
54ea6f23cdSMatt Jacob 	 * Establish (in case of 12X0) which bus is the primary.
55ea6f23cdSMatt Jacob 	 */
56ea6f23cdSMatt Jacob 
57ea6f23cdSMatt Jacob 	primary = 0;
58ea6f23cdSMatt Jacob 	secondary = 1;
59ea6f23cdSMatt Jacob 
60ea6f23cdSMatt Jacob 	/*
61ea6f23cdSMatt Jacob 	 * Create the device queue for our SIM(s).
62478f8a96SJustin T. Gibbs 	 */
63478f8a96SJustin T. Gibbs 	devq = cam_simq_alloc(MAXISPREQUEST);
64478f8a96SJustin T. Gibbs 	if (devq == NULL) {
65478f8a96SJustin T. Gibbs 		return;
66478f8a96SJustin T. Gibbs 	}
67478f8a96SJustin T. Gibbs 
68478f8a96SJustin T. Gibbs 	/*
69ea6f23cdSMatt Jacob 	 * Construct our SIM entry.
70478f8a96SJustin T. Gibbs 	 */
71ea6f23cdSMatt Jacob 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
72478f8a96SJustin T. Gibbs 	    isp->isp_unit, 1, MAXISPREQUEST, devq);
73ea6f23cdSMatt Jacob 	if (sim == NULL) {
74478f8a96SJustin T. Gibbs 		cam_simq_free(devq);
75478f8a96SJustin T. Gibbs 		return;
76478f8a96SJustin T. Gibbs 	}
77ea6f23cdSMatt Jacob 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
78ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
79478f8a96SJustin T. Gibbs 		return;
80478f8a96SJustin T. Gibbs 	}
81478f8a96SJustin T. Gibbs 
82ea6f23cdSMatt Jacob 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
83478f8a96SJustin T. Gibbs 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
84ea6f23cdSMatt Jacob 		xpt_bus_deregister(cam_sim_path(sim));
85ea6f23cdSMatt Jacob 		cam_sim_free(sim, TRUE);
86478f8a96SJustin T. Gibbs 		return;
87478f8a96SJustin T. Gibbs 	}
88478f8a96SJustin T. Gibbs 
89ea6f23cdSMatt Jacob 	xpt_setup_ccb(&csa.ccb_h, path, 5);
90478f8a96SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
91478f8a96SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
92cbf57b47SMatt Jacob 	csa.callback = isp_cam_async;
93ea6f23cdSMatt Jacob 	csa.callback_arg = sim;
94478f8a96SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
95ea6f23cdSMatt Jacob 	isp->isp_sim = sim;
96ea6f23cdSMatt Jacob 	isp->isp_path = path;
97478f8a96SJustin T. Gibbs 
98ea6f23cdSMatt Jacob 	/*
99ea6f23cdSMatt Jacob 	 * If we have a second channel, construct SIM entry for that.
100ea6f23cdSMatt Jacob 	 */
101ea6f23cdSMatt Jacob 	if (IS_12X0(isp)) {
102ea6f23cdSMatt Jacob 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
103ea6f23cdSMatt Jacob 		    isp->isp_unit, 1, MAXISPREQUEST, devq);
104ea6f23cdSMatt Jacob 		if (sim == NULL) {
105ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
106ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
107ea6f23cdSMatt Jacob 			cam_simq_free(devq);
108ea6f23cdSMatt Jacob 			return;
109ea6f23cdSMatt Jacob 		}
110ea6f23cdSMatt Jacob 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
111ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
112ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
113ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
114ea6f23cdSMatt Jacob 			return;
115ea6f23cdSMatt Jacob 		}
116ea6f23cdSMatt Jacob 
117ea6f23cdSMatt Jacob 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
118ea6f23cdSMatt Jacob 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
119ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
120ea6f23cdSMatt Jacob 			xpt_free_path(isp->isp_path);
121ea6f23cdSMatt Jacob 			xpt_bus_deregister(cam_sim_path(sim));
122ea6f23cdSMatt Jacob 			cam_sim_free(sim, TRUE);
123ea6f23cdSMatt Jacob 			return;
124ea6f23cdSMatt Jacob 		}
125ea6f23cdSMatt Jacob 
126ea6f23cdSMatt Jacob 		xpt_setup_ccb(&csa.ccb_h, path, 5);
127ea6f23cdSMatt Jacob 		csa.ccb_h.func_code = XPT_SASYNC_CB;
128ea6f23cdSMatt Jacob 		csa.event_enable = AC_LOST_DEVICE;
129ea6f23cdSMatt Jacob 		csa.callback = isp_cam_async;
130ea6f23cdSMatt Jacob 		csa.callback_arg = sim;
131ea6f23cdSMatt Jacob 		xpt_action((union ccb *)&csa);
132ea6f23cdSMatt Jacob 		isp->isp_sim2 = sim;
133ea6f23cdSMatt Jacob 		isp->isp_path2 = path;
134ea6f23cdSMatt Jacob 	}
13557c801f5SMatt Jacob 	if (isp->isp_state == ISP_INITSTATE)
136478f8a96SJustin T. Gibbs 		isp->isp_state = ISP_RUNSTATE;
137478f8a96SJustin T. Gibbs }
138478f8a96SJustin T. Gibbs 
139478f8a96SJustin T. Gibbs static void
140cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
141478f8a96SJustin T. Gibbs {
142478f8a96SJustin T. Gibbs 	struct cam_sim *sim;
143478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
144478f8a96SJustin T. Gibbs 
145478f8a96SJustin T. Gibbs 	sim = (struct cam_sim *)cbarg;
146478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *) cam_sim_softc(sim);
147478f8a96SJustin T. Gibbs 	switch (code) {
148478f8a96SJustin T. Gibbs 	case AC_LOST_DEVICE:
149478f8a96SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_SCSI) {
150478f8a96SJustin T. Gibbs 			u_int16_t oflags, nflags;
151478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
152478f8a96SJustin T. Gibbs 			int s, tgt = xpt_path_target_id(path);
153478f8a96SJustin T. Gibbs 
154ea6f23cdSMatt Jacob 			s = splcam();
155ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(sim);
156ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << cam_sim_bus(sim));
157ea6f23cdSMatt Jacob 
158478f8a96SJustin T. Gibbs 			nflags = DPARM_SAFE_DFLT;
15992718a7fSMatt Jacob 			if (ISP_FW_REVX(isp->isp_fwrev) >=
16092718a7fSMatt Jacob 			    ISP_FW_REV(7, 55, 0)) {
161478f8a96SJustin T. Gibbs 				nflags |= DPARM_NARROW | DPARM_ASYNC;
162478f8a96SJustin T. Gibbs 			}
163478f8a96SJustin T. Gibbs 			oflags = sdp->isp_devparam[tgt].dev_flags;
164478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_flags = nflags;
165478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
166478f8a96SJustin T. Gibbs 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
167478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_flags = oflags;
168ea6f23cdSMatt Jacob 			(void) splx(s);
169478f8a96SJustin T. Gibbs 		}
170478f8a96SJustin T. Gibbs 		break;
171478f8a96SJustin T. Gibbs 	default:
172478f8a96SJustin T. Gibbs 		break;
173478f8a96SJustin T. Gibbs 	}
174478f8a96SJustin T. Gibbs }
175478f8a96SJustin T. Gibbs 
176478f8a96SJustin T. Gibbs static void
177c3055363SMatt Jacob isp_poll(struct cam_sim *sim)
178478f8a96SJustin T. Gibbs {
179478f8a96SJustin T. Gibbs 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
180478f8a96SJustin T. Gibbs }
181478f8a96SJustin T. Gibbs 
182478f8a96SJustin T. Gibbs 
183478f8a96SJustin T. Gibbs static void
184c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb)
185478f8a96SJustin T. Gibbs {
186478f8a96SJustin T. Gibbs 	int s, tgt, error;
187478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
1884663e367SJustin T. Gibbs 	struct ccb_trans_settings *cts;
189478f8a96SJustin T. Gibbs 
190478f8a96SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
191478f8a96SJustin T. Gibbs 
192478f8a96SJustin T. Gibbs 	isp = (struct ispsoftc *)cam_sim_softc(sim);
193478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[0].field = 0;
194478f8a96SJustin T. Gibbs 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
19557c801f5SMatt Jacob 	/*
19657c801f5SMatt Jacob 	 * This should only happen for Fibre Channel adapters.
19757c801f5SMatt Jacob 	 * We want to pass through all but XPT_SCSI_IO (e.g.,
19857c801f5SMatt Jacob 	 * path inquiry) but fail if we can't get good Fibre
19957c801f5SMatt Jacob 	 * Channel link status.
20057c801f5SMatt Jacob 	 */
20157c801f5SMatt Jacob 	if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
20257c801f5SMatt Jacob 	    isp->isp_state != ISP_RUNSTATE) {
20357c801f5SMatt Jacob 		s = splcam();
20457c801f5SMatt Jacob 		DISABLE_INTS(isp);
20557c801f5SMatt Jacob 		isp_init(isp);
20657c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
20757c801f5SMatt Jacob 			(void) splx(s);
20857c801f5SMatt Jacob 			/*
20957c801f5SMatt Jacob 			 * Lie. Say it was a selection timeout.
21057c801f5SMatt Jacob 			 */
21157c801f5SMatt Jacob 			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
21257c801f5SMatt Jacob 			xpt_done(ccb);
21357c801f5SMatt Jacob 			return;
21457c801f5SMatt Jacob 		}
21557c801f5SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
21657c801f5SMatt Jacob 		ENABLE_INTS(isp);
21757c801f5SMatt Jacob 		(void) splx(s);
21857c801f5SMatt Jacob 	}
219478f8a96SJustin T. Gibbs 
220478f8a96SJustin T. Gibbs 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
221478f8a96SJustin T. Gibbs 	    ccb->ccb_h.func_code));
222478f8a96SJustin T. Gibbs 
223478f8a96SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
224478f8a96SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
225478f8a96SJustin T. Gibbs 		/*
226478f8a96SJustin T. Gibbs 		 * Do a couple of preliminary checks...
227478f8a96SJustin T. Gibbs 		 */
228478f8a96SJustin T. Gibbs 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
229478f8a96SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
230478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_INVALID;
231478f8a96SJustin T. Gibbs 				xpt_done(ccb);
232478f8a96SJustin T. Gibbs 				break;
233478f8a96SJustin T. Gibbs 			}
234478f8a96SJustin T. Gibbs 		}
235478f8a96SJustin T. Gibbs 
236478f8a96SJustin T. Gibbs 
237478f8a96SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_SCSI) {
238478f8a96SJustin T. Gibbs 			if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) {
239478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_PATH_INVALID;
24092718a7fSMatt Jacob 			} else if (ISP_FW_REVX(isp->isp_fwrev) >=
24192718a7fSMatt Jacob 			    ISP_FW_REV(7, 55, 0)) {
242478f8a96SJustin T. Gibbs 				/*
243478f8a96SJustin T. Gibbs 				 * Too much breakage.
244478f8a96SJustin T. Gibbs 				 */
245478f8a96SJustin T. Gibbs #if	0
246478f8a96SJustin T. Gibbs 				if (ccb->ccb_h.target_lun > 31) {
247478f8a96SJustin T. Gibbs 					ccb->ccb_h.status = CAM_PATH_INVALID;
248478f8a96SJustin T. Gibbs 				}
249478f8a96SJustin T. Gibbs #else
250478f8a96SJustin T. Gibbs 				if (ccb->ccb_h.target_lun > 7) {
251478f8a96SJustin T. Gibbs 					ccb->ccb_h.status = CAM_PATH_INVALID;
252478f8a96SJustin T. Gibbs 				}
253478f8a96SJustin T. Gibbs #endif
254478f8a96SJustin T. Gibbs 			} else if (ccb->ccb_h.target_lun > 7) {
255478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_PATH_INVALID;
256478f8a96SJustin T. Gibbs 			}
257478f8a96SJustin T. Gibbs 		} else {
258478f8a96SJustin T. Gibbs 			if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) {
259478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_PATH_INVALID;
260d3a9eb2eSMatt Jacob #ifdef	SCCLUN
261478f8a96SJustin T. Gibbs 			} else if (ccb->ccb_h.target_lun > 15) {
262478f8a96SJustin T. Gibbs 				ccb->ccb_h.status = CAM_PATH_INVALID;
263d3a9eb2eSMatt Jacob #else
264d3a9eb2eSMatt Jacob 			} else if (ccb->ccb_h.target_lun > 65535) {
265d3a9eb2eSMatt Jacob 				ccb->ccb_h.status = CAM_PATH_INVALID;
266d3a9eb2eSMatt Jacob #endif
267478f8a96SJustin T. Gibbs 			}
268478f8a96SJustin T. Gibbs 		}
269478f8a96SJustin T. Gibbs 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
270478f8a96SJustin T. Gibbs 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
271478f8a96SJustin T. Gibbs 			    isp->isp_name, ccb->ccb_h.target_id,
272478f8a96SJustin T. Gibbs 			    ccb->ccb_h.target_lun);
273478f8a96SJustin T. Gibbs 			xpt_done(ccb);
274478f8a96SJustin T. Gibbs 			break;
275478f8a96SJustin T. Gibbs 		}
276478f8a96SJustin T. Gibbs 		s = splcam();
277c3055363SMatt Jacob 		DISABLE_INTS(isp);
278478f8a96SJustin T. Gibbs 		switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) {
279478f8a96SJustin T. Gibbs 		case CMD_QUEUED:
280478f8a96SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
281478f8a96SJustin T. Gibbs 			break;
282478f8a96SJustin T. Gibbs 		case CMD_EAGAIN:
28357c801f5SMatt Jacob 			if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE)) {
284478f8a96SJustin T. Gibbs 				xpt_freeze_simq(sim, 1);
28557c801f5SMatt Jacob 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
28600f50ce8SMatt Jacob 			}
287478f8a96SJustin T. Gibbs 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
288478f8a96SJustin T. Gibbs                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
289478f8a96SJustin T. Gibbs 			xpt_done(ccb);
290478f8a96SJustin T. Gibbs 			break;
291478f8a96SJustin T. Gibbs 		case CMD_COMPLETE:
292c6904df9SMatt Jacob 			/*
293c6904df9SMatt Jacob 			 * Just make sure that we didn't get it returned
294c6904df9SMatt Jacob 			 * as completed, but with the request still in
295c6904df9SMatt Jacob 			 * progress. In theory, 'cannot happen'.
296c6904df9SMatt Jacob 			 */
297c6904df9SMatt Jacob 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
298478f8a96SJustin T. Gibbs 			    CAM_REQ_INPROG) {
299478f8a96SJustin T. Gibbs 				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
300478f8a96SJustin T. Gibbs 				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
301478f8a96SJustin T. Gibbs 			}
302478f8a96SJustin T. Gibbs 			xpt_done(ccb);
303478f8a96SJustin T. Gibbs 			break;
304478f8a96SJustin T. Gibbs 		}
305c3055363SMatt Jacob 		ENABLE_INTS(isp);
306478f8a96SJustin T. Gibbs 		splx(s);
307478f8a96SJustin T. Gibbs 		break;
308478f8a96SJustin T. Gibbs 
309478f8a96SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
310478f8a96SJustin T. Gibbs 	case XPT_TARGET_IO:		/* Execute target I/O request */
311478f8a96SJustin T. Gibbs 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
312478f8a96SJustin T. Gibbs 	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
313478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
314478f8a96SJustin T. Gibbs 		xpt_done(ccb);
315478f8a96SJustin T. Gibbs 		break;
316478f8a96SJustin T. Gibbs 
317478f8a96SJustin T. Gibbs 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
318ea6f23cdSMatt Jacob 		tgt = ccb->ccb_h.target_id; /* XXX: Which Bus? */
319478f8a96SJustin T. Gibbs 		s = splcam();
320ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
321478f8a96SJustin T. Gibbs 		(void) splx(s);
322478f8a96SJustin T. Gibbs 		if (error) {
323478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
324478f8a96SJustin T. Gibbs 		} else {
325478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
326478f8a96SJustin T. Gibbs 		}
327478f8a96SJustin T. Gibbs 		xpt_done(ccb);
328478f8a96SJustin T. Gibbs 		break;
329478f8a96SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
330478f8a96SJustin T. Gibbs 		s = splcam();
331478f8a96SJustin T. Gibbs 		error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
332478f8a96SJustin T. Gibbs 		(void) splx(s);
333478f8a96SJustin T. Gibbs 		if (error) {
334478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
335478f8a96SJustin T. Gibbs 		} else {
336478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
337478f8a96SJustin T. Gibbs 		}
338478f8a96SJustin T. Gibbs 		xpt_done(ccb);
339478f8a96SJustin T. Gibbs 		break;
340478f8a96SJustin T. Gibbs 
341478f8a96SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
342478f8a96SJustin T. Gibbs 
343478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
344478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
345478f8a96SJustin T. Gibbs 		s = splcam();
346478f8a96SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_FC) {
347478f8a96SJustin T. Gibbs 			;	/* nothing to change */
348478f8a96SJustin T. Gibbs 		} else {
349478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
350478f8a96SJustin T. Gibbs 			u_int16_t *dptr;
351ea6f23cdSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
352478f8a96SJustin T. Gibbs 
353ea6f23cdSMatt Jacob 			sdp += bus;
354478f8a96SJustin T. Gibbs #if	0
355478f8a96SJustin T. Gibbs 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
356478f8a96SJustin T. Gibbs 				dptr = &sdp->isp_devparam[tgt].cur_dflags;
357478f8a96SJustin T. Gibbs 			else
358478f8a96SJustin T. Gibbs 				dptr = &sdp->isp_devparam[tgt].dev_flags;
359478f8a96SJustin T. Gibbs #else
360478f8a96SJustin T. Gibbs 			/*
361478f8a96SJustin T. Gibbs 			 * We always update (internally) from dev_flags
362478f8a96SJustin T. Gibbs 			 * so any request to change settings just gets
363478f8a96SJustin T. Gibbs 			 * vectored to that location.
364478f8a96SJustin T. Gibbs 			 */
365478f8a96SJustin T. Gibbs 			dptr = &sdp->isp_devparam[tgt].dev_flags;
366478f8a96SJustin T. Gibbs #endif
367478f8a96SJustin T. Gibbs 
368478f8a96SJustin T. Gibbs 			/*
369478f8a96SJustin T. Gibbs 			 * Note that these operations affect the
3704394c92fSMatt Jacob 			 * the goal flags (dev_flags)- not
371478f8a96SJustin T. Gibbs 			 * the current state flags. Then we mark
372478f8a96SJustin T. Gibbs 			 * things so that the next operation to
373478f8a96SJustin T. Gibbs 			 * this HBA will cause the update to occur.
374478f8a96SJustin T. Gibbs 			 */
375478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_DISC_VALID) {
376478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
377478f8a96SJustin T. Gibbs 					*dptr |= DPARM_DISC;
378478f8a96SJustin T. Gibbs 				} else {
379478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_DISC;
380478f8a96SJustin T. Gibbs 				}
381478f8a96SJustin T. Gibbs 			}
382478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_TQ_VALID) {
383478f8a96SJustin T. Gibbs 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
384478f8a96SJustin T. Gibbs 					*dptr |= DPARM_TQING;
385478f8a96SJustin T. Gibbs 				} else {
386478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_TQING;
387478f8a96SJustin T. Gibbs 				}
388478f8a96SJustin T. Gibbs 			}
389478f8a96SJustin T. Gibbs 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
390478f8a96SJustin T. Gibbs 				switch (cts->bus_width) {
391478f8a96SJustin T. Gibbs 				case MSG_EXT_WDTR_BUS_16_BIT:
392478f8a96SJustin T. Gibbs 					*dptr |= DPARM_WIDE;
393478f8a96SJustin T. Gibbs 					break;
394478f8a96SJustin T. Gibbs 				default:
395478f8a96SJustin T. Gibbs 					*dptr &= ~DPARM_WIDE;
396478f8a96SJustin T. Gibbs 				}
397478f8a96SJustin T. Gibbs 			}
398478f8a96SJustin T. Gibbs 			/*
399478f8a96SJustin T. Gibbs 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
400478f8a96SJustin T. Gibbs 			 * of nonzero will cause us to go to the
401478f8a96SJustin T. Gibbs 			 * selected (from NVRAM) maximum value for
402478f8a96SJustin T. Gibbs 			 * this device. At a later point, we'll
403478f8a96SJustin T. Gibbs 			 * allow finer control.
404478f8a96SJustin T. Gibbs 			 */
405478f8a96SJustin T. Gibbs 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
406478f8a96SJustin T. Gibbs 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
407478f8a96SJustin T. Gibbs 			    (cts->sync_offset > 0)) {
408478f8a96SJustin T. Gibbs 				*dptr |= DPARM_SYNC;
409478f8a96SJustin T. Gibbs 			} else {
410478f8a96SJustin T. Gibbs 				*dptr &= ~DPARM_SYNC;
411478f8a96SJustin T. Gibbs 			}
41283ae4407SMatt Jacob 			if (bootverbose || isp->isp_dblev >= 3)
41383ae4407SMatt Jacob 				printf("%s: %d.%d set %s period 0x%x offset "
41483ae4407SMatt Jacob 				    "0x%x flags 0x%x\n", isp->isp_name, bus,
41583ae4407SMatt Jacob 				    tgt,
4164394c92fSMatt Jacob 				    (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
4174394c92fSMatt Jacob 				    "current" : "user",
4182b052931SMatt Jacob 				    sdp->isp_devparam[tgt].sync_period,
4192b052931SMatt Jacob 				    sdp->isp_devparam[tgt].sync_offset,
42083ae4407SMatt Jacob 				    sdp->isp_devparam[tgt].dev_flags);
421478f8a96SJustin T. Gibbs 			s = splcam();
422478f8a96SJustin T. Gibbs 			sdp->isp_devparam[tgt].dev_update = 1;
423ea6f23cdSMatt Jacob 			isp->isp_update |= (1 << bus);
424478f8a96SJustin T. Gibbs 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
425478f8a96SJustin T. Gibbs 			(void) splx(s);
426478f8a96SJustin T. Gibbs 		}
427478f8a96SJustin T. Gibbs 		(void) splx(s);
428478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
429478f8a96SJustin T. Gibbs 		xpt_done(ccb);
430478f8a96SJustin T. Gibbs 		break;
431478f8a96SJustin T. Gibbs 
432478f8a96SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
433478f8a96SJustin T. Gibbs 
434478f8a96SJustin T. Gibbs 		cts = &ccb->cts;
435478f8a96SJustin T. Gibbs 		tgt = cts->ccb_h.target_id;
436478f8a96SJustin T. Gibbs 		if (isp->isp_type & ISP_HA_FC) {
437478f8a96SJustin T. Gibbs 			/*
438478f8a96SJustin T. Gibbs 			 * a lot of normal SCSI things don't make sense.
439478f8a96SJustin T. Gibbs 			 */
440478f8a96SJustin T. Gibbs 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
441478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
442478f8a96SJustin T. Gibbs 			/*
443478f8a96SJustin T. Gibbs 			 * How do you measure the width of a high
444478f8a96SJustin T. Gibbs 			 * speed serial bus? Well, in bytes.
445478f8a96SJustin T. Gibbs 			 *
446478f8a96SJustin T. Gibbs 			 * Offset and period make no sense, though, so we set
447478f8a96SJustin T. Gibbs 			 * (above) a 'base' transfer speed to be gigabit.
448478f8a96SJustin T. Gibbs 			 */
449478f8a96SJustin T. Gibbs 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
450478f8a96SJustin T. Gibbs 		} else {
451478f8a96SJustin T. Gibbs 			sdparam *sdp = isp->isp_param;
4524394c92fSMatt Jacob 			u_int16_t dval, pval, oval;
453ea6f23cdSMatt Jacob 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
454478f8a96SJustin T. Gibbs 
455ea6f23cdSMatt Jacob 			sdp += bus;
4564394c92fSMatt Jacob 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) {
45783ae4407SMatt Jacob 				s = splcam();
45883ae4407SMatt Jacob 				/*
45983ae4407SMatt Jacob 				 * First do a refresh to see if things
46083ae4407SMatt Jacob 				 * have changed recently!
46183ae4407SMatt Jacob 				 */
46283ae4407SMatt Jacob 				sdp->isp_devparam[tgt].dev_refresh = 1;
46383ae4407SMatt Jacob 				isp->isp_update |= (1 << bus);
46483ae4407SMatt Jacob 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
46583ae4407SMatt Jacob 				    NULL);
46683ae4407SMatt Jacob 				(void) splx(s);
467478f8a96SJustin T. Gibbs 				dval = sdp->isp_devparam[tgt].cur_dflags;
4684394c92fSMatt Jacob 				oval = sdp->isp_devparam[tgt].cur_offset;
4694394c92fSMatt Jacob 				pval = sdp->isp_devparam[tgt].cur_period;
4704394c92fSMatt Jacob 			} else {
471478f8a96SJustin T. Gibbs 				dval = sdp->isp_devparam[tgt].dev_flags;
4724394c92fSMatt Jacob 				oval = sdp->isp_devparam[tgt].sync_offset;
4734394c92fSMatt Jacob 				pval = sdp->isp_devparam[tgt].sync_period;
4744394c92fSMatt Jacob 			}
475478f8a96SJustin T. Gibbs 
476478f8a96SJustin T. Gibbs 			s = splcam();
477478f8a96SJustin T. Gibbs 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
478478f8a96SJustin T. Gibbs 
479478f8a96SJustin T. Gibbs 			if (dval & DPARM_DISC) {
480478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_DISC_ENB;
481478f8a96SJustin T. Gibbs 			}
482478f8a96SJustin T. Gibbs 			if (dval & DPARM_TQING) {
483478f8a96SJustin T. Gibbs 				cts->flags |= CCB_TRANS_TAG_ENB;
484478f8a96SJustin T. Gibbs 			}
485478f8a96SJustin T. Gibbs 			if (dval & DPARM_WIDE) {
486478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
487478f8a96SJustin T. Gibbs 			} else {
488478f8a96SJustin T. Gibbs 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
489478f8a96SJustin T. Gibbs 			}
490478f8a96SJustin T. Gibbs 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
491478f8a96SJustin T. Gibbs 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
492478f8a96SJustin T. Gibbs 
4934394c92fSMatt Jacob 			if ((dval & DPARM_SYNC) && oval != 0) {
4944394c92fSMatt Jacob 				cts->sync_period = pval;
4954394c92fSMatt Jacob 				cts->sync_offset = oval;
496478f8a96SJustin T. Gibbs 				cts->valid |=
497478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_RATE_VALID |
498478f8a96SJustin T. Gibbs 				    CCB_TRANS_SYNC_OFFSET_VALID;
499478f8a96SJustin T. Gibbs 			}
500478f8a96SJustin T. Gibbs 			splx(s);
50183ae4407SMatt Jacob 			if (bootverbose || isp->isp_dblev >= 3)
50283ae4407SMatt Jacob 				printf("%s: %d.%d get %s period 0x%x offset "
50383ae4407SMatt Jacob 				    "0x%x flags 0x%x\n", isp->isp_name, bus,
50483ae4407SMatt Jacob 				    tgt,
5054394c92fSMatt Jacob 			    	    (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
50683ae4407SMatt Jacob 				    "current" : "user", pval, oval, dval);
507478f8a96SJustin T. Gibbs 		}
508478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
509478f8a96SJustin T. Gibbs 		xpt_done(ccb);
510478f8a96SJustin T. Gibbs 		break;
511478f8a96SJustin T. Gibbs 
512478f8a96SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
513478f8a96SJustin T. Gibbs 	{
514478f8a96SJustin T. Gibbs 		struct ccb_calc_geometry *ccg;
515478f8a96SJustin T. Gibbs 		u_int32_t secs_per_cylinder;
516478f8a96SJustin T. Gibbs 		u_int32_t size_mb;
517478f8a96SJustin T. Gibbs 
518478f8a96SJustin T. Gibbs 		ccg = &ccb->ccg;
519478f8a96SJustin T. Gibbs 		if (ccg->block_size == 0) {
520478f8a96SJustin T. Gibbs 			printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n",
521478f8a96SJustin T. Gibbs 				isp->isp_name, ccg->ccb_h.target_id,
522478f8a96SJustin T. Gibbs 				ccg->ccb_h.target_lun);
523478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
524478f8a96SJustin T. Gibbs 			xpt_done(ccb);
525478f8a96SJustin T. Gibbs 			break;
526478f8a96SJustin T. Gibbs 		}
527478f8a96SJustin T. Gibbs 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
528478f8a96SJustin T. Gibbs 		if (size_mb > 1024) {
529478f8a96SJustin T. Gibbs 			ccg->heads = 255;
530478f8a96SJustin T. Gibbs 			ccg->secs_per_track = 63;
531478f8a96SJustin T. Gibbs 		} else {
532478f8a96SJustin T. Gibbs 			ccg->heads = 64;
533478f8a96SJustin T. Gibbs 			ccg->secs_per_track = 32;
534478f8a96SJustin T. Gibbs 		}
535478f8a96SJustin T. Gibbs 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
536478f8a96SJustin T. Gibbs 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
537478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
538478f8a96SJustin T. Gibbs 		xpt_done(ccb);
539478f8a96SJustin T. Gibbs 		break;
540478f8a96SJustin T. Gibbs 	}
541478f8a96SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified bus */
542ea6f23cdSMatt Jacob 		tgt = cam_sim_bus(sim);
543478f8a96SJustin T. Gibbs 		s = splcam();
544ea6f23cdSMatt Jacob 		error = isp_control(isp, ISPCTL_RESET_BUS, &tgt);
545478f8a96SJustin T. Gibbs 		(void) splx(s);
546478f8a96SJustin T. Gibbs 		if (error)
547478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
5482b052931SMatt Jacob 		else {
549ea6f23cdSMatt Jacob 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
550ea6f23cdSMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
551ea6f23cdSMatt Jacob 			else if (isp->isp_path != NULL)
5522b052931SMatt Jacob 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
553478f8a96SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_CMP;
5542b052931SMatt Jacob 		}
555478f8a96SJustin T. Gibbs 		xpt_done(ccb);
556478f8a96SJustin T. Gibbs 		break;
557478f8a96SJustin T. Gibbs 
558478f8a96SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
559478f8a96SJustin T. Gibbs 		/* Does this need to be implemented? */
560478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
561478f8a96SJustin T. Gibbs 		xpt_done(ccb);
562478f8a96SJustin T. Gibbs 		break;
563478f8a96SJustin T. Gibbs 
564478f8a96SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
565478f8a96SJustin T. Gibbs 	{
566478f8a96SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
567478f8a96SJustin T. Gibbs 
568478f8a96SJustin T. Gibbs 		cpi->version_num = 1;
569478f8a96SJustin T. Gibbs 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
570478f8a96SJustin T. Gibbs 		cpi->target_sprt = 0;
571478f8a96SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
5724394c92fSMatt Jacob 		if (IS_FC(isp)) {
5734394c92fSMatt Jacob 			cpi->hba_misc = PIM_NOBUSRESET;
574478f8a96SJustin T. Gibbs 			cpi->max_target = MAX_FC_TARG-1;
575478f8a96SJustin T. Gibbs 			cpi->initiator_id =
576478f8a96SJustin T. Gibbs 			    ((fcparam *)isp->isp_param)->isp_loopid;
577d3a9eb2eSMatt Jacob #ifdef	SCCLUN
578c3055363SMatt Jacob 			cpi->max_lun = (1 << 16) - 1;
579d3a9eb2eSMatt Jacob #else
580c3055363SMatt Jacob 			cpi->max_lun = (1 << 4) - 1;
581d3a9eb2eSMatt Jacob #endif
5829deea857SKenneth D. Merry 			/*
5839deea857SKenneth D. Merry 			 * Set base transfer capabilities for Fibre Channel.
5849deea857SKenneth D. Merry 			 * Technically not correct because we don't know
5859deea857SKenneth D. Merry 			 * what media we're running on top of- but we'll
5869deea857SKenneth D. Merry 			 * look good if we always say 100MB/s.
5879deea857SKenneth D. Merry 			 */
5889deea857SKenneth D. Merry 			cpi->base_transfer_speed = 100000;
589478f8a96SJustin T. Gibbs 		} else {
590ea6f23cdSMatt Jacob 			sdparam *sdp = isp->isp_param;
591ea6f23cdSMatt Jacob 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
5924394c92fSMatt Jacob 			cpi->hba_misc = 0;
593ea6f23cdSMatt Jacob 			cpi->initiator_id = sdp->isp_initiator_id;
594478f8a96SJustin T. Gibbs 			cpi->max_target =  MAX_TARGETS-1;
59592718a7fSMatt Jacob 			if (ISP_FW_REVX(isp->isp_fwrev) >=
59692718a7fSMatt Jacob 			    ISP_FW_REV(7, 55, 0)) {
597d3a9eb2eSMatt Jacob #if	0
598478f8a96SJustin T. Gibbs 				/*
599478f8a96SJustin T. Gibbs 				 * Too much breakage.
600478f8a96SJustin T. Gibbs 				 */
601c3055363SMatt Jacob 				cpi->max_lun = (1 << 5) - 1;
602478f8a96SJustin T. Gibbs #else
603c3055363SMatt Jacob 				cpi->max_lun = (1 << 3) - 1;
604478f8a96SJustin T. Gibbs #endif
605478f8a96SJustin T. Gibbs 			} else {
606c3055363SMatt Jacob 				cpi->max_lun = (1 << 3) - 1;
607478f8a96SJustin T. Gibbs 			}
6089deea857SKenneth D. Merry 			cpi->base_transfer_speed = 3300;
609478f8a96SJustin T. Gibbs 		}
610478f8a96SJustin T. Gibbs 
611478f8a96SJustin T. Gibbs 		cpi->bus_id = cam_sim_bus(sim);
612478f8a96SJustin T. Gibbs 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
613478f8a96SJustin T. Gibbs 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
614478f8a96SJustin T. Gibbs 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
615478f8a96SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
616478f8a96SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
617478f8a96SJustin T. Gibbs 		xpt_done(ccb);
618478f8a96SJustin T. Gibbs 		break;
619478f8a96SJustin T. Gibbs 	}
620478f8a96SJustin T. Gibbs 	default:
621478f8a96SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
622478f8a96SJustin T. Gibbs 		xpt_done(ccb);
623478f8a96SJustin T. Gibbs 		break;
624478f8a96SJustin T. Gibbs 	}
625478f8a96SJustin T. Gibbs }
626d3a9eb2eSMatt Jacob 
627d3a9eb2eSMatt Jacob #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
628d3a9eb2eSMatt Jacob void
629c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb)
630d3a9eb2eSMatt Jacob {
631d3a9eb2eSMatt Jacob 	struct ispsoftc *isp = XS_ISP(sccb);
632d3a9eb2eSMatt Jacob 
633d3a9eb2eSMatt Jacob 	if (XS_NOERR(sccb))
634d3a9eb2eSMatt Jacob 		XS_SETERR(sccb, CAM_REQ_CMP);
635d3a9eb2eSMatt Jacob 	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
636d3a9eb2eSMatt Jacob 	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
637d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
638d3a9eb2eSMatt Jacob 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
639d3a9eb2eSMatt Jacob 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
640d3a9eb2eSMatt Jacob 		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
641d3a9eb2eSMatt Jacob 	}
642d3a9eb2eSMatt Jacob 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
643d3a9eb2eSMatt Jacob 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
644d3a9eb2eSMatt Jacob 			IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n",
645d3a9eb2eSMatt Jacob 			    isp->isp_name, sccb->ccb_h.target_id,
646d3a9eb2eSMatt Jacob 			    sccb->ccb_h.target_lun, sccb->ccb_h.status));
647d3a9eb2eSMatt Jacob 			xpt_freeze_devq(sccb->ccb_h.path, 1);
648d3a9eb2eSMatt Jacob 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
649d3a9eb2eSMatt Jacob 		}
650d3a9eb2eSMatt Jacob 	}
65157c801f5SMatt Jacob 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
65257c801f5SMatt Jacob 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
653d3a9eb2eSMatt Jacob 		sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
65457c801f5SMatt Jacob 		xpt_release_simq(isp->isp_sim, 1);
655d3a9eb2eSMatt Jacob 	}
656d3a9eb2eSMatt Jacob 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
657d3a9eb2eSMatt Jacob 	if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
658d3a9eb2eSMatt Jacob 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
659d3a9eb2eSMatt Jacob 		xpt_print_path(sccb->ccb_h.path);
660d3a9eb2eSMatt Jacob 		printf("cam completion status 0x%x\n", sccb->ccb_h.status);
661d3a9eb2eSMatt Jacob 	}
662d3a9eb2eSMatt Jacob 	xpt_done((union ccb *) sccb);
663d3a9eb2eSMatt Jacob }
664d3a9eb2eSMatt Jacob 
665cbf57b47SMatt Jacob int
666cbf57b47SMatt Jacob isp_async(isp, cmd, arg)
667cbf57b47SMatt Jacob 	struct ispsoftc *isp;
668cbf57b47SMatt Jacob 	ispasync_t cmd;
669cbf57b47SMatt Jacob 	void *arg;
670cbf57b47SMatt Jacob {
671ea6f23cdSMatt Jacob 	int bus, rv = 0;
672cbf57b47SMatt Jacob 	switch (cmd) {
673cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
674cbf57b47SMatt Jacob 		if (isp->isp_type & ISP_HA_SCSI) {
675cbf57b47SMatt Jacob 			int flags, tgt;
676cbf57b47SMatt Jacob 			sdparam *sdp = isp->isp_param;
677cbf57b47SMatt Jacob 			struct ccb_trans_settings neg;
678cbf57b47SMatt Jacob 			struct cam_path *tmppath;
679cbf57b47SMatt Jacob 
680cbf57b47SMatt Jacob 			tgt = *((int *)arg);
681ea6f23cdSMatt Jacob 			bus = (tgt >> 16) & 0xffff;
682ea6f23cdSMatt Jacob 			tgt &= 0xffff;
683ea6f23cdSMatt Jacob 			sdp += bus;
684cbf57b47SMatt Jacob 			if (xpt_create_path(&tmppath, NULL,
685ea6f23cdSMatt Jacob 			    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
686ea6f23cdSMatt Jacob 			    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
687cbf57b47SMatt Jacob 				xpt_print_path(isp->isp_path);
688cbf57b47SMatt Jacob 				printf("isp_async cannot make temp path for "
689ea6f23cdSMatt Jacob 				    "target %d bus %d\n", tgt, bus);
690cbf57b47SMatt Jacob 				rv = -1;
691cbf57b47SMatt Jacob 				break;
692cbf57b47SMatt Jacob 			}
6934394c92fSMatt Jacob 			flags = sdp->isp_devparam[tgt].cur_dflags;
694cbf57b47SMatt Jacob 			neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
695cbf57b47SMatt Jacob 			if (flags & DPARM_DISC) {
696cbf57b47SMatt Jacob 				neg.flags |= CCB_TRANS_DISC_ENB;
697cbf57b47SMatt Jacob 			}
698cbf57b47SMatt Jacob 			if (flags & DPARM_TQING) {
699cbf57b47SMatt Jacob 				neg.flags |= CCB_TRANS_TAG_ENB;
700cbf57b47SMatt Jacob 			}
701cbf57b47SMatt Jacob 			neg.valid |= CCB_TRANS_BUS_WIDTH_VALID;
702cbf57b47SMatt Jacob 			neg.bus_width = (flags & DPARM_WIDE)?
703cbf57b47SMatt Jacob 			    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
7044394c92fSMatt Jacob 			neg.sync_period = sdp->isp_devparam[tgt].cur_period;
7054394c92fSMatt Jacob 			neg.sync_offset = sdp->isp_devparam[tgt].cur_offset;
706cbf57b47SMatt Jacob 			if (flags & DPARM_SYNC) {
7074394c92fSMatt Jacob 				neg.valid |=
7084394c92fSMatt Jacob 				    CCB_TRANS_SYNC_RATE_VALID |
709cbf57b47SMatt Jacob 				    CCB_TRANS_SYNC_OFFSET_VALID;
710cbf57b47SMatt Jacob 			}
711ea6f23cdSMatt Jacob 			IDPRINTF(3, ("%s: NEW_TGT_PARAMS bus %d tgt %d period "
712ea6f23cdSMatt Jacob 			    "0x%x offset 0x%x flags 0x%x\n", isp->isp_name,
713ea6f23cdSMatt Jacob 			    bus, tgt, neg.sync_period, neg.sync_offset, flags));
714cbf57b47SMatt Jacob 			xpt_setup_ccb(&neg.ccb_h, tmppath, 1);
715cbf57b47SMatt Jacob 			xpt_async(AC_TRANSFER_NEG, tmppath, &neg);
716cbf57b47SMatt Jacob 			xpt_free_path(tmppath);
717cbf57b47SMatt Jacob 		}
718cbf57b47SMatt Jacob 		break;
71957c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
720ea6f23cdSMatt Jacob 		bus = *((int *)arg);
721ea6f23cdSMatt Jacob 		printf("%s: SCSI bus reset on bus %d detected\n",
722ea6f23cdSMatt Jacob 		    isp->isp_name, bus);
723ea6f23cdSMatt Jacob 		if (bus > 0 && isp->isp_path2) {
724ea6f23cdSMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
725ea6f23cdSMatt Jacob 		} else if (isp->isp_path) {
72657c801f5SMatt Jacob 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
72757c801f5SMatt Jacob 		}
72857c801f5SMatt Jacob 		break;
72957c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
73057c801f5SMatt Jacob 		if (isp->isp_path) {
73157c801f5SMatt Jacob 			/*
73257c801f5SMatt Jacob 			 * We can get multiple LOOP downs, so only count one.
73357c801f5SMatt Jacob 			 */
73457c801f5SMatt Jacob 			if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN)) {
73557c801f5SMatt Jacob 				xpt_freeze_simq(isp->isp_sim, 1);
73657c801f5SMatt Jacob 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
73757c801f5SMatt Jacob 				printf("%s: Loop DOWN- freezing SIMQ until Loop"
73857c801f5SMatt Jacob 				    " comes up\n", isp->isp_name);
73957c801f5SMatt Jacob 			}
74057c801f5SMatt Jacob 		} else {
74157c801f5SMatt Jacob 			printf("%s: Loop DOWN\n", isp->isp_name);
74257c801f5SMatt Jacob 		}
74357c801f5SMatt Jacob 		break;
74457c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
74557c801f5SMatt Jacob 		if (isp->isp_path) {
74657c801f5SMatt Jacob 			if (isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) {
74757c801f5SMatt Jacob 				xpt_release_simq(isp->isp_sim, 1);
74857c801f5SMatt Jacob 				isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
74957c801f5SMatt Jacob 				if (isp->isp_osinfo.simqfrozen) {
75057c801f5SMatt Jacob 					printf("%s: Loop UP- SIMQ still "
75157c801f5SMatt Jacob 					    "frozen\n", isp->isp_name);
75257c801f5SMatt Jacob 				} else {
75357c801f5SMatt Jacob 					printf("%s: Loop UP-releasing frozen "
75457c801f5SMatt Jacob 					    "SIMQ\n", isp->isp_name);
75557c801f5SMatt Jacob 				}
75657c801f5SMatt Jacob 			}
75757c801f5SMatt Jacob 		} else {
75857c801f5SMatt Jacob 			printf("%s: Loop UP\n", isp->isp_name);
75957c801f5SMatt Jacob 		}
76057c801f5SMatt Jacob 		break;
76157c801f5SMatt Jacob 	case ISPASYNC_PDB_CHANGE_COMPLETE:
7624394c92fSMatt Jacob 	if (IS_FC(isp)) {
7634394c92fSMatt Jacob 		long i = (long) arg;
76457c801f5SMatt Jacob 		static char *roles[4] = {
76557c801f5SMatt Jacob 		    "No", "Target", "Initiator", "Target/Initiator"
76657c801f5SMatt Jacob 		};
7674394c92fSMatt Jacob 		isp_pdb_t *pdbp = &((fcparam *)isp->isp_param)->isp_pdb[i];
7684394c92fSMatt Jacob 		if (pdbp->pdb_options == INVALID_PDB_OPTIONS) {
7694394c92fSMatt Jacob 			break;
7704394c92fSMatt Jacob 		}
7714394c92fSMatt Jacob 		printf("%s: Loop ID %d, %s role\n", isp->isp_name,
7724394c92fSMatt Jacob 		    pdbp->pdb_loopid, roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
77357c801f5SMatt Jacob 		printf("     Node Address 0x%x WWN 0x"
77457c801f5SMatt Jacob 		    "%02x%02x%02x%02x%02x%02x%02x%02x\n",
77557c801f5SMatt Jacob 		    BITS2WORD(pdbp->pdb_portid_bits),
77657c801f5SMatt Jacob 		    pdbp->pdb_portname[0], pdbp->pdb_portname[1],
77757c801f5SMatt Jacob 		    pdbp->pdb_portname[2], pdbp->pdb_portname[3],
77857c801f5SMatt Jacob 		    pdbp->pdb_portname[4], pdbp->pdb_portname[5],
77957c801f5SMatt Jacob 		    pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
78057c801f5SMatt Jacob 		if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
78157c801f5SMatt Jacob 			printf("     Hard Address 0x%x WWN 0x"
78257c801f5SMatt Jacob 			    "%02x%02x%02x%02x%02x%02x%02x%02x\n",
78357c801f5SMatt Jacob 			    BITS2WORD(pdbp->pdb_hardaddr_bits),
7844394c92fSMatt Jacob 			    pdbp->pdb_nodename[0], pdbp->pdb_nodename[1],
7854394c92fSMatt Jacob 			    pdbp->pdb_nodename[2], pdbp->pdb_nodename[3],
7864394c92fSMatt Jacob 			    pdbp->pdb_nodename[4], pdbp->pdb_nodename[5],
7874394c92fSMatt Jacob 			    pdbp->pdb_nodename[6], pdbp->pdb_nodename[7]);
78857c801f5SMatt Jacob 		switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
78957c801f5SMatt Jacob 		case SVC3_TGT_ROLE|SVC3_INI_ROLE:
79057c801f5SMatt Jacob 			printf("     Master State=%s, Slave State=%s\n",
79157c801f5SMatt Jacob 			    isp2100_pdb_statename(pdbp->pdb_mstate),
79257c801f5SMatt Jacob 			    isp2100_pdb_statename(pdbp->pdb_sstate));
79357c801f5SMatt Jacob 			break;
79457c801f5SMatt Jacob 		case SVC3_TGT_ROLE:
79557c801f5SMatt Jacob 			printf("     Master State=%s\n",
79657c801f5SMatt Jacob 			    isp2100_pdb_statename(pdbp->pdb_mstate));
79757c801f5SMatt Jacob 			break;
79857c801f5SMatt Jacob 		case SVC3_INI_ROLE:
79957c801f5SMatt Jacob 			printf("     Slave State=%s\n",
80057c801f5SMatt Jacob 			    isp2100_pdb_statename(pdbp->pdb_sstate));
80157c801f5SMatt Jacob 			break;
80257c801f5SMatt Jacob 		default:
80357c801f5SMatt Jacob 			break;
80457c801f5SMatt Jacob 		}
80557c801f5SMatt Jacob 		break;
80657c801f5SMatt Jacob 	}
80757c801f5SMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
80857c801f5SMatt Jacob 		printf("%s: Name Server Database Changed\n", isp->isp_name);
80957c801f5SMatt Jacob 		break;
810cbf57b47SMatt Jacob 	default:
811cbf57b47SMatt Jacob 		break;
812cbf57b47SMatt Jacob 	}
813cbf57b47SMatt Jacob 	return (rv);
814cbf57b47SMatt Jacob }
815cbf57b47SMatt Jacob 
81692718a7fSMatt Jacob 
81792718a7fSMatt Jacob /*
81892718a7fSMatt Jacob  * Locks are held before coming here.
81992718a7fSMatt Jacob  */
82092718a7fSMatt Jacob void
82192718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp)
82292718a7fSMatt Jacob {
823ea6f23cdSMatt Jacob 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
82492718a7fSMatt Jacob 	DISABLE_INTS(isp);
82592718a7fSMatt Jacob }
826478f8a96SJustin T. Gibbs #else
827478f8a96SJustin T. Gibbs 
82892718a7fSMatt Jacob #define WATCH_INTERVAL          30
82992718a7fSMatt Jacob 
8306054c3f6SMatt Jacob static void ispminphys __P((struct buf *));
8316054c3f6SMatt Jacob static u_int32_t isp_adapter_info __P((int));
832478f8a96SJustin T. Gibbs static int ispcmd __P((ISP_SCSI_XFER_T *));
833c3055363SMatt Jacob static void isp_watch __P((void *arg));
8346054c3f6SMatt Jacob 
8356054c3f6SMatt Jacob static struct scsi_adapter isp_switch = {
836478f8a96SJustin T. Gibbs 	ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 }
8376054c3f6SMatt Jacob };
8386054c3f6SMatt Jacob static struct scsi_device isp_dev = {
8396054c3f6SMatt Jacob 	NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 }
8406054c3f6SMatt Jacob };
841478f8a96SJustin T. Gibbs static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
842478f8a96SJustin T. Gibbs 
8436054c3f6SMatt Jacob 
8446054c3f6SMatt Jacob /*
8456054c3f6SMatt Jacob  * Complete attachment of hardware, include subdevices.
8466054c3f6SMatt Jacob  */
8476054c3f6SMatt Jacob void
848c3055363SMatt Jacob isp_attach(struct ispsoftc *isp)
8496054c3f6SMatt Jacob {
8506054c3f6SMatt Jacob 	struct scsibus_data *scbus;
8516054c3f6SMatt Jacob 
8526054c3f6SMatt Jacob 	scbus = scsi_alloc_bus();
8536054c3f6SMatt Jacob 	if(!scbus) {
8546054c3f6SMatt Jacob 		return;
8556054c3f6SMatt Jacob 	}
85657c801f5SMatt Jacob 	if (isp->isp_state == ISP_INITSTATE)
8576054c3f6SMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
85857c801f5SMatt Jacob 
85992718a7fSMatt Jacob         timeout(isp_watch, isp, WATCH_INTERVAL * hz);
86092718a7fSMatt Jacob 	isp->isp_dogactive = 1;
8616054c3f6SMatt Jacob 
8626054c3f6SMatt Jacob 	isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit;
8636054c3f6SMatt Jacob 	isp->isp_osinfo._link.adapter_softc = isp;
8646054c3f6SMatt Jacob 	isp->isp_osinfo._link.adapter = &isp_switch;
8656054c3f6SMatt Jacob 	isp->isp_osinfo._link.device = &isp_dev;
8666054c3f6SMatt Jacob 	isp->isp_osinfo._link.flags = 0;
8676054c3f6SMatt Jacob 	if (isp->isp_type & ISP_HA_FC) {
868478f8a96SJustin T. Gibbs 		isp->isp_osinfo._link.adapter_targ =
869478f8a96SJustin T. Gibbs 			((fcparam *)isp->isp_param)->isp_loopid;
8706054c3f6SMatt Jacob 		scbus->maxtarg = MAX_FC_TARG-1;
8716054c3f6SMatt Jacob 	} else {
872ea6f23cdSMatt Jacob 		int tmp = 0;	/* XXXX: Which Bus? */
87392718a7fSMatt Jacob 		isp->isp_osinfo.delay_throttle_count = 1;
8746054c3f6SMatt Jacob 		isp->isp_osinfo._link.adapter_targ =
8756054c3f6SMatt Jacob 			((sdparam *)isp->isp_param)->isp_initiator_id;
8766054c3f6SMatt Jacob 		scbus->maxtarg = MAX_TARGETS-1;
877ea6f23cdSMatt Jacob 		(void) isp_control(isp, ISPCTL_RESET_BUS, &tmp);
8788ea807adSMatt Jacob 	}
8792b052931SMatt Jacob 
8806054c3f6SMatt Jacob 	/*
8816054c3f6SMatt Jacob 	 * Prepare the scsibus_data area for the upperlevel scsi code.
8826054c3f6SMatt Jacob 	 */
8836054c3f6SMatt Jacob 	scbus->adapter_link = &isp->isp_osinfo._link;
8846054c3f6SMatt Jacob 
8856054c3f6SMatt Jacob 	/*
8866054c3f6SMatt Jacob 	 * ask the adapter what subunits are present
8876054c3f6SMatt Jacob 	 */
8886054c3f6SMatt Jacob 	scsi_attachdevs(scbus);
8896054c3f6SMatt Jacob }
8906054c3f6SMatt Jacob 
8916054c3f6SMatt Jacob 
8926054c3f6SMatt Jacob /*
8936054c3f6SMatt Jacob  * minphys our xfers
8946054c3f6SMatt Jacob  *
8956054c3f6SMatt Jacob  * Unfortunately, the buffer pointer describes the target device- not the
8966054c3f6SMatt Jacob  * adapter device, so we can't use the pointer to find out what kind of
8976054c3f6SMatt Jacob  * adapter we are and adjust accordingly.
8986054c3f6SMatt Jacob  */
8996054c3f6SMatt Jacob 
9006054c3f6SMatt Jacob static void
901c3055363SMatt Jacob ispminphys(struct buf *bp)
9026054c3f6SMatt Jacob {
9036054c3f6SMatt Jacob 	/*
904478f8a96SJustin T. Gibbs 	 * Only the 10X0 has a 24 bit limit.
9056054c3f6SMatt Jacob 	 */
9066054c3f6SMatt Jacob 	if (bp->b_bcount >= (1 << 24)) {
9076054c3f6SMatt Jacob 		bp->b_bcount = (1 << 24);
9086054c3f6SMatt Jacob 	}
9096054c3f6SMatt Jacob }
9106054c3f6SMatt Jacob 
9116054c3f6SMatt Jacob static u_int32_t
912c3055363SMatt Jacob isp_adapter_info(int unit)
9136054c3f6SMatt Jacob {
9146054c3f6SMatt Jacob 	/*
9156054c3f6SMatt Jacob  	 * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT
9166054c3f6SMatt Jacob 	 */
9176054c3f6SMatt Jacob 	return (2);
9186054c3f6SMatt Jacob }
919478f8a96SJustin T. Gibbs 
920478f8a96SJustin T. Gibbs static int
921c3055363SMatt Jacob ispcmd(ISP_SCSI_XFER_T *xs)
922478f8a96SJustin T. Gibbs {
923478f8a96SJustin T. Gibbs 	struct ispsoftc *isp;
92457c801f5SMatt Jacob 	int r, s;
925478f8a96SJustin T. Gibbs 
926478f8a96SJustin T. Gibbs 	isp = XS_ISP(xs);
92757c801f5SMatt Jacob 	s = splbio();
92857c801f5SMatt Jacob 	DISABLE_INTS(isp);
92957c801f5SMatt Jacob 	if (isp->isp_state != ISP_RUNSTATE) {
93057c801f5SMatt Jacob 		isp_init(isp);
93157c801f5SMatt Jacob 		if (isp->isp_state != ISP_INITSTATE) {
93257c801f5SMatt Jacob 			ENABLE_INTS(isp);
93357c801f5SMatt Jacob 			(void) splx(s);
93457c801f5SMatt Jacob 			XS_SETERR(xs, HBA_BOTCH);
93557c801f5SMatt Jacob 			return (CMD_COMPLETE);
93657c801f5SMatt Jacob 		}
93792718a7fSMatt Jacob 		isp->isp_state = ISP_RUNSTATE;
93857c801f5SMatt Jacob 	}
939478f8a96SJustin T. Gibbs 	r = ispscsicmd(xs);
94057c801f5SMatt Jacob 	ENABLE_INTS(isp);
941478f8a96SJustin T. Gibbs 	if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) {
94257c801f5SMatt Jacob 		(void) splx(s);
943478f8a96SJustin T. Gibbs 		return (r);
944478f8a96SJustin T. Gibbs 	}
945478f8a96SJustin T. Gibbs 
946478f8a96SJustin T. Gibbs 	/*
947478f8a96SJustin T. Gibbs 	 * If we can't use interrupts, poll on completion.
948478f8a96SJustin T. Gibbs 	 */
949478f8a96SJustin T. Gibbs 	if (isp_poll(isp, xs, XS_TIME(xs))) {
950478f8a96SJustin T. Gibbs 		/*
951478f8a96SJustin T. Gibbs 		 * If no other error occurred but we didn't finish,
952478f8a96SJustin T. Gibbs 		 * something bad happened.
953478f8a96SJustin T. Gibbs 		 */
954478f8a96SJustin T. Gibbs 		if (XS_IS_CMD_DONE(xs) == 0) {
955478f8a96SJustin T. Gibbs 			isp->isp_nactive--;
956478f8a96SJustin T. Gibbs 			if (isp->isp_nactive < 0)
957478f8a96SJustin T. Gibbs 				isp->isp_nactive = 0;
958478f8a96SJustin T. Gibbs 			if (XS_NOERR(xs)) {
959478f8a96SJustin T. Gibbs 				isp_lostcmd(isp, xs);
960478f8a96SJustin T. Gibbs 				XS_SETERR(xs, HBA_BOTCH);
961478f8a96SJustin T. Gibbs 			}
962478f8a96SJustin T. Gibbs 		}
963478f8a96SJustin T. Gibbs 	}
96457c801f5SMatt Jacob 	(void) splx(s);
965478f8a96SJustin T. Gibbs 	return (CMD_COMPLETE);
966478f8a96SJustin T. Gibbs }
967478f8a96SJustin T. Gibbs 
968478f8a96SJustin T. Gibbs static int
969c3055363SMatt Jacob isp_poll(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, int mswait)
970478f8a96SJustin T. Gibbs {
971478f8a96SJustin T. Gibbs 
972478f8a96SJustin T. Gibbs 	while (mswait) {
973478f8a96SJustin T. Gibbs 		/* Try the interrupt handling routine */
974478f8a96SJustin T. Gibbs 		(void)isp_intr((void *)isp);
975478f8a96SJustin T. Gibbs 
976478f8a96SJustin T. Gibbs 		/* See if the xs is now done */
977478f8a96SJustin T. Gibbs 		if (XS_IS_CMD_DONE(xs))
978478f8a96SJustin T. Gibbs 			return (0);
979478f8a96SJustin T. Gibbs 		SYS_DELAY(1000);	/* wait one millisecond */
980478f8a96SJustin T. Gibbs 		mswait--;
981478f8a96SJustin T. Gibbs 	}
982478f8a96SJustin T. Gibbs 	return (1);
983478f8a96SJustin T. Gibbs }
984c3055363SMatt Jacob 
985c3055363SMatt Jacob static void
986c3055363SMatt Jacob isp_watch(void *arg)
987c3055363SMatt Jacob {
988c3055363SMatt Jacob 	int i;
989c3055363SMatt Jacob 	struct ispsoftc *isp = arg;
990c3055363SMatt Jacob 	ISP_SCSI_XFER_T *xs;
99192718a7fSMatt Jacob 	int s;
992c3055363SMatt Jacob 
993c3055363SMatt Jacob 	/*
994c3055363SMatt Jacob 	 * Look for completely dead commands (but not polled ones).
995c3055363SMatt Jacob 	 */
99692718a7fSMatt Jacob 	s = splbio();
997c3055363SMatt Jacob 	for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
998c3055363SMatt Jacob 		if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
999c3055363SMatt Jacob 			continue;
1000c3055363SMatt Jacob 		}
1001c3055363SMatt Jacob 		if (XS_TIME(xs) == 0) {
1002c3055363SMatt Jacob 			continue;
1003c3055363SMatt Jacob 		}
1004c3055363SMatt Jacob 		XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
100592718a7fSMatt Jacob 
1006c3055363SMatt Jacob 		/*
1007c3055363SMatt Jacob 		 * Avoid later thinking that this
1008c3055363SMatt Jacob 		 * transaction is not being timed.
1009c3055363SMatt Jacob 		 * Then give ourselves to watchdog
1010c3055363SMatt Jacob 		 * periods of grace.
1011c3055363SMatt Jacob 		 */
1012c3055363SMatt Jacob 		if (XS_TIME(xs) == 0)
1013c3055363SMatt Jacob 			XS_TIME(xs) = 1;
1014c3055363SMatt Jacob 		else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) {
1015c3055363SMatt Jacob 			continue;
1016c3055363SMatt Jacob 		}
101792718a7fSMatt Jacob 		if (IS_SCSI(isp)) {
101892718a7fSMatt Jacob 			isp->isp_osinfo.delay_throttle_count = 1;
101992718a7fSMatt Jacob 		}
1020c3055363SMatt Jacob 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
1021c3055363SMatt Jacob 			printf("%s: isp_watch failed to abort command\n",
1022c3055363SMatt Jacob 			    isp->isp_name);
1023c3055363SMatt Jacob 			isp_restart(isp);
1024c3055363SMatt Jacob 			break;
1025c3055363SMatt Jacob 		}
1026c3055363SMatt Jacob 	}
102792718a7fSMatt Jacob 	if (isp->isp_osinfo.delay_throttle_count) {
102892718a7fSMatt Jacob 		if (--isp->isp_osinfo.delay_throttle_count == 0) {
102992718a7fSMatt Jacob 			sdparam *sdp = isp->isp_param;
103092718a7fSMatt Jacob 			for (i = 0; i < MAX_TARGETS; i++) {
103192718a7fSMatt Jacob 				sdp->isp_devparam[i].dev_flags |=
103292718a7fSMatt Jacob 					DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
103392718a7fSMatt Jacob 				sdp->isp_devparam[i].dev_update = 1;
103492718a7fSMatt Jacob 			}
103592718a7fSMatt Jacob 			isp->isp_update = 1;
103692718a7fSMatt Jacob 		}
103792718a7fSMatt Jacob 	}
103892718a7fSMatt Jacob         timeout(isp_watch, isp, WATCH_INTERVAL * hz);
103992718a7fSMatt Jacob 	isp->isp_dogactive = 1;
104092718a7fSMatt Jacob 	splx(s);
1041c3055363SMatt Jacob }
1042cbf57b47SMatt Jacob 
1043cbf57b47SMatt Jacob int
1044cbf57b47SMatt Jacob isp_async(isp, cmd, arg)
1045cbf57b47SMatt Jacob 	struct ispsoftc *isp;
1046cbf57b47SMatt Jacob 	ispasync_t cmd;
1047cbf57b47SMatt Jacob 	void *arg;
1048cbf57b47SMatt Jacob {
1049cbf57b47SMatt Jacob 	switch (cmd) {
1050cbf57b47SMatt Jacob 	case ISPASYNC_NEW_TGT_PARAMS:
1051cbf57b47SMatt Jacob 		if (isp->isp_type & ISP_HA_SCSI) {
1052cbf57b47SMatt Jacob 			sdparam *sdp = isp->isp_param;
1053cbf57b47SMatt Jacob 			char *wt;
10544394c92fSMatt Jacob 			int mhz, flags, tgt, period;
1055cbf57b47SMatt Jacob 
1056cbf57b47SMatt Jacob 			tgt = *((int *) arg);
1057cbf57b47SMatt Jacob 
10584394c92fSMatt Jacob 			flags = sdp->isp_devparam[tgt].cur_dflags;
10594394c92fSMatt Jacob 			period = sdp->isp_devparam[tgt].cur_period;
10604394c92fSMatt Jacob 			if ((flags & DPARM_SYNC) && period &&
10614394c92fSMatt Jacob 			    (sdp->isp_devparam[tgt].cur_offset) != 0) {
10624394c92fSMatt Jacob 				if (sdp->isp_lvdmode) {
10634394c92fSMatt Jacob 					switch (period) {
10644394c92fSMatt Jacob 					case 0xa:
10654394c92fSMatt Jacob 						mhz = 40;
10664394c92fSMatt Jacob 						break;
10674394c92fSMatt Jacob 					case 0xb:
10684394c92fSMatt Jacob 						mhz = 33;
10694394c92fSMatt Jacob 						break;
10704394c92fSMatt Jacob 					case 0xc:
10714394c92fSMatt Jacob 						mhz = 25;
10724394c92fSMatt Jacob 						break;
10734394c92fSMatt Jacob 					default:
10744394c92fSMatt Jacob 						mhz = 1000 / (period * 4);
10754394c92fSMatt Jacob 						break;
10764394c92fSMatt Jacob 					}
1077cbf57b47SMatt Jacob 				} else {
10784394c92fSMatt Jacob 					mhz = 1000 / (period * 4);
10794394c92fSMatt Jacob 				}
10804394c92fSMatt Jacob 			} else {
10814394c92fSMatt Jacob 				mhz = 0;
1082cbf57b47SMatt Jacob 			}
1083cbf57b47SMatt Jacob 			switch (flags & (DPARM_WIDE|DPARM_TQING)) {
1084cbf57b47SMatt Jacob 			case DPARM_WIDE:
1085cbf57b47SMatt Jacob 				wt = ", 16 bit wide\n";
1086cbf57b47SMatt Jacob 				break;
1087cbf57b47SMatt Jacob 			case DPARM_TQING:
1088cbf57b47SMatt Jacob 				wt = ", Tagged Queueing Enabled\n";
1089cbf57b47SMatt Jacob 				break;
1090cbf57b47SMatt Jacob 			case DPARM_WIDE|DPARM_TQING:
1091cbf57b47SMatt Jacob 				wt = ", 16 bit wide, Tagged Queueing Enabled\n";
1092cbf57b47SMatt Jacob 				break;
1093cbf57b47SMatt Jacob 			default:
1094cbf57b47SMatt Jacob 				wt = "\n";
1095cbf57b47SMatt Jacob 				break;
1096cbf57b47SMatt Jacob 			}
10974394c92fSMatt Jacob 			if (mhz) {
1098cbf57b47SMatt Jacob 				printf("%s: Target %d at %dMHz Max Offset %d%s",
10994394c92fSMatt Jacob 				    isp->isp_name, tgt, mhz,
11004394c92fSMatt Jacob 				    sdp->isp_devparam[tgt].cur_offset, wt);
1101cbf57b47SMatt Jacob 			} else {
1102cbf57b47SMatt Jacob 				printf("%s: Target %d Async Mode%s",
1103cbf57b47SMatt Jacob 				    isp->isp_name, tgt, wt);
1104cbf57b47SMatt Jacob 			}
1105cbf57b47SMatt Jacob 		}
1106cbf57b47SMatt Jacob 		break;
110757c801f5SMatt Jacob 	case ISPASYNC_BUS_RESET:
110857c801f5SMatt Jacob 		printf("%s: SCSI bus reset detected\n", isp->isp_name);
110957c801f5SMatt Jacob 		break;
111057c801f5SMatt Jacob 	case ISPASYNC_LOOP_DOWN:
111157c801f5SMatt Jacob 		printf("%s: Loop DOWN\n", isp->isp_name);
111257c801f5SMatt Jacob 		break;
111357c801f5SMatt Jacob 	case ISPASYNC_LOOP_UP:
111457c801f5SMatt Jacob 		printf("%s: Loop UP\n", isp->isp_name);
111557c801f5SMatt Jacob 		break;
111657c801f5SMatt Jacob 	case ISPASYNC_PDB_CHANGE_COMPLETE:
111757c801f5SMatt Jacob 	if (isp->isp_type & ISP_HA_FC) {
111857c801f5SMatt Jacob 		int i;
111957c801f5SMatt Jacob 		static char *roles[4] = {
112057c801f5SMatt Jacob 		    "No", "Target", "Initiator", "Target/Initiator"
112157c801f5SMatt Jacob 		};
112292718a7fSMatt Jacob 		for (i = 0; i < MAX_FC_TARG; i++)  {
112357c801f5SMatt Jacob 			isp_pdb_t *pdbp =
112457c801f5SMatt Jacob 			    &((fcparam *)isp->isp_param)->isp_pdb[i];
112557c801f5SMatt Jacob 			if (pdbp->pdb_options == INVALID_PDB_OPTIONS)
112657c801f5SMatt Jacob 				continue;
112757c801f5SMatt Jacob 			printf("%s: Loop ID %d, %s role\n",
112857c801f5SMatt Jacob 			    isp->isp_name, pdbp->pdb_loopid,
112957c801f5SMatt Jacob 			    roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
113057c801f5SMatt Jacob 			printf("     Node Address 0x%x WWN 0x"
113157c801f5SMatt Jacob 			    "%02x%02x%02x%02x%02x%02x%02x%02x\n",
113257c801f5SMatt Jacob 			    BITS2WORD(pdbp->pdb_portid_bits),
113357c801f5SMatt Jacob 			    pdbp->pdb_portname[0], pdbp->pdb_portname[1],
113457c801f5SMatt Jacob 			    pdbp->pdb_portname[2], pdbp->pdb_portname[3],
113557c801f5SMatt Jacob 			    pdbp->pdb_portname[4], pdbp->pdb_portname[5],
113657c801f5SMatt Jacob 			    pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
113757c801f5SMatt Jacob 			if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
113857c801f5SMatt Jacob 				printf("     Hard Address 0x%x WWN 0x"
113957c801f5SMatt Jacob 				    "%02x%02x%02x%02x%02x%02x%02x%02x\n",
114057c801f5SMatt Jacob 				    BITS2WORD(pdbp->pdb_hardaddr_bits),
114157c801f5SMatt Jacob 				    pdbp->pdb_nodename[0],
114257c801f5SMatt Jacob 				    pdbp->pdb_nodename[1],
114357c801f5SMatt Jacob 				    pdbp->pdb_nodename[2],
114457c801f5SMatt Jacob 				    pdbp->pdb_nodename[3],
114557c801f5SMatt Jacob 				    pdbp->pdb_nodename[4],
114657c801f5SMatt Jacob 				    pdbp->pdb_nodename[5],
114757c801f5SMatt Jacob 				    pdbp->pdb_nodename[6],
114857c801f5SMatt Jacob 				    pdbp->pdb_nodename[7]);
114957c801f5SMatt Jacob 			switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
115057c801f5SMatt Jacob 			case SVC3_TGT_ROLE|SVC3_INI_ROLE:
115157c801f5SMatt Jacob 				printf("     Master State=%s, Slave State=%s\n",
115257c801f5SMatt Jacob 				    isp2100_pdb_statename(pdbp->pdb_mstate),
115357c801f5SMatt Jacob 				    isp2100_pdb_statename(pdbp->pdb_sstate));
115457c801f5SMatt Jacob 				break;
115557c801f5SMatt Jacob 			case SVC3_TGT_ROLE:
115657c801f5SMatt Jacob 				printf("     Master State=%s\n",
115757c801f5SMatt Jacob 				    isp2100_pdb_statename(pdbp->pdb_mstate));
115857c801f5SMatt Jacob 				break;
115957c801f5SMatt Jacob 			case SVC3_INI_ROLE:
116057c801f5SMatt Jacob 				printf("     Slave State=%s\n",
116157c801f5SMatt Jacob 				    isp2100_pdb_statename(pdbp->pdb_sstate));
116257c801f5SMatt Jacob 				break;
116357c801f5SMatt Jacob 			default:
116457c801f5SMatt Jacob 				break;
116557c801f5SMatt Jacob 			}
116657c801f5SMatt Jacob 		}
116757c801f5SMatt Jacob 		break;
116857c801f5SMatt Jacob 	}
116957c801f5SMatt Jacob 	case ISPASYNC_CHANGE_NOTIFY:
117057c801f5SMatt Jacob 		printf("%s: Name Server Database Changed\n", isp->isp_name);
117157c801f5SMatt Jacob 		break;
1172cbf57b47SMatt Jacob 	default:
1173cbf57b47SMatt Jacob 		break;
1174cbf57b47SMatt Jacob 	}
1175cbf57b47SMatt Jacob 	return (0);
1176cbf57b47SMatt Jacob }
1177c3055363SMatt Jacob 
1178c3055363SMatt Jacob /*
1179c3055363SMatt Jacob  * Free any associated resources prior to decommissioning and
1180c3055363SMatt Jacob  * set the card to a known state (so it doesn't wake up and kick
1181c3055363SMatt Jacob  * us when we aren't expecting it to).
1182c3055363SMatt Jacob  *
1183c3055363SMatt Jacob  * Locks are held before coming here.
1184c3055363SMatt Jacob  */
1185c3055363SMatt Jacob void
118692718a7fSMatt Jacob isp_uninit(isp)
118792718a7fSMatt Jacob 	struct ispsoftc *isp;
1188c3055363SMatt Jacob {
118992718a7fSMatt Jacob 	int s = splbio();
1190c3055363SMatt Jacob 	/*
1191c3055363SMatt Jacob 	 * Leave with interrupts disabled.
1192c3055363SMatt Jacob 	 */
1193ea6f23cdSMatt Jacob 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
1194c3055363SMatt Jacob 	DISABLE_INTS(isp);
1195c3055363SMatt Jacob 
1196c3055363SMatt Jacob 	/*
1197c3055363SMatt Jacob 	 * Turn off the watchdog (if active).
1198c3055363SMatt Jacob 	 */
119992718a7fSMatt Jacob 	if (isp->isp_dogactive) {
120092718a7fSMatt Jacob 		untimeout(isp_watch, isp);
120192718a7fSMatt Jacob 		isp->isp_dogactive = 0;
120292718a7fSMatt Jacob 	}
1203c3055363SMatt Jacob 	/*
1204c3055363SMatt Jacob 	 * And out...
1205c3055363SMatt Jacob 	 */
120692718a7fSMatt Jacob 	splx(s);
1207c3055363SMatt Jacob }
120892718a7fSMatt Jacob #endif
1209