xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 2da199da53835ee2d9228a60717fd2d0fccf9e50)
1 /* $Id: isp_freebsd.c,v 1.10 1998/12/28 19:22:26 mjacob Exp $ */
2 /* release_01_29_99 */
3 /*
4  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
5  *
6  *---------------------------------------
7  * Copyright (c) 1997, 1998 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 #if	__FreeBSD_version >= 300004
39 
40 static void isp_cam_async __P((void *, u_int32_t, struct cam_path *, void *));
41 static void isp_poll __P((struct cam_sim *));
42 static void isp_action __P((struct cam_sim *, union ccb *));
43 
44 void
45 isp_attach(struct ispsoftc *isp)
46 {
47 	struct ccb_setasync csa;
48 	struct cam_devq *devq;
49 
50 	/*
51 	 * Create the device queue for our SIM.
52 	 */
53 	devq = cam_simq_alloc(MAXISPREQUEST);
54 	if (devq == NULL) {
55 		return;
56 	}
57 
58 	/*
59 	 * Construct our SIM entry
60 	 */
61 	isp->isp_sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
62 	    isp->isp_unit, 1, MAXISPREQUEST, devq);
63 	if (isp->isp_sim == NULL) {
64 		cam_simq_free(devq);
65 		return;
66 	}
67 	if (xpt_bus_register(isp->isp_sim, 0) != CAM_SUCCESS) {
68 		cam_sim_free(isp->isp_sim, TRUE);
69 		return;
70 	}
71 
72 	if (xpt_create_path(&isp->isp_path, NULL, cam_sim_path(isp->isp_sim),
73 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
74 		xpt_bus_deregister(cam_sim_path(isp->isp_sim));
75 		cam_sim_free(isp->isp_sim, TRUE);
76 		return;
77 	}
78 
79 	xpt_setup_ccb(&csa.ccb_h, isp->isp_path, 5);
80 	csa.ccb_h.func_code = XPT_SASYNC_CB;
81 	csa.event_enable = AC_LOST_DEVICE;
82 	csa.callback = isp_cam_async;
83 	csa.callback_arg = isp->isp_sim;
84 	xpt_action((union ccb *)&csa);
85 
86 	/*
87 	 * Set base transfer capabilities for Fibre Channel.
88 	 * Technically not correct because we don't know
89 	 * what media we're running on top of- but we'll
90 	 * look good if we always say 100MB/s.
91 	 */
92 	if (isp->isp_type & ISP_HA_FC) {
93 		isp->isp_sim->base_transfer_speed = 100000;
94 	}
95 	isp->isp_state = ISP_RUNSTATE;
96 }
97 
98 static void
99 isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
100 {
101 	struct cam_sim *sim;
102 	struct ispsoftc *isp;
103 
104 	sim = (struct cam_sim *)cbarg;
105 	isp = (struct ispsoftc *) cam_sim_softc(sim);
106 	switch (code) {
107 	case AC_LOST_DEVICE:
108 		if (isp->isp_type & ISP_HA_SCSI) {
109 			u_int16_t oflags, nflags;
110 			sdparam *sdp = isp->isp_param;
111 			int s, tgt = xpt_path_target_id(path);
112 
113 			nflags = DPARM_SAFE_DFLT;
114 			if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
115 				nflags |= DPARM_NARROW | DPARM_ASYNC;
116 			}
117 			oflags = sdp->isp_devparam[tgt].dev_flags;
118 			sdp->isp_devparam[tgt].dev_flags = nflags;
119 			sdp->isp_devparam[tgt].dev_update = 1;
120 
121 			s = splcam();
122 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
123 			(void) splx(s);
124 			sdp->isp_devparam[tgt].dev_flags = oflags;
125 		}
126 		break;
127 	default:
128 		break;
129 	}
130 }
131 
132 static void
133 isp_poll(struct cam_sim *sim)
134 {
135 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
136 }
137 
138 
139 static void
140 isp_action(struct cam_sim *sim, union ccb *ccb)
141 {
142 	int s, tgt, error;
143 	struct ispsoftc *isp;
144 	struct ccb_trans_settings *cts;
145 
146 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
147 
148 	isp = (struct ispsoftc *)cam_sim_softc(sim);
149 	ccb->ccb_h.sim_priv.entries[0].field = 0;
150 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
151 
152 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
153 	    ccb->ccb_h.func_code));
154 
155 	switch (ccb->ccb_h.func_code) {
156 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
157 		/*
158 		 * Do a couple of preliminary checks...
159 		 */
160 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
161 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
162 				ccb->ccb_h.status = CAM_REQ_INVALID;
163 				xpt_done(ccb);
164 				break;
165 			}
166 		}
167 
168 
169 		if (isp->isp_type & ISP_HA_SCSI) {
170 			if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) {
171 				ccb->ccb_h.status = CAM_PATH_INVALID;
172 			} else if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
173 				/*
174 				 * Too much breakage.
175 				 */
176 #if	0
177 				if (ccb->ccb_h.target_lun > 31) {
178 					ccb->ccb_h.status = CAM_PATH_INVALID;
179 				}
180 #else
181 				if (ccb->ccb_h.target_lun > 7) {
182 					ccb->ccb_h.status = CAM_PATH_INVALID;
183 				}
184 #endif
185 			} else if (ccb->ccb_h.target_lun > 7) {
186 				ccb->ccb_h.status = CAM_PATH_INVALID;
187 			}
188 		} else {
189 			if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) {
190 				ccb->ccb_h.status = CAM_PATH_INVALID;
191 #ifdef	SCCLUN
192 			} else if (ccb->ccb_h.target_lun > 15) {
193 				ccb->ccb_h.status = CAM_PATH_INVALID;
194 #else
195 			} else if (ccb->ccb_h.target_lun > 65535) {
196 				ccb->ccb_h.status = CAM_PATH_INVALID;
197 #endif
198 			}
199 		}
200 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
201 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
202 			    isp->isp_name, ccb->ccb_h.target_id,
203 			    ccb->ccb_h.target_lun);
204 			xpt_done(ccb);
205 			break;
206 		}
207 
208 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_INFO,
209 		    ("cdb[0]=0x%x dlen%d\n",
210 		    (ccb->ccb_h.flags & CAM_CDB_POINTER)?
211 			ccb->csio.cdb_io.cdb_ptr[0]:
212 			ccb->csio.cdb_io.cdb_bytes[0], ccb->csio.dxfer_len));
213 
214 		s = splcam();
215 		DISABLE_INTS(isp);
216 		switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) {
217 		case CMD_QUEUED:
218 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
219 			break;
220 		case CMD_EAGAIN:
221 			if (isp->isp_osinfo.simqfrozen == 0) {
222 				xpt_freeze_simq(sim, 1);
223 				isp->isp_osinfo.simqfrozen = 1;
224 			}
225 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
226                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
227 			xpt_done(ccb);
228 			break;
229 		case CMD_COMPLETE:
230 			/*
231 			 * Just make sure that we didn't get it returned
232 			 * as completed, but with the request still in
233 			 * progress. In theory, 'cannot happen'.
234 			 */
235 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
236 			    CAM_REQ_INPROG) {
237 				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
238 				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
239 			}
240 			xpt_done(ccb);
241 			break;
242 		}
243 		ENABLE_INTS(isp);
244 		splx(s);
245 		break;
246 
247 	case XPT_EN_LUN:		/* Enable LUN as a target */
248 	case XPT_TARGET_IO:		/* Execute target I/O request */
249 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
250 	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
251 		ccb->ccb_h.status = CAM_REQ_INVALID;
252 		xpt_done(ccb);
253 		break;
254 
255 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
256 		tgt = ccb->ccb_h.target_id;
257 		s = splcam();
258 		error =
259 		    isp_control(isp, ISPCTL_RESET_DEV, (void *)(intptr_t) tgt);
260 		(void) splx(s);
261 		if (error) {
262 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
263 		} else {
264 			ccb->ccb_h.status = CAM_REQ_CMP;
265 		}
266 		xpt_done(ccb);
267 		break;
268 	case XPT_ABORT:			/* Abort the specified CCB */
269 		s = splcam();
270 		error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
271 		(void) splx(s);
272 		if (error) {
273 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
274 		} else {
275 			ccb->ccb_h.status = CAM_REQ_CMP;
276 		}
277 		xpt_done(ccb);
278 		break;
279 
280 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
281 
282 		cts = &ccb->cts;
283 		tgt = cts->ccb_h.target_id;
284 		s = splcam();
285 		if (isp->isp_type & ISP_HA_FC) {
286 			;	/* nothing to change */
287 		} else {
288 			sdparam *sdp = isp->isp_param;
289 			u_int16_t *dptr;
290 
291 #if	0
292 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
293 				dptr = &sdp->isp_devparam[tgt].cur_dflags;
294 			else
295 				dptr = &sdp->isp_devparam[tgt].dev_flags;
296 #else
297 			/*
298 			 * We always update (internally) from dev_flags
299 			 * so any request to change settings just gets
300 			 * vectored to that location.
301 			 */
302 			dptr = &sdp->isp_devparam[tgt].dev_flags;
303 #endif
304 
305 			/*
306 			 * Note that these operations affect the
307 			 * the permanent flags (dev_flags)- not
308 			 * the current state flags. Then we mark
309 			 * things so that the next operation to
310 			 * this HBA will cause the update to occur.
311 			 */
312 			if (cts->valid & CCB_TRANS_DISC_VALID) {
313 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
314 					*dptr |= DPARM_DISC;
315 				} else {
316 					*dptr &= ~DPARM_DISC;
317 				}
318 			}
319 			if (cts->valid & CCB_TRANS_TQ_VALID) {
320 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
321 					*dptr |= DPARM_TQING;
322 				} else {
323 					*dptr &= ~DPARM_TQING;
324 				}
325 			}
326 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
327 				switch (cts->bus_width) {
328 				case MSG_EXT_WDTR_BUS_16_BIT:
329 					*dptr |= DPARM_WIDE;
330 					break;
331 				default:
332 					*dptr &= ~DPARM_WIDE;
333 				}
334 			}
335 			/*
336 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
337 			 * of nonzero will cause us to go to the
338 			 * selected (from NVRAM) maximum value for
339 			 * this device. At a later point, we'll
340 			 * allow finer control.
341 			 */
342 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
343 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
344 			    (cts->sync_offset > 0)) {
345 				*dptr |= DPARM_SYNC;
346 			} else {
347 				*dptr &= ~DPARM_SYNC;
348 			}
349 			IDPRINTF(3, ("%s: target %d new dev_flags 0x%x\n",
350 			    isp->isp_name, tgt,
351 			    sdp->isp_devparam[tgt].dev_flags));
352 			s = splcam();
353 			sdp->isp_devparam[tgt].dev_update = 1;
354 			isp->isp_update = 1;
355 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
356 			(void) splx(s);
357 		}
358 		(void) splx(s);
359 		ccb->ccb_h.status = CAM_REQ_CMP;
360 		xpt_done(ccb);
361 		break;
362 
363 	case XPT_GET_TRAN_SETTINGS:
364 
365 		cts = &ccb->cts;
366 		tgt = cts->ccb_h.target_id;
367 		if (isp->isp_type & ISP_HA_FC) {
368 			/*
369 			 * a lot of normal SCSI things don't make sense.
370 			 */
371 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
372 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
373 			/*
374 			 * How do you measure the width of a high
375 			 * speed serial bus? Well, in bytes.
376 			 *
377 			 * Offset and period make no sense, though, so we set
378 			 * (above) a 'base' transfer speed to be gigabit.
379 			 */
380 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
381 		} else {
382 			sdparam *sdp = isp->isp_param;
383 			u_int16_t dval;
384 
385 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
386 				dval = sdp->isp_devparam[tgt].cur_dflags;
387 			else
388 				dval = sdp->isp_devparam[tgt].dev_flags;
389 
390 			s = splcam();
391 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
392 
393 			if (dval & DPARM_DISC) {
394 				cts->flags |= CCB_TRANS_DISC_ENB;
395 			}
396 			if (dval & DPARM_TQING) {
397 				cts->flags |= CCB_TRANS_TAG_ENB;
398 			}
399 			if (dval & DPARM_WIDE) {
400 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
401 			} else {
402 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
403 			}
404 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
405 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
406 
407 			if ((dval & DPARM_SYNC) &&
408 			    (sdp->isp_devparam[tgt].sync_offset)) {
409 				cts->sync_period =
410 				    sdp->isp_devparam[tgt].sync_period;
411 				cts->sync_offset =
412 				    sdp->isp_devparam[tgt].sync_offset;
413 				cts->valid |=
414 				    CCB_TRANS_SYNC_RATE_VALID |
415 				    CCB_TRANS_SYNC_OFFSET_VALID;
416 			}
417 			splx(s);
418 		}
419 		ccb->ccb_h.status = CAM_REQ_CMP;
420 		xpt_done(ccb);
421 		break;
422 
423 	case XPT_CALC_GEOMETRY:
424 	{
425 		struct ccb_calc_geometry *ccg;
426 		u_int32_t secs_per_cylinder;
427 		u_int32_t size_mb;
428 
429 		ccg = &ccb->ccg;
430 		if (ccg->block_size == 0) {
431 			printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n",
432 				isp->isp_name, ccg->ccb_h.target_id,
433 				ccg->ccb_h.target_lun);
434 			ccb->ccb_h.status = CAM_REQ_INVALID;
435 			xpt_done(ccb);
436 			break;
437 		}
438 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
439 		if (size_mb > 1024) {
440 			ccg->heads = 255;
441 			ccg->secs_per_track = 63;
442 		} else {
443 			ccg->heads = 64;
444 			ccg->secs_per_track = 32;
445 		}
446 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
447 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
448 		ccb->ccb_h.status = CAM_REQ_CMP;
449 		xpt_done(ccb);
450 		break;
451 	}
452 	case XPT_RESET_BUS:		/* Reset the specified bus */
453 		if (isp->isp_type & ISP_HA_FC) {
454 			ccb->ccb_h.status = CAM_REQ_CMP;
455 			xpt_done(ccb);
456                 	break;
457 		}
458 		s = splcam();
459 		error = isp_control(isp, ISPCTL_RESET_BUS, NULL);
460 		(void) splx(s);
461 		if (error)
462 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
463 		else
464 			ccb->ccb_h.status = CAM_REQ_CMP;
465 		xpt_done(ccb);
466 		break;
467 
468 	case XPT_TERM_IO:		/* Terminate the I/O process */
469 		/* Does this need to be implemented? */
470 		ccb->ccb_h.status = CAM_REQ_INVALID;
471 		xpt_done(ccb);
472 		break;
473 
474 	case XPT_PATH_INQ:		/* Path routing inquiry */
475 	{
476 		struct ccb_pathinq *cpi = &ccb->cpi;
477 
478 		cpi->version_num = 1;
479 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
480 		cpi->target_sprt = 0;
481 		cpi->hba_misc = 0;
482 		cpi->hba_eng_cnt = 0;
483 		if (isp->isp_type & ISP_HA_FC) {
484 			cpi->max_target = MAX_FC_TARG-1;
485 			cpi->initiator_id =
486 			    ((fcparam *)isp->isp_param)->isp_loopid;
487 #ifdef	SCCLUN
488 			cpi->max_lun = (1 << 16) - 1;
489 #else
490 			cpi->max_lun = (1 << 4) - 1;
491 #endif
492 		} else {
493 			cpi->initiator_id =
494 			    ((sdparam *)isp->isp_param)->isp_initiator_id;
495 			cpi->max_target =  MAX_TARGETS-1;
496 			if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
497 #if	0
498 				/*
499 				 * Too much breakage.
500 				 */
501 				cpi->max_lun = (1 << 5) - 1;
502 #else
503 				cpi->max_lun = (1 << 3) - 1;
504 #endif
505 			} else {
506 				cpi->max_lun = (1 << 3) - 1;
507 			}
508 		}
509 
510 		cpi->bus_id = cam_sim_bus(sim);
511 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
512 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
513 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
514 		cpi->unit_number = cam_sim_unit(sim);
515 		cpi->ccb_h.status = CAM_REQ_CMP;
516 		xpt_done(ccb);
517 		break;
518 	}
519 	default:
520 		ccb->ccb_h.status = CAM_REQ_INVALID;
521 		xpt_done(ccb);
522 		break;
523 	}
524 }
525 
526 #define	ISPDDB	(CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB)
527 void
528 isp_done(struct ccb_scsiio *sccb)
529 {
530 	struct ispsoftc *isp = XS_ISP(sccb);
531 
532 	if (XS_NOERR(sccb))
533 		XS_SETERR(sccb, CAM_REQ_CMP);
534 	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
535 	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
536 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
537 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
538 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
539 		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
540 	}
541 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
542 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
543 			IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n",
544 			    isp->isp_name, sccb->ccb_h.target_id,
545 			    sccb->ccb_h.target_lun, sccb->ccb_h.status));
546 			xpt_freeze_devq(sccb->ccb_h.path, 1);
547 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
548 		}
549 	}
550 	if (isp->isp_osinfo.simqfrozen) {
551 		sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
552 		isp->isp_osinfo.simqfrozen = 0;
553 	}
554 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
555 	if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
556 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
557 		xpt_print_path(sccb->ccb_h.path);
558 		printf("cam completion status 0x%x\n", sccb->ccb_h.status);
559 	}
560 	xpt_done((union ccb *) sccb);
561 }
562 
563 int
564 isp_async(isp, cmd, arg)
565 	struct ispsoftc *isp;
566 	ispasync_t cmd;
567 	void *arg;
568 {
569 	int rv = 0;
570 	switch (cmd) {
571 	case ISPASYNC_NEW_TGT_PARAMS:
572 		if (isp->isp_type & ISP_HA_SCSI) {
573 			int flags, tgt;
574 			sdparam *sdp = isp->isp_param;
575 			struct ccb_trans_settings neg;
576 			struct cam_path *tmppath;
577 
578 			tgt = *((int *)arg);
579 			if (xpt_create_path(&tmppath, NULL,
580 			    cam_sim_path(isp->isp_sim), tgt,
581 			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
582 				xpt_print_path(isp->isp_path);
583 				printf("isp_async cannot make temp path for "
584 				    "target %d\n", tgt);
585 				rv = -1;
586 				break;
587 			}
588 
589 			flags = sdp->isp_devparam[tgt].dev_flags;
590 			neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
591 			if (flags & DPARM_DISC) {
592 				neg.flags |= CCB_TRANS_DISC_ENB;
593 			}
594 			if (flags & DPARM_TQING) {
595 				neg.flags |= CCB_TRANS_TAG_ENB;
596 			}
597 			neg.valid |= CCB_TRANS_BUS_WIDTH_VALID;
598 			neg.bus_width = (flags & DPARM_WIDE)?
599 			    MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT;
600 			neg.sync_period = sdp->isp_devparam[tgt].sync_period;
601 			neg.sync_offset = sdp->isp_devparam[tgt].sync_offset;
602 			if (flags & DPARM_SYNC) {
603 				neg.valid |= CCB_TRANS_SYNC_RATE_VALID |
604 						CCB_TRANS_SYNC_OFFSET_VALID;
605 			}
606 			xpt_print_path(tmppath);
607 			printf("new target params period %d offset %d\n",
608 			    neg.sync_period, neg.sync_offset);
609 			xpt_setup_ccb(&neg.ccb_h, tmppath, 1);
610 			xpt_async(AC_TRANSFER_NEG, tmppath, &neg);
611 			xpt_free_path(tmppath);
612 		}
613 		break;
614 	default:
615 		break;
616 	}
617 	return (rv);
618 }
619 
620 #else
621 
622 static void ispminphys __P((struct buf *));
623 static u_int32_t isp_adapter_info __P((int));
624 static int ispcmd __P((ISP_SCSI_XFER_T *));
625 static void isp_watch __P((void *arg));
626 
627 static struct scsi_adapter isp_switch = {
628 	ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 }
629 };
630 static struct scsi_device isp_dev = {
631 	NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 }
632 };
633 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
634 
635 
636 /*
637  * Complete attachment of hardware, include subdevices.
638  */
639 void
640 isp_attach(struct ispsoftc *isp)
641 {
642 	struct scsibus_data *scbus;
643 
644 	scbus = scsi_alloc_bus();
645 	if(!scbus) {
646 		return;
647 	}
648 	isp->isp_state = ISP_RUNSTATE;
649 	START_WATCHDOG(isp);
650 
651 	isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit;
652 	isp->isp_osinfo._link.adapter_softc = isp;
653 	isp->isp_osinfo._link.adapter = &isp_switch;
654 	isp->isp_osinfo._link.device = &isp_dev;
655 	isp->isp_osinfo._link.flags = 0;
656 	if (isp->isp_type & ISP_HA_FC) {
657 		isp->isp_osinfo._link.adapter_targ =
658 			((fcparam *)isp->isp_param)->isp_loopid;
659 		scbus->maxtarg = MAX_FC_TARG-1;
660 	} else {
661 		isp->isp_osinfo._link.adapter_targ =
662 			((sdparam *)isp->isp_param)->isp_initiator_id;
663 		scbus->maxtarg = MAX_TARGETS-1;
664 	}
665 	/*
666 	 * Prepare the scsibus_data area for the upperlevel scsi code.
667 	 */
668 	scbus->adapter_link = &isp->isp_osinfo._link;
669 
670 	/*
671 	 * ask the adapter what subunits are present
672 	 */
673 	scsi_attachdevs(scbus);
674 }
675 
676 
677 /*
678  * minphys our xfers
679  *
680  * Unfortunately, the buffer pointer describes the target device- not the
681  * adapter device, so we can't use the pointer to find out what kind of
682  * adapter we are and adjust accordingly.
683  */
684 
685 static void
686 ispminphys(struct buf *bp)
687 {
688 	/*
689 	 * Only the 10X0 has a 24 bit limit.
690 	 */
691 	if (bp->b_bcount >= (1 << 24)) {
692 		bp->b_bcount = (1 << 24);
693 	}
694 }
695 
696 static u_int32_t
697 isp_adapter_info(int unit)
698 {
699 	/*
700  	 * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT
701 	 */
702 	return (2);
703 }
704 
705 static int
706 ispcmd(ISP_SCSI_XFER_T *xs)
707 {
708 	struct ispsoftc *isp;
709 	int r;
710 	ISP_LOCKVAL_DECL;
711 
712 	isp = XS_ISP(xs);
713 	ISP_LOCK;
714 	r = ispscsicmd(xs);
715 	if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) {
716 		ISP_UNLOCK;
717 		return (r);
718 	}
719 
720 	/*
721 	 * If we can't use interrupts, poll on completion.
722 	 */
723 	if (isp_poll(isp, xs, XS_TIME(xs))) {
724 		/*
725 		 * If no other error occurred but we didn't finish,
726 		 * something bad happened.
727 		 */
728 		if (XS_IS_CMD_DONE(xs) == 0) {
729 			isp->isp_nactive--;
730 			if (isp->isp_nactive < 0)
731 				isp->isp_nactive = 0;
732 			if (XS_NOERR(xs)) {
733 				isp_lostcmd(isp, xs);
734 				XS_SETERR(xs, HBA_BOTCH);
735 			}
736 		}
737 	}
738 	ISP_UNLOCK;
739 	return (CMD_COMPLETE);
740 }
741 
742 static int
743 isp_poll(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, int mswait)
744 {
745 
746 	while (mswait) {
747 		/* Try the interrupt handling routine */
748 		(void)isp_intr((void *)isp);
749 
750 		/* See if the xs is now done */
751 		if (XS_IS_CMD_DONE(xs))
752 			return (0);
753 		SYS_DELAY(1000);	/* wait one millisecond */
754 		mswait--;
755 	}
756 	return (1);
757 }
758 
759 static void
760 isp_watch(void *arg)
761 {
762 	int i;
763 	struct ispsoftc *isp = arg;
764 	ISP_SCSI_XFER_T *xs;
765 	ISP_ILOCKVAL_DECL;
766 
767 	/*
768 	 * Look for completely dead commands (but not polled ones).
769 	 */
770 	ISP_ILOCK(isp);
771 	for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
772 		if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
773 			continue;
774 		}
775 		if (XS_TIME(xs) == 0) {
776 			continue;
777 		}
778 		XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
779 		/*
780 		 * Avoid later thinking that this
781 		 * transaction is not being timed.
782 		 * Then give ourselves to watchdog
783 		 * periods of grace.
784 		 */
785 		if (XS_TIME(xs) == 0)
786 			XS_TIME(xs) = 1;
787 		else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) {
788 			continue;
789 		}
790 		if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
791 			printf("%s: isp_watch failed to abort command\n",
792 			    isp->isp_name);
793 			isp_restart(isp);
794 			break;
795 		}
796 	}
797 	RESTART_WATCHDOG(isp_watch, arg);
798 	ISP_IUNLOCK(isp);
799 }
800 
801 int
802 isp_async(isp, cmd, arg)
803 	struct ispsoftc *isp;
804 	ispasync_t cmd;
805 	void *arg;
806 {
807 	switch (cmd) {
808 	case ISPASYNC_NEW_TGT_PARAMS:
809 		if (isp->isp_type & ISP_HA_SCSI) {
810 			sdparam *sdp = isp->isp_param;
811 			char *wt;
812 			int ns, flags, tgt;
813 
814 			tgt = *((int *) arg);
815 
816 			flags = sdp->isp_devparam[tgt].dev_flags;
817 			if (flags & DPARM_SYNC) {
818 				ns = sdp->isp_devparam[tgt].sync_period * 4;
819 			} else {
820 				ns = 0;
821 			}
822 			switch (flags & (DPARM_WIDE|DPARM_TQING)) {
823 			case DPARM_WIDE:
824 				wt = ", 16 bit wide\n";
825 				break;
826 			case DPARM_TQING:
827 				wt = ", Tagged Queueing Enabled\n";
828 				break;
829 			case DPARM_WIDE|DPARM_TQING:
830 				wt = ", 16 bit wide, Tagged Queueing Enabled\n";
831 				break;
832 			default:
833 				wt = "\n";
834 				break;
835 			}
836 			if (ns) {
837 				printf("%s: Target %d at %dMHz Max Offset %d%s",
838 				    isp->isp_name, tgt, 1000 / ns,
839 				    sdp->isp_devparam[tgt].sync_offset, wt);
840 			} else {
841 				printf("%s: Target %d Async Mode%s",
842 				    isp->isp_name, tgt, wt);
843 			}
844 		}
845 		break;
846 	default:
847 		break;
848 	}
849 	return (0);
850 }
851 #endif
852 
853 /*
854  * Free any associated resources prior to decommissioning and
855  * set the card to a known state (so it doesn't wake up and kick
856  * us when we aren't expecting it to).
857  *
858  * Locks are held before coming here.
859  */
860 void
861 isp_uninit(struct ispsoftc *isp)
862 {
863 	ISP_ILOCKVAL_DECL;
864 	ISP_ILOCK(isp);
865 	/*
866 	 * Leave with interrupts disabled.
867 	 */
868 	DISABLE_INTS(isp);
869 
870 	/*
871 	 * Turn off the watchdog (if active).
872 	 */
873 	STOP_WATCHDOG(isp_watch, isp);
874 
875 	/*
876 	 * And out...
877 	 */
878 	ISP_IUNLOCK(isp);
879 }
880