xref: /freebsd/sys/dev/isp/isp_freebsd.c (revision 2aebedc3ad9e722b272254e6dd3a12e399595e57)
1 /* $Id: $ */
2 /* isp_freebsd.c 1.13 */
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_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(isp)
46 	struct ispsoftc *isp;
47 {
48 	struct ccb_setasync csa;
49 	struct cam_devq *devq;
50 
51 	/*
52 	 * Create the device queue for our SIM.
53 	 */
54 	devq = cam_simq_alloc(MAXISPREQUEST);
55 	if (devq == NULL) {
56 		return;
57 	}
58 
59 	/*
60 	 * Construct our SIM entry
61 	 */
62 	isp->isp_sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,
63 	    isp->isp_unit, 1, MAXISPREQUEST, devq);
64 	if (isp->isp_sim == NULL) {
65 		cam_simq_free(devq);
66 		return;
67 	}
68 	if (xpt_bus_register(isp->isp_sim, 0) != CAM_SUCCESS) {
69 		cam_sim_free(isp->isp_sim, TRUE);
70 		return;
71 	}
72 
73 	if (xpt_create_path(&isp->isp_path, NULL, cam_sim_path(isp->isp_sim),
74 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
75 		xpt_bus_deregister(cam_sim_path(isp->isp_sim));
76 		cam_sim_free(isp->isp_sim, TRUE);
77 		return;
78 	}
79 
80 	xpt_setup_ccb(&csa.ccb_h, isp->isp_path, 5);
81 	csa.ccb_h.func_code = XPT_SASYNC_CB;
82 	csa.event_enable = AC_LOST_DEVICE;
83 	csa.callback = isp_async;
84 	csa.callback_arg = isp->isp_sim;
85 	xpt_action((union ccb *)&csa);
86 
87 	/*
88 	 * Set base transfer capabilities for Fibre Channel.
89 	 * Technically not correct because we don't know
90 	 * what media we're running on top of- but we'll
91 	 * look good if we always say 100MB/s.
92 	 */
93 	if (isp->isp_type & ISP_HA_FC) {
94 		isp->isp_sim->base_transfer_speed = 100000;
95 	}
96 	isp->isp_state = ISP_RUNSTATE;
97 }
98 
99 static void
100 isp_async(cbarg, code, path, arg)
101 	void *cbarg;
102 	u_int32_t code;
103 	struct cam_path *path;
104 	void *arg;
105 {
106 	struct cam_sim *sim;
107 	struct ispsoftc *isp;
108 
109 	sim = (struct cam_sim *)cbarg;
110 	isp = (struct ispsoftc *) cam_sim_softc(sim);
111 	switch (code) {
112 	case AC_LOST_DEVICE:
113 		if (isp->isp_type & ISP_HA_SCSI) {
114 			u_int16_t oflags, nflags;
115 			sdparam *sdp = isp->isp_param;
116 			int s, tgt = xpt_path_target_id(path);
117 
118 			nflags = DPARM_SAFE_DFLT;
119 			if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
120 				nflags |= DPARM_NARROW | DPARM_ASYNC;
121 			}
122 			oflags = sdp->isp_devparam[tgt].dev_flags;
123 			sdp->isp_devparam[tgt].dev_flags = nflags;
124 			sdp->isp_devparam[tgt].dev_update = 1;
125 
126 			s = splcam();
127 			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
128 			(void) splx(s);
129 			sdp->isp_devparam[tgt].dev_flags = oflags;
130 		}
131 		break;
132 	default:
133 		break;
134 	}
135 }
136 
137 static void
138 isp_poll(sim)
139 	struct cam_sim *sim;
140 {
141 	isp_intr((struct ispsoftc *) cam_sim_softc(sim));
142 }
143 
144 
145 static void
146 isp_action(sim, ccb)
147 	struct cam_sim *sim;
148 	union ccb *ccb;
149 {
150 	int s, tgt, error;
151 	struct ispsoftc *isp;
152 	struct ccb_trans_settings *cts;
153 
154 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n"));
155 
156 	isp = (struct ispsoftc *)cam_sim_softc(sim);
157 	ccb->ccb_h.sim_priv.entries[0].field = 0;
158 	ccb->ccb_h.sim_priv.entries[1].ptr = isp;
159 
160 	IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
161 	    ccb->ccb_h.func_code));
162 
163 	switch (ccb->ccb_h.func_code) {
164 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
165 		/*
166 		 * Do a couple of preliminary checks...
167 		 */
168 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
169 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
170 				ccb->ccb_h.status = CAM_REQ_INVALID;
171 				xpt_done(ccb);
172 				break;
173 			}
174 		}
175 
176 
177 		if (isp->isp_type & ISP_HA_SCSI) {
178 			if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) {
179 				ccb->ccb_h.status = CAM_PATH_INVALID;
180 			} else if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
181 				/*
182 				 * Too much breakage.
183 				 */
184 #if	0
185 				if (ccb->ccb_h.target_lun > 31) {
186 					ccb->ccb_h.status = CAM_PATH_INVALID;
187 				}
188 #else
189 				if (ccb->ccb_h.target_lun > 7) {
190 					ccb->ccb_h.status = CAM_PATH_INVALID;
191 				}
192 #endif
193 			} else if (ccb->ccb_h.target_lun > 7) {
194 				ccb->ccb_h.status = CAM_PATH_INVALID;
195 			}
196 		} else {
197 			if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) {
198 				ccb->ccb_h.status = CAM_PATH_INVALID;
199 #ifdef	SCCLUN
200 			} else if (ccb->ccb_h.target_lun > 15) {
201 				ccb->ccb_h.status = CAM_PATH_INVALID;
202 #else
203 			} else if (ccb->ccb_h.target_lun > 65535) {
204 				ccb->ccb_h.status = CAM_PATH_INVALID;
205 #endif
206 			}
207 		}
208 		if (ccb->ccb_h.status == CAM_PATH_INVALID) {
209 			printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n",
210 			    isp->isp_name, ccb->ccb_h.target_id,
211 			    ccb->ccb_h.target_lun);
212 			xpt_done(ccb);
213 			break;
214 		}
215 
216 		s = splcam();
217 		switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) {
218 		case CMD_QUEUED:
219 			ccb->ccb_h.status |= CAM_SIM_QUEUED;
220 			break;
221 		case CMD_EAGAIN:
222 			if (isp->isp_osinfo.simqfrozen == 0) {
223 				xpt_freeze_simq(sim, 1);
224 				isp->isp_osinfo.simqfrozen = 1;
225 			}
226 			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
227                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
228 			xpt_done(ccb);
229 			break;
230 		case CMD_COMPLETE:
231 			/*
232 			 * Just make sure that we didn't get it returned
233 			 * as completed, but with the request still in
234 			 * progress. In theory, 'cannot happen'.
235 			 */
236 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
237 			    CAM_REQ_INPROG) {
238 				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
239 				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
240 			}
241 			xpt_done(ccb);
242 			break;
243 		}
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 = 65535;
489 #else
490 			cpi->max_lun = 15;
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 = 31;
502 #else
503 				cpi->max_lun = 7;
504 #endif
505 			} else {
506 				cpi->max_lun = 7;
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(sccb)
529 	struct ccb_scsiio *sccb;
530 {
531 	struct ispsoftc *isp = XS_ISP(sccb);
532 
533 	if (XS_NOERR(sccb))
534 		XS_SETERR(sccb, CAM_REQ_CMP);
535 	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
536 	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
537 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
538 	    (sccb->scsi_status != SCSI_STATUS_OK)) {
539 		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
540 		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
541 	}
542 	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
543 		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
544 			IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n",
545 			    isp->isp_name, sccb->ccb_h.target_id,
546 			    sccb->ccb_h.target_lun, sccb->ccb_h.status));
547 			xpt_freeze_devq(sccb->ccb_h.path, 1);
548 			sccb->ccb_h.status |= CAM_DEV_QFRZN;
549 		}
550 	}
551 	if (isp->isp_osinfo.simqfrozen) {
552 		sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
553 		isp->isp_osinfo.simqfrozen = 0;
554 	}
555 	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
556 	if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
557 	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
558 		xpt_print_path(sccb->ccb_h.path);
559 		printf("cam completion status 0x%x\n", sccb->ccb_h.status);
560 	}
561 	xpt_done((union ccb *) sccb);
562 }
563 
564 #else
565 
566 static void ispminphys __P((struct buf *));
567 static u_int32_t isp_adapter_info __P((int));
568 static int ispcmd __P((ISP_SCSI_XFER_T *));
569 
570 static struct scsi_adapter isp_switch = {
571 	ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 }
572 };
573 static struct scsi_device isp_dev = {
574 	NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 }
575 };
576 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
577 
578 
579 /*
580  * Complete attachment of hardware, include subdevices.
581  */
582 void
583 isp_attach(isp)
584 	struct ispsoftc *isp;
585 {
586 	struct scsibus_data *scbus;
587 
588 	scbus = scsi_alloc_bus();
589 	if(!scbus) {
590 		return;
591 	}
592 	isp->isp_state = ISP_RUNSTATE;
593 
594 	isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit;
595 	isp->isp_osinfo._link.adapter_softc = isp;
596 	isp->isp_osinfo._link.adapter = &isp_switch;
597 	isp->isp_osinfo._link.device = &isp_dev;
598 	isp->isp_osinfo._link.flags = 0;
599 	if (isp->isp_type & ISP_HA_FC) {
600 		isp->isp_osinfo._link.adapter_targ =
601 			((fcparam *)isp->isp_param)->isp_loopid;
602 		scbus->maxtarg = MAX_FC_TARG-1;
603 	} else {
604 		isp->isp_osinfo._link.adapter_targ =
605 			((sdparam *)isp->isp_param)->isp_initiator_id;
606 		scbus->maxtarg = MAX_TARGETS-1;
607 	}
608 	/*
609 	 * Prepare the scsibus_data area for the upperlevel scsi code.
610 	 */
611 	scbus->adapter_link = &isp->isp_osinfo._link;
612 
613 	/*
614 	 * ask the adapter what subunits are present
615 	 */
616 	scsi_attachdevs(scbus);
617 }
618 
619 
620 /*
621  * minphys our xfers
622  *
623  * Unfortunately, the buffer pointer describes the target device- not the
624  * adapter device, so we can't use the pointer to find out what kind of
625  * adapter we are and adjust accordingly.
626  */
627 
628 static void
629 ispminphys(bp)
630 	struct buf *bp;
631 {
632 	/*
633 	 * Only the 10X0 has a 24 bit limit.
634 	 */
635 	if (bp->b_bcount >= (1 << 24)) {
636 		bp->b_bcount = (1 << 24);
637 	}
638 }
639 
640 static u_int32_t
641 isp_adapter_info(unit)
642 	int unit;
643 {
644 	/*
645  	 * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT
646 	 */
647 	return (2);
648 }
649 
650 static int
651 ispcmd(xs)
652 	ISP_SCSI_XFER_T *xs;
653 {
654 	struct ispsoftc *isp;
655 	int r;
656 	ISP_LOCKVAL_DECL;
657 
658 	isp = XS_ISP(xs);
659 	ISP_LOCK;
660 	r = ispscsicmd(xs);
661 	if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) {
662 		ISP_UNLOCK;
663 		return (r);
664 	}
665 
666 	/*
667 	 * If we can't use interrupts, poll on completion.
668 	 */
669 	if (isp_poll(isp, xs, XS_TIME(xs))) {
670 		/*
671 		 * If no other error occurred but we didn't finish,
672 		 * something bad happened.
673 		 */
674 		if (XS_IS_CMD_DONE(xs) == 0) {
675 			isp->isp_nactive--;
676 			if (isp->isp_nactive < 0)
677 				isp->isp_nactive = 0;
678 			if (XS_NOERR(xs)) {
679 				isp_lostcmd(isp, xs);
680 				XS_SETERR(xs, HBA_BOTCH);
681 			}
682 		}
683 	}
684 	ISP_UNLOCK;
685 	return (CMD_COMPLETE);
686 }
687 
688 static int
689 isp_poll(isp, xs, mswait)
690 	struct ispsoftc *isp;
691 	ISP_SCSI_XFER_T *xs;
692 	int mswait;
693 {
694 
695 	while (mswait) {
696 		/* Try the interrupt handling routine */
697 		(void)isp_intr((void *)isp);
698 
699 		/* See if the xs is now done */
700 		if (XS_IS_CMD_DONE(xs))
701 			return (0);
702 		SYS_DELAY(1000);	/* wait one millisecond */
703 		mswait--;
704 	}
705 	return (1);
706 }
707 #endif
708