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