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