1 /* $NetBSD: isp_netbsd.c,v 1.25 2000/05/13 16:53:03 he 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. 105 */ 106 if (IS_SCSI(isp)) { 107 int bus = 0; 108 (void) isp_control(isp, ISPCTL_RESET_BUS, &bus); 109 if (IS_DUALBUS(isp)) { 110 bus++; 111 (void) isp_control(isp, ISPCTL_RESET_BUS, &bus); 112 } 113 SYS_DELAY(2*1000000); 114 } else { 115 int i, j; 116 fcparam *fcp = isp->isp_param; 117 delay(2 * 1000000); 118 for (j = 0; j < 5; j++) { 119 for (i = 0; i < 5; i++) { 120 if (isp_control(isp, ISPCTL_FCLINK_TEST, NULL)) 121 continue; 122 #ifdef ISP2100_FABRIC 123 /* 124 * Wait extra time to see if the f/w 125 * eventually completed an FLOGI that 126 * will allow us to know we're on a 127 * fabric. 128 */ 129 if (fcp->isp_onfabric == 0) { 130 delay(1 * 1000000); 131 continue; 132 } 133 #endif 134 break; 135 } 136 if (fcp->isp_fwstate == FW_READY && 137 fcp->isp_loopstate >= LOOP_PDB_RCVD) { 138 break; 139 } 140 } 141 isp->isp_osinfo._link.scsipi_scsi.adapter_target = 142 fcp->isp_loopid; 143 } 144 145 /* 146 * Start the watchdog. 147 */ 148 callout_init(&isp->isp_osinfo._watchdog); 149 isp->isp_dogactive = 1; 150 callout_reset(&isp->isp_osinfo._watchdog, WATCH_INTERVAL * hz, 151 isp_watch, isp); 152 153 /* 154 * And attach children (if any). 155 */ 156 config_found((void *)isp, &isp->isp_osinfo._link, scsiprint); 157 if (IS_DUALBUS(isp)) { 158 config_found((void *)isp, &isp->isp_osinfo._link_b, scsiprint); 159 } 160 } 161 162 /* 163 * minphys our xfers 164 * 165 * Unfortunately, the buffer pointer describes the target device- not the 166 * adapter device, so we can't use the pointer to find out what kind of 167 * adapter we are and adjust accordingly. 168 */ 169 170 static void 171 ispminphys(bp) 172 struct buf *bp; 173 { 174 /* 175 * XX: Only the 1020 has a 24 bit limit. 176 */ 177 if (bp->b_bcount >= (1 << 24)) { 178 bp->b_bcount = (1 << 24); 179 } 180 minphys(bp); 181 } 182 183 static int32_t 184 ispcmd_slow(xs) 185 ISP_SCSI_XFER_T *xs; 186 { 187 sdparam *sdp; 188 int tgt, chan, s; 189 u_int16_t flags; 190 struct ispsoftc *isp = XS_ISP(xs); 191 192 /* 193 * Have we completed discovery for this target on this adapter? 194 */ 195 tgt = XS_TGT(xs); 196 chan = XS_CHANNEL(xs); 197 if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 || 198 (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) { 199 return (ispcmd(xs)); 200 } 201 202 flags = DPARM_DEFAULT; 203 if (xs->sc_link->quirks & SDEV_NOSYNC) { 204 flags ^= DPARM_SYNC; 205 #ifdef DEBUG 206 } else { 207 printf("%s: channel %d target %d can do SYNC xfers\n", 208 isp->isp_name, chan, tgt); 209 #endif 210 } 211 if (xs->sc_link->quirks & SDEV_NOWIDE) { 212 flags ^= DPARM_WIDE; 213 #ifdef DEBUG 214 } else { 215 printf("%s: channel %d target %d can do WIDE xfers\n", 216 isp->isp_name, chan, tgt); 217 #endif 218 } 219 if (xs->sc_link->quirks & SDEV_NOTAG) { 220 flags ^= DPARM_TQING; 221 #ifdef DEBUG 222 } else { 223 printf("%s: channel %d target %d can do TAGGED xfers\n", 224 isp->isp_name, chan, tgt); 225 #endif 226 } 227 /* 228 * Okay, we know about this device now, 229 * so mark parameters to be updated for it. 230 */ 231 s = splbio(); 232 isp->isp_osinfo.discovered[chan] |= (1 << tgt); 233 sdp = isp->isp_param; 234 sdp += chan; 235 sdp->isp_devparam[tgt].dev_flags = flags; 236 sdp->isp_devparam[tgt].dev_update = 1; 237 isp->isp_update |= (1 << chan); 238 splx(s); 239 return (ispcmd(xs)); 240 } 241 242 static int 243 ispioctl(sc_link, cmd, addr, flag, p) 244 struct scsipi_link *sc_link; 245 u_long cmd; 246 caddr_t addr; 247 int flag; 248 struct proc *p; 249 { 250 struct ispsoftc *isp = sc_link->adapter_softc; 251 int s, chan, retval = ENOTTY; 252 253 switch (cmd) { 254 case SCBUSIORESET: 255 chan = sc_link->scsipi_scsi.channel; 256 s = splbio(); 257 if (isp_control(isp, ISPCTL_RESET_BUS, &chan)) 258 retval = EIO; 259 else 260 retval = 0; 261 (void) splx(s); 262 break; 263 default: 264 break; 265 } 266 return (retval); 267 } 268 269 270 static int32_t 271 ispcmd(xs) 272 ISP_SCSI_XFER_T *xs; 273 { 274 struct ispsoftc *isp; 275 int result, s; 276 277 isp = XS_ISP(xs); 278 s = splbio(); 279 if (isp->isp_state < ISP_RUNSTATE) { 280 DISABLE_INTS(isp); 281 isp_init(isp); 282 if (isp->isp_state != ISP_INITSTATE) { 283 ENABLE_INTS(isp); 284 (void) splx(s); 285 XS_SETERR(xs, HBA_BOTCH); 286 return (COMPLETE); 287 } 288 isp->isp_state = ISP_RUNSTATE; 289 ENABLE_INTS(isp); 290 } 291 292 /* 293 * Check for queue blockage... 294 */ 295 if (isp->isp_osinfo.blocked) { 296 if (xs->xs_control & XS_CTL_POLL) { 297 xs->error = XS_DRIVER_STUFFUP; 298 splx(s); 299 return (TRY_AGAIN_LATER); 300 } 301 TAILQ_INSERT_TAIL(&isp->isp_osinfo.waitq, xs, adapter_q); 302 splx(s); 303 return (SUCCESSFULLY_QUEUED); 304 } 305 DISABLE_INTS(isp); 306 result = ispscsicmd(xs); 307 ENABLE_INTS(isp); 308 309 if ((xs->xs_control & XS_CTL_POLL) == 0) { 310 switch (result) { 311 case CMD_QUEUED: 312 result = SUCCESSFULLY_QUEUED; 313 break; 314 case CMD_EAGAIN: 315 result = TRY_AGAIN_LATER; 316 break; 317 case CMD_RQLATER: 318 result = SUCCESSFULLY_QUEUED; 319 callout_reset(&xs->xs_callout, hz, 320 isp_command_requeue, xs); 321 break; 322 case CMD_COMPLETE: 323 result = COMPLETE; 324 break; 325 } 326 (void) splx(s); 327 return (result); 328 } 329 330 switch (result) { 331 case CMD_QUEUED: 332 result = SUCCESSFULLY_QUEUED; 333 break; 334 case CMD_RQLATER: 335 case CMD_EAGAIN: 336 if (XS_NOERR(xs)) { 337 xs->error = XS_DRIVER_STUFFUP; 338 } 339 result = TRY_AGAIN_LATER; 340 break; 341 case CMD_COMPLETE: 342 result = COMPLETE; 343 break; 344 345 } 346 /* 347 * If we can't use interrupts, poll on completion. 348 */ 349 if (result == SUCCESSFULLY_QUEUED) { 350 if (isp_poll(isp, xs, XS_TIME(xs))) { 351 /* 352 * If no other error occurred but we didn't finish, 353 * something bad happened. 354 */ 355 if (XS_IS_CMD_DONE(xs) == 0) { 356 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 357 isp_restart(isp); 358 } 359 if (XS_NOERR(xs)) { 360 XS_SETERR(xs, HBA_BOTCH); 361 } 362 } 363 } 364 result = COMPLETE; 365 } 366 (void) splx(s); 367 return (result); 368 } 369 370 static int 371 isp_poll(isp, xs, mswait) 372 struct ispsoftc *isp; 373 ISP_SCSI_XFER_T *xs; 374 int mswait; 375 { 376 377 while (mswait) { 378 /* Try the interrupt handling routine */ 379 (void)isp_intr((void *)isp); 380 381 /* See if the xs is now done */ 382 if (XS_IS_CMD_DONE(xs)) { 383 return (0); 384 } 385 SYS_DELAY(1000); /* wait one millisecond */ 386 mswait--; 387 } 388 return (1); 389 } 390 391 static void 392 isp_watch(arg) 393 void *arg; 394 { 395 int i; 396 struct ispsoftc *isp = arg; 397 struct scsipi_xfer *xs; 398 int s; 399 400 /* 401 * Look for completely dead commands (but not polled ones). 402 */ 403 s = splbio(); 404 for (i = 0; i < isp->isp_maxcmds; i++) { 405 xs = isp->isp_xflist[i]; 406 if (xs == NULL) { 407 continue; 408 } 409 if (xs->timeout == 0 || (xs->xs_control & XS_CTL_POLL)) { 410 continue; 411 } 412 xs->timeout -= (WATCH_INTERVAL * 1000); 413 /* 414 * Avoid later thinking that this 415 * transaction is not being timed. 416 * Then give ourselves to watchdog 417 * periods of grace. 418 */ 419 if (xs->timeout == 0) { 420 xs->timeout = 1; 421 } else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) { 422 continue; 423 } 424 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 425 printf("%s: isp_watch failed to abort command\n", 426 isp->isp_name); 427 isp_restart(isp); 428 break; 429 } 430 } 431 callout_reset(&isp->isp_osinfo._watchdog, WATCH_INTERVAL * hz, 432 isp_watch, isp); 433 isp->isp_dogactive = 1; 434 (void) splx(s); 435 } 436 437 /* 438 * Free any associated resources prior to decommissioning and 439 * set the card to a known state (so it doesn't wake up and kick 440 * us when we aren't expecting it to). 441 * 442 * Locks are held before coming here. 443 */ 444 void 445 isp_uninit(isp) 446 struct ispsoftc *isp; 447 { 448 ISP_ILOCKVAL_DECL; 449 ISP_ILOCK(isp); 450 /* 451 * Leave with interrupts disabled. 452 */ 453 DISABLE_INTS(isp); 454 455 /* 456 * Turn off the watchdog (if active). 457 */ 458 if (isp->isp_dogactive) { 459 callout_stop(&isp->isp_osinfo._watchdog); 460 isp->isp_dogactive = 0; 461 } 462 463 ISP_IUNLOCK(isp); 464 } 465 466 /* 467 * Restart function for a command to be requeued later. 468 */ 469 static void 470 isp_command_requeue(arg) 471 void *arg; 472 { 473 struct scsipi_xfer *xs = arg; 474 struct ispsoftc *isp = XS_ISP(xs); 475 int s = splbio(); 476 switch (ispcmd_slow(xs)) { 477 case SUCCESSFULLY_QUEUED: 478 printf("%s: isp_command_requeue: requeued for %d.%d\n", 479 isp->isp_name, XS_TGT(xs), XS_LUN(xs)); 480 break; 481 case TRY_AGAIN_LATER: 482 printf("%s: EAGAIN for %d.%d\n", 483 isp->isp_name, XS_TGT(xs), XS_LUN(xs)); 484 /* FALLTHROUGH */ 485 case COMPLETE: 486 /* can only be an error */ 487 xs->xs_status |= XS_STS_DONE; 488 if (XS_NOERR(xs)) { 489 XS_SETERR(xs, HBA_BOTCH); 490 } 491 scsipi_done(xs); 492 break; 493 } 494 (void) splx(s); 495 } 496 497 /* 498 * Restart function after a LOOP UP event (e.g.), 499 * done as a timeout for some hysteresis. 500 */ 501 static void 502 isp_internal_restart(arg) 503 void *arg; 504 { 505 struct ispsoftc *isp = arg; 506 int result, nrestarted = 0, s; 507 508 s = splbio(); 509 if (isp->isp_osinfo.blocked == 0) { 510 struct scsipi_xfer *xs; 511 while ((xs = TAILQ_FIRST(&isp->isp_osinfo.waitq)) != NULL) { 512 TAILQ_REMOVE(&isp->isp_osinfo.waitq, xs, adapter_q); 513 DISABLE_INTS(isp); 514 result = ispscsicmd(xs); 515 ENABLE_INTS(isp); 516 if (result != CMD_QUEUED) { 517 printf("%s: botched command restart (0x%x)\n", 518 isp->isp_name, result); 519 xs->xs_status |= XS_STS_DONE; 520 if (xs->error == XS_NOERROR) 521 xs->error = XS_DRIVER_STUFFUP; 522 scsipi_done(xs); 523 } 524 nrestarted++; 525 } 526 printf("%s: requeued %d commands\n", isp->isp_name, nrestarted); 527 } 528 (void) splx(s); 529 } 530 531 int 532 isp_async(isp, cmd, arg) 533 struct ispsoftc *isp; 534 ispasync_t cmd; 535 void *arg; 536 { 537 int bus, tgt; 538 int s = splbio(); 539 switch (cmd) { 540 case ISPASYNC_NEW_TGT_PARAMS: 541 if (IS_SCSI(isp) && isp->isp_dblev) { 542 sdparam *sdp = isp->isp_param; 543 char *wt; 544 int mhz, flags, period; 545 546 tgt = *((int *) arg); 547 bus = (tgt >> 16) & 0xffff; 548 tgt &= 0xffff; 549 sdp += bus; 550 flags = sdp->isp_devparam[tgt].cur_dflags; 551 period = sdp->isp_devparam[tgt].cur_period; 552 553 if ((flags & DPARM_SYNC) && period && 554 (sdp->isp_devparam[tgt].cur_offset) != 0) { 555 #if 0 556 /* CAUSES PANICS */ 557 static char *m = "%s: bus %d now %s mode\n"; 558 u_int16_t r, l; 559 if (bus == 1) 560 r = SXP_PINS_DIFF | SXP_BANK1_SELECT; 561 else 562 r = SXP_PINS_DIFF; 563 l = ISP_READ(isp, r) & ISP1080_MODE_MASK; 564 switch (l) { 565 case ISP1080_LVD_MODE: 566 sdp->isp_lvdmode = 1; 567 printf(m, isp->isp_name, bus, "LVD"); 568 break; 569 case ISP1080_HVD_MODE: 570 sdp->isp_diffmode = 1; 571 printf(m, isp->isp_name, bus, "Differential"); 572 break; 573 case ISP1080_SE_MODE: 574 sdp->isp_ultramode = 1; 575 printf(m, isp->isp_name, bus, "Single-Ended"); 576 break; 577 default: 578 printf("%s: unknown mode on bus %d (0x%x)\n", 579 isp->isp_name, bus, l); 580 break; 581 } 582 #endif 583 /* 584 * There's some ambiguity about our negotiated speed 585 * if we haven't detected LVD mode correctly (which 586 * seems to happen, unfortunately). If we're in LVD 587 * mode, then different rules apply about speed. 588 */ 589 if (sdp->isp_lvdmode || period < 0xc) { 590 switch (period) { 591 case 0x9: 592 mhz = 80; 593 break; 594 case 0xa: 595 mhz = 40; 596 break; 597 case 0xb: 598 mhz = 33; 599 break; 600 case 0xc: 601 mhz = 25; 602 break; 603 default: 604 mhz = 1000 / (period * 4); 605 break; 606 } 607 } else { 608 mhz = 1000 / (period * 4); 609 } 610 } else { 611 mhz = 0; 612 } 613 switch (flags & (DPARM_WIDE|DPARM_TQING)) { 614 case DPARM_WIDE: 615 wt = ", 16 bit wide\n"; 616 break; 617 case DPARM_TQING: 618 wt = ", Tagged Queueing Enabled\n"; 619 break; 620 case DPARM_WIDE|DPARM_TQING: 621 wt = ", 16 bit wide, Tagged Queueing Enabled\n"; 622 break; 623 default: 624 wt = "\n"; 625 break; 626 } 627 if (mhz) { 628 CFGPRINTF("%s: Bus %d Target %d at %dMHz Max " 629 "Offset %d%s", isp->isp_name, bus, tgt, mhz, 630 sdp->isp_devparam[tgt].cur_offset, wt); 631 } else { 632 CFGPRINTF("%s: Bus %d Target %d Async Mode%s", 633 isp->isp_name, bus, tgt, wt); 634 } 635 break; 636 } 637 case ISPASYNC_BUS_RESET: 638 if (arg) 639 bus = *((int *) arg); 640 else 641 bus = 0; 642 printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus); 643 break; 644 case ISPASYNC_LOOP_DOWN: 645 /* 646 * Hopefully we get here in time to minimize the number 647 * of commands we are firing off that are sure to die. 648 */ 649 isp->isp_osinfo.blocked = 1; 650 printf("%s: Loop DOWN\n", isp->isp_name); 651 break; 652 case ISPASYNC_LOOP_UP: 653 isp->isp_osinfo.blocked = 0; 654 callout_reset(&isp->isp_osinfo._restart, 1, 655 isp_internal_restart, isp); 656 printf("%s: Loop UP\n", isp->isp_name); 657 break; 658 case ISPASYNC_PDB_CHANGED: 659 if (IS_FC(isp) && isp->isp_dblev) { 660 const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x " 661 "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n"; 662 const static char *roles[4] = { 663 "No", "Target", "Initiator", "Target/Initiator" 664 }; 665 char *ptr; 666 fcparam *fcp = isp->isp_param; 667 int tgt = *((int *) arg); 668 struct lportdb *lp = &fcp->portdb[tgt]; 669 670 if (lp->valid) { 671 ptr = "arrived"; 672 } else { 673 ptr = "disappeared"; 674 } 675 printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid, 676 roles[lp->roles & 0x3], ptr, 677 (u_int32_t) (lp->port_wwn >> 32), 678 (u_int32_t) (lp->port_wwn & 0xffffffffLL), 679 (u_int32_t) (lp->node_wwn >> 32), 680 (u_int32_t) (lp->node_wwn & 0xffffffffLL)); 681 break; 682 } 683 #ifdef ISP2100_FABRIC 684 case ISPASYNC_CHANGE_NOTIFY: 685 printf("%s: Name Server Database Changed\n", isp->isp_name); 686 break; 687 case ISPASYNC_FABRIC_DEV: 688 { 689 int target; 690 struct lportdb *lp; 691 sns_scrsp_t *resp = (sns_scrsp_t *) arg; 692 u_int32_t portid; 693 u_int64_t wwn; 694 fcparam *fcp = isp->isp_param; 695 696 portid = 697 (((u_int32_t) resp->snscb_port_id[0]) << 16) | 698 (((u_int32_t) resp->snscb_port_id[1]) << 8) | 699 (((u_int32_t) resp->snscb_port_id[2])); 700 wwn = 701 (((u_int64_t)resp->snscb_portname[0]) << 56) | 702 (((u_int64_t)resp->snscb_portname[1]) << 48) | 703 (((u_int64_t)resp->snscb_portname[2]) << 40) | 704 (((u_int64_t)resp->snscb_portname[3]) << 32) | 705 (((u_int64_t)resp->snscb_portname[4]) << 24) | 706 (((u_int64_t)resp->snscb_portname[5]) << 16) | 707 (((u_int64_t)resp->snscb_portname[6]) << 8) | 708 (((u_int64_t)resp->snscb_portname[7])); 709 printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN " 710 "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type, 711 portid, ((u_int32_t)(wwn >> 32)), 712 ((u_int32_t)(wwn & 0xffffffff))); 713 if (resp->snscb_port_type != 2) 714 break; 715 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 716 lp = &fcp->portdb[target]; 717 if (lp->port_wwn == wwn) 718 break; 719 } 720 if (target < MAX_FC_TARG) { 721 break; 722 } 723 for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) { 724 lp = &fcp->portdb[target]; 725 if (lp->port_wwn == 0) 726 break; 727 } 728 if (target == MAX_FC_TARG) { 729 printf("%s: no more space for fabric devices\n", 730 isp->isp_name); 731 return (-1); 732 } 733 lp->port_wwn = lp->node_wwn = wwn; 734 lp->portid = portid; 735 break; 736 } 737 #endif 738 default: 739 break; 740 } 741 (void) splx(s); 742 return (0); 743 } 744