xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
1 /* $FreeBSD$ */
2 /*
3  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
4  *
5  *---------------------------------------
6  * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
7  * NASA/Ames Research Center
8  * All rights reserved.
9  *---------------------------------------
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice immediately at the beginning of the file, without modification,
16  *    this list of conditions, and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 #include <dev/isp/isp_freebsd.h>
36 
37 static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
38 static void isp_poll(struct cam_sim *);
39 static void isp_action(struct cam_sim *, union ccb *);
40 static void isp_relsim(void *);
41 
42 /* #define	ISP_LUN0_ONLY	1 */
43 #ifdef	DEBUG
44 int isp_debug = 2;
45 #elif defined(CAMDEBUG) || defined(DIAGNOSTIC)
46 int isp_debug = 1;
47 #else
48 int isp_debug = 0;
49 #endif
50 
51 void
52 isp_attach(struct ispsoftc *isp)
53 {
54 	int primary, secondary;
55 	struct ccb_setasync csa;
56 	struct cam_devq *devq;
57 	struct cam_sim *sim;
58 	struct cam_path *path;
59 
60 	/*
61 	 * Establish (in case of 12X0) which bus is the primary.
62 	 */
63 
64 	primary = 0;
65 	secondary = 1;
66 
67 	/*
68 	 * Create the device queue for our SIM(s).
69 	 */
70 	devq = cam_simq_alloc(isp->isp_maxcmds);
71 	if (devq == NULL) {
72 		return;
73 	}
74 
75 	/*
76 	 * Construct our SIM entry.
77 	 */
78 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
79 	    isp->isp_unit, 1, isp->isp_maxcmds, devq);
80 	if (sim == NULL) {
81 		cam_simq_free(devq);
82 		return;
83 	}
84 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
85 		cam_sim_free(sim, TRUE);
86 		return;
87 	}
88 
89 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
90 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
91 		xpt_bus_deregister(cam_sim_path(sim));
92 		cam_sim_free(sim, TRUE);
93 		return;
94 	}
95 
96 	xpt_setup_ccb(&csa.ccb_h, path, 5);
97 	csa.ccb_h.func_code = XPT_SASYNC_CB;
98 	csa.event_enable = AC_LOST_DEVICE;
99 	csa.callback = isp_cam_async;
100 	csa.callback_arg = sim;
101 	xpt_action((union ccb *)&csa);
102 	isp->isp_sim = sim;
103 	isp->isp_path = path;
104 
105 	/*
106 	 * If we have a second channel, construct SIM entry for that.
107 	 */
108 	if (IS_DUALBUS(isp)) {
109 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
110 		    isp->isp_unit, 1, isp->isp_maxcmds, devq);
111 		if (sim == NULL) {
112 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
113 			xpt_free_path(isp->isp_path);
114 			cam_simq_free(devq);
115 			return;
116 		}
117 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
118 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
119 			xpt_free_path(isp->isp_path);
120 			cam_sim_free(sim, TRUE);
121 			return;
122 		}
123 
124 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
125 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
126 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
127 			xpt_free_path(isp->isp_path);
128 			xpt_bus_deregister(cam_sim_path(sim));
129 			cam_sim_free(sim, TRUE);
130 			return;
131 		}
132 
133 		xpt_setup_ccb(&csa.ccb_h, path, 5);
134 		csa.ccb_h.func_code = XPT_SASYNC_CB;
135 		csa.event_enable = AC_LOST_DEVICE;
136 		csa.callback = isp_cam_async;
137 		csa.callback_arg = sim;
138 		xpt_action((union ccb *)&csa);
139 		isp->isp_sim2 = sim;
140 		isp->isp_path2 = path;
141 	}
142 	if (isp->isp_state == ISP_INITSTATE) {
143 		isp->isp_state = ISP_RUNSTATE;
144 	}
145 }
146 
147 static void
148 isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
149 {
150 	struct cam_sim *sim;
151 	struct ispsoftc *isp;
152 
153 	sim = (struct cam_sim *)cbarg;
154 	isp = (struct ispsoftc *) cam_sim_softc(sim);
155 	switch (code) {
156 	case AC_LOST_DEVICE:
157 		if (IS_SCSI(isp)) {
158 			u_int16_t oflags, nflags;
159 			sdparam *sdp = isp->isp_param;
160 			int s, rvf, tgt;
161 
162 			tgt = xpt_path_target_id(path);
163 			rvf = ISP_FW_REVX(isp->isp_fwrev);
164 			s = splcam();
165 			sdp += cam_sim_bus(sim);
166 			isp->isp_update |= (1 << cam_sim_bus(sim));
167 			nflags = DPARM_SAFE_DFLT;
168 			if (rvf >= ISP_FW_REV(7, 55, 0) ||
169 			   (ISP_FW_REV(4, 55, 0) <= rvf &&
170 			   (rvf < ISP_FW_REV(5, 0, 0)))) {
171 				nflags |= DPARM_NARROW | DPARM_ASYNC;
172 			}
173 			oflags = sdp->isp_devparam[tgt].dev_flags;
174 			sdp->isp_devparam[tgt].dev_flags = nflags;
175 			sdp->isp_devparam[tgt].dev_update = 1;
176 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
177 			sdp->isp_devparam[tgt].dev_flags = oflags;
178 			(void) splx(s);
179 		}
180 		break;
181 	default:
182 		printf("%s: isp_attach Async Code 0x%x\n", isp->isp_name, code);
183 		break;
184 	}
185 }
186 
187 static void
188 isp_poll(struct cam_sim *sim)
189 {
190 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
191 }
192 
193 static void
194 isp_relsim(void *arg)
195 {
196 	struct ispsoftc *isp = arg;
197 	int s = splcam();
198 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED) {
199 		int wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_TIMED;
200 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_TIMED;
201 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
202 			xpt_release_simq(isp->isp_sim, 1);
203 			IDPRINTF(3, ("%s: timed relsimq\n", isp->isp_name));
204 		}
205 	}
206 	splx(s);
207 }
208 
209 static void
210 isp_action(struct cam_sim *sim, union ccb *ccb)
211 {
212 	int s, bus, tgt, error;
213 	struct ispsoftc *isp;
214 	struct ccb_trans_settings *cts;
215 
216 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
217 
218 	isp = (struct ispsoftc *)cam_sim_softc(sim);
219 	ccb->ccb_h.sim_priv.entries[0].field = 0;
220 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
221 	if (isp->isp_state != ISP_RUNSTATE &&
222 	    ccb->ccb_h.func_code == XPT_SCSI_IO) {
223 		s = splcam();
224 		DISABLE_INTS(isp);
225 		isp_init(isp);
226 		if (isp->isp_state != ISP_INITSTATE) {
227 			(void) splx(s);
228 			/*
229 			 * Lie. Say it was a selection timeout.
230 			 */
231 			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
232 			ccb->ccb_h.status |= CAM_DEV_QFRZN;
233 			xpt_freeze_devq(ccb->ccb_h.path, 1);
234 			xpt_done(ccb);
235 			return;
236 		}
237 		isp->isp_state = ISP_RUNSTATE;
238 		ENABLE_INTS(isp);
239 		(void) splx(s);
240 	}
241 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
242 	    ccb->ccb_h.func_code));
243 
244 	switch (ccb->ccb_h.func_code) {
245 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
246 		/*
247 		 * Do a couple of preliminary checks...
248 		 */
249 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
250 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
251 				ccb->ccb_h.status = CAM_REQ_INVALID;
252 				xpt_done(ccb);
253 				break;
254 			}
255 		}
256 #ifdef	DIAGNOSTIC
257 		if (ccb->ccb_h.target_id > (ISP_MAX_TARGETS(isp) - 1)) {
258 			ccb->ccb_h.status = CAM_PATH_INVALID;
259 		} else if (ccb->ccb_h.target_lun > (ISP_MAX_LUNS(isp) - 1)) {
260 			ccb->ccb_h.status = CAM_PATH_INVALID;
261 		}
262 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
263 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
264 			    isp->isp_name, ccb->ccb_h.target_id,
265 			    ccb->ccb_h.target_lun);
266 			xpt_done(ccb);
267 			break;
268 		}
269 #endif
270 		((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
271 		s = splcam();
272 		DISABLE_INTS(isp);
273 		error = ispscsicmd((ISP_SCSI_XFER_T *) ccb);
274 		ENABLE_INTS(isp);
275 		splx(s);
276 		switch (error) {
277 		case CMD_QUEUED:
278 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
279 			break;
280 		case CMD_RQLATER:
281 			if (isp->isp_osinfo.simqfrozen == 0) {
282 				IDPRINTF(3, ("%s: RQLATER freeze simq\n",
283 				    isp->isp_name));
284 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_TIMED;
285 				timeout(isp_relsim, isp, 500);
286 				xpt_freeze_simq(sim, 1);
287 			}
288 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
289                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
290 			xpt_done(ccb);
291 			break;
292 		case CMD_EAGAIN:
293 			if (isp->isp_osinfo.simqfrozen == 0) {
294 				xpt_freeze_simq(sim, 1);
295 				IDPRINTF(3, ("%s: EAGAIN freeze simq\n",
296 				    isp->isp_name));
297 			}
298 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
299 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
300                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
301 			xpt_done(ccb);
302 			break;
303 		case CMD_COMPLETE:
304 			isp_done((struct ccb_scsiio *) ccb);
305 			break;
306 		default:
307 			printf("%s: What's this? 0x%x at %d in file %s\n",
308 			    isp->isp_name, error, __LINE__, __FILE__);
309 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
310 			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
311 			xpt_done(ccb);
312 		}
313 		break;
314 
315 	case XPT_EN_LUN:		/* Enable LUN as a target */
316 	case XPT_TARGET_IO:		/* Execute target I/O request */
317 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
318 	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
319 		ccb->ccb_h.status = CAM_REQ_INVALID;
320 		xpt_done(ccb);
321 		break;
322 
323 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
324 		tgt = ccb->ccb_h.target_id; /* XXX: Which Bus? */
325 		s = splcam();
326 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
327 		(void) splx(s);
328 		if (error) {
329 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
330 		} else {
331 			ccb->ccb_h.status = CAM_REQ_CMP;
332 		}
333 		xpt_done(ccb);
334 		break;
335 	case XPT_ABORT:			/* Abort the specified CCB */
336 		s = splcam();
337 		error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
338 		(void) splx(s);
339 		if (error) {
340 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
341 		} else {
342 			ccb->ccb_h.status = CAM_REQ_CMP;
343 		}
344 		xpt_done(ccb);
345 		break;
346 
347 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
348 
349 		cts = &ccb->cts;
350 		tgt = cts->ccb_h.target_id;
351 		s = splcam();
352 		if (IS_SCSI(isp)) {
353 			sdparam *sdp = isp->isp_param;
354 			u_int16_t *dptr;
355 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
356 
357 			sdp += bus;
358 #if	0
359 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
360 				dptr = &sdp->isp_devparam[tgt].cur_dflags;
361 			else
362 				dptr = &sdp->isp_devparam[tgt].dev_flags;
363 #else
364 			/*
365 			 * We always update (internally) from dev_flags
366 			 * so any request to change settings just gets
367 			 * vectored to that location.
368 			 */
369 			dptr = &sdp->isp_devparam[tgt].dev_flags;
370 #endif
371 
372 			/*
373 			 * Note that these operations affect the
374 			 * the goal flags (dev_flags)- not
375 			 * the current state flags. Then we mark
376 			 * things so that the next operation to
377 			 * this HBA will cause the update to occur.
378 			 */
379 			if (cts->valid & CCB_TRANS_DISC_VALID) {
380 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
381 					*dptr |= DPARM_DISC;
382 				} else {
383 					*dptr &= ~DPARM_DISC;
384 				}
385 			}
386 			if (cts->valid & CCB_TRANS_TQ_VALID) {
387 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
388 					*dptr |= DPARM_TQING;
389 				} else {
390 					*dptr &= ~DPARM_TQING;
391 				}
392 			}
393 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
394 				switch (cts->bus_width) {
395 				case MSG_EXT_WDTR_BUS_16_BIT:
396 					*dptr |= DPARM_WIDE;
397 					break;
398 				default:
399 					*dptr &= ~DPARM_WIDE;
400 				}
401 			}
402 			/*
403 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
404 			 * of nonzero will cause us to go to the
405 			 * selected (from NVRAM) maximum value for
406 			 * this device. At a later point, we'll
407 			 * allow finer control.
408 			 */
409 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
410 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
411 			    (cts->sync_offset > 0)) {
412 				*dptr |= DPARM_SYNC;
413 			} else {
414 				*dptr &= ~DPARM_SYNC;
415 			}
416 *dptr |= DPARM_SAFE_DFLT;
417 			if (bootverbose || isp->isp_dblev >= 3)
418 				printf("%s: %d.%d set %s period 0x%x offset "
419 				    "0x%x flags 0x%x\n", isp->isp_name, bus,
420 				    tgt,
421 				    (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
422 				    "current" : "user",
423 				    sdp->isp_devparam[tgt].sync_period,
424 				    sdp->isp_devparam[tgt].sync_offset,
425 				    sdp->isp_devparam[tgt].dev_flags);
426 			sdp->isp_devparam[tgt].dev_update = 1;
427 			isp->isp_update |= (1 << bus);
428 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
429 		}
430 		(void) splx(s);
431 		ccb->ccb_h.status = CAM_REQ_CMP;
432 		xpt_done(ccb);
433 		break;
434 
435 	case XPT_GET_TRAN_SETTINGS:
436 
437 		cts = &ccb->cts;
438 		tgt = cts->ccb_h.target_id;
439 		if (IS_FC(isp)) {
440 			/*
441 			 * a lot of normal SCSI things don't make sense.
442 			 */
443 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
444 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
445 			/*
446 			 * How do you measure the width of a high
447 			 * speed serial bus? Well, in bytes.
448 			 *
449 			 * Offset and period make no sense, though, so we set
450 			 * (above) a 'base' transfer speed to be gigabit.
451 			 */
452 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
453 		} else {
454 			sdparam *sdp = isp->isp_param;
455 			u_int16_t dval, pval, oval;
456 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
457 
458 			sdp += bus;
459 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) {
460 				s = splcam();
461 				/*
462 				 * First do a refresh to see if things
463 				 * have changed recently!
464 				 */
465 				sdp->isp_devparam[tgt].dev_refresh = 1;
466 				isp->isp_update |= (1 << bus);
467 				(void) isp_control(isp, ISPCTL_UPDATE_PARAMS,
468 				    NULL);
469 				(void) splx(s);
470 				dval = sdp->isp_devparam[tgt].cur_dflags;
471 				oval = sdp->isp_devparam[tgt].cur_offset;
472 				pval = sdp->isp_devparam[tgt].cur_period;
473 			} else {
474 				dval = sdp->isp_devparam[tgt].dev_flags;
475 				oval = sdp->isp_devparam[tgt].sync_offset;
476 				pval = sdp->isp_devparam[tgt].sync_period;
477 			}
478 
479 			s = splcam();
480 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
481 
482 			if (dval & DPARM_DISC) {
483 				cts->flags |= CCB_TRANS_DISC_ENB;
484 			}
485 			if (dval & DPARM_TQING) {
486 				cts->flags |= CCB_TRANS_TAG_ENB;
487 			}
488 			if (dval & DPARM_WIDE) {
489 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
490 			} else {
491 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
492 			}
493 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
494 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
495 
496 			if ((dval & DPARM_SYNC) && oval != 0) {
497 				cts->sync_period = pval;
498 				cts->sync_offset = oval;
499 				cts->valid |=
500 				    CCB_TRANS_SYNC_RATE_VALID |
501 				    CCB_TRANS_SYNC_OFFSET_VALID;
502 			}
503 			splx(s);
504 			if (bootverbose || isp->isp_dblev >= 3)
505 				printf("%s: %d.%d get %s period 0x%x offset "
506 				    "0x%x flags 0x%x\n", isp->isp_name, bus,
507 				    tgt,
508 			    	    (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
509 				    "current" : "user", pval, oval, dval);
510 		}
511 		ccb->ccb_h.status = CAM_REQ_CMP;
512 		xpt_done(ccb);
513 		break;
514 
515 	case XPT_CALC_GEOMETRY:
516 	{
517 		struct ccb_calc_geometry *ccg;
518 		u_int32_t secs_per_cylinder;
519 		u_int32_t size_mb;
520 
521 		ccg = &ccb->ccg;
522 		if (ccg->block_size == 0) {
523 			printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n",
524 				isp->isp_name, ccg->ccb_h.target_id,
525 				ccg->ccb_h.target_lun);
526 			ccb->ccb_h.status = CAM_REQ_INVALID;
527 			xpt_done(ccb);
528 			break;
529 		}
530 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
531 		if (size_mb > 1024) {
532 			ccg->heads = 255;
533 			ccg->secs_per_track = 63;
534 		} else {
535 			ccg->heads = 64;
536 			ccg->secs_per_track = 32;
537 		}
538 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
539 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
540 		ccb->ccb_h.status = CAM_REQ_CMP;
541 		xpt_done(ccb);
542 		break;
543 	}
544 	case XPT_RESET_BUS:		/* Reset the specified bus */
545 		bus = cam_sim_bus(sim);
546 		s = splcam();
547 		error = isp_control(isp, ISPCTL_RESET_BUS, &bus);
548 		(void) splx(s);
549 		if (error)
550 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
551 		else {
552 			if (cam_sim_bus(sim) && isp->isp_path2 != NULL)
553 				xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
554 			else if (isp->isp_path != NULL)
555 				xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
556 			ccb->ccb_h.status = CAM_REQ_CMP;
557 		}
558 		xpt_done(ccb);
559 		break;
560 
561 	case XPT_TERM_IO:		/* Terminate the I/O process */
562 		/* Does this need to be implemented? */
563 		ccb->ccb_h.status = CAM_REQ_INVALID;
564 		xpt_done(ccb);
565 		break;
566 
567 	case XPT_PATH_INQ:		/* Path routing inquiry */
568 	{
569 		struct ccb_pathinq *cpi = &ccb->cpi;
570 
571 		cpi->version_num = 1;
572 		cpi->target_sprt = 0;
573 		cpi->hba_eng_cnt = 0;
574 		cpi->max_target = ISP_MAX_TARGETS(isp) - 1;
575 		cpi->max_lun = ISP_MAX_LUNS(isp) - 1;
576 		cpi->bus_id = cam_sim_bus(sim);
577 		if (IS_FC(isp)) {
578 			cpi->hba_misc = PIM_NOBUSRESET;
579 			/*
580 			 * Because our loop ID can shift from time to time,
581 			 * make our initiator ID out of range of our bus.
582 			 */
583 			cpi->initiator_id = cpi->max_target + 1;
584 
585 			/*
586 			 * Set base transfer capabilities for Fibre Channel.
587 			 * Technically not correct because we don't know
588 			 * what media we're running on top of- but we'll
589 			 * look good if we always say 100MB/s.
590 			 */
591 			cpi->base_transfer_speed = 100000;
592 			cpi->hba_inquiry = PI_TAG_ABLE;
593 		} else {
594 			sdparam *sdp = isp->isp_param;
595 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
596 			cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
597 			cpi->hba_misc = 0;
598 			cpi->initiator_id = sdp->isp_initiator_id;
599 			cpi->base_transfer_speed = 3300;
600 		}
601 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
602 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
603 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
604 		cpi->unit_number = cam_sim_unit(sim);
605 		cpi->ccb_h.status = CAM_REQ_CMP;
606 		xpt_done(ccb);
607 		break;
608 	}
609 	default:
610 		ccb->ccb_h.status = CAM_REQ_INVALID;
611 		xpt_done(ccb);
612 		break;
613 	}
614 }
615 
616 #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
617 void
618 isp_done(struct ccb_scsiio *sccb)
619 {
620 	struct ispsoftc *isp = XS_ISP(sccb);
621 
622 	if (XS_NOERR(sccb))
623 		XS_SETERR(sccb, CAM_REQ_CMP);
624 	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
625 	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
626 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
627 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
628 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
629 		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
630 	}
631 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
632 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
633 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
634 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
635 			xpt_freeze_devq(sccb->ccb_h.path, 1);
636 			if (sccb->scsi_status != SCSI_STATUS_OK)
637 				IDPRINTF(3, ("%s: fdevq %d.%d %x %x\n",
638 				    isp->isp_name, sccb->ccb_h.target_id,
639 				    sccb->ccb_h.target_lun, sccb->ccb_h.status,
640 				    sccb->scsi_status));
641 		}
642 	}
643 	/*
644 	 * If we were frozen waiting resources, clear that we were frozen
645 	 * waiting for resources. If we are no longer frozen, and the devq
646 	 * isn't frozen, mark the completing CCB to have the XPT layer
647 	 * release the simq.
648 	 */
649 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
650 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
651 		if (isp->isp_osinfo.simqfrozen == 0) {
652 			if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
653 				IDPRINTF(3, ("%s: isp_done -> relsimq\n",
654 				    isp->isp_name));
655 				sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
656 			} else {
657 				IDPRINTF(3, ("%s: isp_done -> devq frozen\n",
658 				    isp->isp_name));
659 			}
660 		} else {
661 			IDPRINTF(3, ("%s: isp_done -> simqfrozen = %x\n",
662 			    isp->isp_name, isp->isp_osinfo.simqfrozen));
663 		}
664 	}
665 	if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
666 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
667 		xpt_print_path(sccb->ccb_h.path);
668 		printf("cam completion status 0x%x\n", sccb->ccb_h.status);
669 	}
670 	xpt_done((union ccb *) sccb);
671 }
672 
673 int
674 isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
675 {
676 	int bus, rv = 0;
677 	switch (cmd) {
678 	case ISPASYNC_NEW_TGT_PARAMS:
679 	{
680 		int flags, tgt;
681 		sdparam *sdp = isp->isp_param;
682 		struct ccb_trans_settings neg;
683 		struct cam_path *tmppath;
684 
685 		tgt = *((int *)arg);
686 		bus = (tgt >> 16) & 0xffff;
687 		tgt &= 0xffff;
688 		sdp += bus;
689 		if (xpt_create_path(&tmppath, NULL,
690 		    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
691 		    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
692 			xpt_print_path(isp->isp_path);
693 			printf("isp_async cannot make temp path for "
694 			    "target %d bus %d\n", tgt, bus);
695 			rv = -1;
696 			break;
697 		}
698 		flags = sdp->isp_devparam[tgt].cur_dflags;
699 		neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
700 		if (flags & DPARM_DISC) {
701 			neg.flags |= CCB_TRANS_DISC_ENB;
702 		}
703 		if (flags & DPARM_TQING) {
704 			neg.flags |= CCB_TRANS_TAG_ENB;
705 		}
706 		neg.valid |= CCB_TRANS_BUS_WIDTH_VALID;
707 		neg.bus_width = (flags & DPARM_WIDE)?
708 		    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
709 		neg.sync_period = sdp->isp_devparam[tgt].cur_period;
710 		neg.sync_offset = sdp->isp_devparam[tgt].cur_offset;
711 		if (flags & DPARM_SYNC) {
712 			neg.valid |=
713 			    CCB_TRANS_SYNC_RATE_VALID |
714 			    CCB_TRANS_SYNC_OFFSET_VALID;
715 		}
716 		IDPRINTF(3, ("%s: NEW_TGT_PARAMS bus %d tgt %d period "
717 		    "0x%x offset 0x%x flags 0x%x\n", isp->isp_name,
718 		    bus, tgt, neg.sync_period, neg.sync_offset, flags));
719 		xpt_setup_ccb(&neg.ccb_h, tmppath, 1);
720 		xpt_async(AC_TRANSFER_NEG, tmppath, &neg);
721 		xpt_free_path(tmppath);
722 		break;
723 	}
724 	case ISPASYNC_BUS_RESET:
725 		bus = *((int *)arg);
726 		printf("%s: SCSI bus reset on bus %d detected\n",
727 		    isp->isp_name, bus);
728 		if (bus > 0 && isp->isp_path2) {
729 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
730 		} else if (isp->isp_path) {
731 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
732 		}
733 		break;
734 	case ISPASYNC_LOOP_DOWN:
735 		if (isp->isp_path) {
736 			if (isp->isp_osinfo.simqfrozen == 0) {
737 				IDPRINTF(3, ("%s: loop down freeze simq\n",
738 				    isp->isp_name));
739 				xpt_freeze_simq(isp->isp_sim, 1);
740 			}
741 			isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
742 		}
743 		printf("%s: Loop DOWN\n", isp->isp_name);
744 		break;
745 	case ISPASYNC_LOOP_UP:
746 		if (isp->isp_path) {
747 			int wasfrozen =
748 			    isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
749 			isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
750 			if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
751 				xpt_release_simq(isp->isp_sim, 1);
752 				IDPRINTF(3, ("%s: loop up release simq\n",
753 					isp->isp_name));
754 			}
755 		}
756 		printf("%s: Loop UP\n", isp->isp_name);
757 		break;
758 	case ISPASYNC_PDB_CHANGED:
759 	{
760 		const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
761 		    "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
762 		const static char *roles[4] = {
763 		    "(none)", "Target", "Initiator", "Target/Initiator"
764 		};
765 		char *ptr;
766 		fcparam *fcp = isp->isp_param;
767 		int tgt = *((int *) arg);
768 		struct lportdb *lp = &fcp->portdb[tgt];
769 
770 		if (lp->valid) {
771 			ptr = "arrived";
772 		} else {
773 			ptr = "disappeared";
774 		}
775 		printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
776 		    roles[lp->roles & 0x3], ptr,
777 		    (u_int32_t) (lp->port_wwn >> 32),
778 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
779 		    (u_int32_t) (lp->node_wwn >> 32),
780 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
781 		break;
782 	}
783 	case ISPASYNC_CHANGE_NOTIFY:
784 		printf("%s: Name Server Database Changed\n", isp->isp_name);
785 		break;
786 #ifdef	ISP2100_FABRIC
787 	case ISPASYNC_FABRIC_DEV:
788 	{
789 		int target;
790 		struct lportdb *lp;
791 		sns_scrsp_t *resp = (sns_scrsp_t *) arg;
792 		u_int32_t portid;
793 		u_int64_t wwn;
794 		fcparam *fcp = isp->isp_param;
795 
796 		rv = -1;
797 
798 		portid =
799 		    (((u_int32_t) resp->snscb_port_id[0]) << 16) |
800 		    (((u_int32_t) resp->snscb_port_id[1]) << 8) |
801 		    (((u_int32_t) resp->snscb_port_id[2]));
802 		wwn =
803 		    (((u_int64_t)resp->snscb_portname[0]) << 56) |
804 		    (((u_int64_t)resp->snscb_portname[1]) << 48) |
805 		    (((u_int64_t)resp->snscb_portname[2]) << 40) |
806 		    (((u_int64_t)resp->snscb_portname[3]) << 32) |
807 		    (((u_int64_t)resp->snscb_portname[4]) << 24) |
808 		    (((u_int64_t)resp->snscb_portname[5]) << 16) |
809 		    (((u_int64_t)resp->snscb_portname[6]) <<  8) |
810 		    (((u_int64_t)resp->snscb_portname[7]));
811 		printf("%s: type 0x%x@portid 0x%x 0x%08x%08x\n", isp->isp_name,
812 		    resp->snscb_port_type, portid,
813 		    ((u_int32_t) (wwn >> 32)), ((u_int32_t) wwn));
814 		if (resp->snscb_port_type != 2) {
815 			rv = 0;
816 			break;
817 		}
818 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
819 			lp = &fcp->portdb[target];
820 			if (lp->port_wwn == wwn)
821 				break;
822 		}
823 		if (target < MAX_FC_TARG) {
824 			rv = 0;
825 			break;
826 		}
827 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
828 			lp = &fcp->portdb[target];
829 			if (lp->port_wwn == 0)
830 				break;
831 		}
832 		if (target == MAX_FC_TARG) {
833 			printf("%s: no more space for fabric devices\n",
834 			    isp->isp_name);
835 			break;
836 		}
837 		lp->port_wwn = lp->node_wwn = wwn;
838 		lp->portid = portid;
839 		rv = 0;
840 		break;
841 	}
842 #endif
843 	default:
844 		rv = -1;
845 		break;
846 	}
847 	return (rv);
848 }
849 
850 
851 /*
852  * Locks are held before coming here.
853  */
854 void
855 isp_uninit(struct ispsoftc *isp)
856 {
857 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
858 	DISABLE_INTS(isp);
859 }
860