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