xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 0640d357f29fb1c0daaaffadd0416c5981413afd)
1 /* $FreeBSD$ */
2 /*
3  * Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
4  *
5  *---------------------------------------
6  * Copyright (c) 1997, 1998 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 #if	__FreeBSD_version >= 300004
38 
39 static void isp_async __P((void *, u_int32_t, struct cam_path *, void *));
40 static void isp_poll __P((struct cam_sim *));
41 static void isp_action __P((struct cam_sim *, union ccb *));
42 
43 void
44 isp_attach(isp)
45 	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_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_async(cbarg, code, path, arg)
100 	void *cbarg;
101 	u_int32_t code;
102 	struct cam_path *path;
103 	void *arg;
104 {
105 	struct cam_sim *sim;
106 	struct ispsoftc *isp;
107 
108 	sim = (struct cam_sim *)cbarg;
109 	isp = (struct ispsoftc *) cam_sim_softc(sim);
110 	switch (code) {
111 	case AC_LOST_DEVICE:
112 		if (isp->isp_type & ISP_HA_SCSI) {
113 			u_int16_t oflags, nflags;
114 			sdparam *sdp = isp->isp_param;
115 			int s, tgt = xpt_path_target_id(path);
116 
117 			nflags = DPARM_SAFE_DFLT;
118 			if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
119 				nflags |= DPARM_NARROW | DPARM_ASYNC;
120 			}
121 			oflags = sdp->isp_devparam[tgt].dev_flags;
122 			sdp->isp_devparam[tgt].dev_flags = nflags;
123 			sdp->isp_devparam[tgt].dev_update = 1;
124 
125 			s = splcam();
126 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
127 			(void) splx(s);
128 			sdp->isp_devparam[tgt].dev_flags = oflags;
129 		}
130 		break;
131 	default:
132 		break;
133 	}
134 }
135 
136 static void
137 isp_poll(sim)
138 	struct cam_sim *sim;
139 {
140 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
141 }
142 
143 
144 static void
145 isp_action(sim, ccb)
146 	struct cam_sim *sim;
147 	union ccb *ccb;
148 {
149 	int s, tgt, error;
150 	struct ispsoftc *isp;
151 	struct ccb_trans_settings *cts;
152 
153 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
154 
155 	isp = (struct ispsoftc *)cam_sim_softc(sim);
156 	ccb->ccb_h.sim_priv.entries[0].field = 0;
157 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
158 
159 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
160 	    ccb->ccb_h.func_code));
161 
162 	switch (ccb->ccb_h.func_code) {
163 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
164 		/*
165 		 * Do a couple of preliminary checks...
166 		 */
167 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
168 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
169 				ccb->ccb_h.status = CAM_REQ_INVALID;
170 				xpt_done(ccb);
171 				break;
172 			}
173 		}
174 
175 
176 		if (isp->isp_type & ISP_HA_SCSI) {
177 			if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) {
178 				ccb->ccb_h.status = CAM_PATH_INVALID;
179 			} else if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
180 				/*
181 				 * Too much breakage.
182 				 */
183 #if	0
184 				if (ccb->ccb_h.target_lun > 31) {
185 					ccb->ccb_h.status = CAM_PATH_INVALID;
186 				}
187 #else
188 				if (ccb->ccb_h.target_lun > 7) {
189 					ccb->ccb_h.status = CAM_PATH_INVALID;
190 				}
191 #endif
192 			} else if (ccb->ccb_h.target_lun > 7) {
193 				ccb->ccb_h.status = CAM_PATH_INVALID;
194 			}
195 		} else {
196 			if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) {
197 				ccb->ccb_h.status = CAM_PATH_INVALID;
198 			} else if (ccb->ccb_h.target_lun > 15) {
199 				ccb->ccb_h.status = CAM_PATH_INVALID;
200 			}
201 		}
202 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
203 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
204 			    isp->isp_name, ccb->ccb_h.target_id,
205 			    ccb->ccb_h.target_lun);
206 			xpt_done(ccb);
207 			break;
208 		}
209 
210 		s = splcam();
211 		switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) {
212 		case CMD_QUEUED:
213 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
214 			break;
215 		case CMD_EAGAIN:
216 			if (isp->isp_osinfo.simqfrozen == 0) {
217 				xpt_freeze_simq(sim, 1);
218 				isp->isp_osinfo.simqfrozen = 1;
219 			}
220 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
221                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
222 			xpt_done(ccb);
223 			break;
224 		case CMD_COMPLETE:
225 			/*
226 			 * Just make sure that we didn't get it returned
227 			 * as completed, but with the request still in
228 			 * progress. In theory, 'cannot happen'.
229 			 */
230 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
231 			    CAM_REQ_INPROG) {
232 				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
233 				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
234 			}
235 			xpt_done(ccb);
236 			break;
237 		}
238 		splx(s);
239 		break;
240 
241 	case XPT_EN_LUN:		/* Enable LUN as a target */
242 	case XPT_TARGET_IO:		/* Execute target I/O request */
243 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
244 	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
245 		ccb->ccb_h.status = CAM_REQ_INVALID;
246 		xpt_done(ccb);
247 		break;
248 
249 	case XPT_RESET_DEV:		/* BDR the specified SCSI device */
250 		tgt = ccb->ccb_h.target_id;
251 		s = splcam();
252 		error =
253 		    isp_control(isp, ISPCTL_RESET_DEV, (void *)(intptr_t) tgt);
254 		(void) splx(s);
255 		if (error) {
256 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
257 		} else {
258 			ccb->ccb_h.status = CAM_REQ_CMP;
259 		}
260 		xpt_done(ccb);
261 		break;
262 	case XPT_ABORT:			/* Abort the specified CCB */
263 		s = splcam();
264 		error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);
265 		(void) splx(s);
266 		if (error) {
267 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
268 		} else {
269 			ccb->ccb_h.status = CAM_REQ_CMP;
270 		}
271 		xpt_done(ccb);
272 		break;
273 
274 	case XPT_SET_TRAN_SETTINGS:	/* Nexus Settings */
275 
276 		cts = &ccb->cts;
277 		tgt = cts->ccb_h.target_id;
278 		s = splcam();
279 		if (isp->isp_type & ISP_HA_FC) {
280 			;	/* nothing to change */
281 		} else {
282 			sdparam *sdp = isp->isp_param;
283 			u_int16_t *dptr;
284 
285 #if	0
286 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
287 				dptr = &sdp->isp_devparam[tgt].cur_dflags;
288 			else
289 				dptr = &sdp->isp_devparam[tgt].dev_flags;
290 #else
291 			/*
292 			 * We always update (internally) from dev_flags
293 			 * so any request to change settings just gets
294 			 * vectored to that location.
295 			 */
296 			dptr = &sdp->isp_devparam[tgt].dev_flags;
297 #endif
298 
299 			/*
300 			 * Note that these operations affect the
301 			 * the permanent flags (dev_flags)- not
302 			 * the current state flags. Then we mark
303 			 * things so that the next operation to
304 			 * this HBA will cause the update to occur.
305 			 */
306 			if (cts->valid & CCB_TRANS_DISC_VALID) {
307 				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) {
308 					*dptr |= DPARM_DISC;
309 				} else {
310 					*dptr &= ~DPARM_DISC;
311 				}
312 			}
313 			if (cts->valid & CCB_TRANS_TQ_VALID) {
314 				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) {
315 					*dptr |= DPARM_TQING;
316 				} else {
317 					*dptr &= ~DPARM_TQING;
318 				}
319 			}
320 			if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
321 				switch (cts->bus_width) {
322 				case MSG_EXT_WDTR_BUS_16_BIT:
323 					*dptr |= DPARM_WIDE;
324 					break;
325 				default:
326 					*dptr &= ~DPARM_WIDE;
327 				}
328 			}
329 			/*
330 			 * Any SYNC RATE of nonzero and SYNC_OFFSET
331 			 * of nonzero will cause us to go to the
332 			 * selected (from NVRAM) maximum value for
333 			 * this device. At a later point, we'll
334 			 * allow finer control.
335 			 */
336 			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
337 			    (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) &&
338 			    (cts->sync_offset > 0)) {
339 				*dptr |= DPARM_SYNC;
340 			} else {
341 				*dptr &= ~DPARM_SYNC;
342 			}
343 			IDPRINTF(3, ("%s: target %d new dev_flags 0x%x\n",
344 			    isp->isp_name, tgt,
345 			    sdp->isp_devparam[tgt].dev_flags));
346 			s = splcam();
347 			sdp->isp_devparam[tgt].dev_update = 1;
348 			isp->isp_update = 1;
349 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
350 			(void) splx(s);
351 		}
352 		(void) splx(s);
353 		ccb->ccb_h.status = CAM_REQ_CMP;
354 		xpt_done(ccb);
355 		break;
356 
357 	case XPT_GET_TRAN_SETTINGS:
358 
359 		cts = &ccb->cts;
360 		tgt = cts->ccb_h.target_id;
361 		if (isp->isp_type & ISP_HA_FC) {
362 			/*
363 			 * a lot of normal SCSI things don't make sense.
364 			 */
365 			cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
366 			cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
367 			/*
368 			 * How do you measure the width of a high
369 			 * speed serial bus? Well, in bytes.
370 			 *
371 			 * Offset and period make no sense, though, so we set
372 			 * (above) a 'base' transfer speed to be gigabit.
373 			 */
374 			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
375 		} else {
376 			sdparam *sdp = isp->isp_param;
377 			u_int16_t dval;
378 
379 			if (cts->flags & CCB_TRANS_CURRENT_SETTINGS)
380 				dval = sdp->isp_devparam[tgt].cur_dflags;
381 			else
382 				dval = sdp->isp_devparam[tgt].dev_flags;
383 
384 			s = splcam();
385 			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
386 
387 			if (dval & DPARM_DISC) {
388 				cts->flags |= CCB_TRANS_DISC_ENB;
389 			}
390 			if (dval & DPARM_TQING) {
391 				cts->flags |= CCB_TRANS_TAG_ENB;
392 			}
393 			if (dval & DPARM_WIDE) {
394 				cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
395 			} else {
396 				cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
397 			}
398 			cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
399 			    CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
400 
401 			if ((dval & DPARM_SYNC) &&
402 			    (sdp->isp_devparam[tgt].sync_offset)) {
403 				cts->sync_period =
404 				    sdp->isp_devparam[tgt].sync_period;
405 				cts->sync_offset =
406 				    sdp->isp_devparam[tgt].sync_offset;
407 				cts->valid |=
408 				    CCB_TRANS_SYNC_RATE_VALID |
409 				    CCB_TRANS_SYNC_OFFSET_VALID;
410 			}
411 			splx(s);
412 		}
413 		ccb->ccb_h.status = CAM_REQ_CMP;
414 		xpt_done(ccb);
415 		break;
416 
417 	case XPT_CALC_GEOMETRY:
418 	{
419 		struct ccb_calc_geometry *ccg;
420 		u_int32_t secs_per_cylinder;
421 		u_int32_t size_mb;
422 
423 		ccg = &ccb->ccg;
424 		if (ccg->block_size == 0) {
425 			printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n",
426 				isp->isp_name, ccg->ccb_h.target_id,
427 				ccg->ccb_h.target_lun);
428 			ccb->ccb_h.status = CAM_REQ_INVALID;
429 			xpt_done(ccb);
430 			break;
431 		}
432 		size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
433 		if (size_mb > 1024) {
434 			ccg->heads = 255;
435 			ccg->secs_per_track = 63;
436 		} else {
437 			ccg->heads = 64;
438 			ccg->secs_per_track = 32;
439 		}
440 		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
441 		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
442 		ccb->ccb_h.status = CAM_REQ_CMP;
443 		xpt_done(ccb);
444 		break;
445 	}
446 	case XPT_RESET_BUS:		/* Reset the specified bus */
447 		if (isp->isp_type & ISP_HA_FC) {
448 			ccb->ccb_h.status = CAM_REQ_CMP;
449 			xpt_done(ccb);
450                 	break;
451 		}
452 		s = splcam();
453 		error = isp_control(isp, ISPCTL_RESET_BUS, NULL);
454 		(void) splx(s);
455 		if (error)
456 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
457 		else
458 			ccb->ccb_h.status = CAM_REQ_CMP;
459 		xpt_done(ccb);
460 		break;
461 
462 	case XPT_TERM_IO:		/* Terminate the I/O process */
463 		/* Does this need to be implemented? */
464 		ccb->ccb_h.status = CAM_REQ_INVALID;
465 		xpt_done(ccb);
466 		break;
467 
468 	case XPT_PATH_INQ:		/* Path routing inquiry */
469 	{
470 		struct ccb_pathinq *cpi = &ccb->cpi;
471 
472 		cpi->version_num = 1;
473 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
474 		cpi->target_sprt = 0;
475 		cpi->hba_misc = 0;
476 		cpi->hba_eng_cnt = 0;
477 		if (isp->isp_type & ISP_HA_FC) {
478 			cpi->max_target = MAX_FC_TARG-1;
479 			cpi->initiator_id =
480 			    ((fcparam *)isp->isp_param)->isp_loopid;
481 			/*
482 			 * XXX: actually, this is not right if we have
483 			 * XXX: 1.14 F/W and the second level lun addressing
484 			 * XXX: in place. It's also probably not right
485 			 * XXX: even for 1.13 f/w.
486 			 */
487 			cpi->max_lun = 15;
488 		} else {
489 			cpi->initiator_id =
490 			    ((sdparam *)isp->isp_param)->isp_initiator_id;
491 			cpi->max_target =  MAX_TARGETS-1;
492 			if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
493 				/*
494 				 * Too much breakage.
495 				 */
496 #if	0
497 				cpi->max_lun = 31;
498 #else
499 				cpi->max_lun = 7;
500 #endif
501 			} else {
502 				cpi->max_lun = 7;
503 			}
504 		}
505 
506 		cpi->bus_id = cam_sim_bus(sim);
507 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
508 		strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN);
509 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
510 		cpi->unit_number = cam_sim_unit(sim);
511 		cpi->ccb_h.status = CAM_REQ_CMP;
512 		xpt_done(ccb);
513 		break;
514 	}
515 	default:
516 		ccb->ccb_h.status = CAM_REQ_INVALID;
517 		xpt_done(ccb);
518 		break;
519 	}
520 }
521 #else
522 
523 static void ispminphys __P((struct buf *));
524 static u_int32_t isp_adapter_info __P((int));
525 static int ispcmd __P((ISP_SCSI_XFER_T *));
526 
527 static struct scsi_adapter isp_switch = {
528 	ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 }
529 };
530 static struct scsi_device isp_dev = {
531 	NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 }
532 };
533 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
534 
535 
536 /*
537  * Complete attachment of hardware, include subdevices.
538  */
539 void
540 isp_attach(isp)
541 	struct ispsoftc *isp;
542 {
543 	struct scsibus_data *scbus;
544 
545 	scbus = scsi_alloc_bus();
546 	if(!scbus) {
547 		return;
548 	}
549 	isp->isp_state = ISP_RUNSTATE;
550 
551 	isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit;
552 	isp->isp_osinfo._link.adapter_softc = isp;
553 	isp->isp_osinfo._link.adapter = &isp_switch;
554 	isp->isp_osinfo._link.device = &isp_dev;
555 	isp->isp_osinfo._link.flags = 0;
556 	if (isp->isp_type & ISP_HA_FC) {
557 		isp->isp_osinfo._link.adapter_targ =
558 			((fcparam *)isp->isp_param)->isp_loopid;
559 		scbus->maxtarg = MAX_FC_TARG-1;
560 	} else {
561 		isp->isp_osinfo._link.adapter_targ =
562 			((sdparam *)isp->isp_param)->isp_initiator_id;
563 		scbus->maxtarg = MAX_TARGETS-1;
564 	}
565 	/*
566 	 * Prepare the scsibus_data area for the upperlevel scsi code.
567 	 */
568 	scbus->adapter_link = &isp->isp_osinfo._link;
569 
570 	/*
571 	 * ask the adapter what subunits are present
572 	 */
573 	scsi_attachdevs(scbus);
574 }
575 
576 
577 /*
578  * minphys our xfers
579  *
580  * Unfortunately, the buffer pointer describes the target device- not the
581  * adapter device, so we can't use the pointer to find out what kind of
582  * adapter we are and adjust accordingly.
583  */
584 
585 static void
586 ispminphys(bp)
587 	struct buf *bp;
588 {
589 	/*
590 	 * Only the 10X0 has a 24 bit limit.
591 	 */
592 	if (bp->b_bcount >= (1 << 24)) {
593 		bp->b_bcount = (1 << 24);
594 	}
595 }
596 
597 static u_int32_t
598 isp_adapter_info(unit)
599 	int unit;
600 {
601 	/*
602  	 * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT
603 	 */
604 	return (2);
605 }
606 
607 static int
608 ispcmd(xs)
609 	ISP_SCSI_XFER_T *xs;
610 {
611 	struct ispsoftc *isp;
612 	int r;
613 	ISP_LOCKVAL_DECL;
614 
615 	isp = XS_ISP(xs);
616 	ISP_LOCK;
617 	r = ispscsicmd(xs);
618 	if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) {
619 		ISP_UNLOCK;
620 		return (r);
621 	}
622 
623 	/*
624 	 * If we can't use interrupts, poll on completion.
625 	 */
626 	if (isp_poll(isp, xs, XS_TIME(xs))) {
627 		/*
628 		 * If no other error occurred but we didn't finish,
629 		 * something bad happened.
630 		 */
631 		if (XS_IS_CMD_DONE(xs) == 0) {
632 			isp->isp_nactive--;
633 			if (isp->isp_nactive < 0)
634 				isp->isp_nactive = 0;
635 			if (XS_NOERR(xs)) {
636 				isp_lostcmd(isp, xs);
637 				XS_SETERR(xs, HBA_BOTCH);
638 			}
639 		}
640 	}
641 	ISP_UNLOCK;
642 	return (CMD_COMPLETE);
643 }
644 
645 static int
646 isp_poll(isp, xs, mswait)
647 	struct ispsoftc *isp;
648 	ISP_SCSI_XFER_T *xs;
649 	int mswait;
650 {
651 
652 	while (mswait) {
653 		/* Try the interrupt handling routine */
654 		(void)isp_intr((void *)isp);
655 
656 		/* See if the xs is now done */
657 		if (XS_IS_CMD_DONE(xs))
658 			return (0);
659 		SYS_DELAY(1000);	/* wait one millisecond */
660 		mswait--;
661 	}
662 	return (1);
663 }
664 #endif
665