xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 98edb3e17869504d0ada58932efa96b71f899181)
1 /* $Id: isp_freebsd.c,v 1.21 1999/07/03 01:44:05 mjacob Exp $ */
2 /* release_6_5_99 */
3 /*
4  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
5  *
6  *---------------------------------------
7  * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
8  * NASA/Ames Research Center
9  * All rights reserved.
10  *---------------------------------------
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice immediately at the beginning of the file, without modification,
17  *    this list of conditions, and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
28  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 #include <dev/isp/isp_freebsd.h>
37 
38 static void isp_cam_async __P((void *, u_int32_t, struct cam_path *, void *));
39 static void isp_poll __P((struct cam_sim *));
40 static void isp_action __P((struct cam_sim *, union ccb *));
41 
42 void
43 isp_attach(struct ispsoftc *isp)
44 {
45 	int primary, secondary;
46 	struct ccb_setasync csa;
47 	struct cam_devq *devq;
48 	struct cam_sim *sim;
49 	struct cam_path *path;
50 
51 	/*
52 	 * Establish (in case of 12X0) which bus is the primary.
53 	 */
54 
55 	primary = 0;
56 	secondary = 1;
57 
58 	/*
59 	 * Create the device queue for our SIM(s).
60 	 */
61 	devq = cam_simq_alloc(MAXISPREQUEST);
62 	if (devq == NULL) {
63 		return;
64 	}
65 
66 	/*
67 	 * Construct our SIM entry.
68 	 */
69 	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
70 	    isp->isp_unit, 1, MAXISPREQUEST, devq);
71 	if (sim == NULL) {
72 		cam_simq_free(devq);
73 		return;
74 	}
75 	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {
76 		cam_sim_free(sim, TRUE);
77 		return;
78 	}
79 
80 	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
81 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
82 		xpt_bus_deregister(cam_sim_path(sim));
83 		cam_sim_free(sim, TRUE);
84 		return;
85 	}
86 
87 	xpt_setup_ccb(&csa.ccb_h, path, 5);
88 	csa.ccb_h.func_code = XPT_SASYNC_CB;
89 	csa.event_enable = AC_LOST_DEVICE;
90 	csa.callback = isp_cam_async;
91 	csa.callback_arg = sim;
92 	xpt_action((union ccb *)&csa);
93 	isp->isp_sim = sim;
94 	isp->isp_path = path;
95 
96 	/*
97 	 * If we have a second channel, construct SIM entry for that.
98 	 */
99 	if (IS_12X0(isp)) {
100 		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
101 		    isp->isp_unit, 1, MAXISPREQUEST, devq);
102 		if (sim == NULL) {
103 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
104 			xpt_free_path(isp->isp_path);
105 			cam_simq_free(devq);
106 			return;
107 		}
108 		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {
109 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
110 			xpt_free_path(isp->isp_path);
111 			cam_sim_free(sim, TRUE);
112 			return;
113 		}
114 
115 		if (xpt_create_path(&path, NULL, cam_sim_path(sim),
116 		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
117 			xpt_bus_deregister(cam_sim_path(isp->isp_sim));
118 			xpt_free_path(isp->isp_path);
119 			xpt_bus_deregister(cam_sim_path(sim));
120 			cam_sim_free(sim, TRUE);
121 			return;
122 		}
123 
124 		xpt_setup_ccb(&csa.ccb_h, path, 5);
125 		csa.ccb_h.func_code = XPT_SASYNC_CB;
126 		csa.event_enable = AC_LOST_DEVICE;
127 		csa.callback = isp_cam_async;
128 		csa.callback_arg = sim;
129 		xpt_action((union ccb *)&csa);
130 		isp->isp_sim2 = sim;
131 		isp->isp_path2 = path;
132 	}
133 	if (isp->isp_state == ISP_INITSTATE)
134 		isp->isp_state = ISP_RUNSTATE;
135 }
136 
137 static void
138 isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
139 {
140 	struct cam_sim *sim;
141 	struct ispsoftc *isp;
142 
143 	sim = (struct cam_sim *)cbarg;
144 	isp = (struct ispsoftc *) cam_sim_softc(sim);
145 	switch (code) {
146 	case AC_LOST_DEVICE:
147 		if (isp->isp_type & ISP_HA_SCSI) {
148 			u_int16_t oflags, nflags;
149 			sdparam *sdp = isp->isp_param;
150 			int s, tgt = xpt_path_target_id(path);
151 
152 			s = splcam();
153 			sdp += cam_sim_bus(sim);
154 			isp->isp_update |= (1 << cam_sim_bus(sim));
155 
156 			nflags = DPARM_SAFE_DFLT;
157 			if (ISP_FW_REVX(isp->isp_fwrev) >=
158 			    ISP_FW_REV(7, 55, 0)) {
159 				nflags |= DPARM_NARROW | DPARM_ASYNC;
160 			}
161 			oflags = sdp->isp_devparam[tgt].dev_flags;
162 			sdp->isp_devparam[tgt].dev_flags = nflags;
163 			sdp->isp_devparam[tgt].dev_update = 1;
164 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
165 			sdp->isp_devparam[tgt].dev_flags = oflags;
166 			(void) splx(s);
167 		}
168 		break;
169 	default:
170 		break;
171 	}
172 }
173 
174 static void
175 isp_poll(struct cam_sim *sim)
176 {
177 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
178 }
179 
180 
181 static void
182 isp_action(struct cam_sim *sim, union ccb *ccb)
183 {
184 	int s, tgt, error;
185 	struct ispsoftc *isp;
186 	struct ccb_trans_settings *cts;
187 
188 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
189 
190 	isp = (struct ispsoftc *)cam_sim_softc(sim);
191 	ccb->ccb_h.sim_priv.entries[0].field = 0;
192 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
193 	/*
194 	 * This should only happen for Fibre Channel adapters.
195 	 * We want to pass through all but XPT_SCSI_IO (e.g.,
196 	 * path inquiry) but fail if we can't get good Fibre
197 	 * Channel link status.
198 	 */
199 	if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
200 	    isp->isp_state != ISP_RUNSTATE) {
201 		s = splcam();
202 		DISABLE_INTS(isp);
203 		isp_init(isp);
204 		if (isp->isp_state != ISP_INITSTATE) {
205 			(void) splx(s);
206 			/*
207 			 * Lie. Say it was a selection timeout.
208 			 */
209 			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
210 			xpt_done(ccb);
211 			return;
212 		}
213 		isp->isp_state = ISP_RUNSTATE;
214 		ENABLE_INTS(isp);
215 		(void) splx(s);
216 	}
217 
218 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
219 	    ccb->ccb_h.func_code));
220 
221 	switch (ccb->ccb_h.func_code) {
222 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
223 		/*
224 		 * Do a couple of preliminary checks...
225 		 */
226 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
227 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
228 				ccb->ccb_h.status = CAM_REQ_INVALID;
229 				xpt_done(ccb);
230 				break;
231 			}
232 		}
233 
234 
235 		if (isp->isp_type & ISP_HA_SCSI) {
236 			if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) {
237 				ccb->ccb_h.status = CAM_PATH_INVALID;
238 			} else if (ISP_FW_REVX(isp->isp_fwrev) >=
239 			    ISP_FW_REV(7, 55, 0)) {
240 				/*
241 				 * Too much breakage.
242 				 */
243 #if	0
244 				if (ccb->ccb_h.target_lun > 31) {
245 					ccb->ccb_h.status = CAM_PATH_INVALID;
246 				}
247 #else
248 				if (ccb->ccb_h.target_lun > 7) {
249 					ccb->ccb_h.status = CAM_PATH_INVALID;
250 				}
251 #endif
252 			} else if (ccb->ccb_h.target_lun > 7) {
253 				ccb->ccb_h.status = CAM_PATH_INVALID;
254 			}
255 		} else {
256 			if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) {
257 				ccb->ccb_h.status = CAM_PATH_INVALID;
258 #ifdef	ISP2100_SCCLUN
259 			} else if (ccb->ccb_h.target_lun > 65535) {
260 				ccb->ccb_h.status = CAM_PATH_INVALID;
261 #else
262 			} else if (ccb->ccb_h.target_lun > 15) {
263 				ccb->ccb_h.status = CAM_PATH_INVALID;
264 #endif
265 			}
266 		}
267 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
268 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
269 			    isp->isp_name, ccb->ccb_h.target_id,
270 			    ccb->ccb_h.target_lun);
271 			xpt_done(ccb);
272 			break;
273 		}
274 		s = splcam();
275 		DISABLE_INTS(isp);
276 		switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) {
277 		case CMD_QUEUED:
278 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
279 			break;
280 		case CMD_EAGAIN:
281 			if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE)) {
282 				xpt_freeze_simq(sim, 1);
283 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
284 			}
285 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
286                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
287 			xpt_done(ccb);
288 			break;
289 		case CMD_COMPLETE:
290 			/*
291 			 * Just make sure that we didn't get it returned
292 			 * as completed, but with the request still in
293 			 * progress. In theory, 'cannot happen'.
294 			 */
295 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
296 			    CAM_REQ_INPROG) {
297 				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
298 				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
299 			}
300 			xpt_done(ccb);
301 			break;
302 		}
303 		ENABLE_INTS(isp);
304 		splx(s);
305 		break;
306 
307 	case XPT_EN_LUN:		/* Enable LUN as a target */
308 	case XPT_TARGET_IO:		/* Execute target I/O request */
309 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
310 	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
311 		ccb->ccb_h.status = CAM_REQ_INVALID;
312 		xpt_done(ccb);
313 		break;
314 
315 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
316 		tgt = ccb->ccb_h.target_id; /* XXX: Which Bus? */
317 		s = splcam();
318 		error = isp_control(isp, ISPCTL_RESET_DEV, &tgt);
319 		(void) splx(s);
320 		if (error) {
321 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
322 		} else {
323 			ccb->ccb_h.status = CAM_REQ_CMP;
324 		}
325 		xpt_done(ccb);
326 		break;
327 	case XPT_ABORT:			/* Abort the specified CCB */
328 		s = splcam();
329 		error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
330 		(void) splx(s);
331 		if (error) {
332 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
333 		} else {
334 			ccb->ccb_h.status = CAM_REQ_CMP;
335 		}
336 		xpt_done(ccb);
337 		break;
338 
339 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
340 
341 		cts = &ccb->cts;
342 		tgt = cts->ccb_h.target_id;
343 		s = splcam();
344 		if (isp->isp_type & ISP_HA_FC) {
345 			;	/* nothing to change */
346 		} else {
347 			sdparam *sdp = isp->isp_param;
348 			u_int16_t *dptr;
349 			int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path));
350 
351 			sdp += bus;
352 #if	0
353 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
354 				dptr = &sdp->isp_devparam[tgt].cur_dflags;
355 			else
356 				dptr = &sdp->isp_devparam[tgt].dev_flags;
357 #else
358 			/*
359 			 * We always update (internally) from dev_flags
360 			 * so any request to change settings just gets
361 			 * vectored to that location.
362 			 */
363 			dptr = &sdp->isp_devparam[tgt].dev_flags;
364 #endif
365 
366 			/*
367 			 * Note that these operations affect the
368 			 * the goal flags (dev_flags)- not
369 			 * the current state flags. Then we mark
370 			 * things so that the next operation to
371 			 * this HBA will cause the update to occur.
372 			 */
373 			if (cts->valid & CCB_TRANS_DISC_VALID) {
374 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
375 					*dptr |= DPARM_DISC;
376 				} else {
377 					*dptr &= ~DPARM_DISC;
378 				}
379 			}
380 			if (cts->valid & CCB_TRANS_TQ_VALID) {
381 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
382 					*dptr |= DPARM_TQING;
383 				} else {
384 					*dptr &= ~DPARM_TQING;
385 				}
386 			}
387 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
388 				switch (cts->bus_width) {
389 				case MSG_EXT_WDTR_BUS_16_BIT:
390 					*dptr |= DPARM_WIDE;
391 					break;
392 				default:
393 					*dptr &= ~DPARM_WIDE;
394 				}
395 			}
396 			/*
397 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
398 			 * of nonzero will cause us to go to the
399 			 * selected (from NVRAM) maximum value for
400 			 * this device. At a later point, we'll
401 			 * allow finer control.
402 			 */
403 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
404 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
405 			    (cts->sync_offset > 0)) {
406 				*dptr |= DPARM_SYNC;
407 			} else {
408 				*dptr &= ~DPARM_SYNC;
409 			}
410 			if (bootverbose || isp->isp_dblev >= 3)
411 				printf("%s: %d.%d set %s period 0x%x offset "
412 				    "0x%x flags 0x%x\n", isp->isp_name, bus,
413 				    tgt,
414 				    (cts->flags & CCB_TRANS_CURRENT_SETTINGS)?
415 				    "current" : "user",
416 				    sdp->isp_devparam[tgt].sync_period,
417 				    sdp->isp_devparam[tgt].sync_offset,
418 				    sdp->isp_devparam[tgt].dev_flags);
419 			s = splcam();
420 			sdp->isp_devparam[tgt].dev_update = 1;
421 			isp->isp_update |= (1 << bus);
422 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
423 			(void) splx(s);
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 (isp->isp_type & ISP_HA_FC) {
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 		tgt = cam_sim_bus(sim);
541 		s = splcam();
542 		error = isp_control(isp, ISPCTL_RESET_BUS, &tgt);
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->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
568 		cpi->target_sprt = 0;
569 		cpi->hba_eng_cnt = 0;
570 		if (IS_FC(isp)) {
571 			cpi->hba_misc = PIM_NOBUSRESET;
572 			cpi->max_target = MAX_FC_TARG-1;
573 			cpi->initiator_id =
574 			    ((fcparam *)isp->isp_param)->isp_loopid;
575 #ifdef	ISP2100_SCCLUN
576 #if	0
577 			/* Too much breakage as yet... */
578 			cpi->max_lun = (1 << 16) - 1;
579 #else
580 			cpi->max_lun = (1 << 4) - 1;
581 #endif
582 #else
583 			cpi->max_lun = (1 << 4) - 1;
584 #endif
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 		} else {
593 			sdparam *sdp = isp->isp_param;
594 			sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path));
595 			cpi->hba_misc = 0;
596 			cpi->initiator_id = sdp->isp_initiator_id;
597 			cpi->max_target =  MAX_TARGETS-1;
598 			if (ISP_FW_REVX(isp->isp_fwrev) >=
599 			    ISP_FW_REV(7, 55, 0)) {
600 #if	0
601 				/*
602 				 * Too much breakage.
603 				 */
604 				cpi->max_lun = (1 << 5) - 1;
605 #else
606 				cpi->max_lun = (1 << 3) - 1;
607 #endif
608 			} else {
609 				cpi->max_lun = (1 << 3) - 1;
610 			}
611 			cpi->base_transfer_speed = 3300;
612 		}
613 
614 		cpi->bus_id = cam_sim_bus(sim);
615 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
616 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
617 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
618 		cpi->unit_number = cam_sim_unit(sim);
619 		cpi->ccb_h.status = CAM_REQ_CMP;
620 		xpt_done(ccb);
621 		break;
622 	}
623 	default:
624 		ccb->ccb_h.status = CAM_REQ_INVALID;
625 		xpt_done(ccb);
626 		break;
627 	}
628 }
629 
630 #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
631 void
632 isp_done(struct ccb_scsiio *sccb)
633 {
634 	struct ispsoftc *isp = XS_ISP(sccb);
635 
636 	if (XS_NOERR(sccb))
637 		XS_SETERR(sccb, CAM_REQ_CMP);
638 	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
639 	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
640 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
641 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
642 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
643 		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
644 	}
645 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
646 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
647 			IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n",
648 			    isp->isp_name, sccb->ccb_h.target_id,
649 			    sccb->ccb_h.target_lun, sccb->ccb_h.status));
650 			xpt_freeze_devq(sccb->ccb_h.path, 1);
651 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
652 		}
653 	}
654 	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
655 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
656 		sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
657 		xpt_release_simq(isp->isp_sim, 1);
658 	}
659 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
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(isp, cmd, arg)
670 	struct ispsoftc *isp;
671 	ispasync_t cmd;
672 	void *arg;
673 {
674 	int bus, rv = 0;
675 	switch (cmd) {
676 	case ISPASYNC_NEW_TGT_PARAMS:
677 		if (isp->isp_type & ISP_HA_SCSI) {
678 			int flags, tgt;
679 			sdparam *sdp = isp->isp_param;
680 			struct ccb_trans_settings neg;
681 			struct cam_path *tmppath;
682 
683 			tgt = *((int *)arg);
684 			bus = (tgt >> 16) & 0xffff;
685 			tgt &= 0xffff;
686 			sdp += bus;
687 			if (xpt_create_path(&tmppath, NULL,
688 			    cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim),
689 			    tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
690 				xpt_print_path(isp->isp_path);
691 				printf("isp_async cannot make temp path for "
692 				    "target %d bus %d\n", tgt, bus);
693 				rv = -1;
694 				break;
695 			}
696 			flags = sdp->isp_devparam[tgt].cur_dflags;
697 			neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
698 			if (flags & DPARM_DISC) {
699 				neg.flags |= CCB_TRANS_DISC_ENB;
700 			}
701 			if (flags & DPARM_TQING) {
702 				neg.flags |= CCB_TRANS_TAG_ENB;
703 			}
704 			neg.valid |= CCB_TRANS_BUS_WIDTH_VALID;
705 			neg.bus_width = (flags & DPARM_WIDE)?
706 			    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
707 			neg.sync_period = sdp->isp_devparam[tgt].cur_period;
708 			neg.sync_offset = sdp->isp_devparam[tgt].cur_offset;
709 			if (flags & DPARM_SYNC) {
710 				neg.valid |=
711 				    CCB_TRANS_SYNC_RATE_VALID |
712 				    CCB_TRANS_SYNC_OFFSET_VALID;
713 			}
714 			IDPRINTF(3, ("%s: NEW_TGT_PARAMS bus %d tgt %d period "
715 			    "0x%x offset 0x%x flags 0x%x\n", isp->isp_name,
716 			    bus, tgt, neg.sync_period, neg.sync_offset, flags));
717 			xpt_setup_ccb(&neg.ccb_h, tmppath, 1);
718 			xpt_async(AC_TRANSFER_NEG, tmppath, &neg);
719 			xpt_free_path(tmppath);
720 		}
721 		break;
722 	case ISPASYNC_BUS_RESET:
723 		bus = *((int *)arg);
724 		printf("%s: SCSI bus reset on bus %d detected\n",
725 		    isp->isp_name, bus);
726 		if (bus > 0 && isp->isp_path2) {
727 			xpt_async(AC_BUS_RESET, isp->isp_path2, NULL);
728 		} else if (isp->isp_path) {
729 			xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
730 		}
731 		break;
732 	case ISPASYNC_LOOP_DOWN:
733 		if (isp->isp_path) {
734 			/*
735 			 * We can get multiple LOOP downs, so only count one.
736 			 */
737 			if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN)) {
738 				xpt_freeze_simq(isp->isp_sim, 1);
739 				isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
740 				printf("%s: Loop DOWN- freezing SIMQ until Loop"
741 				    " comes up\n", isp->isp_name);
742 			}
743 		} else {
744 			printf("%s: Loop DOWN\n", isp->isp_name);
745 		}
746 		break;
747 	case ISPASYNC_LOOP_UP:
748 		if (isp->isp_path) {
749 			if (isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) {
750 				xpt_release_simq(isp->isp_sim, 1);
751 				isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
752 				if (isp->isp_osinfo.simqfrozen) {
753 					printf("%s: Loop UP- SIMQ still "
754 					    "frozen\n", isp->isp_name);
755 				} else {
756 					printf("%s: Loop UP-releasing frozen "
757 					    "SIMQ\n", isp->isp_name);
758 				}
759 			}
760 		} else {
761 			printf("%s: Loop UP\n", isp->isp_name);
762 		}
763 		break;
764 	case ISPASYNC_PDB_CHANGED:
765 	if (IS_FC(isp)) {
766 		const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
767 		    "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
768 		const static char *roles[4] = {
769 		    "No", "Target", "Initiator", "Target/Initiator"
770 		};
771 		char *ptr;
772 		fcparam *fcp = isp->isp_param;
773 		int tgt = *((int *) arg);
774 		struct lportdb *lp = &fcp->portdb[tgt];
775 
776 		if (lp->valid) {
777 			ptr = "arrived";
778 		} else {
779 			ptr = "disappeared";
780 		}
781 		printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
782 		    roles[lp->roles & 0x3], ptr,
783 		    (u_int32_t) (lp->port_wwn >> 32),
784 		    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
785 		    (u_int32_t) (lp->node_wwn >> 32),
786 		    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
787 		break;
788 	}
789 #ifdef	ISP2100_FABRIC
790 	case ISPASYNC_CHANGE_NOTIFY:
791 		printf("%s: Name Server Database Changed\n", isp->isp_name);
792 		break;
793 	case ISPASYNC_FABRIC_DEV:
794 	{
795 		int target;
796 		struct lportdb *lp;
797 		sns_scrsp_t *resp = (sns_scrsp_t *) arg;
798 		u_int32_t portid;
799 		u_int64_t wwn;
800 		fcparam *fcp = isp->isp_param;
801 
802 		rv = -1;
803 
804 		portid =
805 		    (((u_int32_t) resp->snscb_port_id[0]) << 16) |
806 		    (((u_int32_t) resp->snscb_port_id[1]) << 8) |
807 		    (((u_int32_t) resp->snscb_port_id[2]));
808 		wwn =
809 		    (((u_int64_t)resp->snscb_portname[0]) << 56) |
810 		    (((u_int64_t)resp->snscb_portname[1]) << 48) |
811 		    (((u_int64_t)resp->snscb_portname[2]) << 40) |
812 		    (((u_int64_t)resp->snscb_portname[3]) << 32) |
813 		    (((u_int64_t)resp->snscb_portname[4]) << 24) |
814 		    (((u_int64_t)resp->snscb_portname[5]) << 16) |
815 		    (((u_int64_t)resp->snscb_portname[6]) <<  8) |
816 		    (((u_int64_t)resp->snscb_portname[7]));
817 		printf("%s: type 0x%x@portid 0x%x 0x%08x%08x\n",
818 		    isp->isp_name, resp->snscb_port_type, portid,
819 		    ((u_int32_t)(wwn >> 32)), ((u_int32_t)(wwn & 0xffffffff)));
820 
821 		if (resp->snscb_port_type != 2) {
822 			rv = 0;
823 			break;
824 		}
825 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
826 			lp = &fcp->portdb[target];
827 			if (lp->port_wwn == wwn)
828 				break;
829 		}
830 		if (target < MAX_FC_TARG) {
831 			rv = 0;
832 			break;
833 		}
834 		for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
835 			lp = &fcp->portdb[target];
836 			if (lp->port_wwn == 0)
837 				break;
838 		}
839 		if (target == MAX_FC_TARG) {
840 			printf("%s: no more space for fabric devices\n",
841 			    isp->isp_name);
842 			break;
843 		}
844 		lp->port_wwn = lp->node_wwn = wwn;
845 		lp->portid = portid;
846 		rv = 0;
847 		break;
848 	}
849 #endif
850 	default:
851 		rv = -1;
852 		break;
853 	}
854 	return (rv);
855 }
856 
857 
858 /*
859  * Locks are held before coming here.
860  */
861 void
862 isp_uninit(struct ispsoftc *isp)
863 {
864 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
865 	DISABLE_INTS(isp);
866 }
867