1 /* $FreeBSD$ */ 2 /* $Id: isp_freebsd.c,v 1.11 1998/09/14 23:22:12 mjacob Exp $ */ 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 #ifdef SCSI_CAM 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, set; 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 printf("%s: EAGAINed %d.%d\n", isp->isp_name, 217 ccb->ccb_h.target_id, ccb->ccb_h.target_lun); 218 printf("%s: %d EAGAIN\n", __FILE__, __LINE__); 219 xpt_freeze_simq(sim, 1); 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 printf("%s: COMPLETEd for %d.%d with cam status 0%x\n", 226 isp->isp_name, ccb->ccb_h.target_id, 227 ccb->ccb_h.target_lun, ccb->ccb_h.status); 228 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 229 CAM_REQ_INPROG) { 230 /* XXX: Cannot Happen */ 231 ccb->ccb_h.status &= ~CAM_STATUS_MASK; 232 ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 233 } 234 xpt_done(ccb); 235 break; 236 } 237 splx(s); 238 break; 239 240 case XPT_EN_LUN: /* Enable LUN as a target */ 241 case XPT_TARGET_IO: /* Execute target I/O request */ 242 case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 243 case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 244 ccb->ccb_h.status = CAM_REQ_INVALID; 245 xpt_done(ccb); 246 break; 247 248 case XPT_RESET_DEV: /* BDR the specified SCSI device */ 249 tgt = ccb->ccb_h.target_id; 250 s = splcam(); 251 error = isp_control(isp, ISPCTL_RESET_DEV, (void *) tgt); 252 (void) splx(s); 253 if (error) { 254 ccb->ccb_h.status = CAM_REQ_CMP_ERR; 255 } else { 256 ccb->ccb_h.status = CAM_REQ_CMP; 257 } 258 xpt_done(ccb); 259 break; 260 case XPT_ABORT: /* Abort the specified CCB */ 261 s = splcam(); 262 error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 263 (void) splx(s); 264 if (error) { 265 ccb->ccb_h.status = CAM_REQ_CMP_ERR; 266 } else { 267 ccb->ccb_h.status = CAM_REQ_CMP; 268 } 269 xpt_done(ccb); 270 break; 271 272 case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 273 274 cts = &ccb->cts; 275 tgt = cts->ccb_h.target_id; 276 s = splcam(); 277 if (isp->isp_type & ISP_HA_FC) { 278 ; /* nothing to change */ 279 } else { 280 sdparam *sdp = isp->isp_param; 281 u_int16_t *dptr; 282 283 #if 0 284 if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) 285 dptr = &sdp->isp_devparam[tgt].cur_dflags; 286 else 287 dptr = &sdp->isp_devparam[tgt].dev_flags; 288 #else 289 /* 290 * We always update (internally) from dev_flags 291 * so any request to change settings just gets 292 * vectored to that location. 293 */ 294 dptr = &sdp->isp_devparam[tgt].dev_flags; 295 #endif 296 297 /* 298 * Note that these operations affect the 299 * the permanent flags (dev_flags)- not 300 * the current state flags. Then we mark 301 * things so that the next operation to 302 * this HBA will cause the update to occur. 303 */ 304 if (cts->valid & CCB_TRANS_DISC_VALID) { 305 if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 306 *dptr |= DPARM_DISC; 307 } else { 308 *dptr &= ~DPARM_DISC; 309 } 310 } 311 if (cts->valid & CCB_TRANS_TQ_VALID) { 312 if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 313 *dptr |= DPARM_TQING; 314 } else { 315 *dptr &= ~DPARM_TQING; 316 } 317 } 318 if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 319 switch (cts->bus_width) { 320 case MSG_EXT_WDTR_BUS_16_BIT: 321 *dptr |= DPARM_WIDE; 322 break; 323 default: 324 *dptr &= ~DPARM_WIDE; 325 } 326 } 327 /* 328 * Any SYNC RATE of nonzero and SYNC_OFFSET 329 * of nonzero will cause us to go to the 330 * selected (from NVRAM) maximum value for 331 * this device. At a later point, we'll 332 * allow finer control. 333 */ 334 if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 335 (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 336 (cts->sync_offset > 0)) { 337 *dptr |= DPARM_SYNC; 338 } else { 339 *dptr &= ~DPARM_SYNC; 340 } 341 IDPRINTF(3, ("%s: target %d new dev_flags 0x%x\n", 342 isp->isp_name, tgt, 343 sdp->isp_devparam[tgt].dev_flags)); 344 s = splcam(); 345 sdp->isp_devparam[tgt].dev_update = 1; 346 isp->isp_update = 1; 347 (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 348 (void) splx(s); 349 } 350 (void) splx(s); 351 ccb->ccb_h.status = CAM_REQ_CMP; 352 xpt_done(ccb); 353 break; 354 355 case XPT_GET_TRAN_SETTINGS: 356 357 cts = &ccb->cts; 358 tgt = cts->ccb_h.target_id; 359 if (isp->isp_type & ISP_HA_FC) { 360 /* 361 * a lot of normal SCSI things don't make sense. 362 */ 363 cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 364 cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 365 /* 366 * How do you measure the width of a high 367 * speed serial bus? Well, in bytes. 368 * 369 * Offset and period make no sense, though, so we set 370 * (above) a 'base' transfer speed to be gigabit. 371 */ 372 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 373 } else { 374 sdparam *sdp = isp->isp_param; 375 u_int16_t dval; 376 377 if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) 378 dval = sdp->isp_devparam[tgt].cur_dflags; 379 else 380 dval = sdp->isp_devparam[tgt].dev_flags; 381 382 s = splcam(); 383 cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 384 385 if (dval & DPARM_DISC) { 386 cts->flags |= CCB_TRANS_DISC_ENB; 387 } 388 if (dval & DPARM_TQING) { 389 cts->flags |= CCB_TRANS_TAG_ENB; 390 } 391 if (dval & DPARM_WIDE) { 392 cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 393 } else { 394 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 395 } 396 cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 397 CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 398 399 if ((dval & DPARM_SYNC) && 400 (sdp->isp_devparam[tgt].sync_offset)) { 401 cts->sync_period = 402 sdp->isp_devparam[tgt].sync_period; 403 cts->sync_offset = 404 sdp->isp_devparam[tgt].sync_offset; 405 cts->valid |= 406 CCB_TRANS_SYNC_RATE_VALID | 407 CCB_TRANS_SYNC_OFFSET_VALID; 408 } 409 splx(s); 410 } 411 ccb->ccb_h.status = CAM_REQ_CMP; 412 xpt_done(ccb); 413 break; 414 415 case XPT_CALC_GEOMETRY: 416 { 417 struct ccb_calc_geometry *ccg; 418 u_int32_t secs_per_cylinder; 419 u_int32_t size_mb; 420 421 ccg = &ccb->ccg; 422 if (ccg->block_size == 0) { 423 printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n", 424 isp->isp_name, ccg->ccb_h.target_id, 425 ccg->ccb_h.target_lun); 426 ccb->ccb_h.status = CAM_REQ_INVALID; 427 xpt_done(ccb); 428 break; 429 } 430 size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 431 if (size_mb > 1024) { 432 ccg->heads = 255; 433 ccg->secs_per_track = 63; 434 } else { 435 ccg->heads = 64; 436 ccg->secs_per_track = 32; 437 } 438 secs_per_cylinder = ccg->heads * ccg->secs_per_track; 439 ccg->cylinders = ccg->volume_size / secs_per_cylinder; 440 ccb->ccb_h.status = CAM_REQ_CMP; 441 xpt_done(ccb); 442 break; 443 } 444 case XPT_RESET_BUS: /* Reset the specified bus */ 445 if (isp->isp_type & ISP_HA_FC) { 446 ccb->ccb_h.status = CAM_REQ_CMP; 447 xpt_done(ccb); 448 break; 449 } 450 s = splcam(); 451 error = isp_control(isp, ISPCTL_RESET_BUS, NULL); 452 (void) splx(s); 453 if (error) 454 ccb->ccb_h.status = CAM_REQ_CMP_ERR; 455 else 456 ccb->ccb_h.status = CAM_REQ_CMP; 457 xpt_done(ccb); 458 break; 459 460 case XPT_TERM_IO: /* Terminate the I/O process */ 461 /* Does this need to be implemented? */ 462 ccb->ccb_h.status = CAM_REQ_INVALID; 463 xpt_done(ccb); 464 break; 465 466 case XPT_PATH_INQ: /* Path routing inquiry */ 467 { 468 struct ccb_pathinq *cpi = &ccb->cpi; 469 470 cpi->version_num = 1; 471 cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 472 cpi->target_sprt = 0; 473 cpi->hba_misc = 0; 474 cpi->hba_eng_cnt = 0; 475 if (isp->isp_type & ISP_HA_FC) { 476 cpi->max_target = MAX_FC_TARG-1; 477 cpi->initiator_id = 478 ((fcparam *)isp->isp_param)->isp_loopid; 479 /* 480 * XXX: actually, this is not right if we have 481 * XXX: 1.14 F/W and the second level lun addressing 482 * XXX: in place. It's also probably not right 483 * XXX: even for 1.13 f/w. 484 */ 485 cpi->max_lun = 15; 486 } else { 487 cpi->initiator_id = 488 ((sdparam *)isp->isp_param)->isp_initiator_id; 489 cpi->max_target = MAX_TARGETS-1; 490 if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) { 491 /* 492 * Too much breakage. 493 */ 494 #if 0 495 cpi->max_lun = 31; 496 #else 497 cpi->max_lun = 7; 498 #endif 499 } else { 500 cpi->max_lun = 7; 501 } 502 } 503 504 cpi->bus_id = cam_sim_bus(sim); 505 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 506 strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 507 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 508 cpi->unit_number = cam_sim_unit(sim); 509 cpi->ccb_h.status = CAM_REQ_CMP; 510 xpt_done(ccb); 511 break; 512 } 513 default: 514 ccb->ccb_h.status = CAM_REQ_INVALID; 515 xpt_done(ccb); 516 break; 517 } 518 } 519 #else 520 521 static void ispminphys __P((struct buf *)); 522 static u_int32_t isp_adapter_info __P((int)); 523 static int ispcmd __P((ISP_SCSI_XFER_T *)); 524 525 static struct scsi_adapter isp_switch = { 526 ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 } 527 }; 528 static struct scsi_device isp_dev = { 529 NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 } 530 }; 531 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int)); 532 533 534 /* 535 * Complete attachment of hardware, include subdevices. 536 */ 537 void 538 isp_attach(isp) 539 struct ispsoftc *isp; 540 { 541 struct scsibus_data *scbus; 542 543 scbus = scsi_alloc_bus(); 544 if(!scbus) { 545 return; 546 } 547 isp->isp_state = ISP_RUNSTATE; 548 549 isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit; 550 isp->isp_osinfo._link.adapter_softc = isp; 551 isp->isp_osinfo._link.adapter = &isp_switch; 552 isp->isp_osinfo._link.device = &isp_dev; 553 isp->isp_osinfo._link.flags = 0; 554 if (isp->isp_type & ISP_HA_FC) { 555 isp->isp_osinfo._link.adapter_targ = 556 ((fcparam *)isp->isp_param)->isp_loopid; 557 scbus->maxtarg = MAX_FC_TARG-1; 558 } else { 559 isp->isp_osinfo._link.adapter_targ = 560 ((sdparam *)isp->isp_param)->isp_initiator_id; 561 scbus->maxtarg = MAX_TARGETS-1; 562 } 563 /* 564 * Prepare the scsibus_data area for the upperlevel scsi code. 565 */ 566 scbus->adapter_link = &isp->isp_osinfo._link; 567 568 /* 569 * ask the adapter what subunits are present 570 */ 571 scsi_attachdevs(scbus); 572 } 573 574 575 /* 576 * minphys our xfers 577 * 578 * Unfortunately, the buffer pointer describes the target device- not the 579 * adapter device, so we can't use the pointer to find out what kind of 580 * adapter we are and adjust accordingly. 581 */ 582 583 static void 584 ispminphys(bp) 585 struct buf *bp; 586 { 587 /* 588 * Only the 10X0 has a 24 bit limit. 589 */ 590 if (bp->b_bcount >= (1 << 24)) { 591 bp->b_bcount = (1 << 24); 592 } 593 } 594 595 static u_int32_t 596 isp_adapter_info(unit) 597 int unit; 598 { 599 /* 600 * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT 601 */ 602 return (2); 603 } 604 605 static int 606 ispcmd(xs) 607 ISP_SCSI_XFER_T *xs; 608 { 609 struct ispsoftc *isp; 610 int r; 611 ISP_LOCKVAL_DECL; 612 613 isp = XS_ISP(xs); 614 ISP_LOCK; 615 r = ispscsicmd(xs); 616 if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) { 617 ISP_UNLOCK; 618 return (r); 619 } 620 621 /* 622 * If we can't use interrupts, poll on completion. 623 */ 624 if (isp_poll(isp, xs, XS_TIME(xs))) { 625 /* 626 * If no other error occurred but we didn't finish, 627 * something bad happened. 628 */ 629 if (XS_IS_CMD_DONE(xs) == 0) { 630 isp->isp_nactive--; 631 if (isp->isp_nactive < 0) 632 isp->isp_nactive = 0; 633 if (XS_NOERR(xs)) { 634 isp_lostcmd(isp, xs); 635 XS_SETERR(xs, HBA_BOTCH); 636 } 637 } 638 } 639 ISP_UNLOCK; 640 return (CMD_COMPLETE); 641 } 642 643 static int 644 isp_poll(isp, xs, mswait) 645 struct ispsoftc *isp; 646 ISP_SCSI_XFER_T *xs; 647 int mswait; 648 { 649 650 while (mswait) { 651 /* Try the interrupt handling routine */ 652 (void)isp_intr((void *)isp); 653 654 /* See if the xs is now done */ 655 if (XS_IS_CMD_DONE(xs)) 656 return (0); 657 SYS_DELAY(1000); /* wait one millisecond */ 658 mswait--; 659 } 660 return (1); 661 } 662 #endif 663