1 /* $NetBSD: isp_netbsd.c,v 1.23 2000/02/12 02:25:28 mjacob Exp $ */ 2 /* 3 * Platform (NetBSD) dependent common attachment code for Qlogic adapters. 4 * Matthew Jacob <mjacob@nas.nasa.gov> 5 */ 6 /* 7 * Copyright (C) 1997, 1998, 1999 National Aeronautics & Space Administration 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <dev/ic/isp_netbsd.h> 34 #include <sys/scsiio.h> 35 36 static void ispminphys __P((struct buf *)); 37 static int32_t ispcmd_slow __P((ISP_SCSI_XFER_T *)); 38 static int32_t ispcmd __P((ISP_SCSI_XFER_T *)); 39 static int 40 ispioctl __P((struct scsipi_link *, u_long, caddr_t, int, struct proc *)); 41 42 static struct scsipi_device isp_dev = { NULL, NULL, NULL, NULL }; 43 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int)); 44 static void isp_watch __P((void *)); 45 static void isp_command_requeue __P((void *)); 46 static void isp_internal_restart __P((void *)); 47 48 /* 49 * Complete attachment of hardware, include subdevices. 50 */ 51 void 52 isp_attach(isp) 53 struct ispsoftc *isp; 54 { 55 56 isp->isp_osinfo._adapter.scsipi_minphys = ispminphys; 57 isp->isp_osinfo._adapter.scsipi_ioctl = ispioctl; 58 59 isp->isp_state = ISP_RUNSTATE; 60 isp->isp_osinfo._link.scsipi_scsi.channel = 61 (IS_DUALBUS(isp))? 0 : SCSI_CHANNEL_ONLY_ONE; 62 isp->isp_osinfo._link.adapter_softc = isp; 63 isp->isp_osinfo._link.device = &isp_dev; 64 isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter; 65 isp->isp_osinfo._link.openings = isp->isp_maxcmds; 66 TAILQ_INIT(&isp->isp_osinfo.waitq); /* XXX 2nd Bus? */ 67 68 if (IS_FC(isp)) { 69 /* 70 * Give it another chance here to come alive... 71 */ 72 isp->isp_osinfo._adapter.scsipi_cmd = ispcmd; 73 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1; 74 #ifdef ISP2100_SCCLUN 75 /* 76 * 16 bits worth, but let's be reasonable.. 77 */ 78 isp->isp_osinfo._link.scsipi_scsi.max_lun = 255; 79 #else 80 isp->isp_osinfo._link.scsipi_scsi.max_lun = 15; 81 #endif 82 /* set below */ 83 } else { 84 sdparam *sdp = isp->isp_param; 85 isp->isp_osinfo._adapter.scsipi_cmd = ispcmd_slow; 86 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1; 87 isp->isp_osinfo._link.scsipi_scsi.max_lun = 7; 88 isp->isp_osinfo._link.scsipi_scsi.adapter_target = 89 sdp->isp_initiator_id; 90 isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id; 91 if (IS_DUALBUS(isp)) { 92 isp->isp_osinfo._link_b = isp->isp_osinfo._link; 93 sdp++; 94 isp->isp_osinfo.discovered[1] = 95 1 << sdp->isp_initiator_id; 96 isp->isp_osinfo._link_b.scsipi_scsi.adapter_target = 97 sdp->isp_initiator_id; 98 isp->isp_osinfo._link_b.scsipi_scsi.channel = 1; 99 } 100 } 101 isp->isp_osinfo._link.type = BUS_SCSI; 102 103 /* 104 * Send a SCSI Bus Reset (used to be done as part of attach, 105 * but now left to the OS outer layers). 106 */ 107 if (IS_SCSI(isp)) { 108 int bus = 0; 109 (void) isp_control(isp, ISPCTL_RESET_BUS, &bus); 110 if (IS_DUALBUS(isp)) { 111 bus++; 112 (void) isp_control(isp, ISPCTL_RESET_BUS, &bus); 113 } 114 SYS_DELAY(2*1000000); 115 } else { 116 int i, j; 117 fcparam *fcp = isp->isp_param; 118 delay(2 * 1000000); 119 for (j = 0; j < 5; j++) { 120 for (i = 0; i < 5; i++) { 121 if (isp_control(isp, ISPCTL_FCLINK_TEST, NULL)) 122 continue; 123 #ifdef ISP2100_FABRIC 124 /* 125 * Wait extra time to see if the f/w 126 * eventually completed an FLOGI that 127 * will allow us to know we're on a 128 * fabric. 129 */ 130 if (fcp->isp_onfabric == 0) { 131 delay(1 * 1000000); 132 continue; 133 } 134 #endif 135 break; 136 } 137 if (fcp->isp_fwstate == FW_READY && 138 fcp->isp_loopstate >= LOOP_PDB_RCVD) { 139 break; 140 } 141 } 142 isp->isp_osinfo._link.scsipi_scsi.adapter_target = 143 fcp->isp_loopid; 144 } 145 146 /* 147 * Start the watchdog. 148 */ 149 isp->isp_dogactive = 1; 150 timeout(isp_watch, isp, WATCH_INTERVAL * hz); 151 152 /* 153 * And attach children (if any). 154 */ 155 config_found((void *)isp, &isp->isp_osinfo._link, scsiprint); 156 if (IS_DUALBUS(isp)) { 157 config_found((void *)isp, &isp->isp_osinfo._link_b, scsiprint); 158 } 159 } 160 161 /* 162 * minphys our xfers 163 * 164 * Unfortunately, the buffer pointer describes the target device- not the 165 * adapter device, so we can't use the pointer to find out what kind of 166 * adapter we are and adjust accordingly. 167 */ 168 169 static void 170 ispminphys(bp) 171 struct buf *bp; 172 { 173 /* 174 * XX: Only the 1020 has a 24 bit limit. 175 */ 176 if (bp->b_bcount >= (1 << 24)) { 177 bp->b_bcount = (1 << 24); 178 } 179 minphys(bp); 180 } 181 182 static int32_t 183 ispcmd_slow(xs) 184 ISP_SCSI_XFER_T *xs; 185 { 186 sdparam *sdp; 187 int tgt, chan, s; 188 u_int16_t flags; 189 struct ispsoftc *isp = XS_ISP(xs); 190 191 /* 192 * Have we completed discovery for this target on this adapter? 193 */ 194 tgt = XS_TGT(xs); 195 chan = XS_CHANNEL(xs); 196 if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 || 197 (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) { 198 return (ispcmd(xs)); 199 } 200 201 flags = DPARM_DEFAULT; 202 if (xs->sc_link->quirks & SDEV_NOSYNC) { 203 flags ^= DPARM_SYNC; 204 #ifdef DEBUG 205 } else { 206 printf("%s: channel %d target %d can do SYNC xfers\n", 207 isp->isp_name, chan, tgt); 208 #endif 209 } 210 if (xs->sc_link->quirks & SDEV_NOWIDE) { 211 flags ^= DPARM_WIDE; 212 #ifdef DEBUG 213 } else { 214 printf("%s: channel %d target %d can do WIDE xfers\n", 215 isp->isp_name, chan, tgt); 216 #endif 217 } 218 if (xs->sc_link->quirks & SDEV_NOTAG) { 219 flags ^= DPARM_TQING; 220 #ifdef DEBUG 221 } else { 222 printf("%s: channel %d target %d can do TAGGED xfers\n", 223 isp->isp_name, chan, tgt); 224 #endif 225 } 226 /* 227 * Okay, we know about this device now, 228 * so mark parameters to be updated for it. 229 */ 230 s = splbio(); 231 isp->isp_osinfo.discovered[chan] |= (1 << tgt); 232 sdp = isp->isp_param; 233 sdp += chan; 234 sdp->isp_devparam[tgt].dev_flags = flags; 235 sdp->isp_devparam[tgt].dev_update = 1; 236 isp->isp_update |= (1 << chan); 237 splx(s); 238 return (ispcmd(xs)); 239 } 240 241 static int 242 ispioctl(sc_link, cmd, addr, flag, p) 243 struct scsipi_link *sc_link; 244 u_long cmd; 245 caddr_t addr; 246 int flag; 247 struct proc *p; 248 { 249 struct ispsoftc *isp = sc_link->adapter_softc; 250 int s, chan, retval = ENOTTY; 251 252 switch (cmd) { 253 case SCBUSIORESET: 254 chan = sc_link->scsipi_scsi.channel; 255 s = splbio(); 256 if (isp_control(isp, ISPCTL_RESET_BUS, &chan)) 257 retval = EIO; 258 else 259 retval = 0; 260 (void) splx(s); 261 break; 262 default: 263 break; 264 } 265 return (retval); 266 } 267 268 269 static int32_t 270 ispcmd(xs) 271 ISP_SCSI_XFER_T *xs; 272 { 273 struct ispsoftc *isp; 274 int result, s; 275 276 isp = XS_ISP(xs); 277 s = splbio(); 278 if (isp->isp_state < ISP_RUNSTATE) { 279 DISABLE_INTS(isp); 280 isp_init(isp); 281 if (isp->isp_state != ISP_INITSTATE) { 282 ENABLE_INTS(isp); 283 (void) splx(s); 284 XS_SETERR(xs, HBA_BOTCH); 285 return (COMPLETE); 286 } 287 isp->isp_state = ISP_RUNSTATE; 288 ENABLE_INTS(isp); 289 } 290 291 /* 292 * Check for queue blockage... 293 */ 294 if (isp->isp_osinfo.blocked) { 295 if (xs->xs_control & XS_CTL_POLL) { 296 xs->error = XS_DRIVER_STUFFUP; 297 splx(s); 298 return (TRY_AGAIN_LATER); 299 } 300 TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs, adapter_q); 301 splx(s); 302 return (SUCCESSFULLY_QUEUED); 303 } 304 DISABLE_INTS(isp); 305 result = ispscsicmd(xs); 306 ENABLE_INTS(isp); 307 308 if ((xs->xs_control & XS_CTL_POLL) == 0) { 309 switch (result) { 310 case CMD_QUEUED: 311 result = SUCCESSFULLY_QUEUED; 312 break; 313 case CMD_EAGAIN: 314 result = TRY_AGAIN_LATER; 315 break; 316 case CMD_RQLATER: 317 result = SUCCESSFULLY_QUEUED; 318 timeout(isp_command_requeue, xs, hz); 319 break; 320 case CMD_COMPLETE: 321 result = COMPLETE; 322 break; 323 } 324 (void) splx(s); 325 return (result); 326 } 327 328 switch (result) { 329 case CMD_QUEUED: 330 result = SUCCESSFULLY_QUEUED; 331 break; 332 case CMD_RQLATER: 333 case CMD_EAGAIN: 334 if (XS_NOERR(xs)) { 335 xs->error = XS_DRIVER_STUFFUP; 336 } 337 result = TRY_AGAIN_LATER; 338 break; 339 case CMD_COMPLETE: 340 result = COMPLETE; 341 break; 342 343 } 344 /* 345 * If we can't use interrupts, poll on completion. 346 */ 347 if (result == SUCCESSFULLY_QUEUED) { 348 if (isp_poll(isp, xs, XS_TIME(xs))) { 349 /* 350 * If no other error occurred but we didn't finish, 351 * something bad happened. 352 */ 353 if (XS_IS_CMD_DONE(xs) == 0) { 354 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 355 isp_restart(isp); 356 } 357 if (XS_NOERR(xs)) { 358 XS_SETERR(xs, HBA_BOTCH); 359 } 360 } 361 } 362 result = COMPLETE; 363 } 364 (void) splx(s); 365 return (result); 366 } 367 368 static int 369 isp_poll(isp, xs, mswait) 370 struct ispsoftc *isp; 371 ISP_SCSI_XFER_T *xs; 372 int mswait; 373 { 374 375 while (mswait) { 376 /* Try the interrupt handling routine */ 377 (void)isp_intr((void *)isp); 378 379 /* See if the xs is now done */ 380 if (XS_IS_CMD_DONE(xs)) { 381 return (0); 382 } 383 SYS_DELAY(1000); /* wait one millisecond */ 384 mswait--; 385 } 386 return (1); 387 } 388 389 static void 390 isp_watch(arg) 391 void *arg; 392 { 393 int i; 394 struct ispsoftc *isp = arg; 395 struct scsipi_xfer *xs; 396 int s; 397 398 /* 399 * Look for completely dead commands (but not polled ones). 400 */ 401 s = splbio(); 402 for (i = 0; i < isp->isp_maxcmds; i++) { 403 xs = isp->isp_xflist[i]; 404 if (xs == NULL) { 405 continue; 406 } 407 if (xs->timeout == 0 || (xs->xs_control & XS_CTL_POLL)) { 408 continue; 409 } 410 xs->timeout -= (WATCH_INTERVAL * 1000); 411 /* 412 * Avoid later thinking that this 413 * transaction is not being timed. 414 * Then give ourselves to watchdog 415 * periods of grace. 416 */ 417 if (xs->timeout == 0) { 418 xs->timeout = 1; 419 } else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) { 420 continue; 421 } 422 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 423 printf("%s: isp_watch failed to abort command\n", 424 isp->isp_name); 425 isp_restart(isp); 426 break; 427 } 428 } 429 timeout(isp_watch, isp, WATCH_INTERVAL * hz); 430 isp->isp_dogactive = 1; 431 (void) splx(s); 432 } 433 434 /* 435 * Free any associated resources prior to decommissioning and 436 * set the card to a known state (so it doesn't wake up and kick 437 * us when we aren't expecting it to). 438 * 439 * Locks are held before coming here. 440 */ 441 void 442 isp_uninit(isp) 443 struct ispsoftc *isp; 444 { 445 ISP_ILOCKVAL_DECL; 446 ISP_ILOCK(isp); 447 /* 448 * Leave with interrupts disabled. 449 */ 450 DISABLE_INTS(isp); 451 452 /* 453 * Turn off the watchdog (if active). 454 */ 455 if (isp->isp_dogactive) { 456 untimeout(isp_watch, isp); 457 isp->isp_dogactive = 0; 458 } 459 460 ISP_IUNLOCK(isp); 461 } 462 463 /* 464 * Restart function for a command to be requeued later. 465 */ 466 static void 467 isp_command_requeue(arg) 468 void *arg; 469 { 470 struct scsipi_xfer *xs = arg; 471 struct ispsoftc *isp = XS_ISP(xs); 472 int s = splbio(); 473 switch (ispcmd_slow(xs)) { 474 case SUCCESSFULLY_QUEUED: 475 printf("%s: isp_command_requeue: requeued for %d.%d\n", 476 isp->isp_name, XS_TGT(xs), XS_LUN(xs)); 477 break; 478 case TRY_AGAIN_LATER: 479 printf("%s: EAGAIN for %d.%d\n", 480 isp->isp_name, XS_TGT(xs), XS_LUN(xs)); 481 /* FALLTHROUGH */ 482 case COMPLETE: 483 /* can only be an error */ 484 xs->xs_status |= XS_STS_DONE; 485 if (XS_NOERR(xs)) { 486 XS_SETERR(xs, HBA_BOTCH); 487 } 488 scsipi_done(xs); 489 break; 490 } 491 (void) splx(s); 492 } 493 494 /* 495 * Restart function after a LOOP UP event (e.g.), 496 * done as a timeout for some hysteresis. 497 */ 498 static void 499 isp_internal_restart(arg) 500 void *arg; 501 { 502 struct ispsoftc *isp = arg; 503 int result, nrestarted = 0, s; 504 505 s = splbio(); 506 if (isp->isp_osinfo.blocked == 0) { 507 struct scsipi_xfer *xs; 508 while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) { 509 TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, adapter_q); 510 DISABLE_INTS(isp); 511 result = ispscsicmd(xs); 512 ENABLE_INTS(isp); 513 if (result != CMD_QUEUED) { 514 printf("%s: botched command restart (0x%x)\n", 515 isp->isp_name, result); 516 xs->xs_status |= XS_STS_DONE; 517 if (xs->error == XS_NOERROR) 518 xs->error = XS_DRIVER_STUFFUP; 519 scsipi_done(xs); 520 } 521 nrestarted++; 522 } 523 printf("%s: requeued %d commands\n", isp->isp_name, nrestarted); 524 } 525 (void) splx(s); 526 } 527 528 int 529 isp_async(isp, cmd, arg) 530 struct ispsoftc *isp; 531 ispasync_t cmd; 532 void *arg; 533 { 534 int bus, tgt; 535 int s = splbio(); 536 switch (cmd) { 537 case ISPASYNC_NEW_TGT_PARAMS: 538 if (IS_SCSI(isp) && isp->isp_dblev) { 539 sdparam *sdp = isp->isp_param; 540 char *wt; 541 int mhz, flags, period; 542 543 tgt = *((int *) arg); 544 bus = (tgt >> 16) & 0xffff; 545 tgt &= 0xffff; 546 sdp += bus; 547 flags = sdp->isp_devparam[tgt].cur_dflags; 548 period = sdp->isp_devparam[tgt].cur_period; 549 550 if ((flags & DPARM_SYNC) && period && 551 (sdp->isp_devparam[tgt].cur_offset) != 0) { 552 #if 0 553 /* CAUSES PANICS */ 554 static char *m = "%s: bus %d now %s mode\n"; 555 u_int16_t r, l; 556 if (bus == 1) 557 r = SXP_PINS_DIFF | SXP_BANK1_SELECT; 558 else 559 r = SXP_PINS_DIFF; 560 l = ISP_READ(isp, r) & ISP1080_MODE_MASK; 561 switch (l) { 562 case ISP1080_LVD_MODE: 563 sdp->isp_lvdmode = 1; 564 printf(m, isp->isp_name, bus, "LVD"); 565 break; 566 case ISP1080_HVD_MODE: 567 sdp->isp_diffmode = 1; 568 printf(m, isp->isp_name, bus, "Differential"); 569 break; 570 case ISP1080_SE_MODE: 571 sdp->isp_ultramode = 1; 572 printf(m, isp->isp_name, bus, "Single-Ended"); 573 break; 574 default: 575 printf("%s: unknown mode on bus %d (0x%x)\n", 576 isp->isp_name, bus, l); 577 break; 578 } 579 #endif 580 /* 581 * There's some ambiguity about our negotiated speed 582 * if we haven't detected LVD mode correctly (which 583 * seems to happen, unfortunately). If we're in LVD 584 * mode, then different rules apply about speed. 585 */ 586 if (sdp->isp_lvdmode || period < 0xc) { 587 switch (period) { 588 case 0x9: 589 mhz = 80; 590 break; 591 case 0xa: 592 mhz = 40; 593 break; 594 case 0xb: 595 mhz = 33; 596 break; 597 case 0xc: 598 mhz = 25; 599 break; 600 default: 601 mhz = 1000 / (period * 4); 602 break; 603 } 604 } else { 605 mhz = 1000 / (period * 4); 606 } 607 } else { 608 mhz = 0; 609 } 610 switch (flags & (DPARM_WIDE|DPARM_TQING)) { 611 case DPARM_WIDE: 612 wt = ", 16 bit wide\n"; 613 break; 614 case DPARM_TQING: 615 wt = ", Tagged Queueing Enabled\n"; 616 break; 617 case DPARM_WIDE|DPARM_TQING: 618 wt = ", 16 bit wide, Tagged Queueing Enabled\n"; 619 break; 620 default: 621 wt = "\n"; 622 break; 623 } 624 if (mhz) { 625 CFGPRINTF("%s: Bus %d Target %d at %dMHz Max " 626 "Offset %d%s", isp->isp_name, bus, tgt, mhz, 627 sdp->isp_devparam[tgt].cur_offset, wt); 628 } else { 629 CFGPRINTF("%s: Bus %d Target %d Async Mode%s", 630 isp->isp_name, bus, tgt, wt); 631 } 632 break; 633 } 634 case ISPASYNC_BUS_RESET: 635 if (arg) 636 bus = *((int *) arg); 637 else 638 bus = 0; 639 printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus); 640 break; 641 case ISPASYNC_LOOP_DOWN: 642 /* 643 * Hopefully we get here in time to minimize the number 644 * of commands we are firing off that are sure to die. 645 */ 646 isp->isp_osinfo.blocked = 1; 647 printf("%s: Loop DOWN\n", isp->isp_name); 648 break; 649 case ISPASYNC_LOOP_UP: 650 isp->isp_osinfo.blocked = 0; 651 timeout(isp_internal_restart, isp, 1); 652 printf("%s: Loop UP\n", isp->isp_name); 653 break; 654 case ISPASYNC_PDB_CHANGED: 655 if (IS_FC(isp) && isp->isp_dblev) { 656 const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x " 657 "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n"; 658 const static char *roles[4] = { 659 "No", "Target", "Initiator", "Target/Initiator" 660 }; 661 char *ptr; 662 fcparam *fcp = isp->isp_param; 663 int tgt = *((int *) arg); 664 struct lportdb *lp = &fcp->portdb[tgt]; 665 666 if (lp->valid) { 667 ptr = "arrived"; 668 } else { 669 ptr = "disappeared"; 670 } 671 printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid, 672 roles[lp->roles & 0x3], ptr, 673 (u_int32_t) (lp->port_wwn >> 32), 674 (u_int32_t) (lp->port_wwn & 0xffffffffLL), 675 (u_int32_t) (lp->node_wwn >> 32), 676 (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 677 break; 678 } 679 #ifdef ISP2100_FABRIC 680 case ISPASYNC_CHANGE_NOTIFY: 681 printf("%s: Name Server Database Changed\n", isp->isp_name); 682 break; 683 case ISPASYNC_FABRIC_DEV: 684 { 685 int target; 686 struct lportdb *lp; 687 sns_scrsp_t *resp = (sns_scrsp_t *) arg; 688 u_int32_t portid; 689 u_int64_t wwn; 690 fcparam *fcp = isp->isp_param; 691 692 portid = 693 (((u_int32_t) resp->snscb_port_id[0]) << 16) | 694 (((u_int32_t) resp->snscb_port_id[1]) << 8) | 695 (((u_int32_t) resp->snscb_port_id[2])); 696 wwn = 697 (((u_int64_t)resp->snscb_portname[0]) << 56) | 698 (((u_int64_t)resp->snscb_portname[1]) << 48) | 699 (((u_int64_t)resp->snscb_portname[2]) << 40) | 700 (((u_int64_t)resp->snscb_portname[3]) << 32) | 701 (((u_int64_t)resp->snscb_portname[4]) << 24) | 702 (((u_int64_t)resp->snscb_portname[5]) << 16) | 703 (((u_int64_t)resp->snscb_portname[6]) << 8) | 704 (((u_int64_t)resp->snscb_portname[7])); 705 printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN " 706 "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type, 707 portid, ((u_int32_t)(wwn >> 32)), 708 ((u_int32_t)(wwn & 0xffffffff))); 709 if (resp->snscb_port_type != 2) 710 break; 711 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 712 lp = &fcp->portdb[target]; 713 if (lp->port_wwn == wwn) 714 break; 715 } 716 if (target < MAX_FC_TARG) { 717 break; 718 } 719 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 720 lp = &fcp->portdb[target]; 721 if (lp->port_wwn == 0) 722 break; 723 } 724 if (target == MAX_FC_TARG) { 725 printf("%s: no more space for fabric devices\n", 726 isp->isp_name); 727 return (-1); 728 } 729 lp->port_wwn = lp->node_wwn = wwn; 730 lp->portid = portid; 731 break; 732 } 733 #endif 734 default: 735 break; 736 } 737 (void) splx(s); 738 return (0); 739 } 740