1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 * 24 * NOT a DDI compliant Sun Fibre Channel port driver(fp) 25 * 26 */ 27 28 #include <sys/types.h> 29 #include <sys/varargs.h> 30 #include <sys/param.h> 31 #include <sys/errno.h> 32 #include <sys/uio.h> 33 #include <sys/buf.h> 34 #include <sys/modctl.h> 35 #include <sys/open.h> 36 #include <sys/file.h> 37 #include <sys/kmem.h> 38 #include <sys/poll.h> 39 #include <sys/conf.h> 40 #include <sys/thread.h> 41 #include <sys/var.h> 42 #include <sys/cmn_err.h> 43 #include <sys/stat.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/promif.h> 47 #include <sys/nvpair.h> 48 #include <sys/byteorder.h> 49 #include <sys/scsi/scsi.h> 50 #include <sys/fibre-channel/fc.h> 51 #include <sys/fibre-channel/impl/fc_ulpif.h> 52 #include <sys/fibre-channel/impl/fc_fcaif.h> 53 #include <sys/fibre-channel/impl/fctl_private.h> 54 #include <sys/fibre-channel/impl/fc_portif.h> 55 #include <sys/fibre-channel/impl/fp.h> 56 57 /* These are defined in fctl.c! */ 58 extern int did_table_size; 59 extern int pwwn_table_size; 60 61 static struct cb_ops fp_cb_ops = { 62 fp_open, /* open */ 63 fp_close, /* close */ 64 nodev, /* strategy */ 65 nodev, /* print */ 66 nodev, /* dump */ 67 nodev, /* read */ 68 nodev, /* write */ 69 fp_ioctl, /* ioctl */ 70 nodev, /* devmap */ 71 nodev, /* mmap */ 72 nodev, /* segmap */ 73 nochpoll, /* chpoll */ 74 ddi_prop_op, /* cb_prop_op */ 75 0, /* streamtab */ 76 D_NEW | D_MP | D_HOTPLUG, /* cb_flag */ 77 CB_REV, /* rev */ 78 nodev, /* aread */ 79 nodev /* awrite */ 80 }; 81 82 static struct dev_ops fp_ops = { 83 DEVO_REV, /* build revision */ 84 0, /* reference count */ 85 fp_getinfo, /* getinfo */ 86 nulldev, /* identify - Obsoleted */ 87 nulldev, /* probe */ 88 fp_attach, /* attach */ 89 fp_detach, /* detach */ 90 nodev, /* reset */ 91 &fp_cb_ops, /* cb_ops */ 92 NULL, /* bus_ops */ 93 fp_power, /* power */ 94 ddi_quiesce_not_needed /* quiesce */ 95 }; 96 97 #define FP_VERSION "20091123-1.101" 98 #define FP_NAME_VERSION "SunFC Port v" FP_VERSION 99 100 char *fp_version = FP_NAME_VERSION; 101 102 static struct modldrv modldrv = { 103 &mod_driverops, /* Type of Module */ 104 FP_NAME_VERSION, /* Name/Version of fp */ 105 &fp_ops /* driver ops */ 106 }; 107 108 static struct modlinkage modlinkage = { 109 MODREV_1, /* Rev of the loadable modules system */ 110 &modldrv, /* NULL terminated list of */ 111 NULL /* Linkage structures */ 112 }; 113 114 115 116 static uint16_t ns_reg_cmds[] = { 117 NS_RPN_ID, 118 NS_RNN_ID, 119 NS_RCS_ID, 120 NS_RFT_ID, 121 NS_RPT_ID, 122 NS_RSPN_ID, 123 NS_RSNN_NN 124 }; 125 126 struct fp_xlat { 127 uchar_t xlat_state; 128 int xlat_rval; 129 } fp_xlat [] = { 130 { FC_PKT_SUCCESS, FC_SUCCESS }, 131 { FC_PKT_REMOTE_STOP, FC_FAILURE }, 132 { FC_PKT_LOCAL_RJT, FC_FAILURE }, 133 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT }, 134 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT }, 135 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY }, 136 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY }, 137 { FC_PKT_NPORT_BSY, FC_PBUSY }, 138 { FC_PKT_FABRIC_BSY, FC_FBUSY }, 139 { FC_PKT_LS_RJT, FC_FAILURE }, 140 { FC_PKT_BA_RJT, FC_FAILURE }, 141 { FC_PKT_TIMEOUT, FC_FAILURE }, 142 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR }, 143 { FC_PKT_FAILURE, FC_FAILURE }, 144 { FC_PKT_PORT_OFFLINE, FC_OFFLINE } 145 }; 146 147 static uchar_t fp_valid_alpas[] = { 148 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 149 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 150 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 151 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 152 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 153 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 154 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, 155 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82, 156 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E, 157 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC, 158 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 159 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 160 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 161 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF 162 }; 163 164 static struct fp_perms { 165 uint16_t fp_ioctl_cmd; 166 uchar_t fp_open_flag; 167 } fp_perm_list [] = { 168 { FCIO_GET_NUM_DEVS, FP_OPEN }, 169 { FCIO_GET_DEV_LIST, FP_OPEN }, 170 { FCIO_GET_SYM_PNAME, FP_OPEN }, 171 { FCIO_GET_SYM_NNAME, FP_OPEN }, 172 { FCIO_SET_SYM_PNAME, FP_EXCL }, 173 { FCIO_SET_SYM_NNAME, FP_EXCL }, 174 { FCIO_GET_LOGI_PARAMS, FP_OPEN }, 175 { FCIO_DEV_LOGIN, FP_EXCL }, 176 { FCIO_DEV_LOGOUT, FP_EXCL }, 177 { FCIO_GET_STATE, FP_OPEN }, 178 { FCIO_DEV_REMOVE, FP_EXCL }, 179 { FCIO_GET_FCODE_REV, FP_OPEN }, 180 { FCIO_GET_FW_REV, FP_OPEN }, 181 { FCIO_GET_DUMP_SIZE, FP_OPEN }, 182 { FCIO_FORCE_DUMP, FP_EXCL }, 183 { FCIO_GET_DUMP, FP_OPEN }, 184 { FCIO_GET_TOPOLOGY, FP_OPEN }, 185 { FCIO_RESET_LINK, FP_EXCL }, 186 { FCIO_RESET_HARD, FP_EXCL }, 187 { FCIO_RESET_HARD_CORE, FP_EXCL }, 188 { FCIO_DIAG, FP_OPEN }, 189 { FCIO_NS, FP_EXCL }, 190 { FCIO_DOWNLOAD_FW, FP_EXCL }, 191 { FCIO_DOWNLOAD_FCODE, FP_EXCL }, 192 { FCIO_LINK_STATUS, FP_OPEN }, 193 { FCIO_GET_HOST_PARAMS, FP_OPEN }, 194 { FCIO_GET_NODE_ID, FP_OPEN }, 195 { FCIO_SET_NODE_ID, FP_EXCL }, 196 { FCIO_SEND_NODE_ID, FP_OPEN }, 197 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN }, 198 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN }, 199 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN }, 200 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN }, 201 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN }, 202 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN }, 203 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN }, 204 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN }, 205 { FCIO_DELETE_NPIV_PORT, FP_OPEN }, 206 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN }, 207 { FCIO_CREATE_NPIV_PORT, FP_OPEN }, 208 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN } 209 }; 210 211 static char *fp_pm_comps[] = { 212 "NAME=FC Port", 213 "0=Port Down", 214 "1=Port Up" 215 }; 216 217 218 #ifdef _LITTLE_ENDIAN 219 #define MAKE_BE_32(x) { \ 220 uint32_t *ptr1, i; \ 221 ptr1 = (uint32_t *)(x); \ 222 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \ 223 *ptr1 = BE_32(*ptr1); \ 224 ptr1++; \ 225 } \ 226 } 227 #else 228 #define MAKE_BE_32(x) 229 #endif 230 231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES); 232 static uint32_t fp_options = 0; 233 234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY; 235 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */ 236 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */ 237 unsigned int fp_offline_ticker; /* seconds */ 238 239 /* 240 * Driver global variable to anchor the list of soft state structs for 241 * all fp driver instances. Used with the Solaris DDI soft state functions. 242 */ 243 static void *fp_driver_softstate; 244 245 static clock_t fp_retry_ticks; 246 static clock_t fp_offline_ticks; 247 248 static int fp_retry_ticker; 249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT; 250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE; 251 252 static int fp_log_size = FP_LOG_SIZE; 253 static int fp_trace = FP_TRACE_DEFAULT; 254 static fc_trace_logq_t *fp_logq = NULL; 255 256 int fp_get_adapter_paths(char *pathList, int count); 257 static void fp_log_port_event(fc_local_port_t *port, char *subclass); 258 static void fp_log_target_event(fc_local_port_t *port, char *subclass, 259 la_wwn_t tgt_pwwn, uint32_t port_id); 260 static uint32_t fp_map_remote_port_state(uint32_t rm_state); 261 static void fp_init_symbolic_names(fc_local_port_t *port); 262 263 264 /* 265 * Perform global initialization 266 */ 267 int 268 _init(void) 269 { 270 int ret; 271 272 if ((ret = ddi_soft_state_init(&fp_driver_softstate, 273 sizeof (struct fc_local_port), 8)) != 0) { 274 return (ret); 275 } 276 277 if ((ret = scsi_hba_init(&modlinkage)) != 0) { 278 ddi_soft_state_fini(&fp_driver_softstate); 279 return (ret); 280 } 281 282 fp_logq = fc_trace_alloc_logq(fp_log_size); 283 284 if ((ret = mod_install(&modlinkage)) != 0) { 285 fc_trace_free_logq(fp_logq); 286 ddi_soft_state_fini(&fp_driver_softstate); 287 scsi_hba_fini(&modlinkage); 288 } 289 290 return (ret); 291 } 292 293 294 /* 295 * Prepare for driver unload 296 */ 297 int 298 _fini(void) 299 { 300 int ret; 301 302 if ((ret = mod_remove(&modlinkage)) == 0) { 303 fc_trace_free_logq(fp_logq); 304 ddi_soft_state_fini(&fp_driver_softstate); 305 scsi_hba_fini(&modlinkage); 306 } 307 308 return (ret); 309 } 310 311 312 /* 313 * Request mod_info() to handle all cases 314 */ 315 int 316 _info(struct modinfo *modinfo) 317 { 318 return (mod_info(&modlinkage, modinfo)); 319 } 320 321 322 /* 323 * fp_attach: 324 * 325 * The respective cmd handlers take care of performing 326 * ULP related invocations 327 */ 328 static int 329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 330 { 331 int rval; 332 333 /* 334 * We check the value of fp_offline_ticker at this 335 * point. The variable is global for the driver and 336 * not specific to an instance. 337 * 338 * If there is no user-defined value found in /etc/system 339 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER). 340 * The minimum setting for this offline timeout according 341 * to the FC-FS2 standard (Fibre Channel Framing and 342 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec. 343 * 344 * We do not recommend setting the value to less than 10 345 * seconds (RA_TOV) or more than 90 seconds. If this 346 * variable is greater than 90 seconds then drivers above 347 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain. 348 */ 349 350 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY, 351 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker", 352 FP_OFFLINE_TICKER); 353 354 if ((fp_offline_ticker < 10) || 355 (fp_offline_ticker > 90)) { 356 cmn_err(CE_WARN, "Setting fp_offline_ticker to " 357 "%d second(s). This is outside the " 358 "recommended range of 10..90 seconds", 359 fp_offline_ticker); 360 } 361 362 /* 363 * Tick every second when there are commands to retry. 364 * It should tick at the least granular value of pkt_timeout 365 * (which is one second) 366 */ 367 fp_retry_ticker = 1; 368 369 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000); 370 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000); 371 372 switch (cmd) { 373 case DDI_ATTACH: 374 rval = fp_attach_handler(dip); 375 break; 376 377 case DDI_RESUME: 378 rval = fp_resume_handler(dip); 379 break; 380 381 default: 382 rval = DDI_FAILURE; 383 break; 384 } 385 return (rval); 386 } 387 388 389 /* 390 * fp_detach: 391 * 392 * If a ULP fails to handle cmd request converse of 393 * cmd is invoked for ULPs that previously succeeded 394 * cmd request. 395 */ 396 static int 397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 398 { 399 int rval = DDI_FAILURE; 400 fc_local_port_t *port; 401 fc_attach_cmd_t converse; 402 uint8_t cnt; 403 404 if ((port = ddi_get_soft_state(fp_driver_softstate, 405 ddi_get_instance(dip))) == NULL) { 406 return (DDI_FAILURE); 407 } 408 409 mutex_enter(&port->fp_mutex); 410 411 if (port->fp_ulp_attach) { 412 mutex_exit(&port->fp_mutex); 413 return (DDI_FAILURE); 414 } 415 416 switch (cmd) { 417 case DDI_DETACH: 418 if (port->fp_task != FP_TASK_IDLE) { 419 mutex_exit(&port->fp_mutex); 420 return (DDI_FAILURE); 421 } 422 423 /* Let's attempt to quit the job handler gracefully */ 424 port->fp_soft_state |= FP_DETACH_INPROGRESS; 425 426 mutex_exit(&port->fp_mutex); 427 converse = FC_CMD_ATTACH; 428 if (fctl_detach_ulps(port, FC_CMD_DETACH, 429 &modlinkage) != FC_SUCCESS) { 430 mutex_enter(&port->fp_mutex); 431 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 432 mutex_exit(&port->fp_mutex); 433 rval = DDI_FAILURE; 434 break; 435 } 436 437 mutex_enter(&port->fp_mutex); 438 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt); 439 cnt++) { 440 mutex_exit(&port->fp_mutex); 441 delay(drv_usectohz(1000000)); 442 mutex_enter(&port->fp_mutex); 443 } 444 445 if (port->fp_job_head) { 446 mutex_exit(&port->fp_mutex); 447 rval = DDI_FAILURE; 448 break; 449 } 450 mutex_exit(&port->fp_mutex); 451 452 rval = fp_detach_handler(port); 453 break; 454 455 case DDI_SUSPEND: 456 mutex_exit(&port->fp_mutex); 457 converse = FC_CMD_RESUME; 458 if (fctl_detach_ulps(port, FC_CMD_SUSPEND, 459 &modlinkage) != FC_SUCCESS) { 460 rval = DDI_FAILURE; 461 break; 462 } 463 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) { 464 (void) callb_generic_cpr(&port->fp_cpr_info, 465 CB_CODE_CPR_RESUME); 466 } 467 break; 468 469 default: 470 mutex_exit(&port->fp_mutex); 471 break; 472 } 473 474 /* 475 * Use softint to perform reattach. Mark fp_ulp_attach so we 476 * don't attempt to do this repeatedly on behalf of some persistent 477 * caller. 478 */ 479 if (rval != DDI_SUCCESS) { 480 mutex_enter(&port->fp_mutex); 481 port->fp_ulp_attach = 1; 482 483 /* 484 * If the port is in the low power mode then there is 485 * possibility that fca too could be in low power mode. 486 * Try to raise the power before calling attach ulps. 487 */ 488 489 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 490 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 491 mutex_exit(&port->fp_mutex); 492 (void) pm_raise_power(port->fp_port_dip, 493 FP_PM_COMPONENT, FP_PM_PORT_UP); 494 } else { 495 mutex_exit(&port->fp_mutex); 496 } 497 498 499 fp_attach_ulps(port, converse); 500 501 mutex_enter(&port->fp_mutex); 502 while (port->fp_ulp_attach) { 503 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 504 } 505 506 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 507 508 /* 509 * Mark state as detach failed so asynchronous ULP attach 510 * events (downstream, not the ones we're initiating with 511 * the call to fp_attach_ulps) are not honored. We're 512 * really still in pending detach. 513 */ 514 port->fp_soft_state |= FP_DETACH_FAILED; 515 516 mutex_exit(&port->fp_mutex); 517 } 518 519 return (rval); 520 } 521 522 523 /* 524 * fp_getinfo: 525 * Given the device number, return either the 526 * dev_info_t pointer or the instance number. 527 */ 528 529 /* ARGSUSED */ 530 static int 531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 532 { 533 int rval; 534 minor_t instance; 535 fc_local_port_t *port; 536 537 rval = DDI_SUCCESS; 538 instance = getminor((dev_t)arg); 539 540 switch (cmd) { 541 case DDI_INFO_DEVT2DEVINFO: 542 if ((port = ddi_get_soft_state(fp_driver_softstate, 543 instance)) == NULL) { 544 rval = DDI_FAILURE; 545 break; 546 } 547 *result = (void *)port->fp_port_dip; 548 break; 549 550 case DDI_INFO_DEVT2INSTANCE: 551 *result = (void *)(uintptr_t)instance; 552 break; 553 554 default: 555 rval = DDI_FAILURE; 556 break; 557 } 558 559 return (rval); 560 } 561 562 563 /* 564 * Entry point for power up and power down request from kernel 565 */ 566 static int 567 fp_power(dev_info_t *dip, int comp, int level) 568 { 569 int rval = DDI_FAILURE; 570 fc_local_port_t *port; 571 572 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 573 if (port == NULL || comp != FP_PM_COMPONENT) { 574 return (rval); 575 } 576 577 switch (level) { 578 case FP_PM_PORT_UP: 579 rval = DDI_SUCCESS; 580 581 /* 582 * If the port is DDI_SUSPENDed, let the DDI_RESUME 583 * code complete the rediscovery. 584 */ 585 mutex_enter(&port->fp_mutex); 586 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 587 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 588 port->fp_pm_level = FP_PM_PORT_UP; 589 mutex_exit(&port->fp_mutex); 590 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage); 591 break; 592 } 593 594 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 595 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 596 597 port->fp_pm_level = FP_PM_PORT_UP; 598 rval = fp_power_up(port); 599 if (rval != DDI_SUCCESS) { 600 port->fp_pm_level = FP_PM_PORT_DOWN; 601 } 602 } else { 603 port->fp_pm_level = FP_PM_PORT_UP; 604 } 605 mutex_exit(&port->fp_mutex); 606 break; 607 608 case FP_PM_PORT_DOWN: 609 mutex_enter(&port->fp_mutex); 610 611 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP)); 612 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 613 /* 614 * PM framework goofed up. We have don't 615 * have any PM components. Let's never go down. 616 */ 617 mutex_exit(&port->fp_mutex); 618 break; 619 620 } 621 622 if (port->fp_ulp_attach) { 623 /* We shouldn't let the power go down */ 624 mutex_exit(&port->fp_mutex); 625 break; 626 } 627 628 /* 629 * Not a whole lot to do if we are detaching 630 */ 631 if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 632 port->fp_pm_level = FP_PM_PORT_DOWN; 633 mutex_exit(&port->fp_mutex); 634 rval = DDI_SUCCESS; 635 break; 636 } 637 638 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) { 639 port->fp_pm_level = FP_PM_PORT_DOWN; 640 641 rval = fp_power_down(port); 642 if (rval != DDI_SUCCESS) { 643 port->fp_pm_level = FP_PM_PORT_UP; 644 ASSERT(!(port->fp_soft_state & 645 FP_SOFT_POWER_DOWN)); 646 } else { 647 ASSERT(port->fp_soft_state & 648 FP_SOFT_POWER_DOWN); 649 } 650 } 651 mutex_exit(&port->fp_mutex); 652 break; 653 654 default: 655 break; 656 } 657 658 return (rval); 659 } 660 661 662 /* 663 * Open FC port devctl node 664 */ 665 static int 666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp) 667 { 668 int instance; 669 fc_local_port_t *port; 670 671 if (otype != OTYP_CHR) { 672 return (EINVAL); 673 } 674 675 /* 676 * This is not a toy to play with. Allow only powerful 677 * users (hopefully knowledgeable) to access the port 678 * (A hacker potentially could download a sick binary 679 * file into FCA) 680 */ 681 if (drv_priv(credp)) { 682 return (EPERM); 683 } 684 685 instance = (int)getminor(*devp); 686 687 port = ddi_get_soft_state(fp_driver_softstate, instance); 688 if (port == NULL) { 689 return (ENXIO); 690 } 691 692 mutex_enter(&port->fp_mutex); 693 if (port->fp_flag & FP_EXCL) { 694 /* 695 * It is already open for exclusive access. 696 * So shut the door on this caller. 697 */ 698 mutex_exit(&port->fp_mutex); 699 return (EBUSY); 700 } 701 702 if (flag & FEXCL) { 703 if (port->fp_flag & FP_OPEN) { 704 /* 705 * Exclusive operation not possible 706 * as it is already opened 707 */ 708 mutex_exit(&port->fp_mutex); 709 return (EBUSY); 710 } 711 port->fp_flag |= FP_EXCL; 712 } 713 port->fp_flag |= FP_OPEN; 714 mutex_exit(&port->fp_mutex); 715 716 return (0); 717 } 718 719 720 /* 721 * The driver close entry point is called on the last close() 722 * of a device. So it is perfectly alright to just clobber the 723 * open flag and reset it to idle (instead of having to reset 724 * each flag bits). For any confusion, check out close(9E). 725 */ 726 727 /* ARGSUSED */ 728 static int 729 fp_close(dev_t dev, int flag, int otype, cred_t *credp) 730 { 731 int instance; 732 fc_local_port_t *port; 733 734 if (otype != OTYP_CHR) { 735 return (EINVAL); 736 } 737 738 instance = (int)getminor(dev); 739 740 port = ddi_get_soft_state(fp_driver_softstate, instance); 741 if (port == NULL) { 742 return (ENXIO); 743 } 744 745 mutex_enter(&port->fp_mutex); 746 if ((port->fp_flag & FP_OPEN) == 0) { 747 mutex_exit(&port->fp_mutex); 748 return (ENODEV); 749 } 750 port->fp_flag = FP_IDLE; 751 mutex_exit(&port->fp_mutex); 752 753 return (0); 754 } 755 756 /* 757 * Handle IOCTL requests 758 */ 759 760 /* ARGSUSED */ 761 static int 762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval) 763 { 764 int instance; 765 int ret = 0; 766 fcio_t fcio; 767 fc_local_port_t *port; 768 769 instance = (int)getminor(dev); 770 771 port = ddi_get_soft_state(fp_driver_softstate, instance); 772 if (port == NULL) { 773 return (ENXIO); 774 } 775 776 mutex_enter(&port->fp_mutex); 777 if ((port->fp_flag & FP_OPEN) == 0) { 778 mutex_exit(&port->fp_mutex); 779 return (ENXIO); 780 } 781 782 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 783 mutex_exit(&port->fp_mutex); 784 return (ENXIO); 785 } 786 787 mutex_exit(&port->fp_mutex); 788 789 /* this will raise power if necessary */ 790 ret = fctl_busy_port(port); 791 if (ret != 0) { 792 return (ret); 793 } 794 795 ASSERT(port->fp_pm_level == FP_PM_PORT_UP); 796 797 798 switch (cmd) { 799 case FCIO_CMD: { 800 #ifdef _MULTI_DATAMODEL 801 switch (ddi_model_convert_from(mode & FMODELS)) { 802 case DDI_MODEL_ILP32: { 803 struct fcio32 fcio32; 804 805 if (ddi_copyin((void *)data, (void *)&fcio32, 806 sizeof (struct fcio32), mode)) { 807 ret = EFAULT; 808 break; 809 } 810 fcio.fcio_xfer = fcio32.fcio_xfer; 811 fcio.fcio_cmd = fcio32.fcio_cmd; 812 fcio.fcio_flags = fcio32.fcio_flags; 813 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags; 814 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen; 815 fcio.fcio_ibuf = 816 (caddr_t)(uintptr_t)fcio32.fcio_ibuf; 817 fcio.fcio_olen = (size_t)fcio32.fcio_olen; 818 fcio.fcio_obuf = 819 (caddr_t)(uintptr_t)fcio32.fcio_obuf; 820 fcio.fcio_alen = (size_t)fcio32.fcio_alen; 821 fcio.fcio_abuf = 822 (caddr_t)(uintptr_t)fcio32.fcio_abuf; 823 fcio.fcio_errno = fcio32.fcio_errno; 824 break; 825 } 826 827 case DDI_MODEL_NONE: 828 if (ddi_copyin((void *)data, (void *)&fcio, 829 sizeof (fcio_t), mode)) { 830 ret = EFAULT; 831 } 832 break; 833 } 834 #else /* _MULTI_DATAMODEL */ 835 if (ddi_copyin((void *)data, (void *)&fcio, 836 sizeof (fcio_t), mode)) { 837 ret = EFAULT; 838 break; 839 } 840 #endif /* _MULTI_DATAMODEL */ 841 if (!ret) { 842 ret = fp_fciocmd(port, data, mode, &fcio); 843 } 844 break; 845 } 846 847 default: 848 ret = fctl_ulp_port_ioctl(port, dev, cmd, data, 849 mode, credp, rval); 850 } 851 852 fctl_idle_port(port); 853 854 return (ret); 855 } 856 857 858 /* 859 * Init Symbolic Port Name and Node Name 860 * LV will try to get symbolic names from FCA driver 861 * and register these to name server, 862 * if LV fails to get these, 863 * LV will register its default symbolic names to name server. 864 * The Default symbolic node name format is : 865 * <hostname>:<hba driver name>(instance) 866 * The Default symbolic port name format is : 867 * <fp path name> 868 */ 869 static void 870 fp_init_symbolic_names(fc_local_port_t *port) 871 { 872 const char *vendorname = ddi_driver_name(port->fp_fca_dip); 873 char *sym_name; 874 char fcaname[50] = {0}; 875 int hostnlen, fcanlen; 876 877 if (port->fp_sym_node_namelen == 0) { 878 hostnlen = strlen(utsname.nodename); 879 (void) snprintf(fcaname, sizeof (fcaname), 880 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip)); 881 fcanlen = strlen(fcaname); 882 883 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP); 884 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname); 885 port->fp_sym_node_namelen = strlen(sym_name); 886 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) { 887 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN; 888 } 889 (void) strncpy(port->fp_sym_node_name, sym_name, 890 port->fp_sym_node_namelen); 891 kmem_free(sym_name, hostnlen + fcanlen + 2); 892 } 893 894 if (port->fp_sym_port_namelen == 0) { 895 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 896 897 (void) ddi_pathname(port->fp_port_dip, pathname); 898 port->fp_sym_port_namelen = strlen(pathname); 899 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) { 900 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN; 901 } 902 (void) strncpy(port->fp_sym_port_name, pathname, 903 port->fp_sym_port_namelen); 904 kmem_free(pathname, MAXPATHLEN); 905 } 906 } 907 908 909 /* 910 * Perform port attach 911 */ 912 static int 913 fp_attach_handler(dev_info_t *dip) 914 { 915 int rval; 916 int instance; 917 int port_num; 918 int port_len; 919 char name[30]; 920 char i_pwwn[17]; 921 fp_cmd_t *pkt; 922 uint32_t ub_count; 923 fc_local_port_t *port; 924 job_request_t *job; 925 fc_local_port_t *phyport = NULL; 926 int portpro1; 927 char pwwn[17], nwwn[17]; 928 929 instance = ddi_get_instance(dip); 930 port_len = sizeof (port_num); 931 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 932 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 933 (caddr_t)&port_num, &port_len); 934 if (rval != DDI_SUCCESS) { 935 cmn_err(CE_WARN, "fp(%d): No port property in devinfo", 936 instance); 937 return (DDI_FAILURE); 938 } 939 940 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 941 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 942 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node", 943 instance); 944 return (DDI_FAILURE); 945 } 946 947 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance, 948 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 949 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment" 950 " point minor node", instance); 951 ddi_remove_minor_node(dip, NULL); 952 return (DDI_FAILURE); 953 } 954 955 if (ddi_soft_state_zalloc(fp_driver_softstate, instance) 956 != DDI_SUCCESS) { 957 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state", 958 instance); 959 ddi_remove_minor_node(dip, NULL); 960 return (DDI_FAILURE); 961 } 962 port = ddi_get_soft_state(fp_driver_softstate, instance); 963 964 (void) sprintf(port->fp_ibuf, "fp(%d)", instance); 965 966 port->fp_instance = instance; 967 port->fp_ulp_attach = 1; 968 port->fp_port_num = port_num; 969 port->fp_verbose = fp_verbosity; 970 port->fp_options = fp_options; 971 972 port->fp_fca_dip = ddi_get_parent(dip); 973 port->fp_port_dip = dip; 974 port->fp_fca_tran = (fc_fca_tran_t *) 975 ddi_get_driver_private(port->fp_fca_dip); 976 977 port->fp_task = port->fp_last_task = FP_TASK_IDLE; 978 979 /* 980 * Init the starting value of fp_rscn_count. Note that if 981 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the 982 * actual # of RSCNs will be (fp_rscn_count - 1) 983 */ 984 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1; 985 986 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL); 987 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL); 988 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL); 989 990 (void) sprintf(name, "fp%d_cache", instance); 991 992 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY, 993 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 994 "phyport-instance", -1)) != -1) { 995 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1); 996 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn); 997 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn); 998 port->fp_npiv_type = FC_NPIV_PORT; 999 } 1000 1001 /* 1002 * Allocate the pool of fc_packet_t structs to be used with 1003 * this fp instance. 1004 */ 1005 port->fp_pkt_cache = kmem_cache_create(name, 1006 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8, 1007 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port, 1008 NULL, 0); 1009 port->fp_out_fpcmds = 0; 1010 if (port->fp_pkt_cache == NULL) { 1011 goto cache_alloc_failed; 1012 } 1013 1014 1015 /* 1016 * Allocate the d_id and pwwn hash tables for all remote ports 1017 * connected to this local port. 1018 */ 1019 port->fp_did_table = kmem_zalloc(did_table_size * 1020 sizeof (struct d_id_hash), KM_SLEEP); 1021 1022 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size * 1023 sizeof (struct pwwn_hash), KM_SLEEP); 1024 1025 port->fp_taskq = taskq_create("fp_ulp_callback", 1, 1026 MINCLSYSPRI, 1, 16, 0); 1027 1028 /* Indicate that don't have the pm components yet */ 1029 port->fp_soft_state |= FP_SOFT_NO_PMCOMP; 1030 1031 /* 1032 * Bind the callbacks with the FCA driver. This will open the gate 1033 * for asynchronous callbacks, so after this call the fp_mutex 1034 * must be held when updating the fc_local_port_t struct. 1035 * 1036 * This is done _before_ setting up the job thread so we can avoid 1037 * cleaning up after the thread_create() in the error path. This 1038 * also means fp will be operating with fp_els_resp_pkt set to NULL. 1039 */ 1040 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1041 goto bind_callbacks_failed; 1042 } 1043 1044 if (phyport) { 1045 mutex_enter(&phyport->fp_mutex); 1046 if (phyport->fp_port_next) { 1047 phyport->fp_port_next->fp_port_prev = port; 1048 port->fp_port_next = phyport->fp_port_next; 1049 phyport->fp_port_next = port; 1050 port->fp_port_prev = phyport; 1051 } else { 1052 phyport->fp_port_next = port; 1053 phyport->fp_port_prev = port; 1054 port->fp_port_next = phyport; 1055 port->fp_port_prev = phyport; 1056 } 1057 mutex_exit(&phyport->fp_mutex); 1058 } 1059 1060 /* 1061 * Init Symbolic Names 1062 */ 1063 fp_init_symbolic_names(port); 1064 1065 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t), 1066 KM_SLEEP, NULL); 1067 1068 if (pkt == NULL) { 1069 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet", 1070 instance); 1071 goto alloc_els_packet_failed; 1072 } 1073 1074 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN, 1075 v.v_maxsyspri - 2); 1076 1077 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn); 1078 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port", 1079 i_pwwn) != DDI_PROP_SUCCESS) { 1080 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1081 "fp(%d): Updating 'initiator-port' property" 1082 " on fp dev_info node failed", instance); 1083 } 1084 1085 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn); 1086 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node", 1087 i_pwwn) != DDI_PROP_SUCCESS) { 1088 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1089 "fp(%d): Updating 'initiator-node' property" 1090 " on fp dev_info node failed", instance); 1091 } 1092 1093 mutex_enter(&port->fp_mutex); 1094 port->fp_els_resp_pkt = pkt; 1095 mutex_exit(&port->fp_mutex); 1096 1097 /* 1098 * Determine the count of unsolicited buffers this FCA can support 1099 */ 1100 fp_retrieve_caps(port); 1101 1102 /* 1103 * Allocate unsolicited buffer tokens 1104 */ 1105 if (port->fp_ub_count) { 1106 ub_count = port->fp_ub_count; 1107 port->fp_ub_tokens = kmem_zalloc(ub_count * 1108 sizeof (*port->fp_ub_tokens), KM_SLEEP); 1109 /* 1110 * Do not fail the attach if unsolicited buffer allocation 1111 * fails; Just try to get along with whatever the FCA can do. 1112 */ 1113 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size, 1114 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) != 1115 FC_SUCCESS || ub_count != port->fp_ub_count) { 1116 cmn_err(CE_WARN, "fp(%d): failed to allocate " 1117 " Unsolicited buffers. proceeding with attach...", 1118 instance); 1119 kmem_free(port->fp_ub_tokens, 1120 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1121 port->fp_ub_tokens = NULL; 1122 } 1123 } 1124 1125 fp_load_ulp_modules(dip, port); 1126 1127 /* 1128 * Enable DDI_SUSPEND and DDI_RESUME for this instance. 1129 */ 1130 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 1131 "pm-hardware-state", "needs-suspend-resume", 1132 strlen("needs-suspend-resume") + 1); 1133 1134 /* 1135 * fctl maintains a list of all port handles, so 1136 * help fctl add this one to its list now. 1137 */ 1138 mutex_enter(&port->fp_mutex); 1139 fctl_add_port(port); 1140 1141 /* 1142 * If a state change is already in progress, set the bind state t 1143 * OFFLINE as well, so further state change callbacks into ULPs 1144 * will pass the appropriate states 1145 */ 1146 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE || 1147 port->fp_statec_busy) { 1148 port->fp_bind_state = FC_STATE_OFFLINE; 1149 mutex_exit(&port->fp_mutex); 1150 1151 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 1152 } else { 1153 /* 1154 * Without dropping the mutex, ensure that the port 1155 * startup happens ahead of state change callback 1156 * processing 1157 */ 1158 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL); 1159 1160 port->fp_last_task = port->fp_task; 1161 port->fp_task = FP_TASK_PORT_STARTUP; 1162 1163 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC, 1164 fp_startup_done, (opaque_t)port, KM_SLEEP); 1165 1166 port->fp_job_head = port->fp_job_tail = job; 1167 1168 cv_signal(&port->fp_cv); 1169 1170 mutex_exit(&port->fp_mutex); 1171 } 1172 1173 mutex_enter(&port->fp_mutex); 1174 while (port->fp_ulp_attach) { 1175 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 1176 } 1177 mutex_exit(&port->fp_mutex); 1178 1179 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1180 "pm-components", fp_pm_comps, 1181 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) != 1182 DDI_PROP_SUCCESS) { 1183 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM" 1184 " components property, PM disabled on this port."); 1185 mutex_enter(&port->fp_mutex); 1186 port->fp_pm_level = FP_PM_PORT_UP; 1187 mutex_exit(&port->fp_mutex); 1188 } else { 1189 if (pm_raise_power(dip, FP_PM_COMPONENT, 1190 FP_PM_PORT_UP) != DDI_SUCCESS) { 1191 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise" 1192 " power level"); 1193 mutex_enter(&port->fp_mutex); 1194 port->fp_pm_level = FP_PM_PORT_UP; 1195 mutex_exit(&port->fp_mutex); 1196 } 1197 1198 /* 1199 * Don't unset the FP_SOFT_NO_PMCOMP flag until after 1200 * the call to pm_raise_power. The PM framework can't 1201 * handle multiple threads calling into it during attach. 1202 */ 1203 1204 mutex_enter(&port->fp_mutex); 1205 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP; 1206 mutex_exit(&port->fp_mutex); 1207 } 1208 1209 ddi_report_dev(dip); 1210 1211 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH); 1212 1213 return (DDI_SUCCESS); 1214 1215 /* 1216 * Unwind any/all preceeding allocations in the event of an error. 1217 */ 1218 1219 alloc_els_packet_failed: 1220 1221 if (port->fp_fca_handle != NULL) { 1222 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1223 port->fp_fca_handle = NULL; 1224 } 1225 1226 if (port->fp_ub_tokens != NULL) { 1227 (void) fc_ulp_ubfree(port, port->fp_ub_count, 1228 port->fp_ub_tokens); 1229 kmem_free(port->fp_ub_tokens, 1230 port->fp_ub_count * sizeof (*port->fp_ub_tokens)); 1231 port->fp_ub_tokens = NULL; 1232 } 1233 1234 if (port->fp_els_resp_pkt != NULL) { 1235 fp_free_pkt(port->fp_els_resp_pkt); 1236 port->fp_els_resp_pkt = NULL; 1237 } 1238 1239 bind_callbacks_failed: 1240 1241 if (port->fp_taskq != NULL) { 1242 taskq_destroy(port->fp_taskq); 1243 } 1244 1245 if (port->fp_pwwn_table != NULL) { 1246 kmem_free(port->fp_pwwn_table, 1247 pwwn_table_size * sizeof (struct pwwn_hash)); 1248 port->fp_pwwn_table = NULL; 1249 } 1250 1251 if (port->fp_did_table != NULL) { 1252 kmem_free(port->fp_did_table, 1253 did_table_size * sizeof (struct d_id_hash)); 1254 port->fp_did_table = NULL; 1255 } 1256 1257 if (port->fp_pkt_cache != NULL) { 1258 kmem_cache_destroy(port->fp_pkt_cache); 1259 port->fp_pkt_cache = NULL; 1260 } 1261 1262 cache_alloc_failed: 1263 1264 cv_destroy(&port->fp_attach_cv); 1265 cv_destroy(&port->fp_cv); 1266 mutex_destroy(&port->fp_mutex); 1267 ddi_remove_minor_node(port->fp_port_dip, NULL); 1268 ddi_soft_state_free(fp_driver_softstate, instance); 1269 ddi_prop_remove_all(dip); 1270 1271 return (DDI_FAILURE); 1272 } 1273 1274 1275 /* 1276 * Handle DDI_RESUME request 1277 */ 1278 static int 1279 fp_resume_handler(dev_info_t *dip) 1280 { 1281 int rval; 1282 fc_local_port_t *port; 1283 1284 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 1285 1286 ASSERT(port != NULL); 1287 1288 #ifdef DEBUG 1289 mutex_enter(&port->fp_mutex); 1290 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND); 1291 mutex_exit(&port->fp_mutex); 1292 #endif 1293 1294 /* 1295 * If the port was power suspended, raise the power level 1296 */ 1297 mutex_enter(&port->fp_mutex); 1298 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 1299 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 1300 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 1301 1302 mutex_exit(&port->fp_mutex); 1303 if (pm_raise_power(dip, FP_PM_COMPONENT, 1304 FP_PM_PORT_UP) != DDI_SUCCESS) { 1305 FP_TRACE(FP_NHEAD2(9, 0), 1306 "Failed to raise the power level"); 1307 return (DDI_FAILURE); 1308 } 1309 mutex_enter(&port->fp_mutex); 1310 } 1311 port->fp_soft_state &= ~FP_SOFT_SUSPEND; 1312 mutex_exit(&port->fp_mutex); 1313 1314 /* 1315 * All the discovery is initiated and handled by per-port thread. 1316 * Further all the discovery is done in handled in callback mode 1317 * (not polled mode); In a specific case such as this, the discovery 1318 * is required to happen in polled mode. The easiest way out is 1319 * to bail out port thread and get started. Come back and fix this 1320 * to do on demand discovery initiated by ULPs. ULPs such as FCP 1321 * will do on-demand discovery during pre-power-up busctl handling 1322 * which will only be possible when SCSA provides a new HBA vector 1323 * for sending down the PM busctl requests. 1324 */ 1325 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME); 1326 1327 rval = fp_resume_all(port, FC_CMD_RESUME); 1328 if (rval != DDI_SUCCESS) { 1329 mutex_enter(&port->fp_mutex); 1330 port->fp_soft_state |= FP_SOFT_SUSPEND; 1331 mutex_exit(&port->fp_mutex); 1332 (void) callb_generic_cpr(&port->fp_cpr_info, 1333 CB_CODE_CPR_CHKPT); 1334 } 1335 1336 return (rval); 1337 } 1338 1339 /* 1340 * Perform FC Port power on initialization 1341 */ 1342 static int 1343 fp_power_up(fc_local_port_t *port) 1344 { 1345 int rval; 1346 1347 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1348 1349 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0); 1350 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN); 1351 1352 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1353 1354 mutex_exit(&port->fp_mutex); 1355 1356 rval = fp_resume_all(port, FC_CMD_POWER_UP); 1357 if (rval != DDI_SUCCESS) { 1358 mutex_enter(&port->fp_mutex); 1359 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1360 } else { 1361 mutex_enter(&port->fp_mutex); 1362 } 1363 1364 return (rval); 1365 } 1366 1367 1368 /* 1369 * It is important to note that the power may possibly be removed between 1370 * SUSPEND and the ensuing RESUME operation. In such a context the underlying 1371 * FC port hardware would have gone through an OFFLINE to ONLINE transition 1372 * (hardware state). In this case, the port driver may need to rediscover the 1373 * topology, perform LOGINs, register with the name server again and perform 1374 * any such port initialization procedures. To perform LOGINs, the driver could 1375 * use the port device handle to see if a LOGIN needs to be performed and use 1376 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured 1377 * or removed) which will be reflected in the map the ULPs will see. 1378 */ 1379 static int 1380 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd) 1381 { 1382 1383 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1384 1385 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1386 return (DDI_FAILURE); 1387 } 1388 1389 mutex_enter(&port->fp_mutex); 1390 1391 /* 1392 * If there are commands queued for delayed retry, instead of 1393 * working the hard way to figure out which ones are good for 1394 * restart and which ones not (ELSs are definitely not good 1395 * as the port will have to go through a new spin of rediscovery 1396 * now), so just flush them out. 1397 */ 1398 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) { 1399 fp_cmd_t *cmd; 1400 1401 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT; 1402 1403 mutex_exit(&port->fp_mutex); 1404 while ((cmd = fp_deque_cmd(port)) != NULL) { 1405 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 1406 fp_iodone(cmd); 1407 } 1408 mutex_enter(&port->fp_mutex); 1409 } 1410 1411 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) { 1412 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) || 1413 port->fp_dev_count) { 1414 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1415 port->fp_offline_tid = timeout(fp_offline_timeout, 1416 (caddr_t)port, fp_offline_ticks); 1417 } 1418 if (port->fp_job_head) { 1419 cv_signal(&port->fp_cv); 1420 } 1421 mutex_exit(&port->fp_mutex); 1422 fctl_attach_ulps(port, cmd, &modlinkage); 1423 } else { 1424 struct job_request *job; 1425 1426 /* 1427 * If an OFFLINE timer was running at the time of 1428 * suspending, there is no need to restart it as 1429 * the port is ONLINE now. 1430 */ 1431 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1432 if (port->fp_statec_busy == 0) { 1433 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 1434 } 1435 port->fp_statec_busy++; 1436 mutex_exit(&port->fp_mutex); 1437 1438 job = fctl_alloc_job(JOB_PORT_ONLINE, 1439 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP); 1440 fctl_enque_job(port, job); 1441 1442 fctl_jobwait(job); 1443 fctl_remove_oldies(port); 1444 1445 fctl_attach_ulps(port, cmd, &modlinkage); 1446 fctl_dealloc_job(job); 1447 } 1448 1449 return (DDI_SUCCESS); 1450 } 1451 1452 1453 /* 1454 * At this time, there shouldn't be any I/O requests on this port. 1455 * But the unsolicited callbacks from the underlying FCA port need 1456 * to be handled very carefully. The steps followed to handle the 1457 * DDI_DETACH are: 1458 * + Grab the port driver mutex, check if the unsolicited 1459 * callback is currently under processing. If true, fail 1460 * the DDI_DETACH request by printing a message; If false 1461 * mark the DDI_DETACH as under progress, so that any 1462 * further unsolicited callbacks get bounced. 1463 * + Perform PRLO/LOGO if necessary, cleanup all the data 1464 * structures. 1465 * + Get the job_handler thread to gracefully exit. 1466 * + Unregister callbacks with the FCA port. 1467 * + Now that some peace is found, notify all the ULPs of 1468 * DDI_DETACH request (using ulp_port_detach entry point) 1469 * + Free all mutexes, semaphores, conditional variables. 1470 * + Free the soft state, return success. 1471 * 1472 * Important considerations: 1473 * Port driver de-registers state change and unsolicited 1474 * callbacks before taking up the task of notifying ULPs 1475 * and performing PRLO and LOGOs. 1476 * 1477 * A port may go offline at the time PRLO/LOGO is being 1478 * requested. It is expected of all FCA drivers to fail 1479 * such requests either immediately with a FC_OFFLINE 1480 * return code to fc_fca_transport() or return the packet 1481 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE 1482 */ 1483 static int 1484 fp_detach_handler(fc_local_port_t *port) 1485 { 1486 job_request_t *job; 1487 uint32_t delay_count; 1488 fc_orphan_t *orp, *tmporp; 1489 1490 /* 1491 * In a Fabric topology with many host ports connected to 1492 * a switch, another detaching instance of fp might have 1493 * triggered a LOGO (which is an unsolicited request to 1494 * this instance). So in order to be able to successfully 1495 * detach by taking care of such cases a delay of about 1496 * 30 seconds is introduced. 1497 */ 1498 delay_count = 0; 1499 mutex_enter(&port->fp_mutex); 1500 if (port->fp_out_fpcmds != 0) { 1501 /* 1502 * At this time we can only check fp internal commands, because 1503 * sd/ssd/scsi_vhci should have finsihed all their commands, 1504 * fcp/fcip/fcsm should have finished all their commands. 1505 * 1506 * It seems that all fp internal commands are asynchronous now. 1507 */ 1508 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1509 mutex_exit(&port->fp_mutex); 1510 1511 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress" 1512 " Failing detach", port->fp_instance, port->fp_out_fpcmds); 1513 return (DDI_FAILURE); 1514 } 1515 1516 while ((port->fp_soft_state & 1517 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) && 1518 (delay_count < 30)) { 1519 mutex_exit(&port->fp_mutex); 1520 delay_count++; 1521 delay(drv_usectohz(1000000)); 1522 mutex_enter(&port->fp_mutex); 1523 } 1524 1525 if (port->fp_soft_state & 1526 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) { 1527 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1528 mutex_exit(&port->fp_mutex); 1529 1530 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1531 " Failing detach", port->fp_instance); 1532 return (DDI_FAILURE); 1533 } 1534 1535 port->fp_soft_state |= FP_SOFT_IN_DETACH; 1536 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1537 mutex_exit(&port->fp_mutex); 1538 1539 /* 1540 * If we're powered down, we need to raise power prior to submitting 1541 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never 1542 * process the shutdown job. 1543 */ 1544 if (fctl_busy_port(port) != 0) { 1545 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed", 1546 port->fp_instance); 1547 mutex_enter(&port->fp_mutex); 1548 port->fp_soft_state &= ~FP_SOFT_IN_DETACH; 1549 mutex_exit(&port->fp_mutex); 1550 return (DDI_FAILURE); 1551 } 1552 1553 /* 1554 * This will deallocate data structs and cause the "job" thread 1555 * to exit, in preparation for DDI_DETACH on the instance. 1556 * This can sleep for an arbitrary duration, since it waits for 1557 * commands over the wire, timeout(9F) callbacks, etc. 1558 * 1559 * CAUTION: There is still a race here, where the "job" thread 1560 * can still be executing code even tho the fctl_jobwait() call 1561 * below has returned to us. In theory the fp driver could even be 1562 * modunloaded even tho the job thread isn't done executing. 1563 * without creating the race condition. 1564 */ 1565 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL, 1566 (opaque_t)port, KM_SLEEP); 1567 fctl_enque_job(port, job); 1568 fctl_jobwait(job); 1569 fctl_dealloc_job(job); 1570 1571 1572 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT, 1573 FP_PM_PORT_DOWN); 1574 1575 if (port->fp_taskq) { 1576 taskq_destroy(port->fp_taskq); 1577 } 1578 1579 ddi_prop_remove_all(port->fp_port_dip); 1580 1581 ddi_remove_minor_node(port->fp_port_dip, NULL); 1582 1583 fctl_remove_port(port); 1584 1585 fp_free_pkt(port->fp_els_resp_pkt); 1586 1587 if (port->fp_ub_tokens) { 1588 if (fc_ulp_ubfree(port, port->fp_ub_count, 1589 port->fp_ub_tokens) != FC_SUCCESS) { 1590 cmn_err(CE_WARN, "fp(%d): couldn't free " 1591 " unsolicited buffers", port->fp_instance); 1592 } 1593 kmem_free(port->fp_ub_tokens, 1594 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1595 port->fp_ub_tokens = NULL; 1596 } 1597 1598 if (port->fp_pkt_cache != NULL) { 1599 kmem_cache_destroy(port->fp_pkt_cache); 1600 } 1601 1602 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1603 1604 mutex_enter(&port->fp_mutex); 1605 if (port->fp_did_table) { 1606 kmem_free(port->fp_did_table, did_table_size * 1607 sizeof (struct d_id_hash)); 1608 } 1609 1610 if (port->fp_pwwn_table) { 1611 kmem_free(port->fp_pwwn_table, pwwn_table_size * 1612 sizeof (struct pwwn_hash)); 1613 } 1614 orp = port->fp_orphan_list; 1615 while (orp) { 1616 tmporp = orp; 1617 orp = orp->orp_next; 1618 kmem_free(tmporp, sizeof (*orp)); 1619 } 1620 1621 mutex_exit(&port->fp_mutex); 1622 1623 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH); 1624 1625 mutex_destroy(&port->fp_mutex); 1626 cv_destroy(&port->fp_attach_cv); 1627 cv_destroy(&port->fp_cv); 1628 ddi_soft_state_free(fp_driver_softstate, port->fp_instance); 1629 1630 return (DDI_SUCCESS); 1631 } 1632 1633 1634 /* 1635 * Steps to perform DDI_SUSPEND operation on a FC port 1636 * 1637 * - If already suspended return DDI_FAILURE 1638 * - If already power-suspended return DDI_SUCCESS 1639 * - If an unsolicited callback or state change handling is in 1640 * in progress, throw a warning message, return DDI_FAILURE 1641 * - Cancel timeouts 1642 * - SUSPEND the job_handler thread (means do nothing as it is 1643 * taken care of by the CPR frame work) 1644 */ 1645 static int 1646 fp_suspend_handler(fc_local_port_t *port) 1647 { 1648 uint32_t delay_count; 1649 1650 mutex_enter(&port->fp_mutex); 1651 1652 /* 1653 * The following should never happen, but 1654 * let the driver be more defensive here 1655 */ 1656 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1657 mutex_exit(&port->fp_mutex); 1658 return (DDI_FAILURE); 1659 } 1660 1661 /* 1662 * If the port is already power suspended, there 1663 * is nothing else to do, So return DDI_SUCCESS, 1664 * but mark the SUSPEND bit in the soft state 1665 * before leaving. 1666 */ 1667 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1668 port->fp_soft_state |= FP_SOFT_SUSPEND; 1669 mutex_exit(&port->fp_mutex); 1670 return (DDI_SUCCESS); 1671 } 1672 1673 /* 1674 * Check if an unsolicited callback or state change handling is 1675 * in progress. If true, fail the suspend operation; also throw 1676 * a warning message notifying the failure. Note that Sun PCI 1677 * hotplug spec recommends messages in cases of failure (but 1678 * not flooding the console) 1679 * 1680 * Busy waiting for a short interval (500 millisecond ?) to see 1681 * if the callback processing completes may be another idea. Since 1682 * most of the callback processing involves a lot of work, it 1683 * is safe to just fail the SUSPEND operation. It is definitely 1684 * not bad to fail the SUSPEND operation if the driver is busy. 1685 */ 1686 delay_count = 0; 1687 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1688 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) { 1689 mutex_exit(&port->fp_mutex); 1690 delay_count++; 1691 delay(drv_usectohz(1000000)); 1692 mutex_enter(&port->fp_mutex); 1693 } 1694 1695 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1696 FP_SOFT_IN_UNSOL_CB)) { 1697 mutex_exit(&port->fp_mutex); 1698 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1699 " Failing suspend", port->fp_instance); 1700 return (DDI_FAILURE); 1701 } 1702 1703 /* 1704 * Check of FC port thread is busy 1705 */ 1706 if (port->fp_job_head) { 1707 mutex_exit(&port->fp_mutex); 1708 FP_TRACE(FP_NHEAD2(9, 0), 1709 "FC port thread is busy: Failing suspend"); 1710 return (DDI_FAILURE); 1711 } 1712 port->fp_soft_state |= FP_SOFT_SUSPEND; 1713 1714 fp_suspend_all(port); 1715 mutex_exit(&port->fp_mutex); 1716 1717 return (DDI_SUCCESS); 1718 } 1719 1720 1721 /* 1722 * Prepare for graceful power down of a FC port 1723 */ 1724 static int 1725 fp_power_down(fc_local_port_t *port) 1726 { 1727 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1728 1729 /* 1730 * Power down request followed by a DDI_SUSPEND should 1731 * never happen; If it does return DDI_SUCCESS 1732 */ 1733 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1734 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1735 return (DDI_SUCCESS); 1736 } 1737 1738 /* 1739 * If the port is already power suspended, there 1740 * is nothing else to do, So return DDI_SUCCESS, 1741 */ 1742 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1743 return (DDI_SUCCESS); 1744 } 1745 1746 /* 1747 * Check if an unsolicited callback or state change handling 1748 * is in progress. If true, fail the PM suspend operation. 1749 * But don't print a message unless the verbosity of the 1750 * driver desires otherwise. 1751 */ 1752 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) || 1753 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) { 1754 FP_TRACE(FP_NHEAD2(9, 0), 1755 "Unsolicited callback in progress: Failing power down"); 1756 return (DDI_FAILURE); 1757 } 1758 1759 /* 1760 * Check of FC port thread is busy 1761 */ 1762 if (port->fp_job_head) { 1763 FP_TRACE(FP_NHEAD2(9, 0), 1764 "FC port thread is busy: Failing power down"); 1765 return (DDI_FAILURE); 1766 } 1767 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1768 1769 /* 1770 * check if the ULPs are ready for power down 1771 */ 1772 mutex_exit(&port->fp_mutex); 1773 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN, 1774 &modlinkage) != FC_SUCCESS) { 1775 mutex_enter(&port->fp_mutex); 1776 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1777 mutex_exit(&port->fp_mutex); 1778 1779 /* 1780 * Power back up the obedient ULPs that went down 1781 */ 1782 fp_attach_ulps(port, FC_CMD_POWER_UP); 1783 1784 FP_TRACE(FP_NHEAD2(9, 0), 1785 "ULP(s) busy, detach_ulps failed. Failing power down"); 1786 mutex_enter(&port->fp_mutex); 1787 return (DDI_FAILURE); 1788 } 1789 mutex_enter(&port->fp_mutex); 1790 1791 fp_suspend_all(port); 1792 1793 return (DDI_SUCCESS); 1794 } 1795 1796 1797 /* 1798 * Suspend the entire FC port 1799 */ 1800 static void 1801 fp_suspend_all(fc_local_port_t *port) 1802 { 1803 int index; 1804 struct pwwn_hash *head; 1805 fc_remote_port_t *pd; 1806 1807 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1808 1809 if (port->fp_wait_tid != 0) { 1810 timeout_id_t tid; 1811 1812 tid = port->fp_wait_tid; 1813 port->fp_wait_tid = (timeout_id_t)NULL; 1814 mutex_exit(&port->fp_mutex); 1815 (void) untimeout(tid); 1816 mutex_enter(&port->fp_mutex); 1817 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT; 1818 } 1819 1820 if (port->fp_offline_tid) { 1821 timeout_id_t tid; 1822 1823 tid = port->fp_offline_tid; 1824 port->fp_offline_tid = (timeout_id_t)NULL; 1825 mutex_exit(&port->fp_mutex); 1826 (void) untimeout(tid); 1827 mutex_enter(&port->fp_mutex); 1828 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT; 1829 } 1830 mutex_exit(&port->fp_mutex); 1831 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1832 mutex_enter(&port->fp_mutex); 1833 1834 /* 1835 * Mark all devices as OLD, and reset the LOGIN state as well 1836 * (this will force the ULPs to perform a LOGIN after calling 1837 * fc_portgetmap() during RESUME/PM_RESUME) 1838 */ 1839 for (index = 0; index < pwwn_table_size; index++) { 1840 head = &port->fp_pwwn_table[index]; 1841 pd = head->pwwn_head; 1842 while (pd != NULL) { 1843 mutex_enter(&pd->pd_mutex); 1844 fp_remote_port_offline(pd); 1845 fctl_delist_did_table(port, pd); 1846 pd->pd_state = PORT_DEVICE_VALID; 1847 pd->pd_login_count = 0; 1848 mutex_exit(&pd->pd_mutex); 1849 pd = pd->pd_wwn_hnext; 1850 } 1851 } 1852 } 1853 1854 1855 /* 1856 * fp_cache_constructor: Constructor function for kmem_cache_create(9F). 1857 * Performs intializations for fc_packet_t structs. 1858 * Returns 0 for success or -1 for failure. 1859 * 1860 * This function allocates DMA handles for both command and responses. 1861 * Most of the ELSs used have both command and responses so it is strongly 1862 * desired to move them to cache constructor routine. 1863 * 1864 * Context: Can sleep iff called with KM_SLEEP flag. 1865 */ 1866 static int 1867 fp_cache_constructor(void *buf, void *cdarg, int kmflags) 1868 { 1869 int (*cb) (caddr_t); 1870 fc_packet_t *pkt; 1871 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1872 fc_local_port_t *port = (fc_local_port_t *)cdarg; 1873 1874 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1875 1876 cmd->cmd_next = NULL; 1877 cmd->cmd_flags = 0; 1878 cmd->cmd_dflags = 0; 1879 cmd->cmd_job = NULL; 1880 cmd->cmd_port = port; 1881 pkt = &cmd->cmd_pkt; 1882 1883 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 1884 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1885 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1886 &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 1887 return (-1); 1888 } 1889 1890 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1891 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1892 &pkt->pkt_resp_dma) != DDI_SUCCESS) { 1893 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1894 return (-1); 1895 } 1896 } else { 1897 pkt->pkt_cmd_dma = 0; 1898 pkt->pkt_resp_dma = 0; 1899 } 1900 1901 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL; 1902 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt = 1903 pkt->pkt_data_cookie_cnt = 0; 1904 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie = 1905 pkt->pkt_data_cookie = NULL; 1906 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t); 1907 1908 return (0); 1909 } 1910 1911 1912 /* 1913 * fp_cache_destructor: Destructor function for kmem_cache_create(). 1914 * Performs un-intializations for fc_packet_t structs. 1915 */ 1916 /* ARGSUSED */ 1917 static void 1918 fp_cache_destructor(void *buf, void *cdarg) 1919 { 1920 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1921 fc_packet_t *pkt; 1922 1923 pkt = &cmd->cmd_pkt; 1924 if (pkt->pkt_cmd_dma) { 1925 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1926 } 1927 1928 if (pkt->pkt_resp_dma) { 1929 ddi_dma_free_handle(&pkt->pkt_resp_dma); 1930 } 1931 } 1932 1933 1934 /* 1935 * Packet allocation for ELS and any other port driver commands 1936 * 1937 * Some ELSs like FLOGI and PLOGI are critical for topology and 1938 * device discovery and a system's inability to allocate memory 1939 * or DVMA resources while performing some of these critical ELSs 1940 * cause a lot of problem. While memory allocation failures are 1941 * rare, DVMA resource failures are common as the applications 1942 * are becoming more and more powerful on huge servers. So it 1943 * is desirable to have a framework support to reserve a fragment 1944 * of DVMA. So until this is fixed the correct way, the suffering 1945 * is huge whenever a LIP happens at a time DVMA resources are 1946 * drained out completely - So an attempt needs to be made to 1947 * KM_SLEEP while requesting for these resources, hoping that 1948 * the requests won't hang forever. 1949 * 1950 * The fc_remote_port_t argument is stored into the pkt_pd field in the 1951 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This 1952 * ensures that the pd_ref_count for the fc_remote_port_t is valid. 1953 * If there is no fc_remote_port_t associated with the fc_packet_t, then 1954 * fp_alloc_pkt() must be called with pd set to NULL. 1955 * 1956 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen, 1957 * actually, it's a design fault. But there's no problem for physical 1958 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei. 1959 * 1960 * For FCAs that don't support DMA, such as fcoei, we will use 1961 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len. 1962 */ 1963 1964 static fp_cmd_t * 1965 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags, 1966 fc_remote_port_t *pd) 1967 { 1968 int rval; 1969 ulong_t real_len; 1970 fp_cmd_t *cmd; 1971 fc_packet_t *pkt; 1972 int (*cb) (caddr_t); 1973 ddi_dma_cookie_t pkt_cookie; 1974 ddi_dma_cookie_t *cp; 1975 uint32_t cnt; 1976 1977 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1978 1979 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1980 1981 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags); 1982 if (cmd == NULL) { 1983 return (cmd); 1984 } 1985 1986 cmd->cmd_ulp_pkt = NULL; 1987 cmd->cmd_flags = 0; 1988 pkt = &cmd->cmd_pkt; 1989 ASSERT(cmd->cmd_dflags == 0); 1990 1991 pkt->pkt_datalen = 0; 1992 pkt->pkt_data = NULL; 1993 pkt->pkt_state = 0; 1994 pkt->pkt_action = 0; 1995 pkt->pkt_reason = 0; 1996 pkt->pkt_expln = 0; 1997 pkt->pkt_cmd = NULL; 1998 pkt->pkt_resp = NULL; 1999 pkt->pkt_fctl_rsvd1 = NULL; 2000 pkt->pkt_fctl_rsvd2 = NULL; 2001 2002 /* 2003 * Init pkt_pd with the given pointer; this must be done _before_ 2004 * the call to fc_ulp_init_packet(). 2005 */ 2006 pkt->pkt_pd = pd; 2007 2008 /* Now call the FCA driver to init its private, per-packet fields */ 2009 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) { 2010 goto alloc_pkt_failed; 2011 } 2012 2013 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2014 ASSERT(pkt->pkt_cmd_dma != NULL); 2015 2016 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len, 2017 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT, 2018 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len, 2019 &pkt->pkt_cmd_acc); 2020 2021 if (rval != DDI_SUCCESS) { 2022 goto alloc_pkt_failed; 2023 } 2024 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM; 2025 2026 if (real_len < cmd_len) { 2027 goto alloc_pkt_failed; 2028 } 2029 2030 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 2031 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | 2032 DDI_DMA_CONSISTENT, cb, NULL, 2033 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt); 2034 2035 if (rval != DDI_DMA_MAPPED) { 2036 goto alloc_pkt_failed; 2037 } 2038 2039 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND; 2040 2041 if (pkt->pkt_cmd_cookie_cnt > 2042 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2043 goto alloc_pkt_failed; 2044 } 2045 2046 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2047 2048 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2049 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie), 2050 KM_NOSLEEP); 2051 2052 if (cp == NULL) { 2053 goto alloc_pkt_failed; 2054 } 2055 2056 *cp = pkt_cookie; 2057 cp++; 2058 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) { 2059 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie); 2060 *cp = pkt_cookie; 2061 } 2062 } else if (cmd_len != 0) { 2063 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP); 2064 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len; 2065 } 2066 2067 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2068 ASSERT(pkt->pkt_resp_dma != NULL); 2069 2070 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len, 2071 port->fp_fca_tran->fca_acc_attr, 2072 DDI_DMA_CONSISTENT, cb, NULL, 2073 (caddr_t *)&pkt->pkt_resp, &real_len, 2074 &pkt->pkt_resp_acc); 2075 2076 if (rval != DDI_SUCCESS) { 2077 goto alloc_pkt_failed; 2078 } 2079 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM; 2080 2081 if (real_len < resp_len) { 2082 goto alloc_pkt_failed; 2083 } 2084 2085 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 2086 pkt->pkt_resp, real_len, DDI_DMA_READ | 2087 DDI_DMA_CONSISTENT, cb, NULL, 2088 &pkt_cookie, &pkt->pkt_resp_cookie_cnt); 2089 2090 if (rval != DDI_DMA_MAPPED) { 2091 goto alloc_pkt_failed; 2092 } 2093 2094 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND; 2095 2096 if (pkt->pkt_resp_cookie_cnt > 2097 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2098 goto alloc_pkt_failed; 2099 } 2100 2101 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2102 2103 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2104 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie), 2105 KM_NOSLEEP); 2106 2107 if (cp == NULL) { 2108 goto alloc_pkt_failed; 2109 } 2110 2111 *cp = pkt_cookie; 2112 cp++; 2113 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) { 2114 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie); 2115 *cp = pkt_cookie; 2116 } 2117 } else if (resp_len != 0) { 2118 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP); 2119 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len; 2120 } 2121 2122 pkt->pkt_cmdlen = cmd_len; 2123 pkt->pkt_rsplen = resp_len; 2124 pkt->pkt_ulp_private = cmd; 2125 2126 return (cmd); 2127 2128 alloc_pkt_failed: 2129 2130 fp_free_dma(cmd); 2131 2132 if (pkt->pkt_cmd_cookie != NULL) { 2133 kmem_free(pkt->pkt_cmd_cookie, 2134 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2135 pkt->pkt_cmd_cookie = NULL; 2136 } 2137 2138 if (pkt->pkt_resp_cookie != NULL) { 2139 kmem_free(pkt->pkt_resp_cookie, 2140 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2141 pkt->pkt_resp_cookie = NULL; 2142 } 2143 2144 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2145 if (pkt->pkt_cmd) { 2146 kmem_free(pkt->pkt_cmd, cmd_len); 2147 } 2148 2149 if (pkt->pkt_resp) { 2150 kmem_free(pkt->pkt_resp, resp_len); 2151 } 2152 } 2153 2154 kmem_cache_free(port->fp_pkt_cache, cmd); 2155 2156 return (NULL); 2157 } 2158 2159 2160 /* 2161 * Free FC packet 2162 */ 2163 static void 2164 fp_free_pkt(fp_cmd_t *cmd) 2165 { 2166 fc_local_port_t *port; 2167 fc_packet_t *pkt; 2168 2169 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex)); 2170 2171 cmd->cmd_next = NULL; 2172 cmd->cmd_job = NULL; 2173 pkt = &cmd->cmd_pkt; 2174 pkt->pkt_ulp_private = 0; 2175 pkt->pkt_tran_flags = 0; 2176 pkt->pkt_tran_type = 0; 2177 port = cmd->cmd_port; 2178 2179 if (pkt->pkt_cmd_cookie != NULL) { 2180 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt * 2181 sizeof (ddi_dma_cookie_t)); 2182 pkt->pkt_cmd_cookie = NULL; 2183 } 2184 2185 if (pkt->pkt_resp_cookie != NULL) { 2186 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt * 2187 sizeof (ddi_dma_cookie_t)); 2188 pkt->pkt_resp_cookie = NULL; 2189 } 2190 2191 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2192 if (pkt->pkt_cmd) { 2193 kmem_free(pkt->pkt_cmd, 2194 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1); 2195 } 2196 2197 if (pkt->pkt_resp) { 2198 kmem_free(pkt->pkt_resp, 2199 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2); 2200 } 2201 } 2202 2203 fp_free_dma(cmd); 2204 (void) fc_ulp_uninit_packet((opaque_t)port, pkt); 2205 kmem_cache_free(port->fp_pkt_cache, (void *)cmd); 2206 } 2207 2208 2209 /* 2210 * Release DVMA resources 2211 */ 2212 static void 2213 fp_free_dma(fp_cmd_t *cmd) 2214 { 2215 fc_packet_t *pkt = &cmd->cmd_pkt; 2216 2217 pkt->pkt_cmdlen = 0; 2218 pkt->pkt_rsplen = 0; 2219 pkt->pkt_tran_type = 0; 2220 pkt->pkt_tran_flags = 0; 2221 2222 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) { 2223 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 2224 } 2225 2226 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) { 2227 if (pkt->pkt_cmd_acc) { 2228 ddi_dma_mem_free(&pkt->pkt_cmd_acc); 2229 } 2230 } 2231 2232 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) { 2233 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 2234 } 2235 2236 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) { 2237 if (pkt->pkt_resp_acc) { 2238 ddi_dma_mem_free(&pkt->pkt_resp_acc); 2239 } 2240 } 2241 cmd->cmd_dflags = 0; 2242 } 2243 2244 2245 /* 2246 * Dedicated thread to perform various activities. One thread for 2247 * each fc_local_port_t (driver soft state) instance. 2248 * Note, this effectively works out to one thread for each local 2249 * port, but there are also some Solaris taskq threads in use on a per-local 2250 * port basis; these also need to be taken into consideration. 2251 */ 2252 static void 2253 fp_job_handler(fc_local_port_t *port) 2254 { 2255 int rval; 2256 uint32_t *d_id; 2257 fc_remote_port_t *pd; 2258 job_request_t *job; 2259 2260 #ifndef __lock_lint 2261 /* 2262 * Solaris-internal stuff for proper operation of kernel threads 2263 * with Solaris CPR. 2264 */ 2265 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex, 2266 callb_generic_cpr, "fp_job_handler"); 2267 #endif 2268 2269 2270 /* Loop forever waiting for work to do */ 2271 for (;;) { 2272 2273 mutex_enter(&port->fp_mutex); 2274 2275 /* 2276 * Sleep if no work to do right now, or if we want 2277 * to suspend or power-down. 2278 */ 2279 while (port->fp_job_head == NULL || 2280 (port->fp_soft_state & (FP_SOFT_POWER_DOWN | 2281 FP_SOFT_SUSPEND))) { 2282 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info); 2283 cv_wait(&port->fp_cv, &port->fp_mutex); 2284 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex); 2285 } 2286 2287 /* 2288 * OK, we've just been woken up, so retrieve the next entry 2289 * from the head of the job queue for this local port. 2290 */ 2291 job = fctl_deque_job(port); 2292 2293 /* 2294 * Handle all the fp driver's supported job codes here 2295 * in this big honkin' switch. 2296 */ 2297 switch (job->job_code) { 2298 case JOB_PORT_SHUTDOWN: 2299 /* 2300 * fp_port_shutdown() is only called from here. This 2301 * will prepare the local port instance (softstate) 2302 * for detaching. This cancels timeout callbacks, 2303 * executes LOGOs with remote ports, cleans up tables, 2304 * and deallocates data structs. 2305 */ 2306 fp_port_shutdown(port, job); 2307 2308 /* 2309 * This will exit the job thread. 2310 */ 2311 #ifndef __lock_lint 2312 CALLB_CPR_EXIT(&(port->fp_cpr_info)); 2313 #else 2314 mutex_exit(&port->fp_mutex); 2315 #endif 2316 fctl_jobdone(job); 2317 thread_exit(); 2318 2319 /* NOTREACHED */ 2320 2321 case JOB_ATTACH_ULP: { 2322 /* 2323 * This job is spawned in response to a ULP calling 2324 * fc_ulp_add(). 2325 */ 2326 2327 boolean_t do_attach_ulps = B_TRUE; 2328 2329 /* 2330 * If fp is detaching, we don't want to call 2331 * fp_startup_done as this asynchronous 2332 * notification may interfere with the re-attach. 2333 */ 2334 2335 if (port->fp_soft_state & (FP_DETACH_INPROGRESS | 2336 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) { 2337 do_attach_ulps = B_FALSE; 2338 } else { 2339 /* 2340 * We are going to force the transport 2341 * to attach to the ULPs, so set 2342 * fp_ulp_attach. This will keep any 2343 * potential detach from occurring until 2344 * we are done. 2345 */ 2346 port->fp_ulp_attach = 1; 2347 } 2348 2349 mutex_exit(&port->fp_mutex); 2350 2351 /* 2352 * NOTE: Since we just dropped the mutex, there is now 2353 * a race window where the fp_soft_state check above 2354 * could change here. This race is covered because an 2355 * additional check was added in the functions hidden 2356 * under fp_startup_done(). 2357 */ 2358 if (do_attach_ulps == B_TRUE) { 2359 /* 2360 * This goes thru a bit of a convoluted call 2361 * chain before spawning off a DDI taskq 2362 * request to perform the actual attach 2363 * operations. Blocking can occur at a number 2364 * of points. 2365 */ 2366 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 2367 } 2368 job->job_result = FC_SUCCESS; 2369 fctl_jobdone(job); 2370 break; 2371 } 2372 2373 case JOB_ULP_NOTIFY: { 2374 /* 2375 * Pass state change notifications up to any/all 2376 * registered ULPs. 2377 */ 2378 uint32_t statec; 2379 2380 statec = job->job_ulp_listlen; 2381 if (statec == FC_STATE_RESET_REQUESTED) { 2382 port->fp_last_task = port->fp_task; 2383 port->fp_task = FP_TASK_OFFLINE; 2384 fp_port_offline(port, 0); 2385 port->fp_task = port->fp_last_task; 2386 port->fp_last_task = FP_TASK_IDLE; 2387 } 2388 2389 if (--port->fp_statec_busy == 0) { 2390 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2391 } 2392 2393 mutex_exit(&port->fp_mutex); 2394 2395 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP); 2396 fctl_jobdone(job); 2397 break; 2398 } 2399 2400 case JOB_PLOGI_ONE: 2401 /* 2402 * Issue a PLOGI to a single remote port. Multiple 2403 * PLOGIs to different remote ports may occur in 2404 * parallel. 2405 * This can create the fc_remote_port_t if it does not 2406 * already exist. 2407 */ 2408 2409 mutex_exit(&port->fp_mutex); 2410 d_id = (uint32_t *)job->job_private; 2411 pd = fctl_get_remote_port_by_did(port, *d_id); 2412 2413 if (pd) { 2414 mutex_enter(&pd->pd_mutex); 2415 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 2416 pd->pd_login_count++; 2417 mutex_exit(&pd->pd_mutex); 2418 job->job_result = FC_SUCCESS; 2419 fctl_jobdone(job); 2420 break; 2421 } 2422 mutex_exit(&pd->pd_mutex); 2423 } else { 2424 mutex_enter(&port->fp_mutex); 2425 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2426 mutex_exit(&port->fp_mutex); 2427 pd = fp_create_remote_port_by_ns(port, 2428 *d_id, KM_SLEEP); 2429 if (pd == NULL) { 2430 job->job_result = FC_FAILURE; 2431 fctl_jobdone(job); 2432 break; 2433 } 2434 } else { 2435 mutex_exit(&port->fp_mutex); 2436 } 2437 } 2438 2439 job->job_flags |= JOB_TYPE_FP_ASYNC; 2440 job->job_counter = 1; 2441 2442 rval = fp_port_login(port, *d_id, job, 2443 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 2444 2445 if (rval != FC_SUCCESS) { 2446 job->job_result = rval; 2447 fctl_jobdone(job); 2448 } 2449 break; 2450 2451 case JOB_LOGO_ONE: { 2452 /* 2453 * Issue a PLOGO to a single remote port. Multiple 2454 * PLOGOs to different remote ports may occur in 2455 * parallel. 2456 */ 2457 fc_remote_port_t *pd; 2458 2459 #ifndef __lock_lint 2460 ASSERT(job->job_counter > 0); 2461 #endif 2462 2463 pd = (fc_remote_port_t *)job->job_ulp_pkts; 2464 2465 mutex_enter(&pd->pd_mutex); 2466 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 2467 mutex_exit(&pd->pd_mutex); 2468 job->job_result = FC_LOGINREQ; 2469 mutex_exit(&port->fp_mutex); 2470 fctl_jobdone(job); 2471 break; 2472 } 2473 if (pd->pd_login_count > 1) { 2474 pd->pd_login_count--; 2475 mutex_exit(&pd->pd_mutex); 2476 job->job_result = FC_SUCCESS; 2477 mutex_exit(&port->fp_mutex); 2478 fctl_jobdone(job); 2479 break; 2480 } 2481 mutex_exit(&pd->pd_mutex); 2482 mutex_exit(&port->fp_mutex); 2483 job->job_flags |= JOB_TYPE_FP_ASYNC; 2484 (void) fp_logout(port, pd, job); 2485 break; 2486 } 2487 2488 case JOB_FCIO_LOGIN: 2489 /* 2490 * PLOGI initiated at ioctl request. 2491 */ 2492 mutex_exit(&port->fp_mutex); 2493 job->job_result = 2494 fp_fcio_login(port, job->job_private, job); 2495 fctl_jobdone(job); 2496 break; 2497 2498 case JOB_FCIO_LOGOUT: 2499 /* 2500 * PLOGO initiated at ioctl request. 2501 */ 2502 mutex_exit(&port->fp_mutex); 2503 job->job_result = 2504 fp_fcio_logout(port, job->job_private, job); 2505 fctl_jobdone(job); 2506 break; 2507 2508 case JOB_PORT_GETMAP: 2509 case JOB_PORT_GETMAP_PLOGI_ALL: { 2510 port->fp_last_task = port->fp_task; 2511 port->fp_task = FP_TASK_GETMAP; 2512 2513 switch (port->fp_topology) { 2514 case FC_TOP_PRIVATE_LOOP: 2515 job->job_counter = 1; 2516 2517 fp_get_loopmap(port, job); 2518 mutex_exit(&port->fp_mutex); 2519 fp_jobwait(job); 2520 fctl_fillout_map(port, 2521 (fc_portmap_t **)job->job_private, 2522 (uint32_t *)job->job_arg, 1, 0, 0); 2523 fctl_jobdone(job); 2524 mutex_enter(&port->fp_mutex); 2525 break; 2526 2527 case FC_TOP_PUBLIC_LOOP: 2528 case FC_TOP_FABRIC: 2529 mutex_exit(&port->fp_mutex); 2530 job->job_counter = 1; 2531 2532 job->job_result = fp_ns_getmap(port, 2533 job, (fc_portmap_t **)job->job_private, 2534 (uint32_t *)job->job_arg, 2535 FCTL_GAN_START_ID); 2536 fctl_jobdone(job); 2537 mutex_enter(&port->fp_mutex); 2538 break; 2539 2540 case FC_TOP_PT_PT: 2541 mutex_exit(&port->fp_mutex); 2542 fctl_fillout_map(port, 2543 (fc_portmap_t **)job->job_private, 2544 (uint32_t *)job->job_arg, 1, 0, 0); 2545 fctl_jobdone(job); 2546 mutex_enter(&port->fp_mutex); 2547 break; 2548 2549 default: 2550 mutex_exit(&port->fp_mutex); 2551 fctl_jobdone(job); 2552 mutex_enter(&port->fp_mutex); 2553 break; 2554 } 2555 port->fp_task = port->fp_last_task; 2556 port->fp_last_task = FP_TASK_IDLE; 2557 mutex_exit(&port->fp_mutex); 2558 break; 2559 } 2560 2561 case JOB_PORT_OFFLINE: { 2562 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE); 2563 2564 port->fp_last_task = port->fp_task; 2565 port->fp_task = FP_TASK_OFFLINE; 2566 2567 if (port->fp_statec_busy > 2) { 2568 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2569 fp_port_offline(port, 0); 2570 if (--port->fp_statec_busy == 0) { 2571 port->fp_soft_state &= 2572 ~FP_SOFT_IN_STATEC_CB; 2573 } 2574 } else { 2575 fp_port_offline(port, 1); 2576 } 2577 2578 port->fp_task = port->fp_last_task; 2579 port->fp_last_task = FP_TASK_IDLE; 2580 2581 mutex_exit(&port->fp_mutex); 2582 2583 fctl_jobdone(job); 2584 break; 2585 } 2586 2587 case JOB_PORT_STARTUP: { 2588 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2589 if (port->fp_statec_busy > 1) { 2590 mutex_exit(&port->fp_mutex); 2591 break; 2592 } 2593 mutex_exit(&port->fp_mutex); 2594 2595 FP_TRACE(FP_NHEAD2(9, rval), 2596 "Topology discovery failed"); 2597 break; 2598 } 2599 2600 /* 2601 * Attempt building device handles in case 2602 * of private Loop. 2603 */ 2604 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) { 2605 job->job_counter = 1; 2606 2607 fp_get_loopmap(port, job); 2608 mutex_exit(&port->fp_mutex); 2609 fp_jobwait(job); 2610 mutex_enter(&port->fp_mutex); 2611 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 2612 ASSERT(port->fp_total_devices == 0); 2613 port->fp_total_devices = 2614 port->fp_dev_count; 2615 } 2616 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2617 /* 2618 * Hack to avoid state changes going up early 2619 */ 2620 port->fp_statec_busy++; 2621 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 2622 2623 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2624 fp_fabric_online(port, job); 2625 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION; 2626 } 2627 mutex_exit(&port->fp_mutex); 2628 fctl_jobdone(job); 2629 break; 2630 } 2631 2632 case JOB_PORT_ONLINE: { 2633 char *newtop; 2634 char *oldtop; 2635 uint32_t old_top; 2636 2637 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE); 2638 2639 /* 2640 * Bail out early if there are a lot of 2641 * state changes in the pipeline 2642 */ 2643 if (port->fp_statec_busy > 1) { 2644 --port->fp_statec_busy; 2645 mutex_exit(&port->fp_mutex); 2646 fctl_jobdone(job); 2647 break; 2648 } 2649 2650 switch (old_top = port->fp_topology) { 2651 case FC_TOP_PRIVATE_LOOP: 2652 oldtop = "Private Loop"; 2653 break; 2654 2655 case FC_TOP_PUBLIC_LOOP: 2656 oldtop = "Public Loop"; 2657 break; 2658 2659 case FC_TOP_PT_PT: 2660 oldtop = "Point to Point"; 2661 break; 2662 2663 case FC_TOP_FABRIC: 2664 oldtop = "Fabric"; 2665 break; 2666 2667 default: 2668 oldtop = NULL; 2669 break; 2670 } 2671 2672 port->fp_last_task = port->fp_task; 2673 port->fp_task = FP_TASK_ONLINE; 2674 2675 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2676 2677 port->fp_task = port->fp_last_task; 2678 port->fp_last_task = FP_TASK_IDLE; 2679 2680 if (port->fp_statec_busy > 1) { 2681 --port->fp_statec_busy; 2682 mutex_exit(&port->fp_mutex); 2683 break; 2684 } 2685 2686 port->fp_state = FC_STATE_OFFLINE; 2687 2688 FP_TRACE(FP_NHEAD2(9, rval), 2689 "Topology discovery failed"); 2690 2691 if (--port->fp_statec_busy == 0) { 2692 port->fp_soft_state &= 2693 ~FP_SOFT_IN_STATEC_CB; 2694 } 2695 2696 if (port->fp_offline_tid == NULL) { 2697 port->fp_offline_tid = 2698 timeout(fp_offline_timeout, 2699 (caddr_t)port, fp_offline_ticks); 2700 } 2701 2702 mutex_exit(&port->fp_mutex); 2703 break; 2704 } 2705 2706 switch (port->fp_topology) { 2707 case FC_TOP_PRIVATE_LOOP: 2708 newtop = "Private Loop"; 2709 break; 2710 2711 case FC_TOP_PUBLIC_LOOP: 2712 newtop = "Public Loop"; 2713 break; 2714 2715 case FC_TOP_PT_PT: 2716 newtop = "Point to Point"; 2717 break; 2718 2719 case FC_TOP_FABRIC: 2720 newtop = "Fabric"; 2721 break; 2722 2723 default: 2724 newtop = NULL; 2725 break; 2726 } 2727 2728 if (oldtop && newtop && strcmp(oldtop, newtop)) { 2729 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2730 "Change in FC Topology old = %s new = %s", 2731 oldtop, newtop); 2732 } 2733 2734 switch (port->fp_topology) { 2735 case FC_TOP_PRIVATE_LOOP: { 2736 int orphan = (old_top == FC_TOP_FABRIC || 2737 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0; 2738 2739 mutex_exit(&port->fp_mutex); 2740 fp_loop_online(port, job, orphan); 2741 break; 2742 } 2743 2744 case FC_TOP_PUBLIC_LOOP: 2745 /* FALLTHROUGH */ 2746 case FC_TOP_FABRIC: 2747 fp_fabric_online(port, job); 2748 mutex_exit(&port->fp_mutex); 2749 break; 2750 2751 case FC_TOP_PT_PT: 2752 fp_p2p_online(port, job); 2753 mutex_exit(&port->fp_mutex); 2754 break; 2755 2756 default: 2757 if (--port->fp_statec_busy != 0) { 2758 /* 2759 * Watch curiously at what the next 2760 * state transition can do. 2761 */ 2762 mutex_exit(&port->fp_mutex); 2763 break; 2764 } 2765 2766 FP_TRACE(FP_NHEAD2(9, 0), 2767 "Topology Unknown, Offlining the port.."); 2768 2769 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2770 port->fp_state = FC_STATE_OFFLINE; 2771 2772 if (port->fp_offline_tid == NULL) { 2773 port->fp_offline_tid = 2774 timeout(fp_offline_timeout, 2775 (caddr_t)port, fp_offline_ticks); 2776 } 2777 mutex_exit(&port->fp_mutex); 2778 break; 2779 } 2780 2781 mutex_enter(&port->fp_mutex); 2782 2783 port->fp_task = port->fp_last_task; 2784 port->fp_last_task = FP_TASK_IDLE; 2785 2786 mutex_exit(&port->fp_mutex); 2787 2788 fctl_jobdone(job); 2789 break; 2790 } 2791 2792 case JOB_PLOGI_GROUP: { 2793 mutex_exit(&port->fp_mutex); 2794 fp_plogi_group(port, job); 2795 break; 2796 } 2797 2798 case JOB_UNSOL_REQUEST: { 2799 mutex_exit(&port->fp_mutex); 2800 fp_handle_unsol_buf(port, 2801 (fc_unsol_buf_t *)job->job_private, job); 2802 fctl_dealloc_job(job); 2803 break; 2804 } 2805 2806 case JOB_NS_CMD: { 2807 fctl_ns_req_t *ns_cmd; 2808 2809 mutex_exit(&port->fp_mutex); 2810 2811 job->job_flags |= JOB_TYPE_FP_ASYNC; 2812 ns_cmd = (fctl_ns_req_t *)job->job_private; 2813 if (ns_cmd->ns_cmd_code < NS_GA_NXT || 2814 ns_cmd->ns_cmd_code > NS_DA_ID) { 2815 job->job_result = FC_BADCMD; 2816 fctl_jobdone(job); 2817 break; 2818 } 2819 2820 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) { 2821 if (ns_cmd->ns_pd != NULL) { 2822 job->job_result = FC_BADOBJECT; 2823 fctl_jobdone(job); 2824 break; 2825 } 2826 2827 job->job_counter = 1; 2828 2829 rval = fp_ns_reg(port, ns_cmd->ns_pd, 2830 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP); 2831 2832 if (rval != FC_SUCCESS) { 2833 job->job_result = rval; 2834 fctl_jobdone(job); 2835 } 2836 break; 2837 } 2838 job->job_result = FC_SUCCESS; 2839 job->job_counter = 1; 2840 2841 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP); 2842 if (rval != FC_SUCCESS) { 2843 fctl_jobdone(job); 2844 } 2845 break; 2846 } 2847 2848 case JOB_LINK_RESET: { 2849 la_wwn_t *pwwn; 2850 uint32_t topology; 2851 2852 pwwn = (la_wwn_t *)job->job_private; 2853 ASSERT(pwwn != NULL); 2854 2855 topology = port->fp_topology; 2856 mutex_exit(&port->fp_mutex); 2857 2858 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS || 2859 topology == FC_TOP_PRIVATE_LOOP) { 2860 job->job_flags |= JOB_TYPE_FP_ASYNC; 2861 rval = port->fp_fca_tran->fca_reset( 2862 port->fp_fca_handle, FC_FCA_LINK_RESET); 2863 job->job_result = rval; 2864 fp_jobdone(job); 2865 } else { 2866 ASSERT((job->job_flags & 2867 JOB_TYPE_FP_ASYNC) == 0); 2868 2869 if (FC_IS_TOP_SWITCH(topology)) { 2870 rval = fp_remote_lip(port, pwwn, 2871 KM_SLEEP, job); 2872 } else { 2873 rval = FC_FAILURE; 2874 } 2875 if (rval != FC_SUCCESS) { 2876 job->job_result = rval; 2877 } 2878 fctl_jobdone(job); 2879 } 2880 break; 2881 } 2882 2883 default: 2884 mutex_exit(&port->fp_mutex); 2885 job->job_result = FC_BADCMD; 2886 fctl_jobdone(job); 2887 break; 2888 } 2889 } 2890 /* NOTREACHED */ 2891 } 2892 2893 2894 /* 2895 * Perform FC port bring up initialization 2896 */ 2897 static int 2898 fp_port_startup(fc_local_port_t *port, job_request_t *job) 2899 { 2900 int rval; 2901 uint32_t state; 2902 uint32_t src_id; 2903 fc_lilpmap_t *lilp_map; 2904 2905 ASSERT(MUTEX_HELD(&port->fp_mutex)); 2906 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 2907 2908 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;" 2909 " port=%p, job=%p", port, job); 2910 2911 port->fp_topology = FC_TOP_UNKNOWN; 2912 port->fp_port_id.port_id = 0; 2913 state = FC_PORT_STATE_MASK(port->fp_state); 2914 2915 if (state == FC_STATE_OFFLINE) { 2916 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2917 job->job_result = FC_OFFLINE; 2918 mutex_exit(&port->fp_mutex); 2919 fctl_jobdone(job); 2920 mutex_enter(&port->fp_mutex); 2921 return (FC_OFFLINE); 2922 } 2923 2924 if (state == FC_STATE_LOOP) { 2925 port->fp_port_type.port_type = FC_NS_PORT_NL; 2926 mutex_exit(&port->fp_mutex); 2927 2928 lilp_map = &port->fp_lilp_map; 2929 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) { 2930 job->job_result = FC_FAILURE; 2931 fctl_jobdone(job); 2932 2933 FP_TRACE(FP_NHEAD1(9, rval), 2934 "LILP map Invalid or not present"); 2935 mutex_enter(&port->fp_mutex); 2936 return (FC_FAILURE); 2937 } 2938 2939 if (lilp_map->lilp_length == 0) { 2940 job->job_result = FC_NO_MAP; 2941 fctl_jobdone(job); 2942 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2943 "LILP map length zero"); 2944 mutex_enter(&port->fp_mutex); 2945 return (FC_NO_MAP); 2946 } 2947 src_id = lilp_map->lilp_myalpa & 0xFF; 2948 } else { 2949 fc_remote_port_t *pd; 2950 fc_fca_pm_t pm; 2951 fc_fca_p2p_info_t p2p_info; 2952 int pd_recepient; 2953 2954 /* 2955 * Get P2P remote port info if possible 2956 */ 2957 bzero((caddr_t)&pm, sizeof (pm)); 2958 2959 pm.pm_cmd_flags = FC_FCA_PM_READ; 2960 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO; 2961 pm.pm_data_len = sizeof (fc_fca_p2p_info_t); 2962 pm.pm_data_buf = (caddr_t)&p2p_info; 2963 2964 rval = port->fp_fca_tran->fca_port_manage( 2965 port->fp_fca_handle, &pm); 2966 2967 if (rval == FC_SUCCESS) { 2968 port->fp_port_id.port_id = p2p_info.fca_d_id; 2969 port->fp_port_type.port_type = FC_NS_PORT_N; 2970 port->fp_topology = FC_TOP_PT_PT; 2971 port->fp_total_devices = 1; 2972 pd_recepient = fctl_wwn_cmp( 2973 &port->fp_service_params.nport_ww_name, 2974 &p2p_info.pwwn) < 0 ? 2975 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR; 2976 mutex_exit(&port->fp_mutex); 2977 pd = fctl_create_remote_port(port, 2978 &p2p_info.nwwn, 2979 &p2p_info.pwwn, 2980 p2p_info.d_id, 2981 pd_recepient, KM_NOSLEEP); 2982 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;" 2983 " P2P port=%p pd=%p fp %x pd %x", port, pd, 2984 port->fp_port_id.port_id, p2p_info.d_id); 2985 mutex_enter(&port->fp_mutex); 2986 return (FC_SUCCESS); 2987 } 2988 port->fp_port_type.port_type = FC_NS_PORT_N; 2989 mutex_exit(&port->fp_mutex); 2990 src_id = 0; 2991 } 2992 2993 job->job_counter = 1; 2994 job->job_result = FC_SUCCESS; 2995 2996 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE, 2997 KM_SLEEP)) != FC_SUCCESS) { 2998 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2999 job->job_result = FC_FAILURE; 3000 fctl_jobdone(job); 3001 3002 mutex_enter(&port->fp_mutex); 3003 if (port->fp_statec_busy <= 1) { 3004 mutex_exit(&port->fp_mutex); 3005 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL, 3006 "Couldn't transport FLOGI"); 3007 mutex_enter(&port->fp_mutex); 3008 } 3009 return (FC_FAILURE); 3010 } 3011 3012 fp_jobwait(job); 3013 3014 mutex_enter(&port->fp_mutex); 3015 if (job->job_result == FC_SUCCESS) { 3016 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3017 mutex_exit(&port->fp_mutex); 3018 fp_ns_init(port, job, KM_SLEEP); 3019 mutex_enter(&port->fp_mutex); 3020 } 3021 } else { 3022 if (state == FC_STATE_LOOP) { 3023 port->fp_topology = FC_TOP_PRIVATE_LOOP; 3024 port->fp_port_id.port_id = 3025 port->fp_lilp_map.lilp_myalpa & 0xFF; 3026 } 3027 } 3028 3029 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p", 3030 port, job); 3031 3032 return (FC_SUCCESS); 3033 } 3034 3035 3036 /* 3037 * Perform ULP invocations following FC port startup 3038 */ 3039 /* ARGSUSED */ 3040 static void 3041 fp_startup_done(opaque_t arg, uchar_t result) 3042 { 3043 fc_local_port_t *port = arg; 3044 3045 fp_attach_ulps(port, FC_CMD_ATTACH); 3046 3047 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port); 3048 } 3049 3050 3051 /* 3052 * Perform ULP port attach 3053 */ 3054 static void 3055 fp_ulp_port_attach(void *arg) 3056 { 3057 fp_soft_attach_t *att = (fp_soft_attach_t *)arg; 3058 fc_local_port_t *port = att->att_port; 3059 3060 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3061 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd); 3062 3063 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage); 3064 3065 if (att->att_need_pm_idle == B_TRUE) { 3066 fctl_idle_port(port); 3067 } 3068 3069 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3070 " ULPs end; port=%p, cmd=%x", port, att->att_cmd); 3071 3072 mutex_enter(&att->att_port->fp_mutex); 3073 att->att_port->fp_ulp_attach = 0; 3074 3075 port->fp_task = port->fp_last_task; 3076 port->fp_last_task = FP_TASK_IDLE; 3077 3078 cv_signal(&att->att_port->fp_attach_cv); 3079 3080 mutex_exit(&att->att_port->fp_mutex); 3081 3082 kmem_free(att, sizeof (fp_soft_attach_t)); 3083 } 3084 3085 /* 3086 * Entry point to funnel all requests down to FCAs 3087 */ 3088 static int 3089 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle) 3090 { 3091 int rval; 3092 3093 mutex_enter(&port->fp_mutex); 3094 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL && 3095 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) == 3096 FC_STATE_OFFLINE))) { 3097 /* 3098 * This means there is more than one state change 3099 * at this point of time - Since they are processed 3100 * serially, any processing of the current one should 3101 * be failed, failed and move up in processing the next 3102 */ 3103 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS; 3104 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3105 if (cmd->cmd_job) { 3106 /* 3107 * A state change that is going to be invalidated 3108 * by another one already in the port driver's queue 3109 * need not go up to all ULPs. This will minimize 3110 * needless processing and ripples in ULP modules 3111 */ 3112 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3113 } 3114 mutex_exit(&port->fp_mutex); 3115 return (FC_STATEC_BUSY); 3116 } 3117 3118 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3119 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE; 3120 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3121 mutex_exit(&port->fp_mutex); 3122 3123 return (FC_OFFLINE); 3124 } 3125 mutex_exit(&port->fp_mutex); 3126 3127 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt); 3128 if (rval != FC_SUCCESS) { 3129 if (rval == FC_TRAN_BUSY) { 3130 cmd->cmd_retry_interval = fp_retry_delay; 3131 rval = fp_retry_cmd(&cmd->cmd_pkt); 3132 if (rval == FC_FAILURE) { 3133 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY; 3134 } 3135 } 3136 } else { 3137 mutex_enter(&port->fp_mutex); 3138 port->fp_out_fpcmds++; 3139 mutex_exit(&port->fp_mutex); 3140 } 3141 3142 return (rval); 3143 } 3144 3145 3146 /* 3147 * Each time a timeout kicks in, walk the wait queue, decrement the 3148 * the retry_interval, when the retry_interval becomes less than 3149 * or equal to zero, re-transport the command: If the re-transport 3150 * fails with BUSY, enqueue the command in the wait queue. 3151 * 3152 * In order to prevent looping forever because of commands enqueued 3153 * from within this function itself, save the current tail pointer 3154 * (in cur_tail) and exit the loop after serving this command. 3155 */ 3156 static void 3157 fp_resendcmd(void *port_handle) 3158 { 3159 int rval; 3160 fc_local_port_t *port; 3161 fp_cmd_t *cmd; 3162 fp_cmd_t *cur_tail; 3163 3164 port = port_handle; 3165 mutex_enter(&port->fp_mutex); 3166 cur_tail = port->fp_wait_tail; 3167 mutex_exit(&port->fp_mutex); 3168 3169 while ((cmd = fp_deque_cmd(port)) != NULL) { 3170 cmd->cmd_retry_interval -= fp_retry_ticker; 3171 /* Check if we are detaching */ 3172 if (port->fp_soft_state & 3173 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) { 3174 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 3175 cmd->cmd_pkt.pkt_reason = 0; 3176 fp_iodone(cmd); 3177 } else if (cmd->cmd_retry_interval <= 0) { 3178 rval = cmd->cmd_transport(port->fp_fca_handle, 3179 &cmd->cmd_pkt); 3180 3181 if (rval != FC_SUCCESS) { 3182 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) { 3183 if (--cmd->cmd_retry_count) { 3184 fp_enque_cmd(port, cmd); 3185 if (cmd == cur_tail) { 3186 break; 3187 } 3188 continue; 3189 } 3190 cmd->cmd_pkt.pkt_state = 3191 FC_PKT_TRAN_BSY; 3192 } else { 3193 cmd->cmd_pkt.pkt_state = 3194 FC_PKT_TRAN_ERROR; 3195 } 3196 cmd->cmd_pkt.pkt_reason = 0; 3197 fp_iodone(cmd); 3198 } else { 3199 mutex_enter(&port->fp_mutex); 3200 port->fp_out_fpcmds++; 3201 mutex_exit(&port->fp_mutex); 3202 } 3203 } else { 3204 fp_enque_cmd(port, cmd); 3205 } 3206 3207 if (cmd == cur_tail) { 3208 break; 3209 } 3210 } 3211 3212 mutex_enter(&port->fp_mutex); 3213 if (port->fp_wait_head) { 3214 timeout_id_t tid; 3215 3216 mutex_exit(&port->fp_mutex); 3217 tid = timeout(fp_resendcmd, (caddr_t)port, 3218 fp_retry_ticks); 3219 mutex_enter(&port->fp_mutex); 3220 port->fp_wait_tid = tid; 3221 } else { 3222 port->fp_wait_tid = NULL; 3223 } 3224 mutex_exit(&port->fp_mutex); 3225 } 3226 3227 3228 /* 3229 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here. 3230 * 3231 * Yes, as you can see below, cmd_retry_count is used here too. That means 3232 * the retries for BUSY are less if there were transport failures (transport 3233 * failure means fca_transport failure). The goal is not to exceed overall 3234 * retries set in the cmd_retry_count (whatever may be the reason for retry) 3235 * 3236 * Return Values: 3237 * FC_SUCCESS 3238 * FC_FAILURE 3239 */ 3240 static int 3241 fp_retry_cmd(fc_packet_t *pkt) 3242 { 3243 fp_cmd_t *cmd; 3244 3245 cmd = pkt->pkt_ulp_private; 3246 3247 if (--cmd->cmd_retry_count) { 3248 fp_enque_cmd(cmd->cmd_port, cmd); 3249 return (FC_SUCCESS); 3250 } else { 3251 return (FC_FAILURE); 3252 } 3253 } 3254 3255 3256 /* 3257 * Queue up FC packet for deferred retry 3258 */ 3259 static void 3260 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd) 3261 { 3262 timeout_id_t tid; 3263 3264 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3265 3266 #ifdef DEBUG 3267 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt, 3268 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id); 3269 #endif 3270 3271 mutex_enter(&port->fp_mutex); 3272 if (port->fp_wait_tail) { 3273 port->fp_wait_tail->cmd_next = cmd; 3274 port->fp_wait_tail = cmd; 3275 } else { 3276 ASSERT(port->fp_wait_head == NULL); 3277 port->fp_wait_head = port->fp_wait_tail = cmd; 3278 if (port->fp_wait_tid == NULL) { 3279 mutex_exit(&port->fp_mutex); 3280 tid = timeout(fp_resendcmd, (caddr_t)port, 3281 fp_retry_ticks); 3282 mutex_enter(&port->fp_mutex); 3283 port->fp_wait_tid = tid; 3284 } 3285 } 3286 mutex_exit(&port->fp_mutex); 3287 } 3288 3289 3290 /* 3291 * Handle all RJT codes 3292 */ 3293 static int 3294 fp_handle_reject(fc_packet_t *pkt) 3295 { 3296 int rval = FC_FAILURE; 3297 uchar_t next_class; 3298 fp_cmd_t *cmd; 3299 fc_local_port_t *port; 3300 3301 cmd = pkt->pkt_ulp_private; 3302 port = cmd->cmd_port; 3303 3304 switch (pkt->pkt_state) { 3305 case FC_PKT_FABRIC_RJT: 3306 case FC_PKT_NPORT_RJT: 3307 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) { 3308 next_class = fp_get_nextclass(cmd->cmd_port, 3309 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 3310 3311 if (next_class == FC_TRAN_CLASS_INVALID) { 3312 return (rval); 3313 } 3314 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class; 3315 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 3316 3317 rval = fp_sendcmd(cmd->cmd_port, cmd, 3318 cmd->cmd_port->fp_fca_handle); 3319 3320 if (rval != FC_SUCCESS) { 3321 pkt->pkt_state = FC_PKT_TRAN_ERROR; 3322 } 3323 } 3324 break; 3325 3326 case FC_PKT_LS_RJT: 3327 case FC_PKT_BA_RJT: 3328 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) || 3329 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) { 3330 cmd->cmd_retry_interval = fp_retry_delay; 3331 rval = fp_retry_cmd(pkt); 3332 } 3333 break; 3334 3335 case FC_PKT_FS_RJT: 3336 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) || 3337 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) && 3338 (pkt->pkt_expln == 0x00))) { 3339 cmd->cmd_retry_interval = fp_retry_delay; 3340 rval = fp_retry_cmd(pkt); 3341 } 3342 break; 3343 3344 case FC_PKT_LOCAL_RJT: 3345 if (pkt->pkt_reason == FC_REASON_QFULL) { 3346 cmd->cmd_retry_interval = fp_retry_delay; 3347 rval = fp_retry_cmd(pkt); 3348 } 3349 break; 3350 3351 default: 3352 FP_TRACE(FP_NHEAD1(1, 0), 3353 "fp_handle_reject(): Invalid pkt_state"); 3354 break; 3355 } 3356 3357 return (rval); 3358 } 3359 3360 3361 /* 3362 * Return the next class of service supported by the FCA 3363 */ 3364 static uchar_t 3365 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class) 3366 { 3367 uchar_t next_class; 3368 3369 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3370 3371 switch (cur_class) { 3372 case FC_TRAN_CLASS_INVALID: 3373 if (port->fp_cos & FC_NS_CLASS1) { 3374 next_class = FC_TRAN_CLASS1; 3375 break; 3376 } 3377 /* FALLTHROUGH */ 3378 3379 case FC_TRAN_CLASS1: 3380 if (port->fp_cos & FC_NS_CLASS2) { 3381 next_class = FC_TRAN_CLASS2; 3382 break; 3383 } 3384 /* FALLTHROUGH */ 3385 3386 case FC_TRAN_CLASS2: 3387 if (port->fp_cos & FC_NS_CLASS3) { 3388 next_class = FC_TRAN_CLASS3; 3389 break; 3390 } 3391 /* FALLTHROUGH */ 3392 3393 case FC_TRAN_CLASS3: 3394 default: 3395 next_class = FC_TRAN_CLASS_INVALID; 3396 break; 3397 } 3398 3399 return (next_class); 3400 } 3401 3402 3403 /* 3404 * Determine if a class of service is supported by the FCA 3405 */ 3406 static int 3407 fp_is_class_supported(uint32_t cos, uchar_t tran_class) 3408 { 3409 int rval; 3410 3411 switch (tran_class) { 3412 case FC_TRAN_CLASS1: 3413 if (cos & FC_NS_CLASS1) { 3414 rval = FC_SUCCESS; 3415 } else { 3416 rval = FC_FAILURE; 3417 } 3418 break; 3419 3420 case FC_TRAN_CLASS2: 3421 if (cos & FC_NS_CLASS2) { 3422 rval = FC_SUCCESS; 3423 } else { 3424 rval = FC_FAILURE; 3425 } 3426 break; 3427 3428 case FC_TRAN_CLASS3: 3429 if (cos & FC_NS_CLASS3) { 3430 rval = FC_SUCCESS; 3431 } else { 3432 rval = FC_FAILURE; 3433 } 3434 break; 3435 3436 default: 3437 rval = FC_FAILURE; 3438 break; 3439 } 3440 3441 return (rval); 3442 } 3443 3444 3445 /* 3446 * Dequeue FC packet for retry 3447 */ 3448 static fp_cmd_t * 3449 fp_deque_cmd(fc_local_port_t *port) 3450 { 3451 fp_cmd_t *cmd; 3452 3453 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3454 3455 mutex_enter(&port->fp_mutex); 3456 3457 if (port->fp_wait_head == NULL) { 3458 /* 3459 * To avoid races, NULL the fp_wait_tid as 3460 * we are about to exit the timeout thread. 3461 */ 3462 port->fp_wait_tid = NULL; 3463 mutex_exit(&port->fp_mutex); 3464 return (NULL); 3465 } 3466 3467 cmd = port->fp_wait_head; 3468 port->fp_wait_head = cmd->cmd_next; 3469 cmd->cmd_next = NULL; 3470 3471 if (port->fp_wait_head == NULL) { 3472 port->fp_wait_tail = NULL; 3473 } 3474 mutex_exit(&port->fp_mutex); 3475 3476 return (cmd); 3477 } 3478 3479 3480 /* 3481 * Wait for job completion 3482 */ 3483 static void 3484 fp_jobwait(job_request_t *job) 3485 { 3486 sema_p(&job->job_port_sema); 3487 } 3488 3489 3490 /* 3491 * Convert FC packet state to FC errno 3492 */ 3493 int 3494 fp_state_to_rval(uchar_t state) 3495 { 3496 int count; 3497 3498 for (count = 0; count < sizeof (fp_xlat) / 3499 sizeof (fp_xlat[0]); count++) { 3500 if (fp_xlat[count].xlat_state == state) { 3501 return (fp_xlat[count].xlat_rval); 3502 } 3503 } 3504 3505 return (FC_FAILURE); 3506 } 3507 3508 3509 /* 3510 * For Synchronous I/O requests, the caller is 3511 * expected to do fctl_jobdone(if necessary) 3512 * 3513 * We want to preserve at least one failure in the 3514 * job_result if it happens. 3515 * 3516 */ 3517 static void 3518 fp_iodone(fp_cmd_t *cmd) 3519 { 3520 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt; 3521 job_request_t *job = cmd->cmd_job; 3522 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd; 3523 3524 ASSERT(job != NULL); 3525 ASSERT(cmd->cmd_port != NULL); 3526 ASSERT(&cmd->cmd_pkt != NULL); 3527 3528 mutex_enter(&job->job_mutex); 3529 if (job->job_result == FC_SUCCESS) { 3530 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state); 3531 } 3532 mutex_exit(&job->job_mutex); 3533 3534 if (pd) { 3535 mutex_enter(&pd->pd_mutex); 3536 pd->pd_flags = PD_IDLE; 3537 mutex_exit(&pd->pd_mutex); 3538 } 3539 3540 if (ulp_pkt) { 3541 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR && 3542 FP_IS_PKT_ERROR(ulp_pkt)) { 3543 fc_local_port_t *port; 3544 fc_remote_node_t *node; 3545 3546 port = cmd->cmd_port; 3547 3548 mutex_enter(&pd->pd_mutex); 3549 pd->pd_state = PORT_DEVICE_INVALID; 3550 pd->pd_ref_count--; 3551 node = pd->pd_remote_nodep; 3552 mutex_exit(&pd->pd_mutex); 3553 3554 ASSERT(node != NULL); 3555 ASSERT(port != NULL); 3556 3557 if (fctl_destroy_remote_port(port, pd) == 0) { 3558 fctl_destroy_remote_node(node); 3559 } 3560 3561 ulp_pkt->pkt_pd = NULL; 3562 } 3563 3564 ulp_pkt->pkt_comp(ulp_pkt); 3565 } 3566 3567 fp_free_pkt(cmd); 3568 fp_jobdone(job); 3569 } 3570 3571 3572 /* 3573 * Job completion handler 3574 */ 3575 static void 3576 fp_jobdone(job_request_t *job) 3577 { 3578 mutex_enter(&job->job_mutex); 3579 ASSERT(job->job_counter > 0); 3580 3581 if (--job->job_counter != 0) { 3582 mutex_exit(&job->job_mutex); 3583 return; 3584 } 3585 3586 if (job->job_ulp_pkts) { 3587 ASSERT(job->job_ulp_listlen > 0); 3588 kmem_free(job->job_ulp_pkts, 3589 sizeof (fc_packet_t *) * job->job_ulp_listlen); 3590 } 3591 3592 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3593 mutex_exit(&job->job_mutex); 3594 fctl_jobdone(job); 3595 } else { 3596 mutex_exit(&job->job_mutex); 3597 sema_v(&job->job_port_sema); 3598 } 3599 } 3600 3601 3602 /* 3603 * Try to perform shutdown of a port during a detach. No return 3604 * value since the detach should not fail because the port shutdown 3605 * failed. 3606 */ 3607 static void 3608 fp_port_shutdown(fc_local_port_t *port, job_request_t *job) 3609 { 3610 int index; 3611 int count; 3612 int flags; 3613 fp_cmd_t *cmd; 3614 struct pwwn_hash *head; 3615 fc_remote_port_t *pd; 3616 3617 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3618 3619 job->job_result = FC_SUCCESS; 3620 3621 if (port->fp_taskq) { 3622 /* 3623 * We must release the mutex here to ensure that other 3624 * potential jobs can complete their processing. Many 3625 * also need this mutex. 3626 */ 3627 mutex_exit(&port->fp_mutex); 3628 taskq_wait(port->fp_taskq); 3629 mutex_enter(&port->fp_mutex); 3630 } 3631 3632 if (port->fp_offline_tid) { 3633 timeout_id_t tid; 3634 3635 tid = port->fp_offline_tid; 3636 port->fp_offline_tid = NULL; 3637 mutex_exit(&port->fp_mutex); 3638 (void) untimeout(tid); 3639 mutex_enter(&port->fp_mutex); 3640 } 3641 3642 if (port->fp_wait_tid) { 3643 timeout_id_t tid; 3644 3645 tid = port->fp_wait_tid; 3646 port->fp_wait_tid = NULL; 3647 mutex_exit(&port->fp_mutex); 3648 (void) untimeout(tid); 3649 } else { 3650 mutex_exit(&port->fp_mutex); 3651 } 3652 3653 /* 3654 * While we cancel the timeout, let's also return the 3655 * the outstanding requests back to the callers. 3656 */ 3657 while ((cmd = fp_deque_cmd(port)) != NULL) { 3658 ASSERT(cmd->cmd_job != NULL); 3659 cmd->cmd_job->job_result = FC_OFFLINE; 3660 fp_iodone(cmd); 3661 } 3662 3663 /* 3664 * Gracefully LOGO with all the devices logged in. 3665 */ 3666 mutex_enter(&port->fp_mutex); 3667 3668 for (count = index = 0; index < pwwn_table_size; index++) { 3669 head = &port->fp_pwwn_table[index]; 3670 pd = head->pwwn_head; 3671 while (pd != NULL) { 3672 mutex_enter(&pd->pd_mutex); 3673 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3674 count++; 3675 } 3676 mutex_exit(&pd->pd_mutex); 3677 pd = pd->pd_wwn_hnext; 3678 } 3679 } 3680 3681 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3682 flags = job->job_flags; 3683 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 3684 } else { 3685 flags = 0; 3686 } 3687 if (count) { 3688 job->job_counter = count; 3689 3690 for (index = 0; index < pwwn_table_size; index++) { 3691 head = &port->fp_pwwn_table[index]; 3692 pd = head->pwwn_head; 3693 while (pd != NULL) { 3694 mutex_enter(&pd->pd_mutex); 3695 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3696 ASSERT(pd->pd_login_count > 0); 3697 /* 3698 * Force the counter to ONE in order 3699 * for us to really send LOGO els. 3700 */ 3701 pd->pd_login_count = 1; 3702 mutex_exit(&pd->pd_mutex); 3703 mutex_exit(&port->fp_mutex); 3704 (void) fp_logout(port, pd, job); 3705 mutex_enter(&port->fp_mutex); 3706 } else { 3707 mutex_exit(&pd->pd_mutex); 3708 } 3709 pd = pd->pd_wwn_hnext; 3710 } 3711 } 3712 mutex_exit(&port->fp_mutex); 3713 fp_jobwait(job); 3714 } else { 3715 mutex_exit(&port->fp_mutex); 3716 } 3717 3718 if (job->job_result != FC_SUCCESS) { 3719 FP_TRACE(FP_NHEAD1(9, 0), 3720 "Can't logout all devices. Proceeding with" 3721 " port shutdown"); 3722 job->job_result = FC_SUCCESS; 3723 } 3724 3725 fctl_destroy_all_remote_ports(port); 3726 3727 mutex_enter(&port->fp_mutex); 3728 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3729 mutex_exit(&port->fp_mutex); 3730 fp_ns_fini(port, job); 3731 } else { 3732 mutex_exit(&port->fp_mutex); 3733 } 3734 3735 if (flags) { 3736 job->job_flags = flags; 3737 } 3738 3739 mutex_enter(&port->fp_mutex); 3740 3741 } 3742 3743 3744 /* 3745 * Build the port driver's data structures based on the AL_PA list 3746 */ 3747 static void 3748 fp_get_loopmap(fc_local_port_t *port, job_request_t *job) 3749 { 3750 int rval; 3751 int flag; 3752 int count; 3753 uint32_t d_id; 3754 fc_remote_port_t *pd; 3755 fc_lilpmap_t *lilp_map; 3756 3757 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3758 3759 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3760 job->job_result = FC_OFFLINE; 3761 mutex_exit(&port->fp_mutex); 3762 fp_jobdone(job); 3763 mutex_enter(&port->fp_mutex); 3764 return; 3765 } 3766 3767 if (port->fp_lilp_map.lilp_length == 0) { 3768 mutex_exit(&port->fp_mutex); 3769 job->job_result = FC_NO_MAP; 3770 fp_jobdone(job); 3771 mutex_enter(&port->fp_mutex); 3772 return; 3773 } 3774 mutex_exit(&port->fp_mutex); 3775 3776 lilp_map = &port->fp_lilp_map; 3777 job->job_counter = lilp_map->lilp_length; 3778 3779 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) { 3780 flag = FP_CMD_PLOGI_RETAIN; 3781 } else { 3782 flag = FP_CMD_PLOGI_DONT_CARE; 3783 } 3784 3785 for (count = 0; count < lilp_map->lilp_length; count++) { 3786 d_id = lilp_map->lilp_alpalist[count]; 3787 3788 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3789 fp_jobdone(job); 3790 continue; 3791 } 3792 3793 pd = fctl_get_remote_port_by_did(port, d_id); 3794 if (pd) { 3795 mutex_enter(&pd->pd_mutex); 3796 if (flag == FP_CMD_PLOGI_DONT_CARE || 3797 pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3798 mutex_exit(&pd->pd_mutex); 3799 fp_jobdone(job); 3800 continue; 3801 } 3802 mutex_exit(&pd->pd_mutex); 3803 } 3804 3805 rval = fp_port_login(port, d_id, job, flag, 3806 KM_SLEEP, pd, NULL); 3807 if (rval != FC_SUCCESS) { 3808 fp_jobdone(job); 3809 } 3810 } 3811 3812 mutex_enter(&port->fp_mutex); 3813 } 3814 3815 3816 /* 3817 * Perform loop ONLINE processing 3818 */ 3819 static void 3820 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan) 3821 { 3822 int count; 3823 int rval; 3824 uint32_t d_id; 3825 uint32_t listlen; 3826 fc_lilpmap_t *lilp_map; 3827 fc_remote_port_t *pd; 3828 fc_portmap_t *changelist; 3829 3830 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3831 3832 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p", 3833 port, job); 3834 3835 lilp_map = &port->fp_lilp_map; 3836 3837 if (lilp_map->lilp_length) { 3838 mutex_enter(&port->fp_mutex); 3839 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 3840 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 3841 mutex_exit(&port->fp_mutex); 3842 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000)); 3843 } else { 3844 mutex_exit(&port->fp_mutex); 3845 } 3846 3847 job->job_counter = lilp_map->lilp_length; 3848 3849 for (count = 0; count < lilp_map->lilp_length; count++) { 3850 d_id = lilp_map->lilp_alpalist[count]; 3851 3852 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3853 fp_jobdone(job); 3854 continue; 3855 } 3856 3857 pd = fctl_get_remote_port_by_did(port, d_id); 3858 if (pd != NULL) { 3859 #ifdef DEBUG 3860 mutex_enter(&pd->pd_mutex); 3861 if (pd->pd_recepient == PD_PLOGI_INITIATOR) { 3862 ASSERT(pd->pd_type != PORT_DEVICE_OLD); 3863 } 3864 mutex_exit(&pd->pd_mutex); 3865 #endif 3866 fp_jobdone(job); 3867 continue; 3868 } 3869 3870 rval = fp_port_login(port, d_id, job, 3871 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL); 3872 3873 if (rval != FC_SUCCESS) { 3874 fp_jobdone(job); 3875 } 3876 } 3877 fp_jobwait(job); 3878 } 3879 listlen = 0; 3880 changelist = NULL; 3881 3882 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3883 mutex_enter(&port->fp_mutex); 3884 ASSERT(port->fp_statec_busy > 0); 3885 if (port->fp_statec_busy == 1) { 3886 mutex_exit(&port->fp_mutex); 3887 fctl_fillout_map(port, &changelist, &listlen, 3888 1, 0, orphan); 3889 3890 mutex_enter(&port->fp_mutex); 3891 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 3892 ASSERT(port->fp_total_devices == 0); 3893 port->fp_total_devices = port->fp_dev_count; 3894 } 3895 } else { 3896 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3897 } 3898 mutex_exit(&port->fp_mutex); 3899 } 3900 3901 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3902 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 3903 listlen, listlen, KM_SLEEP); 3904 } else { 3905 mutex_enter(&port->fp_mutex); 3906 if (--port->fp_statec_busy == 0) { 3907 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 3908 } 3909 ASSERT(changelist == NULL && listlen == 0); 3910 mutex_exit(&port->fp_mutex); 3911 } 3912 3913 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p", 3914 port, job); 3915 } 3916 3917 3918 /* 3919 * Get an Arbitrated Loop map from the underlying FCA 3920 */ 3921 static int 3922 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map) 3923 { 3924 int rval; 3925 3926 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p", 3927 port, lilp_map); 3928 3929 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t)); 3930 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map); 3931 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */ 3932 3933 if (rval != FC_SUCCESS) { 3934 rval = FC_NO_MAP; 3935 } else if (lilp_map->lilp_length == 0 && 3936 (lilp_map->lilp_magic >= MAGIC_LISM && 3937 lilp_map->lilp_magic < MAGIC_LIRP)) { 3938 uchar_t lilp_length; 3939 3940 /* 3941 * Since the map length is zero, provide all 3942 * the valid AL_PAs for NL_ports discovery. 3943 */ 3944 lilp_length = sizeof (fp_valid_alpas) / 3945 sizeof (fp_valid_alpas[0]); 3946 lilp_map->lilp_length = lilp_length; 3947 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist, 3948 lilp_length); 3949 } else { 3950 rval = fp_validate_lilp_map(lilp_map); 3951 3952 if (rval == FC_SUCCESS) { 3953 mutex_enter(&port->fp_mutex); 3954 port->fp_total_devices = lilp_map->lilp_length - 1; 3955 mutex_exit(&port->fp_mutex); 3956 } 3957 } 3958 3959 mutex_enter(&port->fp_mutex); 3960 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) { 3961 port->fp_soft_state |= FP_SOFT_BAD_LINK; 3962 mutex_exit(&port->fp_mutex); 3963 3964 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle, 3965 FC_FCA_RESET_CORE) != FC_SUCCESS) { 3966 FP_TRACE(FP_NHEAD1(9, 0), 3967 "FCA reset failed after LILP map was found" 3968 " to be invalid"); 3969 } 3970 } else if (rval == FC_SUCCESS) { 3971 port->fp_soft_state &= ~FP_SOFT_BAD_LINK; 3972 mutex_exit(&port->fp_mutex); 3973 } else { 3974 mutex_exit(&port->fp_mutex); 3975 } 3976 3977 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port, 3978 lilp_map); 3979 3980 return (rval); 3981 } 3982 3983 3984 /* 3985 * Perform Fabric Login: 3986 * 3987 * Return Values: 3988 * FC_SUCCESS 3989 * FC_FAILURE 3990 * FC_NOMEM 3991 * FC_TRANSPORT_ERROR 3992 * and a lot others defined in fc_error.h 3993 */ 3994 static int 3995 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job, 3996 int flag, int sleep) 3997 { 3998 int rval; 3999 fp_cmd_t *cmd; 4000 uchar_t class; 4001 4002 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4003 4004 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p", 4005 port, job); 4006 4007 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4008 if (class == FC_TRAN_CLASS_INVALID) { 4009 return (FC_ELS_BAD); 4010 } 4011 4012 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4013 sizeof (la_els_logi_t), sleep, NULL); 4014 if (cmd == NULL) { 4015 return (FC_NOMEM); 4016 } 4017 4018 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4019 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4020 cmd->cmd_flags = flag; 4021 cmd->cmd_retry_count = fp_retry_count; 4022 cmd->cmd_ulp_pkt = NULL; 4023 4024 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr, 4025 job, LA_ELS_FLOGI); 4026 4027 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 4028 if (rval != FC_SUCCESS) { 4029 fp_free_pkt(cmd); 4030 } 4031 4032 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p", 4033 port, job); 4034 4035 return (rval); 4036 } 4037 4038 4039 /* 4040 * In some scenarios such as private loop device discovery period 4041 * the fc_remote_port_t data structure isn't allocated. The allocation 4042 * is done when the PLOGI is successful. In some other scenarios 4043 * such as Fabric topology, the fc_remote_port_t is already created 4044 * and initialized with appropriate values (as the NS provides 4045 * them) 4046 */ 4047 static int 4048 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job, 4049 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt) 4050 { 4051 uchar_t class; 4052 fp_cmd_t *cmd; 4053 uint32_t src_id; 4054 fc_remote_port_t *tmp_pd; 4055 int relogin; 4056 int found = 0; 4057 4058 #ifdef DEBUG 4059 if (pd == NULL) { 4060 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL); 4061 } 4062 #endif 4063 ASSERT(job->job_counter > 0); 4064 4065 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4066 if (class == FC_TRAN_CLASS_INVALID) { 4067 return (FC_ELS_BAD); 4068 } 4069 4070 mutex_enter(&port->fp_mutex); 4071 tmp_pd = fctl_lookup_pd_by_did(port, d_id); 4072 mutex_exit(&port->fp_mutex); 4073 4074 relogin = 1; 4075 if (tmp_pd) { 4076 mutex_enter(&tmp_pd->pd_mutex); 4077 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) && 4078 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) { 4079 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN; 4080 relogin = 0; 4081 } 4082 mutex_exit(&tmp_pd->pd_mutex); 4083 } 4084 4085 if (!relogin) { 4086 mutex_enter(&tmp_pd->pd_mutex); 4087 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4088 cmd_flag |= FP_CMD_PLOGI_RETAIN; 4089 } 4090 mutex_exit(&tmp_pd->pd_mutex); 4091 4092 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 4093 sizeof (la_els_adisc_t), sleep, tmp_pd); 4094 if (cmd == NULL) { 4095 return (FC_NOMEM); 4096 } 4097 4098 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4099 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4100 cmd->cmd_flags = cmd_flag; 4101 cmd->cmd_retry_count = fp_retry_count; 4102 cmd->cmd_ulp_pkt = ulp_pkt; 4103 4104 mutex_enter(&port->fp_mutex); 4105 mutex_enter(&tmp_pd->pd_mutex); 4106 fp_adisc_init(cmd, job); 4107 mutex_exit(&tmp_pd->pd_mutex); 4108 mutex_exit(&port->fp_mutex); 4109 4110 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t); 4111 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t); 4112 4113 } else { 4114 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4115 sizeof (la_els_logi_t), sleep, pd); 4116 if (cmd == NULL) { 4117 return (FC_NOMEM); 4118 } 4119 4120 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4121 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4122 cmd->cmd_flags = cmd_flag; 4123 cmd->cmd_retry_count = fp_retry_count; 4124 cmd->cmd_ulp_pkt = ulp_pkt; 4125 4126 mutex_enter(&port->fp_mutex); 4127 src_id = port->fp_port_id.port_id; 4128 mutex_exit(&port->fp_mutex); 4129 4130 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr, 4131 job, LA_ELS_PLOGI); 4132 } 4133 4134 if (pd) { 4135 mutex_enter(&pd->pd_mutex); 4136 pd->pd_flags = PD_ELS_IN_PROGRESS; 4137 mutex_exit(&pd->pd_mutex); 4138 } 4139 4140 /* npiv check to make sure we don't log into ourself */ 4141 if (relogin && 4142 ((port->fp_npiv_type == FC_NPIV_PORT) || 4143 (port->fp_npiv_flag == FC_NPIV_ENABLE))) { 4144 if ((d_id & 0xffff00) == 4145 (port->fp_port_id.port_id & 0xffff00)) { 4146 found = 1; 4147 } 4148 } 4149 4150 if (found || 4151 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) { 4152 if (found) { 4153 fc_packet_t *pkt = &cmd->cmd_pkt; 4154 pkt->pkt_state = FC_PKT_NPORT_RJT; 4155 } 4156 if (pd) { 4157 mutex_enter(&pd->pd_mutex); 4158 pd->pd_flags = PD_IDLE; 4159 mutex_exit(&pd->pd_mutex); 4160 } 4161 4162 if (ulp_pkt) { 4163 fc_packet_t *pkt = &cmd->cmd_pkt; 4164 4165 ulp_pkt->pkt_state = pkt->pkt_state; 4166 ulp_pkt->pkt_reason = pkt->pkt_reason; 4167 ulp_pkt->pkt_action = pkt->pkt_action; 4168 ulp_pkt->pkt_expln = pkt->pkt_expln; 4169 } 4170 4171 fp_iodone(cmd); 4172 } 4173 4174 return (FC_SUCCESS); 4175 } 4176 4177 4178 /* 4179 * Register the LOGIN parameters with a port device 4180 */ 4181 static void 4182 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 4183 la_els_logi_t *acc, uchar_t class) 4184 { 4185 fc_remote_node_t *node; 4186 4187 ASSERT(pd != NULL); 4188 4189 mutex_enter(&pd->pd_mutex); 4190 node = pd->pd_remote_nodep; 4191 if (pd->pd_login_count == 0) { 4192 pd->pd_login_count++; 4193 } 4194 4195 if (handle) { 4196 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp, 4197 (uint8_t *)&acc->common_service, 4198 sizeof (acc->common_service), DDI_DEV_AUTOINCR); 4199 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1, 4200 (uint8_t *)&acc->class_1, sizeof (acc->class_1), 4201 DDI_DEV_AUTOINCR); 4202 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2, 4203 (uint8_t *)&acc->class_2, sizeof (acc->class_2), 4204 DDI_DEV_AUTOINCR); 4205 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3, 4206 (uint8_t *)&acc->class_3, sizeof (acc->class_3), 4207 DDI_DEV_AUTOINCR); 4208 } else { 4209 pd->pd_csp = acc->common_service; 4210 pd->pd_clsp1 = acc->class_1; 4211 pd->pd_clsp2 = acc->class_2; 4212 pd->pd_clsp3 = acc->class_3; 4213 } 4214 4215 pd->pd_state = PORT_DEVICE_LOGGED_IN; 4216 pd->pd_login_class = class; 4217 mutex_exit(&pd->pd_mutex); 4218 4219 #ifndef __lock_lint 4220 ASSERT(fctl_get_remote_port_by_did(pd->pd_port, 4221 pd->pd_port_id.port_id) == pd); 4222 #endif 4223 4224 mutex_enter(&node->fd_mutex); 4225 if (handle) { 4226 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv, 4227 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv), 4228 DDI_DEV_AUTOINCR); 4229 } else { 4230 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv)); 4231 } 4232 mutex_exit(&node->fd_mutex); 4233 } 4234 4235 4236 /* 4237 * Mark the remote port as OFFLINE 4238 */ 4239 static void 4240 fp_remote_port_offline(fc_remote_port_t *pd) 4241 { 4242 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4243 if (pd->pd_login_count && 4244 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) { 4245 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4246 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4247 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4248 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4249 pd->pd_login_class = 0; 4250 } 4251 pd->pd_type = PORT_DEVICE_OLD; 4252 pd->pd_flags = PD_IDLE; 4253 fctl_tc_reset(&pd->pd_logo_tc); 4254 } 4255 4256 4257 /* 4258 * Deregistration of a port device 4259 */ 4260 static void 4261 fp_unregister_login(fc_remote_port_t *pd) 4262 { 4263 fc_remote_node_t *node; 4264 4265 ASSERT(pd != NULL); 4266 4267 mutex_enter(&pd->pd_mutex); 4268 pd->pd_login_count = 0; 4269 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4270 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4271 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4272 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4273 4274 pd->pd_state = PORT_DEVICE_VALID; 4275 pd->pd_login_class = 0; 4276 node = pd->pd_remote_nodep; 4277 mutex_exit(&pd->pd_mutex); 4278 4279 mutex_enter(&node->fd_mutex); 4280 bzero(node->fd_vv, sizeof (node->fd_vv)); 4281 mutex_exit(&node->fd_mutex); 4282 } 4283 4284 4285 /* 4286 * Handle OFFLINE state of an FCA port 4287 */ 4288 static void 4289 fp_port_offline(fc_local_port_t *port, int notify) 4290 { 4291 int index; 4292 int statec; 4293 timeout_id_t tid; 4294 struct pwwn_hash *head; 4295 fc_remote_port_t *pd; 4296 4297 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4298 4299 for (index = 0; index < pwwn_table_size; index++) { 4300 head = &port->fp_pwwn_table[index]; 4301 pd = head->pwwn_head; 4302 while (pd != NULL) { 4303 mutex_enter(&pd->pd_mutex); 4304 fp_remote_port_offline(pd); 4305 fctl_delist_did_table(port, pd); 4306 mutex_exit(&pd->pd_mutex); 4307 pd = pd->pd_wwn_hnext; 4308 } 4309 } 4310 port->fp_total_devices = 0; 4311 4312 statec = 0; 4313 if (notify) { 4314 /* 4315 * Decrement the statec busy counter as we 4316 * are almost done with handling the state 4317 * change 4318 */ 4319 ASSERT(port->fp_statec_busy > 0); 4320 if (--port->fp_statec_busy == 0) { 4321 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4322 } 4323 mutex_exit(&port->fp_mutex); 4324 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL, 4325 0, 0, KM_SLEEP); 4326 mutex_enter(&port->fp_mutex); 4327 4328 if (port->fp_statec_busy) { 4329 statec++; 4330 } 4331 } else if (port->fp_statec_busy > 1) { 4332 statec++; 4333 } 4334 4335 if ((tid = port->fp_offline_tid) != NULL) { 4336 mutex_exit(&port->fp_mutex); 4337 (void) untimeout(tid); 4338 mutex_enter(&port->fp_mutex); 4339 } 4340 4341 if (!statec) { 4342 port->fp_offline_tid = timeout(fp_offline_timeout, 4343 (caddr_t)port, fp_offline_ticks); 4344 } 4345 } 4346 4347 4348 /* 4349 * Offline devices and send up a state change notification to ULPs 4350 */ 4351 static void 4352 fp_offline_timeout(void *port_handle) 4353 { 4354 int ret; 4355 fc_local_port_t *port = port_handle; 4356 uint32_t listlen = 0; 4357 fc_portmap_t *changelist = NULL; 4358 4359 mutex_enter(&port->fp_mutex); 4360 4361 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) || 4362 (port->fp_soft_state & 4363 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 4364 port->fp_dev_count == 0 || port->fp_statec_busy) { 4365 port->fp_offline_tid = NULL; 4366 mutex_exit(&port->fp_mutex); 4367 return; 4368 } 4369 4370 mutex_exit(&port->fp_mutex); 4371 4372 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout"); 4373 4374 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) { 4375 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4376 FC_FCA_CORE)) != FC_SUCCESS) { 4377 FP_TRACE(FP_NHEAD1(9, ret), 4378 "Failed to force adapter dump"); 4379 } else { 4380 FP_TRACE(FP_NHEAD1(9, 0), 4381 "Forced adapter dump successfully"); 4382 } 4383 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) { 4384 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4385 FC_FCA_RESET_CORE)) != FC_SUCCESS) { 4386 FP_TRACE(FP_NHEAD1(9, ret), 4387 "Failed to force adapter dump and reset"); 4388 } else { 4389 FP_TRACE(FP_NHEAD1(9, 0), 4390 "Forced adapter dump and reset successfully"); 4391 } 4392 } 4393 4394 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 4395 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist, 4396 listlen, listlen, KM_SLEEP); 4397 4398 mutex_enter(&port->fp_mutex); 4399 port->fp_offline_tid = NULL; 4400 mutex_exit(&port->fp_mutex); 4401 } 4402 4403 4404 /* 4405 * Perform general purpose ELS request initialization 4406 */ 4407 static void 4408 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id, 4409 void (*comp) (), job_request_t *job) 4410 { 4411 fc_packet_t *pkt; 4412 4413 pkt = &cmd->cmd_pkt; 4414 cmd->cmd_job = job; 4415 4416 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; 4417 pkt->pkt_cmd_fhdr.d_id = d_id; 4418 pkt->pkt_cmd_fhdr.s_id = s_id; 4419 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 4420 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ; 4421 pkt->pkt_cmd_fhdr.seq_id = 0; 4422 pkt->pkt_cmd_fhdr.df_ctl = 0; 4423 pkt->pkt_cmd_fhdr.seq_cnt = 0; 4424 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 4425 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 4426 pkt->pkt_cmd_fhdr.ro = 0; 4427 pkt->pkt_cmd_fhdr.rsvd = 0; 4428 pkt->pkt_comp = comp; 4429 pkt->pkt_timeout = FP_ELS_TIMEOUT; 4430 } 4431 4432 4433 /* 4434 * Initialize PLOGI/FLOGI ELS request 4435 */ 4436 static void 4437 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id, 4438 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code) 4439 { 4440 ls_code_t payload; 4441 4442 fp_els_init(cmd, s_id, d_id, intr, job); 4443 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4444 4445 payload.ls_code = ls_code; 4446 payload.mbz = 0; 4447 4448 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, 4449 (uint8_t *)&port->fp_service_params, 4450 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params), 4451 DDI_DEV_AUTOINCR); 4452 4453 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload, 4454 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload), 4455 DDI_DEV_AUTOINCR); 4456 } 4457 4458 4459 /* 4460 * Initialize LOGO ELS request 4461 */ 4462 static void 4463 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job) 4464 { 4465 fc_local_port_t *port; 4466 fc_packet_t *pkt; 4467 la_els_logo_t payload; 4468 4469 port = pd->pd_port; 4470 pkt = &cmd->cmd_pkt; 4471 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4472 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4473 4474 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4475 fp_logo_intr, job); 4476 4477 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4478 4479 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4480 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4481 4482 payload.ls_code.ls_code = LA_ELS_LOGO; 4483 payload.ls_code.mbz = 0; 4484 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 4485 payload.nport_id = port->fp_port_id; 4486 4487 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4488 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4489 } 4490 4491 /* 4492 * Initialize RNID ELS request 4493 */ 4494 static void 4495 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job) 4496 { 4497 fc_local_port_t *port; 4498 fc_packet_t *pkt; 4499 la_els_rnid_t payload; 4500 fc_remote_port_t *pd; 4501 4502 pkt = &cmd->cmd_pkt; 4503 pd = pkt->pkt_pd; 4504 port = pd->pd_port; 4505 4506 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4507 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4508 4509 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4510 fp_rnid_intr, job); 4511 4512 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4513 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4514 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4515 4516 payload.ls_code.ls_code = LA_ELS_RNID; 4517 payload.ls_code.mbz = 0; 4518 payload.data_format = flag; 4519 4520 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4521 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4522 } 4523 4524 /* 4525 * Initialize RLS ELS request 4526 */ 4527 static void 4528 fp_rls_init(fp_cmd_t *cmd, job_request_t *job) 4529 { 4530 fc_local_port_t *port; 4531 fc_packet_t *pkt; 4532 la_els_rls_t payload; 4533 fc_remote_port_t *pd; 4534 4535 pkt = &cmd->cmd_pkt; 4536 pd = pkt->pkt_pd; 4537 port = pd->pd_port; 4538 4539 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4540 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4541 4542 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4543 fp_rls_intr, job); 4544 4545 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4546 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4547 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4548 4549 payload.ls_code.ls_code = LA_ELS_RLS; 4550 payload.ls_code.mbz = 0; 4551 payload.rls_portid = port->fp_port_id; 4552 4553 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4554 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4555 } 4556 4557 4558 /* 4559 * Initialize an ADISC ELS request 4560 */ 4561 static void 4562 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job) 4563 { 4564 fc_local_port_t *port; 4565 fc_packet_t *pkt; 4566 la_els_adisc_t payload; 4567 fc_remote_port_t *pd; 4568 4569 pkt = &cmd->cmd_pkt; 4570 pd = pkt->pkt_pd; 4571 port = pd->pd_port; 4572 4573 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4574 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex)); 4575 4576 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4577 fp_adisc_intr, job); 4578 4579 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4580 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4581 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4582 4583 payload.ls_code.ls_code = LA_ELS_ADISC; 4584 payload.ls_code.mbz = 0; 4585 payload.nport_id = port->fp_port_id; 4586 payload.port_wwn = port->fp_service_params.nport_ww_name; 4587 payload.node_wwn = port->fp_service_params.node_ww_name; 4588 payload.hard_addr = port->fp_hard_addr; 4589 4590 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4591 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4592 } 4593 4594 4595 /* 4596 * Send up a state change notification to ULPs. 4597 * Spawns a call to fctl_ulp_statec_cb in a taskq thread. 4598 */ 4599 static int 4600 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state, 4601 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep) 4602 { 4603 fc_port_clist_t *clist; 4604 fc_remote_port_t *pd; 4605 int count; 4606 4607 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4608 4609 clist = kmem_zalloc(sizeof (*clist), sleep); 4610 if (clist == NULL) { 4611 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4612 return (FC_NOMEM); 4613 } 4614 4615 clist->clist_state = state; 4616 4617 mutex_enter(&port->fp_mutex); 4618 clist->clist_flags = port->fp_topology; 4619 mutex_exit(&port->fp_mutex); 4620 4621 clist->clist_port = (opaque_t)port; 4622 clist->clist_len = listlen; 4623 clist->clist_size = alloc_len; 4624 clist->clist_map = changelist; 4625 4626 /* 4627 * Bump the reference count of each fc_remote_port_t in this changelist. 4628 * This is necessary since these devices will be sitting in a taskq 4629 * and referenced later. When the state change notification is 4630 * complete, the reference counts will be decremented. 4631 */ 4632 for (count = 0; count < clist->clist_len; count++) { 4633 pd = clist->clist_map[count].map_pd; 4634 4635 if (pd != NULL) { 4636 mutex_enter(&pd->pd_mutex); 4637 ASSERT((pd->pd_ref_count >= 0) || 4638 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4639 pd->pd_ref_count++; 4640 4641 if (clist->clist_map[count].map_state != 4642 PORT_DEVICE_INVALID) { 4643 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4644 } 4645 4646 mutex_exit(&pd->pd_mutex); 4647 } 4648 } 4649 4650 #ifdef DEBUG 4651 /* 4652 * Sanity check for presence of OLD devices in the hash lists 4653 */ 4654 if (clist->clist_size) { 4655 ASSERT(clist->clist_map != NULL); 4656 for (count = 0; count < clist->clist_len; count++) { 4657 if (clist->clist_map[count].map_state == 4658 PORT_DEVICE_INVALID) { 4659 la_wwn_t pwwn; 4660 fc_portid_t d_id; 4661 4662 pd = clist->clist_map[count].map_pd; 4663 ASSERT(pd != NULL); 4664 4665 mutex_enter(&pd->pd_mutex); 4666 pwwn = pd->pd_port_name; 4667 d_id = pd->pd_port_id; 4668 mutex_exit(&pd->pd_mutex); 4669 4670 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4671 ASSERT(pd != clist->clist_map[count].map_pd); 4672 4673 pd = fctl_get_remote_port_by_did(port, 4674 d_id.port_id); 4675 ASSERT(pd != clist->clist_map[count].map_pd); 4676 } 4677 } 4678 } 4679 #endif 4680 4681 mutex_enter(&port->fp_mutex); 4682 4683 if (state == FC_STATE_ONLINE) { 4684 if (--port->fp_statec_busy == 0) { 4685 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4686 } 4687 } 4688 mutex_exit(&port->fp_mutex); 4689 4690 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 4691 clist, KM_SLEEP); 4692 4693 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p," 4694 "state=%x, len=%d", port, state, listlen); 4695 4696 return (FC_SUCCESS); 4697 } 4698 4699 4700 /* 4701 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs 4702 */ 4703 static int 4704 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist, 4705 uint32_t listlen, uint32_t alloc_len, int sleep, int sync) 4706 { 4707 int ret; 4708 fc_port_clist_t *clist; 4709 4710 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4711 4712 clist = kmem_zalloc(sizeof (*clist), sleep); 4713 if (clist == NULL) { 4714 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4715 return (FC_NOMEM); 4716 } 4717 4718 clist->clist_state = FC_STATE_DEVICE_CHANGE; 4719 4720 mutex_enter(&port->fp_mutex); 4721 clist->clist_flags = port->fp_topology; 4722 mutex_exit(&port->fp_mutex); 4723 4724 clist->clist_port = (opaque_t)port; 4725 clist->clist_len = listlen; 4726 clist->clist_size = alloc_len; 4727 clist->clist_map = changelist; 4728 4729 /* Send sysevents for target state changes */ 4730 4731 if (clist->clist_size) { 4732 int count; 4733 fc_remote_port_t *pd; 4734 4735 ASSERT(clist->clist_map != NULL); 4736 for (count = 0; count < clist->clist_len; count++) { 4737 pd = clist->clist_map[count].map_pd; 4738 4739 /* 4740 * Bump reference counts on all fc_remote_port_t 4741 * structs in this list. We don't know when the task 4742 * will fire, and we don't need these fc_remote_port_t 4743 * structs going away behind our back. 4744 */ 4745 if (pd) { 4746 mutex_enter(&pd->pd_mutex); 4747 ASSERT((pd->pd_ref_count >= 0) || 4748 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4749 pd->pd_ref_count++; 4750 mutex_exit(&pd->pd_mutex); 4751 } 4752 4753 if (clist->clist_map[count].map_state == 4754 PORT_DEVICE_VALID) { 4755 if (clist->clist_map[count].map_type == 4756 PORT_DEVICE_NEW) { 4757 /* Update our state change counter */ 4758 mutex_enter(&port->fp_mutex); 4759 port->fp_last_change++; 4760 mutex_exit(&port->fp_mutex); 4761 4762 /* Additions */ 4763 fp_log_target_event(port, 4764 ESC_SUNFC_TARGET_ADD, 4765 clist->clist_map[count].map_pwwn, 4766 clist->clist_map[count].map_did. 4767 port_id); 4768 } 4769 4770 } else if ((clist->clist_map[count].map_type == 4771 PORT_DEVICE_OLD) && 4772 (clist->clist_map[count].map_state == 4773 PORT_DEVICE_INVALID)) { 4774 /* Update our state change counter */ 4775 mutex_enter(&port->fp_mutex); 4776 port->fp_last_change++; 4777 mutex_exit(&port->fp_mutex); 4778 4779 /* 4780 * For removals, we don't decrement 4781 * pd_ref_count until after the ULP's 4782 * state change callback function has 4783 * completed. 4784 */ 4785 4786 /* Removals */ 4787 fp_log_target_event(port, 4788 ESC_SUNFC_TARGET_REMOVE, 4789 clist->clist_map[count].map_pwwn, 4790 clist->clist_map[count].map_did.port_id); 4791 } 4792 4793 if (clist->clist_map[count].map_state != 4794 PORT_DEVICE_INVALID) { 4795 /* 4796 * Indicate that the ULPs are now aware of 4797 * this device. 4798 */ 4799 4800 mutex_enter(&pd->pd_mutex); 4801 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4802 mutex_exit(&pd->pd_mutex); 4803 } 4804 4805 #ifdef DEBUG 4806 /* 4807 * Sanity check for OLD devices in the hash lists 4808 */ 4809 if (pd && clist->clist_map[count].map_state == 4810 PORT_DEVICE_INVALID) { 4811 la_wwn_t pwwn; 4812 fc_portid_t d_id; 4813 4814 mutex_enter(&pd->pd_mutex); 4815 pwwn = pd->pd_port_name; 4816 d_id = pd->pd_port_id; 4817 mutex_exit(&pd->pd_mutex); 4818 4819 /* 4820 * This overwrites the 'pd' local variable. 4821 * Beware of this if 'pd' ever gets 4822 * referenced below this block. 4823 */ 4824 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4825 ASSERT(pd != clist->clist_map[count].map_pd); 4826 4827 pd = fctl_get_remote_port_by_did(port, 4828 d_id.port_id); 4829 ASSERT(pd != clist->clist_map[count].map_pd); 4830 } 4831 #endif 4832 } 4833 } 4834 4835 if (sync) { 4836 clist->clist_wait = 1; 4837 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL); 4838 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL); 4839 } 4840 4841 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep); 4842 if (sync && ret != TASKQID_INVALID) { 4843 mutex_enter(&clist->clist_mutex); 4844 while (clist->clist_wait) { 4845 cv_wait(&clist->clist_cv, &clist->clist_mutex); 4846 } 4847 mutex_exit(&clist->clist_mutex); 4848 4849 mutex_destroy(&clist->clist_mutex); 4850 cv_destroy(&clist->clist_cv); 4851 kmem_free(clist, sizeof (*clist)); 4852 } 4853 4854 if (!ret) { 4855 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; " 4856 "port=%p", port); 4857 kmem_free(clist->clist_map, 4858 sizeof (*(clist->clist_map)) * clist->clist_size); 4859 kmem_free(clist, sizeof (*clist)); 4860 } else { 4861 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d", 4862 port, listlen); 4863 } 4864 4865 return (FC_SUCCESS); 4866 } 4867 4868 4869 /* 4870 * Perform PLOGI to the group of devices for ULPs 4871 */ 4872 static void 4873 fp_plogi_group(fc_local_port_t *port, job_request_t *job) 4874 { 4875 int offline; 4876 int count; 4877 int rval; 4878 uint32_t listlen; 4879 uint32_t done; 4880 uint32_t d_id; 4881 fc_remote_node_t *node; 4882 fc_remote_port_t *pd; 4883 fc_remote_port_t *tmp_pd; 4884 fc_packet_t *ulp_pkt; 4885 la_els_logi_t *els_data; 4886 ls_code_t ls_code; 4887 4888 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p", 4889 port, job); 4890 4891 done = 0; 4892 listlen = job->job_ulp_listlen; 4893 job->job_counter = job->job_ulp_listlen; 4894 4895 mutex_enter(&port->fp_mutex); 4896 offline = (port->fp_statec_busy || 4897 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0; 4898 mutex_exit(&port->fp_mutex); 4899 4900 for (count = 0; count < listlen; count++) { 4901 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >= 4902 sizeof (la_els_logi_t)); 4903 4904 ulp_pkt = job->job_ulp_pkts[count]; 4905 pd = ulp_pkt->pkt_pd; 4906 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 4907 4908 if (offline) { 4909 done++; 4910 4911 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 4912 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4913 ulp_pkt->pkt_pd = NULL; 4914 ulp_pkt->pkt_comp(ulp_pkt); 4915 4916 job->job_ulp_pkts[count] = NULL; 4917 4918 fp_jobdone(job); 4919 continue; 4920 } 4921 4922 if (pd == NULL) { 4923 pd = fctl_get_remote_port_by_did(port, d_id); 4924 if (pd == NULL) { 4925 /* reset later */ 4926 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4927 continue; 4928 } 4929 mutex_enter(&pd->pd_mutex); 4930 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 4931 mutex_exit(&pd->pd_mutex); 4932 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 4933 done++; 4934 ulp_pkt->pkt_comp(ulp_pkt); 4935 job->job_ulp_pkts[count] = NULL; 4936 fp_jobdone(job); 4937 } else { 4938 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4939 mutex_exit(&pd->pd_mutex); 4940 } 4941 continue; 4942 } 4943 4944 switch (ulp_pkt->pkt_state) { 4945 case FC_PKT_ELS_IN_PROGRESS: 4946 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4947 /* FALLTHRU */ 4948 case FC_PKT_LOCAL_RJT: 4949 done++; 4950 ulp_pkt->pkt_comp(ulp_pkt); 4951 job->job_ulp_pkts[count] = NULL; 4952 fp_jobdone(job); 4953 continue; 4954 default: 4955 break; 4956 } 4957 4958 /* 4959 * Validate the pd corresponding to the d_id passed 4960 * by the ULPs 4961 */ 4962 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 4963 if ((tmp_pd == NULL) || (pd != tmp_pd)) { 4964 done++; 4965 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4966 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION; 4967 ulp_pkt->pkt_pd = NULL; 4968 ulp_pkt->pkt_comp(ulp_pkt); 4969 job->job_ulp_pkts[count] = NULL; 4970 fp_jobdone(job); 4971 continue; 4972 } 4973 4974 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; " 4975 "port=%p, pd=%p", port, pd); 4976 4977 mutex_enter(&pd->pd_mutex); 4978 4979 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4980 done++; 4981 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp; 4982 4983 ls_code.ls_code = LA_ELS_ACC; 4984 ls_code.mbz = 0; 4985 4986 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4987 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code, 4988 sizeof (ls_code_t), DDI_DEV_AUTOINCR); 4989 4990 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4991 (uint8_t *)&pd->pd_csp, 4992 (uint8_t *)&els_data->common_service, 4993 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR); 4994 4995 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4996 (uint8_t *)&pd->pd_port_name, 4997 (uint8_t *)&els_data->nport_ww_name, 4998 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR); 4999 5000 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5001 (uint8_t *)&pd->pd_clsp1, 5002 (uint8_t *)&els_data->class_1, 5003 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR); 5004 5005 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5006 (uint8_t *)&pd->pd_clsp2, 5007 (uint8_t *)&els_data->class_2, 5008 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR); 5009 5010 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5011 (uint8_t *)&pd->pd_clsp3, 5012 (uint8_t *)&els_data->class_3, 5013 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR); 5014 5015 node = pd->pd_remote_nodep; 5016 pd->pd_login_count++; 5017 pd->pd_flags = PD_IDLE; 5018 ulp_pkt->pkt_pd = pd; 5019 mutex_exit(&pd->pd_mutex); 5020 5021 mutex_enter(&node->fd_mutex); 5022 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5023 (uint8_t *)&node->fd_node_name, 5024 (uint8_t *)(&els_data->node_ww_name), 5025 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR); 5026 5027 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5028 (uint8_t *)&node->fd_vv, 5029 (uint8_t *)(&els_data->vendor_version), 5030 sizeof (node->fd_vv), DDI_DEV_AUTOINCR); 5031 5032 mutex_exit(&node->fd_mutex); 5033 ulp_pkt->pkt_state = FC_PKT_SUCCESS; 5034 } else { 5035 5036 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */ 5037 mutex_exit(&pd->pd_mutex); 5038 } 5039 5040 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) { 5041 ulp_pkt->pkt_comp(ulp_pkt); 5042 job->job_ulp_pkts[count] = NULL; 5043 fp_jobdone(job); 5044 } 5045 } 5046 5047 if (done == listlen) { 5048 fp_jobwait(job); 5049 fctl_jobdone(job); 5050 return; 5051 } 5052 5053 job->job_counter = listlen - done; 5054 5055 for (count = 0; count < listlen; count++) { 5056 int cmd_flags; 5057 5058 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) { 5059 continue; 5060 } 5061 5062 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE); 5063 5064 cmd_flags = FP_CMD_PLOGI_RETAIN; 5065 5066 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5067 ASSERT(d_id != 0); 5068 5069 pd = fctl_get_remote_port_by_did(port, d_id); 5070 5071 /* 5072 * We need to properly adjust the port device 5073 * reference counter before we assign the pd 5074 * to the ULP packets port device pointer. 5075 */ 5076 if (pd != NULL && ulp_pkt->pkt_pd == NULL) { 5077 mutex_enter(&pd->pd_mutex); 5078 pd->pd_ref_count++; 5079 mutex_exit(&pd->pd_mutex); 5080 FP_TRACE(FP_NHEAD1(3, 0), 5081 "fp_plogi_group: DID = 0x%x using new pd %p \ 5082 old pd NULL\n", d_id, pd); 5083 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL && 5084 ulp_pkt->pkt_pd != pd) { 5085 mutex_enter(&pd->pd_mutex); 5086 pd->pd_ref_count++; 5087 mutex_exit(&pd->pd_mutex); 5088 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5089 ulp_pkt->pkt_pd->pd_ref_count--; 5090 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5091 FP_TRACE(FP_NHEAD1(3, 0), 5092 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n", 5093 d_id, ulp_pkt->pkt_pd, pd); 5094 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) { 5095 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5096 ulp_pkt->pkt_pd->pd_ref_count--; 5097 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5098 FP_TRACE(FP_NHEAD1(3, 0), 5099 "fp_plogi_group: DID = 0x%x pd is NULL and \ 5100 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd); 5101 } 5102 5103 ulp_pkt->pkt_pd = pd; 5104 5105 if (pd != NULL) { 5106 mutex_enter(&pd->pd_mutex); 5107 d_id = pd->pd_port_id.port_id; 5108 pd->pd_flags = PD_ELS_IN_PROGRESS; 5109 mutex_exit(&pd->pd_mutex); 5110 } else { 5111 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5112 #ifdef DEBUG 5113 pd = fctl_get_remote_port_by_did(port, d_id); 5114 ASSERT(pd == NULL); 5115 #endif 5116 /* 5117 * In the Fabric topology, use NS to create 5118 * port device, and if that fails still try 5119 * with PLOGI - which will make yet another 5120 * attempt to create after successful PLOGI 5121 */ 5122 mutex_enter(&port->fp_mutex); 5123 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 5124 mutex_exit(&port->fp_mutex); 5125 pd = fp_create_remote_port_by_ns(port, 5126 d_id, KM_SLEEP); 5127 if (pd) { 5128 cmd_flags |= FP_CMD_DELDEV_ON_ERROR; 5129 5130 mutex_enter(&pd->pd_mutex); 5131 pd->pd_flags = PD_ELS_IN_PROGRESS; 5132 mutex_exit(&pd->pd_mutex); 5133 5134 FP_TRACE(FP_NHEAD1(3, 0), 5135 "fp_plogi_group;" 5136 " NS created PD port=%p, job=%p," 5137 " pd=%p", port, job, pd); 5138 } 5139 } else { 5140 mutex_exit(&port->fp_mutex); 5141 } 5142 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) { 5143 FP_TRACE(FP_NHEAD1(3, 0), 5144 "fp_plogi_group;" 5145 "ulp_pkt's pd is NULL, get a pd %p", 5146 pd); 5147 mutex_enter(&pd->pd_mutex); 5148 pd->pd_ref_count++; 5149 mutex_exit(&pd->pd_mutex); 5150 } 5151 ulp_pkt->pkt_pd = pd; 5152 } 5153 5154 rval = fp_port_login(port, d_id, job, cmd_flags, 5155 KM_SLEEP, pd, ulp_pkt); 5156 5157 if (rval == FC_SUCCESS) { 5158 continue; 5159 } 5160 5161 if (rval == FC_STATEC_BUSY) { 5162 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5163 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5164 } else { 5165 ulp_pkt->pkt_state = FC_PKT_FAILURE; 5166 } 5167 5168 if (pd) { 5169 mutex_enter(&pd->pd_mutex); 5170 pd->pd_flags = PD_IDLE; 5171 mutex_exit(&pd->pd_mutex); 5172 } 5173 5174 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) { 5175 ASSERT(pd != NULL); 5176 5177 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created," 5178 " PD removed; port=%p, job=%p", port, job); 5179 5180 mutex_enter(&pd->pd_mutex); 5181 pd->pd_ref_count--; 5182 node = pd->pd_remote_nodep; 5183 mutex_exit(&pd->pd_mutex); 5184 5185 ASSERT(node != NULL); 5186 5187 if (fctl_destroy_remote_port(port, pd) == 0) { 5188 fctl_destroy_remote_node(node); 5189 } 5190 ulp_pkt->pkt_pd = NULL; 5191 } 5192 ulp_pkt->pkt_comp(ulp_pkt); 5193 fp_jobdone(job); 5194 } 5195 5196 fp_jobwait(job); 5197 fctl_jobdone(job); 5198 5199 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p", 5200 port, job); 5201 } 5202 5203 5204 /* 5205 * Name server request initialization 5206 */ 5207 static void 5208 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep) 5209 { 5210 int rval; 5211 int count; 5212 int size; 5213 5214 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5215 5216 job->job_counter = 1; 5217 job->job_result = FC_SUCCESS; 5218 5219 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN, 5220 KM_SLEEP, NULL, NULL); 5221 5222 if (rval != FC_SUCCESS) { 5223 mutex_enter(&port->fp_mutex); 5224 port->fp_topology = FC_TOP_NO_NS; 5225 mutex_exit(&port->fp_mutex); 5226 return; 5227 } 5228 5229 fp_jobwait(job); 5230 5231 if (job->job_result != FC_SUCCESS) { 5232 mutex_enter(&port->fp_mutex); 5233 port->fp_topology = FC_TOP_NO_NS; 5234 mutex_exit(&port->fp_mutex); 5235 return; 5236 } 5237 5238 /* 5239 * At this time, we'll do NS registration for objects in the 5240 * ns_reg_cmds (see top of this file) array. 5241 * 5242 * Each time a ULP module registers with the transport, the 5243 * appropriate fc4 bit is set fc4 types and registered with 5244 * the NS for this support. Also, ULPs and FC admin utilities 5245 * may do registration for objects like IP address, symbolic 5246 * port/node name, Initial process associator at run time. 5247 */ 5248 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]); 5249 job->job_counter = size; 5250 job->job_result = FC_SUCCESS; 5251 5252 for (count = 0; count < size; count++) { 5253 if (fp_ns_reg(port, NULL, ns_reg_cmds[count], 5254 job, 0, sleep) != FC_SUCCESS) { 5255 fp_jobdone(job); 5256 } 5257 } 5258 if (size) { 5259 fp_jobwait(job); 5260 } 5261 5262 job->job_result = FC_SUCCESS; 5263 5264 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 5265 5266 if (port->fp_dev_count < FP_MAX_DEVICES) { 5267 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP); 5268 } 5269 5270 job->job_counter = 1; 5271 5272 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION, 5273 sleep) == FC_SUCCESS) { 5274 fp_jobwait(job); 5275 } 5276 } 5277 5278 5279 /* 5280 * Name server finish: 5281 * Unregister for RSCNs 5282 * Unregister all the host port objects in the Name Server 5283 * Perform LOGO with the NS; 5284 */ 5285 static void 5286 fp_ns_fini(fc_local_port_t *port, job_request_t *job) 5287 { 5288 fp_cmd_t *cmd; 5289 uchar_t class; 5290 uint32_t s_id; 5291 fc_packet_t *pkt; 5292 la_els_logo_t payload; 5293 5294 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5295 5296 job->job_counter = 1; 5297 5298 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) != 5299 FC_SUCCESS) { 5300 fp_jobdone(job); 5301 } 5302 fp_jobwait(job); 5303 5304 job->job_counter = 1; 5305 5306 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) { 5307 fp_jobdone(job); 5308 } 5309 fp_jobwait(job); 5310 5311 job->job_counter = 1; 5312 5313 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 5314 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL); 5315 pkt = &cmd->cmd_pkt; 5316 5317 mutex_enter(&port->fp_mutex); 5318 class = port->fp_ns_login_class; 5319 s_id = port->fp_port_id.port_id; 5320 payload.nport_id = port->fp_port_id; 5321 mutex_exit(&port->fp_mutex); 5322 5323 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 5324 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 5325 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 5326 cmd->cmd_retry_count = 1; 5327 cmd->cmd_ulp_pkt = NULL; 5328 5329 if (port->fp_npiv_type == FC_NPIV_PORT) { 5330 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job); 5331 } else { 5332 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job); 5333 } 5334 5335 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 5336 5337 payload.ls_code.ls_code = LA_ELS_LOGO; 5338 payload.ls_code.mbz = 0; 5339 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 5340 5341 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 5342 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 5343 5344 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 5345 fp_iodone(cmd); 5346 } 5347 fp_jobwait(job); 5348 } 5349 5350 5351 /* 5352 * NS Registration function. 5353 * 5354 * It should be seriously noted that FC-GS-2 currently doesn't support 5355 * an Object Registration by a D_ID other than the owner of the object. 5356 * What we are aiming at currently is to at least allow Symbolic Node/Port 5357 * Name registration for any N_Port Identifier by the host software. 5358 * 5359 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this 5360 * function treats the request as Host NS Object. 5361 */ 5362 static int 5363 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code, 5364 job_request_t *job, int polled, int sleep) 5365 { 5366 int rval; 5367 fc_portid_t s_id; 5368 fc_packet_t *pkt; 5369 fp_cmd_t *cmd; 5370 5371 if (pd == NULL) { 5372 mutex_enter(&port->fp_mutex); 5373 s_id = port->fp_port_id; 5374 mutex_exit(&port->fp_mutex); 5375 } else { 5376 mutex_enter(&pd->pd_mutex); 5377 s_id = pd->pd_port_id; 5378 mutex_exit(&pd->pd_mutex); 5379 } 5380 5381 if (polled) { 5382 job->job_counter = 1; 5383 } 5384 5385 switch (cmd_code) { 5386 case NS_RPN_ID: 5387 case NS_RNN_ID: { 5388 ns_rxn_req_t rxn; 5389 5390 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5391 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL); 5392 if (cmd == NULL) { 5393 return (FC_NOMEM); 5394 } 5395 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5396 pkt = &cmd->cmd_pkt; 5397 5398 if (pd == NULL) { 5399 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ? 5400 (port->fp_service_params.nport_ww_name) : 5401 (port->fp_service_params.node_ww_name)); 5402 } else { 5403 if (cmd_code == NS_RPN_ID) { 5404 mutex_enter(&pd->pd_mutex); 5405 rxn.rxn_xname = pd->pd_port_name; 5406 mutex_exit(&pd->pd_mutex); 5407 } else { 5408 fc_remote_node_t *node; 5409 5410 mutex_enter(&pd->pd_mutex); 5411 node = pd->pd_remote_nodep; 5412 mutex_exit(&pd->pd_mutex); 5413 5414 mutex_enter(&node->fd_mutex); 5415 rxn.rxn_xname = node->fd_node_name; 5416 mutex_exit(&node->fd_mutex); 5417 } 5418 } 5419 rxn.rxn_port_id = s_id; 5420 5421 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn, 5422 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5423 sizeof (rxn), DDI_DEV_AUTOINCR); 5424 5425 break; 5426 } 5427 5428 case NS_RCS_ID: { 5429 ns_rcos_t rcos; 5430 5431 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5432 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL); 5433 if (cmd == NULL) { 5434 return (FC_NOMEM); 5435 } 5436 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5437 pkt = &cmd->cmd_pkt; 5438 5439 if (pd == NULL) { 5440 rcos.rcos_cos = port->fp_cos; 5441 } else { 5442 mutex_enter(&pd->pd_mutex); 5443 rcos.rcos_cos = pd->pd_cos; 5444 mutex_exit(&pd->pd_mutex); 5445 } 5446 rcos.rcos_port_id = s_id; 5447 5448 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos, 5449 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5450 sizeof (rcos), DDI_DEV_AUTOINCR); 5451 5452 break; 5453 } 5454 5455 case NS_RFT_ID: { 5456 ns_rfc_type_t rfc; 5457 5458 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5459 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep, 5460 NULL); 5461 if (cmd == NULL) { 5462 return (FC_NOMEM); 5463 } 5464 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5465 pkt = &cmd->cmd_pkt; 5466 5467 if (pd == NULL) { 5468 mutex_enter(&port->fp_mutex); 5469 bcopy(port->fp_fc4_types, rfc.rfc_types, 5470 sizeof (port->fp_fc4_types)); 5471 mutex_exit(&port->fp_mutex); 5472 } else { 5473 mutex_enter(&pd->pd_mutex); 5474 bcopy(pd->pd_fc4types, rfc.rfc_types, 5475 sizeof (pd->pd_fc4types)); 5476 mutex_exit(&pd->pd_mutex); 5477 } 5478 rfc.rfc_port_id = s_id; 5479 5480 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc, 5481 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5482 sizeof (rfc), DDI_DEV_AUTOINCR); 5483 5484 break; 5485 } 5486 5487 case NS_RSPN_ID: { 5488 uchar_t name_len; 5489 int pl_size; 5490 fc_portid_t spn; 5491 5492 if (pd == NULL) { 5493 mutex_enter(&port->fp_mutex); 5494 name_len = port->fp_sym_port_namelen; 5495 mutex_exit(&port->fp_mutex); 5496 } else { 5497 mutex_enter(&pd->pd_mutex); 5498 name_len = pd->pd_spn_len; 5499 mutex_exit(&pd->pd_mutex); 5500 } 5501 5502 pl_size = sizeof (fc_portid_t) + name_len + 1; 5503 5504 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size, 5505 sizeof (fc_reg_resp_t), sleep, NULL); 5506 if (cmd == NULL) { 5507 return (FC_NOMEM); 5508 } 5509 5510 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5511 5512 pkt = &cmd->cmd_pkt; 5513 5514 spn = s_id; 5515 5516 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *) 5517 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn), 5518 DDI_DEV_AUTOINCR); 5519 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5520 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) 5521 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR); 5522 5523 if (pd == NULL) { 5524 mutex_enter(&port->fp_mutex); 5525 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5526 (uint8_t *)port->fp_sym_port_name, (uint8_t *) 5527 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5528 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5529 mutex_exit(&port->fp_mutex); 5530 } else { 5531 mutex_enter(&pd->pd_mutex); 5532 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5533 (uint8_t *)pd->pd_spn, 5534 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5535 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5536 mutex_exit(&pd->pd_mutex); 5537 } 5538 break; 5539 } 5540 5541 case NS_RPT_ID: { 5542 ns_rpt_t rpt; 5543 5544 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5545 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL); 5546 if (cmd == NULL) { 5547 return (FC_NOMEM); 5548 } 5549 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5550 pkt = &cmd->cmd_pkt; 5551 5552 if (pd == NULL) { 5553 rpt.rpt_type = port->fp_port_type; 5554 } else { 5555 mutex_enter(&pd->pd_mutex); 5556 rpt.rpt_type = pd->pd_porttype; 5557 mutex_exit(&pd->pd_mutex); 5558 } 5559 rpt.rpt_port_id = s_id; 5560 5561 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt, 5562 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5563 sizeof (rpt), DDI_DEV_AUTOINCR); 5564 5565 break; 5566 } 5567 5568 case NS_RIP_NN: { 5569 ns_rip_t rip; 5570 5571 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5572 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL); 5573 if (cmd == NULL) { 5574 return (FC_NOMEM); 5575 } 5576 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5577 pkt = &cmd->cmd_pkt; 5578 5579 if (pd == NULL) { 5580 rip.rip_node_name = 5581 port->fp_service_params.node_ww_name; 5582 bcopy(port->fp_ip_addr, rip.rip_ip_addr, 5583 sizeof (port->fp_ip_addr)); 5584 } else { 5585 fc_remote_node_t *node; 5586 5587 /* 5588 * The most correct implementation should have the IP 5589 * address in the fc_remote_node_t structure; I believe 5590 * Node WWN and IP address should have one to one 5591 * correlation (but guess what this is changing in 5592 * FC-GS-2 latest draft) 5593 */ 5594 mutex_enter(&pd->pd_mutex); 5595 node = pd->pd_remote_nodep; 5596 bcopy(pd->pd_ip_addr, rip.rip_ip_addr, 5597 sizeof (pd->pd_ip_addr)); 5598 mutex_exit(&pd->pd_mutex); 5599 5600 mutex_enter(&node->fd_mutex); 5601 rip.rip_node_name = node->fd_node_name; 5602 mutex_exit(&node->fd_mutex); 5603 } 5604 5605 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip, 5606 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5607 sizeof (rip), DDI_DEV_AUTOINCR); 5608 5609 break; 5610 } 5611 5612 case NS_RIPA_NN: { 5613 ns_ipa_t ipa; 5614 5615 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5616 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL); 5617 if (cmd == NULL) { 5618 return (FC_NOMEM); 5619 } 5620 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5621 pkt = &cmd->cmd_pkt; 5622 5623 if (pd == NULL) { 5624 ipa.ipa_node_name = 5625 port->fp_service_params.node_ww_name; 5626 bcopy(port->fp_ipa, ipa.ipa_value, 5627 sizeof (port->fp_ipa)); 5628 } else { 5629 fc_remote_node_t *node; 5630 5631 mutex_enter(&pd->pd_mutex); 5632 node = pd->pd_remote_nodep; 5633 mutex_exit(&pd->pd_mutex); 5634 5635 mutex_enter(&node->fd_mutex); 5636 ipa.ipa_node_name = node->fd_node_name; 5637 bcopy(node->fd_ipa, ipa.ipa_value, 5638 sizeof (node->fd_ipa)); 5639 mutex_exit(&node->fd_mutex); 5640 } 5641 5642 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa, 5643 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5644 sizeof (ipa), DDI_DEV_AUTOINCR); 5645 5646 break; 5647 } 5648 5649 case NS_RSNN_NN: { 5650 uchar_t name_len; 5651 int pl_size; 5652 la_wwn_t snn; 5653 fc_remote_node_t *node = NULL; 5654 5655 if (pd == NULL) { 5656 mutex_enter(&port->fp_mutex); 5657 name_len = port->fp_sym_node_namelen; 5658 mutex_exit(&port->fp_mutex); 5659 } else { 5660 mutex_enter(&pd->pd_mutex); 5661 node = pd->pd_remote_nodep; 5662 mutex_exit(&pd->pd_mutex); 5663 5664 mutex_enter(&node->fd_mutex); 5665 name_len = node->fd_snn_len; 5666 mutex_exit(&node->fd_mutex); 5667 } 5668 5669 pl_size = sizeof (la_wwn_t) + name_len + 1; 5670 5671 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5672 pl_size, sizeof (fc_reg_resp_t), sleep, NULL); 5673 if (cmd == NULL) { 5674 return (FC_NOMEM); 5675 } 5676 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5677 5678 pkt = &cmd->cmd_pkt; 5679 5680 bcopy(&port->fp_service_params.node_ww_name, 5681 &snn, sizeof (la_wwn_t)); 5682 5683 if (pd == NULL) { 5684 mutex_enter(&port->fp_mutex); 5685 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5686 (uint8_t *)port->fp_sym_node_name, (uint8_t *) 5687 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5688 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5689 mutex_exit(&port->fp_mutex); 5690 } else { 5691 ASSERT(node != NULL); 5692 mutex_enter(&node->fd_mutex); 5693 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5694 (uint8_t *)node->fd_snn, 5695 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5696 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5697 mutex_exit(&node->fd_mutex); 5698 } 5699 5700 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn, 5701 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5702 sizeof (snn), DDI_DEV_AUTOINCR); 5703 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5704 (uint8_t *)(pkt->pkt_cmd 5705 + sizeof (fc_ct_header_t) + sizeof (snn)), 5706 1, DDI_DEV_AUTOINCR); 5707 5708 break; 5709 } 5710 5711 case NS_DA_ID: { 5712 ns_remall_t rall; 5713 char tmp[4] = {0}; 5714 char *ptr; 5715 5716 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5717 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL); 5718 5719 if (cmd == NULL) { 5720 return (FC_NOMEM); 5721 } 5722 5723 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5724 pkt = &cmd->cmd_pkt; 5725 5726 ptr = (char *)(&s_id); 5727 tmp[3] = *ptr++; 5728 tmp[2] = *ptr++; 5729 tmp[1] = *ptr++; 5730 tmp[0] = *ptr; 5731 #if defined(_BIT_FIELDS_LTOH) 5732 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4); 5733 #else 5734 rall.rem_port_id = s_id; 5735 #endif 5736 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall, 5737 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5738 sizeof (rall), DDI_DEV_AUTOINCR); 5739 5740 break; 5741 } 5742 5743 default: 5744 return (FC_FAILURE); 5745 } 5746 5747 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 5748 5749 if (rval != FC_SUCCESS) { 5750 job->job_result = rval; 5751 fp_iodone(cmd); 5752 } 5753 5754 if (polled) { 5755 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5756 fp_jobwait(job); 5757 } else { 5758 rval = FC_SUCCESS; 5759 } 5760 5761 return (rval); 5762 } 5763 5764 5765 /* 5766 * Common interrupt handler 5767 */ 5768 static int 5769 fp_common_intr(fc_packet_t *pkt, int iodone) 5770 { 5771 int rval = FC_FAILURE; 5772 fp_cmd_t *cmd; 5773 fc_local_port_t *port; 5774 5775 cmd = pkt->pkt_ulp_private; 5776 port = cmd->cmd_port; 5777 5778 /* 5779 * Fail fast the upper layer requests if 5780 * a state change has occurred amidst. 5781 */ 5782 mutex_enter(&port->fp_mutex); 5783 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) { 5784 mutex_exit(&port->fp_mutex); 5785 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5786 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5787 } else if (!(port->fp_soft_state & 5788 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) { 5789 mutex_exit(&port->fp_mutex); 5790 5791 switch (pkt->pkt_state) { 5792 case FC_PKT_LOCAL_BSY: 5793 case FC_PKT_FABRIC_BSY: 5794 case FC_PKT_NPORT_BSY: 5795 case FC_PKT_TIMEOUT: 5796 cmd->cmd_retry_interval = (pkt->pkt_state == 5797 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay; 5798 rval = fp_retry_cmd(pkt); 5799 break; 5800 5801 case FC_PKT_FABRIC_RJT: 5802 case FC_PKT_NPORT_RJT: 5803 case FC_PKT_LOCAL_RJT: 5804 case FC_PKT_LS_RJT: 5805 case FC_PKT_FS_RJT: 5806 case FC_PKT_BA_RJT: 5807 rval = fp_handle_reject(pkt); 5808 break; 5809 5810 default: 5811 if (pkt->pkt_resp_resid) { 5812 cmd->cmd_retry_interval = 0; 5813 rval = fp_retry_cmd(pkt); 5814 } 5815 break; 5816 } 5817 } else { 5818 mutex_exit(&port->fp_mutex); 5819 } 5820 5821 if (rval != FC_SUCCESS && iodone) { 5822 fp_iodone(cmd); 5823 rval = FC_SUCCESS; 5824 } 5825 5826 return (rval); 5827 } 5828 5829 5830 /* 5831 * Some not so long winding theory on point to point topology: 5832 * 5833 * In the ACC payload, if the D_ID is ZERO and the common service 5834 * parameters indicate N_Port, then the topology is POINT TO POINT. 5835 * 5836 * In a point to point topology with an N_Port, during Fabric Login, 5837 * the destination N_Port will check with our WWN and decide if it 5838 * needs to issue PLOGI or not. That means, FLOGI could potentially 5839 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited 5840 * PLOGI creates the device handles. 5841 * 5842 * Assuming that the host port WWN is greater than the other N_Port 5843 * WWN, then we become the master (be aware that this isn't the word 5844 * used in the FC standards) and initiate the PLOGI. 5845 * 5846 */ 5847 static void 5848 fp_flogi_intr(fc_packet_t *pkt) 5849 { 5850 int state; 5851 int f_port; 5852 uint32_t s_id; 5853 uint32_t d_id; 5854 fp_cmd_t *cmd; 5855 fc_local_port_t *port; 5856 la_wwn_t *swwn; 5857 la_wwn_t dwwn; 5858 la_wwn_t nwwn; 5859 fc_remote_port_t *pd; 5860 la_els_logi_t *acc; 5861 com_svc_t csp; 5862 ls_code_t resp; 5863 5864 cmd = pkt->pkt_ulp_private; 5865 port = cmd->cmd_port; 5866 5867 mutex_enter(&port->fp_mutex); 5868 port->fp_out_fpcmds--; 5869 mutex_exit(&port->fp_mutex); 5870 5871 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x", 5872 port, pkt, pkt->pkt_state); 5873 5874 if (FP_IS_PKT_ERROR(pkt)) { 5875 (void) fp_common_intr(pkt, 1); 5876 return; 5877 } 5878 5879 /* 5880 * Currently, we don't need to swap bytes here because qlc is faking the 5881 * response for us and so endianness is getting taken care of. But we 5882 * have to fix this and generalize this at some point 5883 */ 5884 acc = (la_els_logi_t *)pkt->pkt_resp; 5885 5886 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 5887 sizeof (resp), DDI_DEV_AUTOINCR); 5888 5889 ASSERT(resp.ls_code == LA_ELS_ACC); 5890 if (resp.ls_code != LA_ELS_ACC) { 5891 (void) fp_common_intr(pkt, 1); 5892 return; 5893 } 5894 5895 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp, 5896 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR); 5897 5898 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0; 5899 5900 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 5901 5902 mutex_enter(&port->fp_mutex); 5903 state = FC_PORT_STATE_MASK(port->fp_state); 5904 mutex_exit(&port->fp_mutex); 5905 5906 if (f_port == 0) { 5907 if (state != FC_STATE_LOOP) { 5908 swwn = &port->fp_service_params.nport_ww_name; 5909 5910 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn, 5911 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 5912 DDI_DEV_AUTOINCR); 5913 5914 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 5915 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 5916 DDI_DEV_AUTOINCR); 5917 5918 mutex_enter(&port->fp_mutex); 5919 5920 port->fp_topology = FC_TOP_PT_PT; 5921 port->fp_total_devices = 1; 5922 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) { 5923 port->fp_ptpt_master = 1; 5924 /* 5925 * Let us choose 'X' as S_ID and 'Y' 5926 * as D_ID and that'll work; hopefully 5927 * If not, it will get changed. 5928 */ 5929 s_id = port->fp_instance + FP_DEFAULT_SID; 5930 d_id = port->fp_instance + FP_DEFAULT_DID; 5931 port->fp_port_id.port_id = s_id; 5932 mutex_exit(&port->fp_mutex); 5933 5934 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x" 5935 "pd %x", port->fp_port_id.port_id, d_id); 5936 pd = fctl_create_remote_port(port, 5937 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR, 5938 KM_NOSLEEP); 5939 if (pd == NULL) { 5940 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 5941 0, NULL, "couldn't create device" 5942 " d_id=%X", d_id); 5943 fp_iodone(cmd); 5944 return; 5945 } 5946 5947 cmd->cmd_pkt.pkt_tran_flags = 5948 pkt->pkt_tran_flags; 5949 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type; 5950 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN; 5951 cmd->cmd_retry_count = fp_retry_count; 5952 5953 fp_xlogi_init(port, cmd, s_id, d_id, 5954 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI); 5955 5956 (&cmd->cmd_pkt)->pkt_pd = pd; 5957 5958 /* 5959 * We've just created this fc_remote_port_t, and 5960 * we're about to use it to send a PLOGI, so 5961 * bump the reference count right now. When 5962 * the packet is freed, the reference count will 5963 * be decremented. The ULP may also start using 5964 * it, so mark it as given away as well. 5965 */ 5966 pd->pd_ref_count++; 5967 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 5968 5969 if (fp_sendcmd(port, cmd, 5970 port->fp_fca_handle) == FC_SUCCESS) { 5971 return; 5972 } 5973 } else { 5974 /* 5975 * The device handles will be created when the 5976 * unsolicited PLOGI is completed successfully 5977 */ 5978 port->fp_ptpt_master = 0; 5979 mutex_exit(&port->fp_mutex); 5980 } 5981 } 5982 pkt->pkt_state = FC_PKT_FAILURE; 5983 } else { 5984 if (f_port) { 5985 mutex_enter(&port->fp_mutex); 5986 if (state == FC_STATE_LOOP) { 5987 port->fp_topology = FC_TOP_PUBLIC_LOOP; 5988 } else { 5989 port->fp_topology = FC_TOP_FABRIC; 5990 5991 FC_GET_RSP(port, pkt->pkt_resp_acc, 5992 (uint8_t *)&port->fp_fabric_name, 5993 (uint8_t *)&acc->node_ww_name, 5994 sizeof (la_wwn_t), 5995 DDI_DEV_AUTOINCR); 5996 } 5997 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id; 5998 mutex_exit(&port->fp_mutex); 5999 } else { 6000 pkt->pkt_state = FC_PKT_FAILURE; 6001 } 6002 } 6003 fp_iodone(cmd); 6004 } 6005 6006 6007 /* 6008 * Handle solicited PLOGI response 6009 */ 6010 static void 6011 fp_plogi_intr(fc_packet_t *pkt) 6012 { 6013 int nl_port; 6014 int bailout; 6015 uint32_t d_id; 6016 fp_cmd_t *cmd; 6017 la_els_logi_t *acc; 6018 fc_local_port_t *port; 6019 fc_remote_port_t *pd; 6020 la_wwn_t nwwn; 6021 la_wwn_t pwwn; 6022 ls_code_t resp; 6023 6024 nl_port = 0; 6025 cmd = pkt->pkt_ulp_private; 6026 port = cmd->cmd_port; 6027 d_id = pkt->pkt_cmd_fhdr.d_id; 6028 6029 #ifndef __lock_lint 6030 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6031 #endif 6032 6033 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x," 6034 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id, 6035 cmd->cmd_job->job_counter, pkt, pkt->pkt_state); 6036 6037 /* 6038 * Bail out early on ULP initiated requests if the 6039 * state change has occurred 6040 */ 6041 mutex_enter(&port->fp_mutex); 6042 port->fp_out_fpcmds--; 6043 bailout = ((port->fp_statec_busy || 6044 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6045 cmd->cmd_ulp_pkt) ? 1 : 0; 6046 mutex_exit(&port->fp_mutex); 6047 6048 if (FP_IS_PKT_ERROR(pkt) || bailout) { 6049 int skip_msg = 0; 6050 int giveup = 0; 6051 6052 if (cmd->cmd_ulp_pkt) { 6053 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6054 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason; 6055 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6056 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6057 } 6058 6059 /* 6060 * If an unsolicited cross login already created 6061 * a device speed up the discovery by not retrying 6062 * the command mindlessly. 6063 */ 6064 if (pkt->pkt_pd == NULL && 6065 fctl_get_remote_port_by_did(port, d_id) != NULL) { 6066 fp_iodone(cmd); 6067 return; 6068 } 6069 6070 if (pkt->pkt_pd != NULL) { 6071 giveup = (pkt->pkt_pd->pd_recepient == 6072 PD_PLOGI_RECEPIENT) ? 1 : 0; 6073 if (giveup) { 6074 /* 6075 * This pd is marked as plogi 6076 * recipient, stop retrying 6077 */ 6078 FP_TRACE(FP_NHEAD1(3, 0), 6079 "fp_plogi_intr: stop retry as" 6080 " a cross login was accepted" 6081 " from d_id=%x, port=%p.", 6082 d_id, port); 6083 fp_iodone(cmd); 6084 return; 6085 } 6086 } 6087 6088 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6089 return; 6090 } 6091 6092 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) { 6093 mutex_enter(&pd->pd_mutex); 6094 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 6095 skip_msg++; 6096 } 6097 mutex_exit(&pd->pd_mutex); 6098 } 6099 6100 mutex_enter(&port->fp_mutex); 6101 if (!bailout && !(skip_msg && port->fp_statec_busy) && 6102 port->fp_statec_busy <= 1 && 6103 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) { 6104 mutex_exit(&port->fp_mutex); 6105 /* 6106 * In case of Login Collisions, JNI HBAs returns the 6107 * FC pkt back to the Initiator with the state set to 6108 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR. 6109 * QLC HBAs handles such cases in the FW and doesnot 6110 * return the LS_RJT with Logical error when 6111 * login collision happens. 6112 */ 6113 if ((pkt->pkt_state != FC_PKT_LS_RJT) || 6114 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) { 6115 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6116 "PLOGI to %x failed", d_id); 6117 } 6118 FP_TRACE(FP_NHEAD2(9, 0), 6119 "PLOGI to %x failed. state=%x reason=%x.", 6120 d_id, pkt->pkt_state, pkt->pkt_reason); 6121 } else { 6122 mutex_exit(&port->fp_mutex); 6123 } 6124 6125 fp_iodone(cmd); 6126 return; 6127 } 6128 6129 acc = (la_els_logi_t *)pkt->pkt_resp; 6130 6131 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 6132 sizeof (resp), DDI_DEV_AUTOINCR); 6133 6134 ASSERT(resp.ls_code == LA_ELS_ACC); 6135 if (resp.ls_code != LA_ELS_ACC) { 6136 (void) fp_common_intr(pkt, 1); 6137 return; 6138 } 6139 6140 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) { 6141 mutex_enter(&port->fp_mutex); 6142 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags); 6143 mutex_exit(&port->fp_mutex); 6144 fp_iodone(cmd); 6145 return; 6146 } 6147 6148 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp); 6149 6150 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 6151 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 6152 DDI_DEV_AUTOINCR); 6153 6154 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 6155 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 6156 DDI_DEV_AUTOINCR); 6157 6158 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE); 6159 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE); 6160 6161 if ((pd = pkt->pkt_pd) == NULL) { 6162 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6163 if (pd == NULL) { 6164 FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x", 6165 port->fp_port_id.port_id, d_id); 6166 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id, 6167 PD_PLOGI_INITIATOR, KM_NOSLEEP); 6168 if (pd == NULL) { 6169 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6170 "couldn't create port device handles" 6171 " d_id=%x", d_id); 6172 fp_iodone(cmd); 6173 return; 6174 } 6175 } else { 6176 fc_remote_port_t *tmp_pd; 6177 6178 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6179 if (tmp_pd != NULL) { 6180 fp_iodone(cmd); 6181 return; 6182 } 6183 6184 mutex_enter(&port->fp_mutex); 6185 mutex_enter(&pd->pd_mutex); 6186 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) || 6187 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6188 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN; 6189 } 6190 6191 if (pd->pd_type == PORT_DEVICE_OLD) { 6192 if (pd->pd_port_id.port_id != d_id) { 6193 fctl_delist_did_table(port, pd); 6194 pd->pd_type = PORT_DEVICE_CHANGED; 6195 pd->pd_port_id.port_id = d_id; 6196 } else { 6197 pd->pd_type = PORT_DEVICE_NOCHANGE; 6198 } 6199 } 6200 6201 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6202 char ww_name[17]; 6203 6204 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6205 6206 mutex_exit(&pd->pd_mutex); 6207 mutex_exit(&port->fp_mutex); 6208 FP_TRACE(FP_NHEAD2(9, 0), 6209 "Possible Duplicate name or address" 6210 " identifiers in the PLOGI response" 6211 " D_ID=%x, PWWN=%s: Please check the" 6212 " configuration", d_id, ww_name); 6213 fp_iodone(cmd); 6214 return; 6215 } 6216 fctl_enlist_did_table(port, pd); 6217 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6218 mutex_exit(&pd->pd_mutex); 6219 mutex_exit(&port->fp_mutex); 6220 } 6221 } else { 6222 fc_remote_port_t *tmp_pd, *new_wwn_pd; 6223 6224 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6225 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6226 6227 mutex_enter(&port->fp_mutex); 6228 mutex_enter(&pd->pd_mutex); 6229 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) { 6230 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x," 6231 " pd_state=%x pd_type=%x", d_id, pd->pd_state, 6232 pd->pd_type); 6233 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN && 6234 pd->pd_type == PORT_DEVICE_OLD) || 6235 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6236 pd->pd_type = PORT_DEVICE_NOCHANGE; 6237 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 6238 pd->pd_type = PORT_DEVICE_NEW; 6239 } 6240 } else { 6241 char old_name[17]; 6242 char new_name[17]; 6243 6244 fc_wwn_to_str(&pd->pd_port_name, old_name); 6245 fc_wwn_to_str(&pwwn, new_name); 6246 6247 FP_TRACE(FP_NHEAD1(9, 0), 6248 "fp_plogi_intr: PWWN of a device with D_ID=%x " 6249 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p " 6250 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x", 6251 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd, 6252 cmd->cmd_ulp_pkt, bailout); 6253 6254 FP_TRACE(FP_NHEAD2(9, 0), 6255 "PWWN of a device with D_ID=%x changed." 6256 " New PWWN = %s, OLD PWWN = %s", d_id, 6257 new_name, old_name); 6258 6259 if (cmd->cmd_ulp_pkt && !bailout) { 6260 fc_remote_node_t *rnodep; 6261 fc_portmap_t *changelist; 6262 fc_portmap_t *listptr; 6263 int len = 1; 6264 /* # entries in changelist */ 6265 6266 fctl_delist_pwwn_table(port, pd); 6267 6268 /* 6269 * Lets now check if there already is a pd with 6270 * this new WWN in the table. If so, we'll mark 6271 * it as invalid 6272 */ 6273 6274 if (new_wwn_pd) { 6275 /* 6276 * There is another pd with in the pwwn 6277 * table with the same WWN that we got 6278 * in the PLOGI payload. We have to get 6279 * it out of the pwwn table, update the 6280 * pd's state (fp_fillout_old_map does 6281 * this for us) and add it to the 6282 * changelist that goes up to ULPs. 6283 * 6284 * len is length of changelist and so 6285 * increment it. 6286 */ 6287 len++; 6288 6289 if (tmp_pd != pd) { 6290 /* 6291 * Odd case where pwwn and did 6292 * tables are out of sync but 6293 * we will handle that too. See 6294 * more comments below. 6295 * 6296 * One more device that ULPs 6297 * should know about and so len 6298 * gets incremented again. 6299 */ 6300 len++; 6301 } 6302 6303 listptr = changelist = kmem_zalloc(len * 6304 sizeof (*changelist), KM_SLEEP); 6305 6306 mutex_enter(&new_wwn_pd->pd_mutex); 6307 rnodep = new_wwn_pd->pd_remote_nodep; 6308 mutex_exit(&new_wwn_pd->pd_mutex); 6309 6310 /* 6311 * Hold the fd_mutex since 6312 * fctl_copy_portmap_held expects it. 6313 * Preserve lock hierarchy by grabbing 6314 * fd_mutex before pd_mutex 6315 */ 6316 if (rnodep) { 6317 mutex_enter(&rnodep->fd_mutex); 6318 } 6319 mutex_enter(&new_wwn_pd->pd_mutex); 6320 fp_fillout_old_map_held(listptr++, 6321 new_wwn_pd, 0); 6322 mutex_exit(&new_wwn_pd->pd_mutex); 6323 if (rnodep) { 6324 mutex_exit(&rnodep->fd_mutex); 6325 } 6326 6327 /* 6328 * Safety check : 6329 * Lets ensure that the pwwn and did 6330 * tables are in sync. Ideally, we 6331 * should not find that these two pd's 6332 * are different. 6333 */ 6334 if (tmp_pd != pd) { 6335 mutex_enter(&tmp_pd->pd_mutex); 6336 rnodep = 6337 tmp_pd->pd_remote_nodep; 6338 mutex_exit(&tmp_pd->pd_mutex); 6339 6340 /* As above grab fd_mutex */ 6341 if (rnodep) { 6342 mutex_enter(&rnodep-> 6343 fd_mutex); 6344 } 6345 mutex_enter(&tmp_pd->pd_mutex); 6346 6347 fp_fillout_old_map_held( 6348 listptr++, tmp_pd, 0); 6349 6350 mutex_exit(&tmp_pd->pd_mutex); 6351 if (rnodep) { 6352 mutex_exit(&rnodep-> 6353 fd_mutex); 6354 } 6355 6356 /* 6357 * Now add "pd" (not tmp_pd) 6358 * to fp_did_table to sync it up 6359 * with fp_pwwn_table 6360 * 6361 * pd->pd_mutex is already held 6362 * at this point 6363 */ 6364 fctl_enlist_did_table(port, pd); 6365 } 6366 } else { 6367 listptr = changelist = kmem_zalloc( 6368 sizeof (*changelist), KM_SLEEP); 6369 } 6370 6371 ASSERT(changelist != NULL); 6372 6373 fp_fillout_changed_map(listptr, pd, &d_id, 6374 &pwwn); 6375 fctl_enlist_pwwn_table(port, pd); 6376 6377 mutex_exit(&pd->pd_mutex); 6378 mutex_exit(&port->fp_mutex); 6379 6380 fp_iodone(cmd); 6381 6382 (void) fp_ulp_devc_cb(port, changelist, len, 6383 len, KM_NOSLEEP, 0); 6384 6385 return; 6386 } 6387 } 6388 6389 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) { 6390 nl_port = 1; 6391 } 6392 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6393 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6394 } 6395 6396 mutex_exit(&pd->pd_mutex); 6397 mutex_exit(&port->fp_mutex); 6398 6399 if (tmp_pd == NULL) { 6400 mutex_enter(&port->fp_mutex); 6401 mutex_enter(&pd->pd_mutex); 6402 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6403 char ww_name[17]; 6404 6405 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6406 mutex_exit(&pd->pd_mutex); 6407 mutex_exit(&port->fp_mutex); 6408 FP_TRACE(FP_NHEAD2(9, 0), 6409 "Possible Duplicate name or address" 6410 " identifiers in the PLOGI response" 6411 " D_ID=%x, PWWN=%s: Please check the" 6412 " configuration", d_id, ww_name); 6413 fp_iodone(cmd); 6414 return; 6415 } 6416 fctl_enlist_did_table(port, pd); 6417 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6418 mutex_exit(&pd->pd_mutex); 6419 mutex_exit(&port->fp_mutex); 6420 } 6421 } 6422 fp_register_login(&pkt->pkt_resp_acc, pd, acc, 6423 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 6424 6425 if (cmd->cmd_ulp_pkt) { 6426 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6427 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6428 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6429 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6430 if (pd != NULL) { 6431 FP_TRACE(FP_NHEAD1(9, 0), 6432 "fp_plogi_intr;" 6433 "ulp_pkt's pd is NULL, get a pd %p", 6434 pd); 6435 mutex_enter(&pd->pd_mutex); 6436 pd->pd_ref_count++; 6437 mutex_exit(&pd->pd_mutex); 6438 } 6439 cmd->cmd_ulp_pkt->pkt_pd = pd; 6440 } 6441 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6442 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6443 sizeof (fc_frame_hdr_t)); 6444 bcopy((caddr_t)pkt->pkt_resp, 6445 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6446 sizeof (la_els_logi_t)); 6447 } 6448 6449 mutex_enter(&port->fp_mutex); 6450 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) { 6451 mutex_enter(&pd->pd_mutex); 6452 6453 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6454 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6455 cmd->cmd_retry_count = fp_retry_count; 6456 6457 /* 6458 * If the fc_remote_port_t pointer is not set in the given 6459 * fc_packet_t, then this fc_remote_port_t must have just 6460 * been created. Save the pointer and also increment the 6461 * fc_remote_port_t reference count. 6462 */ 6463 if (pkt->pkt_pd == NULL) { 6464 pkt->pkt_pd = pd; 6465 pd->pd_ref_count++; /* It's in use! */ 6466 } 6467 6468 fp_adisc_init(cmd, cmd->cmd_job); 6469 6470 pkt->pkt_cmdlen = sizeof (la_els_adisc_t); 6471 pkt->pkt_rsplen = sizeof (la_els_adisc_t); 6472 6473 mutex_exit(&pd->pd_mutex); 6474 mutex_exit(&port->fp_mutex); 6475 6476 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6477 return; 6478 } 6479 } else { 6480 mutex_exit(&port->fp_mutex); 6481 } 6482 6483 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6484 mutex_enter(&port->fp_mutex); 6485 mutex_enter(&pd->pd_mutex); 6486 6487 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6488 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6489 cmd->cmd_retry_count = fp_retry_count; 6490 6491 fp_logo_init(pd, cmd, cmd->cmd_job); 6492 6493 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6494 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6495 6496 mutex_exit(&pd->pd_mutex); 6497 mutex_exit(&port->fp_mutex); 6498 6499 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6500 return; 6501 } 6502 6503 } 6504 fp_iodone(cmd); 6505 } 6506 6507 6508 /* 6509 * Handle solicited ADISC response 6510 */ 6511 static void 6512 fp_adisc_intr(fc_packet_t *pkt) 6513 { 6514 int rval; 6515 int bailout; 6516 fp_cmd_t *cmd, *logi_cmd; 6517 fc_local_port_t *port; 6518 fc_remote_port_t *pd; 6519 la_els_adisc_t *acc; 6520 ls_code_t resp; 6521 fc_hardaddr_t ha; 6522 fc_portmap_t *changelist; 6523 int initiator, adiscfail = 0; 6524 6525 pd = pkt->pkt_pd; 6526 cmd = pkt->pkt_ulp_private; 6527 port = cmd->cmd_port; 6528 6529 #ifndef __lock_lint 6530 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6531 #endif 6532 6533 ASSERT(pd != NULL && port != NULL && cmd != NULL); 6534 6535 mutex_enter(&port->fp_mutex); 6536 port->fp_out_fpcmds--; 6537 bailout = ((port->fp_statec_busy || 6538 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6539 cmd->cmd_ulp_pkt) ? 1 : 0; 6540 mutex_exit(&port->fp_mutex); 6541 6542 if (bailout) { 6543 fp_iodone(cmd); 6544 return; 6545 } 6546 6547 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) { 6548 acc = (la_els_adisc_t *)pkt->pkt_resp; 6549 6550 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6551 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR); 6552 6553 if (resp.ls_code == LA_ELS_ACC) { 6554 int is_private; 6555 6556 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha, 6557 (uint8_t *)&acc->hard_addr, sizeof (ha), 6558 DDI_DEV_AUTOINCR); 6559 6560 mutex_enter(&port->fp_mutex); 6561 6562 is_private = 6563 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0; 6564 6565 mutex_enter(&pd->pd_mutex); 6566 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) { 6567 fctl_enlist_did_table(port, pd); 6568 } 6569 mutex_exit(&pd->pd_mutex); 6570 6571 mutex_exit(&port->fp_mutex); 6572 6573 mutex_enter(&pd->pd_mutex); 6574 if (pd->pd_type != PORT_DEVICE_NEW) { 6575 if (is_private && (pd->pd_hard_addr.hard_addr != 6576 ha.hard_addr)) { 6577 pd->pd_type = PORT_DEVICE_CHANGED; 6578 } else { 6579 pd->pd_type = PORT_DEVICE_NOCHANGE; 6580 } 6581 } 6582 6583 if (is_private && (ha.hard_addr && 6584 pd->pd_port_id.port_id != ha.hard_addr)) { 6585 char ww_name[17]; 6586 6587 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6588 6589 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6590 "NL_Port Identifier %x doesn't match" 6591 " with Hard Address %x, Will use Port" 6592 " WWN %s", pd->pd_port_id.port_id, 6593 ha.hard_addr, ww_name); 6594 6595 pd->pd_hard_addr.hard_addr = 0; 6596 } else { 6597 pd->pd_hard_addr.hard_addr = ha.hard_addr; 6598 } 6599 mutex_exit(&pd->pd_mutex); 6600 } else { 6601 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6602 return; 6603 } 6604 } 6605 } else { 6606 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6607 return; 6608 } 6609 6610 mutex_enter(&port->fp_mutex); 6611 if (port->fp_statec_busy <= 1) { 6612 mutex_exit(&port->fp_mutex); 6613 if (pkt->pkt_state == FC_PKT_LS_RJT && 6614 pkt->pkt_reason == FC_REASON_CMD_UNABLE) { 6615 uchar_t class; 6616 int cmd_flag; 6617 uint32_t src_id; 6618 6619 class = fp_get_nextclass(port, 6620 FC_TRAN_CLASS_INVALID); 6621 if (class == FC_TRAN_CLASS_INVALID) { 6622 fp_iodone(cmd); 6623 return; 6624 } 6625 6626 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; " 6627 "fp_state=0x%x, pkt_state=0x%x, " 6628 "reason=0x%x, class=0x%x", 6629 port->fp_state, pkt->pkt_state, 6630 pkt->pkt_reason, class); 6631 cmd_flag = FP_CMD_PLOGI_RETAIN; 6632 6633 logi_cmd = fp_alloc_pkt(port, 6634 sizeof (la_els_logi_t), 6635 sizeof (la_els_logi_t), KM_SLEEP, pd); 6636 if (logi_cmd == NULL) { 6637 fp_iodone(cmd); 6638 return; 6639 } 6640 6641 logi_cmd->cmd_pkt.pkt_tran_flags = 6642 FC_TRAN_INTR | class; 6643 logi_cmd->cmd_pkt.pkt_tran_type = 6644 FC_PKT_EXCHANGE; 6645 logi_cmd->cmd_flags = cmd_flag; 6646 logi_cmd->cmd_retry_count = fp_retry_count; 6647 logi_cmd->cmd_ulp_pkt = NULL; 6648 6649 mutex_enter(&port->fp_mutex); 6650 src_id = port->fp_port_id.port_id; 6651 mutex_exit(&port->fp_mutex); 6652 6653 fp_xlogi_init(port, logi_cmd, src_id, 6654 pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr, 6655 cmd->cmd_job, LA_ELS_PLOGI); 6656 if (pd) { 6657 mutex_enter(&pd->pd_mutex); 6658 pd->pd_flags = PD_ELS_IN_PROGRESS; 6659 mutex_exit(&pd->pd_mutex); 6660 } 6661 6662 if (fp_sendcmd(port, logi_cmd, 6663 port->fp_fca_handle) == FC_SUCCESS) { 6664 fp_free_pkt(cmd); 6665 return; 6666 } else { 6667 fp_free_pkt(logi_cmd); 6668 } 6669 } else { 6670 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6671 "ADISC to %x failed, cmd_flags=%x", 6672 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags); 6673 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN; 6674 adiscfail = 1; 6675 } 6676 } else { 6677 mutex_exit(&port->fp_mutex); 6678 } 6679 } 6680 6681 if (cmd->cmd_ulp_pkt) { 6682 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6683 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6684 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6685 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6686 cmd->cmd_ulp_pkt->pkt_pd = pd; 6687 FP_TRACE(FP_NHEAD1(9, 0), 6688 "fp_adisc__intr;" 6689 "ulp_pkt's pd is NULL, get a pd %p", 6690 pd); 6691 6692 } 6693 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6694 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6695 sizeof (fc_frame_hdr_t)); 6696 bcopy((caddr_t)pkt->pkt_resp, 6697 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6698 sizeof (la_els_adisc_t)); 6699 } 6700 6701 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6702 FP_TRACE(FP_NHEAD1(9, 0), 6703 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, " 6704 "fp_retry_count=%x, ulp_pkt=%p", 6705 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt); 6706 6707 mutex_enter(&port->fp_mutex); 6708 mutex_enter(&pd->pd_mutex); 6709 6710 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6711 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6712 cmd->cmd_retry_count = fp_retry_count; 6713 6714 fp_logo_init(pd, cmd, cmd->cmd_job); 6715 6716 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6717 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6718 6719 mutex_exit(&pd->pd_mutex); 6720 mutex_exit(&port->fp_mutex); 6721 6722 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 6723 if (adiscfail) { 6724 mutex_enter(&pd->pd_mutex); 6725 initiator = 6726 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0); 6727 pd->pd_state = PORT_DEVICE_VALID; 6728 pd->pd_aux_flags |= PD_LOGGED_OUT; 6729 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6730 pd->pd_type = PORT_DEVICE_NEW; 6731 } else { 6732 pd->pd_type = PORT_DEVICE_NOCHANGE; 6733 } 6734 mutex_exit(&pd->pd_mutex); 6735 6736 changelist = 6737 kmem_zalloc(sizeof (*changelist), KM_SLEEP); 6738 6739 if (initiator) { 6740 fp_unregister_login(pd); 6741 fctl_copy_portmap(changelist, pd); 6742 } else { 6743 fp_fillout_old_map(changelist, pd, 0); 6744 } 6745 6746 FP_TRACE(FP_NHEAD1(9, 0), 6747 "fp_adisc_intr: Dev change notification " 6748 "to ULP port=%p, pd=%p, map_type=%x map_state=%x " 6749 "map_flags=%x initiator=%d", port, pd, 6750 changelist->map_type, changelist->map_state, 6751 changelist->map_flags, initiator); 6752 6753 (void) fp_ulp_devc_cb(port, changelist, 6754 1, 1, KM_SLEEP, 0); 6755 } 6756 if (rval == FC_SUCCESS) { 6757 return; 6758 } 6759 } 6760 fp_iodone(cmd); 6761 } 6762 6763 6764 /* 6765 * Handle solicited LOGO response 6766 */ 6767 static void 6768 fp_logo_intr(fc_packet_t *pkt) 6769 { 6770 ls_code_t resp; 6771 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6772 6773 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6774 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6775 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6776 6777 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6778 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6779 6780 if (FP_IS_PKT_ERROR(pkt)) { 6781 (void) fp_common_intr(pkt, 1); 6782 return; 6783 } 6784 6785 ASSERT(resp.ls_code == LA_ELS_ACC); 6786 if (resp.ls_code != LA_ELS_ACC) { 6787 (void) fp_common_intr(pkt, 1); 6788 return; 6789 } 6790 6791 if (pkt->pkt_pd != NULL) { 6792 fp_unregister_login(pkt->pkt_pd); 6793 } 6794 6795 fp_iodone(pkt->pkt_ulp_private); 6796 } 6797 6798 6799 /* 6800 * Handle solicited RNID response 6801 */ 6802 static void 6803 fp_rnid_intr(fc_packet_t *pkt) 6804 { 6805 ls_code_t resp; 6806 job_request_t *job; 6807 fp_cmd_t *cmd; 6808 la_els_rnid_acc_t *acc; 6809 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6810 6811 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6812 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6813 cmd = pkt->pkt_ulp_private; 6814 6815 mutex_enter(&cmd->cmd_port->fp_mutex); 6816 cmd->cmd_port->fp_out_fpcmds--; 6817 mutex_exit(&cmd->cmd_port->fp_mutex); 6818 6819 job = cmd->cmd_job; 6820 ASSERT(job->job_private != NULL); 6821 6822 /* If failure or LS_RJT then retry the packet, if needed */ 6823 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) { 6824 (void) fp_common_intr(pkt, 1); 6825 return; 6826 } 6827 6828 /* Save node_id memory allocated in ioctl code */ 6829 acc = (la_els_rnid_acc_t *)pkt->pkt_resp; 6830 6831 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6832 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR); 6833 6834 /* wakeup the ioctl thread and free the pkt */ 6835 fp_iodone(cmd); 6836 } 6837 6838 6839 /* 6840 * Handle solicited RLS response 6841 */ 6842 static void 6843 fp_rls_intr(fc_packet_t *pkt) 6844 { 6845 ls_code_t resp; 6846 job_request_t *job; 6847 fp_cmd_t *cmd; 6848 la_els_rls_acc_t *acc; 6849 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6850 6851 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6852 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6853 cmd = pkt->pkt_ulp_private; 6854 6855 mutex_enter(&cmd->cmd_port->fp_mutex); 6856 cmd->cmd_port->fp_out_fpcmds--; 6857 mutex_exit(&cmd->cmd_port->fp_mutex); 6858 6859 job = cmd->cmd_job; 6860 ASSERT(job->job_private != NULL); 6861 6862 /* If failure or LS_RJT then retry the packet, if needed */ 6863 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) { 6864 (void) fp_common_intr(pkt, 1); 6865 return; 6866 } 6867 6868 /* Save link error status block in memory allocated in ioctl code */ 6869 acc = (la_els_rls_acc_t *)pkt->pkt_resp; 6870 6871 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6872 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t), 6873 DDI_DEV_AUTOINCR); 6874 6875 /* wakeup the ioctl thread and free the pkt */ 6876 fp_iodone(cmd); 6877 } 6878 6879 6880 /* 6881 * A solicited command completion interrupt (mostly for commands 6882 * that require almost no post processing such as SCR ELS) 6883 */ 6884 static void 6885 fp_intr(fc_packet_t *pkt) 6886 { 6887 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6888 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6889 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6890 6891 if (FP_IS_PKT_ERROR(pkt)) { 6892 (void) fp_common_intr(pkt, 1); 6893 return; 6894 } 6895 fp_iodone(pkt->pkt_ulp_private); 6896 } 6897 6898 6899 /* 6900 * Handle the underlying port's state change 6901 */ 6902 static void 6903 fp_statec_cb(opaque_t port_handle, uint32_t state) 6904 { 6905 fc_local_port_t *port = port_handle; 6906 job_request_t *job; 6907 6908 /* 6909 * If it is not possible to process the callbacks 6910 * just drop the callback on the floor; Don't bother 6911 * to do something that isn't safe at this time 6912 */ 6913 mutex_enter(&port->fp_mutex); 6914 if ((port->fp_soft_state & 6915 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 6916 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) { 6917 mutex_exit(&port->fp_mutex); 6918 return; 6919 } 6920 6921 if (port->fp_statec_busy == 0) { 6922 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 6923 #ifdef DEBUG 6924 } else { 6925 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB); 6926 #endif 6927 } 6928 6929 port->fp_statec_busy++; 6930 6931 /* 6932 * For now, force the trusted method of device authentication (by 6933 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition. 6934 */ 6935 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP || 6936 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) { 6937 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP; 6938 fp_port_offline(port, 0); 6939 } 6940 mutex_exit(&port->fp_mutex); 6941 6942 switch (FC_PORT_STATE_MASK(state)) { 6943 case FC_STATE_OFFLINE: 6944 job = fctl_alloc_job(JOB_PORT_OFFLINE, 6945 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6946 if (job == NULL) { 6947 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6948 " fp_statec_cb() couldn't submit a job " 6949 " to the thread: failing.."); 6950 mutex_enter(&port->fp_mutex); 6951 if (--port->fp_statec_busy == 0) { 6952 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6953 } 6954 mutex_exit(&port->fp_mutex); 6955 return; 6956 } 6957 mutex_enter(&port->fp_mutex); 6958 /* 6959 * Zero out this field so that we do not retain 6960 * the fabric name as its no longer valid 6961 */ 6962 bzero(&port->fp_fabric_name, sizeof (la_wwn_t)); 6963 port->fp_state = state; 6964 mutex_exit(&port->fp_mutex); 6965 6966 fctl_enque_job(port, job); 6967 break; 6968 6969 case FC_STATE_ONLINE: 6970 case FC_STATE_LOOP: 6971 mutex_enter(&port->fp_mutex); 6972 port->fp_state = state; 6973 6974 if (port->fp_offline_tid) { 6975 timeout_id_t tid; 6976 6977 tid = port->fp_offline_tid; 6978 port->fp_offline_tid = NULL; 6979 mutex_exit(&port->fp_mutex); 6980 (void) untimeout(tid); 6981 } else { 6982 mutex_exit(&port->fp_mutex); 6983 } 6984 6985 job = fctl_alloc_job(JOB_PORT_ONLINE, 6986 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6987 if (job == NULL) { 6988 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6989 "fp_statec_cb() couldn't submit a job " 6990 "to the thread: failing.."); 6991 6992 mutex_enter(&port->fp_mutex); 6993 if (--port->fp_statec_busy == 0) { 6994 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6995 } 6996 mutex_exit(&port->fp_mutex); 6997 return; 6998 } 6999 fctl_enque_job(port, job); 7000 break; 7001 7002 case FC_STATE_RESET_REQUESTED: 7003 mutex_enter(&port->fp_mutex); 7004 port->fp_state = FC_STATE_OFFLINE; 7005 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET; 7006 mutex_exit(&port->fp_mutex); 7007 /* FALLTHROUGH */ 7008 7009 case FC_STATE_RESET: 7010 job = fctl_alloc_job(JOB_ULP_NOTIFY, 7011 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 7012 if (job == NULL) { 7013 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 7014 "fp_statec_cb() couldn't submit a job" 7015 " to the thread: failing.."); 7016 7017 mutex_enter(&port->fp_mutex); 7018 if (--port->fp_statec_busy == 0) { 7019 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 7020 } 7021 mutex_exit(&port->fp_mutex); 7022 return; 7023 } 7024 7025 /* squeeze into some field in the job structure */ 7026 job->job_ulp_listlen = FC_PORT_STATE_MASK(state); 7027 fctl_enque_job(port, job); 7028 break; 7029 7030 case FC_STATE_TARGET_PORT_RESET: 7031 (void) fp_ulp_notify(port, state, KM_NOSLEEP); 7032 /* FALLTHROUGH */ 7033 7034 case FC_STATE_NAMESERVICE: 7035 /* FALLTHROUGH */ 7036 7037 default: 7038 mutex_enter(&port->fp_mutex); 7039 if (--port->fp_statec_busy == 0) { 7040 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 7041 } 7042 mutex_exit(&port->fp_mutex); 7043 break; 7044 } 7045 } 7046 7047 7048 /* 7049 * Register with the Name Server for RSCNs 7050 */ 7051 static int 7052 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func, 7053 int sleep) 7054 { 7055 uint32_t s_id; 7056 uchar_t class; 7057 fc_scr_req_t payload; 7058 fp_cmd_t *cmd; 7059 fc_packet_t *pkt; 7060 7061 mutex_enter(&port->fp_mutex); 7062 s_id = port->fp_port_id.port_id; 7063 class = port->fp_ns_login_class; 7064 mutex_exit(&port->fp_mutex); 7065 7066 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t), 7067 sizeof (fc_scr_resp_t), sleep, NULL); 7068 if (cmd == NULL) { 7069 return (FC_NOMEM); 7070 } 7071 7072 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 7073 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 7074 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 7075 cmd->cmd_retry_count = fp_retry_count; 7076 cmd->cmd_ulp_pkt = NULL; 7077 7078 pkt = &cmd->cmd_pkt; 7079 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 7080 7081 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job); 7082 7083 payload.ls_code.ls_code = LA_ELS_SCR; 7084 payload.ls_code.mbz = 0; 7085 payload.scr_rsvd = 0; 7086 payload.scr_func = scr_func; 7087 7088 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 7089 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 7090 7091 job->job_counter = 1; 7092 7093 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 7094 fp_iodone(cmd); 7095 } 7096 7097 return (FC_SUCCESS); 7098 } 7099 7100 7101 /* 7102 * There are basically two methods to determine the total number of 7103 * devices out in the NS database; Reading the details of the two 7104 * methods described below, it shouldn't be hard to identify which 7105 * of the two methods is better. 7106 * 7107 * Method 1. 7108 * Iteratively issue GANs until all ports identifiers are walked 7109 * 7110 * Method 2. 7111 * Issue GID_PT (get port Identifiers) with Maximum residual 7112 * field in the request CT HEADER set to accommodate only the 7113 * CT HEADER in the response frame. And if FC-GS2 has been 7114 * carefully read, the NS here has a chance to FS_ACC the 7115 * request and indicate the residual size in the FS_ACC. 7116 * 7117 * Method 2 is wonderful, although it's not mandatory for the NS 7118 * to update the Maximum/Residual Field as can be seen in 4.3.1.6 7119 * (note with particular care the use of the auxiliary verb 'may') 7120 * 7121 */ 7122 static int 7123 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create, 7124 int sleep) 7125 { 7126 int flags; 7127 int rval; 7128 uint32_t src_id; 7129 fctl_ns_req_t *ns_cmd; 7130 7131 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 7132 7133 mutex_enter(&port->fp_mutex); 7134 src_id = port->fp_port_id.port_id; 7135 mutex_exit(&port->fp_mutex); 7136 7137 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7138 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t), 7139 sizeof (ns_resp_gid_pt_t), 0, 7140 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep); 7141 7142 if (ns_cmd == NULL) { 7143 return (FC_NOMEM); 7144 } 7145 7146 ns_cmd->ns_cmd_code = NS_GID_PT; 7147 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type 7148 = FC_NS_PORT_NX; /* All port types */ 7149 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0; 7150 7151 } else { 7152 uint32_t ns_flags; 7153 7154 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF; 7155 if (create) { 7156 ns_flags |= FCTL_NS_CREATE_DEVICE; 7157 } 7158 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 7159 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep); 7160 7161 if (ns_cmd == NULL) { 7162 return (FC_NOMEM); 7163 } 7164 ns_cmd->ns_gan_index = 0; 7165 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 7166 ns_cmd->ns_cmd_code = NS_GA_NXT; 7167 ns_cmd->ns_gan_max = 0xFFFF; 7168 7169 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id; 7170 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 7171 } 7172 7173 flags = job->job_flags; 7174 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 7175 job->job_counter = 1; 7176 7177 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 7178 job->job_flags = flags; 7179 7180 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7181 uint16_t max_resid; 7182 7183 /* 7184 * Revert to scanning the NS if NS_GID_PT isn't 7185 * helping us figure out total number of devices. 7186 */ 7187 if (job->job_result != FC_SUCCESS || 7188 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) { 7189 mutex_enter(&port->fp_mutex); 7190 port->fp_options &= ~FP_NS_SMART_COUNT; 7191 mutex_exit(&port->fp_mutex); 7192 7193 fctl_free_ns_cmd(ns_cmd); 7194 return (fp_ns_get_devcount(port, job, create, sleep)); 7195 } 7196 7197 mutex_enter(&port->fp_mutex); 7198 port->fp_total_devices = 1; 7199 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize; 7200 if (max_resid) { 7201 /* 7202 * Since port identifier is 4 bytes and max_resid 7203 * is also in WORDS, max_resid simply indicates 7204 * the total number of port identifiers not 7205 * transferred 7206 */ 7207 port->fp_total_devices += max_resid; 7208 } 7209 mutex_exit(&port->fp_mutex); 7210 } 7211 mutex_enter(&port->fp_mutex); 7212 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf); 7213 mutex_exit(&port->fp_mutex); 7214 fctl_free_ns_cmd(ns_cmd); 7215 7216 return (rval); 7217 } 7218 7219 /* 7220 * One heck of a function to serve userland. 7221 */ 7222 static int 7223 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 7224 { 7225 int rval = 0; 7226 int jcode; 7227 uint32_t ret; 7228 uchar_t open_flag; 7229 fcio_t *kfcio; 7230 job_request_t *job; 7231 boolean_t use32 = B_FALSE; 7232 7233 #ifdef _MULTI_DATAMODEL 7234 switch (ddi_model_convert_from(mode & FMODELS)) { 7235 case DDI_MODEL_ILP32: 7236 use32 = B_TRUE; 7237 break; 7238 7239 case DDI_MODEL_NONE: 7240 default: 7241 break; 7242 } 7243 #endif 7244 7245 mutex_enter(&port->fp_mutex); 7246 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 7247 FP_SOFT_IN_UNSOL_CB)) { 7248 fcio->fcio_errno = FC_STATEC_BUSY; 7249 mutex_exit(&port->fp_mutex); 7250 rval = EAGAIN; 7251 if (fp_fcio_copyout(fcio, data, mode)) { 7252 rval = EFAULT; 7253 } 7254 return (rval); 7255 } 7256 open_flag = port->fp_flag; 7257 mutex_exit(&port->fp_mutex); 7258 7259 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) { 7260 fcio->fcio_errno = FC_FAILURE; 7261 rval = EACCES; 7262 if (fp_fcio_copyout(fcio, data, mode)) { 7263 rval = EFAULT; 7264 } 7265 return (rval); 7266 } 7267 7268 /* 7269 * If an exclusive open was demanded during open, don't let 7270 * either innocuous or devil threads to share the file 7271 * descriptor and fire down exclusive access commands 7272 */ 7273 mutex_enter(&port->fp_mutex); 7274 if (port->fp_flag & FP_EXCL) { 7275 if (port->fp_flag & FP_EXCL_BUSY) { 7276 mutex_exit(&port->fp_mutex); 7277 fcio->fcio_errno = FC_FAILURE; 7278 return (EBUSY); 7279 } 7280 port->fp_flag |= FP_EXCL_BUSY; 7281 } 7282 mutex_exit(&port->fp_mutex); 7283 7284 fcio->fcio_errno = FC_SUCCESS; 7285 7286 switch (fcio->fcio_cmd) { 7287 case FCIO_GET_HOST_PARAMS: { 7288 fc_port_dev_t *val; 7289 fc_port_dev32_t *val32; 7290 int index; 7291 int lilp_device_count; 7292 fc_lilpmap_t *lilp_map; 7293 uchar_t *alpa_list; 7294 7295 if (use32 == B_TRUE) { 7296 if (fcio->fcio_olen != sizeof (*val32) || 7297 fcio->fcio_xfer != FCIO_XFER_READ) { 7298 rval = EINVAL; 7299 break; 7300 } 7301 } else { 7302 if (fcio->fcio_olen != sizeof (*val) || 7303 fcio->fcio_xfer != FCIO_XFER_READ) { 7304 rval = EINVAL; 7305 break; 7306 } 7307 } 7308 7309 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7310 7311 mutex_enter(&port->fp_mutex); 7312 val->dev_did = port->fp_port_id; 7313 val->dev_hard_addr = port->fp_hard_addr; 7314 val->dev_pwwn = port->fp_service_params.nport_ww_name; 7315 val->dev_nwwn = port->fp_service_params.node_ww_name; 7316 val->dev_state = port->fp_state; 7317 7318 lilp_map = &port->fp_lilp_map; 7319 alpa_list = &lilp_map->lilp_alpalist[0]; 7320 lilp_device_count = lilp_map->lilp_length; 7321 for (index = 0; index < lilp_device_count; index++) { 7322 uint32_t d_id; 7323 7324 d_id = alpa_list[index]; 7325 if (d_id == port->fp_port_id.port_id) { 7326 break; 7327 } 7328 } 7329 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff); 7330 7331 bcopy(port->fp_fc4_types, val->dev_type, 7332 sizeof (port->fp_fc4_types)); 7333 mutex_exit(&port->fp_mutex); 7334 7335 if (use32 == B_TRUE) { 7336 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7337 7338 val32->dev_did = val->dev_did; 7339 val32->dev_hard_addr = val->dev_hard_addr; 7340 val32->dev_pwwn = val->dev_pwwn; 7341 val32->dev_nwwn = val->dev_nwwn; 7342 val32->dev_state = val->dev_state; 7343 val32->dev_did.priv_lilp_posit = 7344 val->dev_did.priv_lilp_posit; 7345 7346 bcopy(val->dev_type, val32->dev_type, 7347 sizeof (port->fp_fc4_types)); 7348 7349 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7350 fcio->fcio_olen, mode) == 0) { 7351 if (fp_fcio_copyout(fcio, data, mode)) { 7352 rval = EFAULT; 7353 } 7354 } else { 7355 rval = EFAULT; 7356 } 7357 7358 kmem_free(val32, sizeof (*val32)); 7359 } else { 7360 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7361 fcio->fcio_olen, mode) == 0) { 7362 if (fp_fcio_copyout(fcio, data, mode)) { 7363 rval = EFAULT; 7364 } 7365 } else { 7366 rval = EFAULT; 7367 } 7368 } 7369 7370 /* need to free "val" here */ 7371 kmem_free(val, sizeof (*val)); 7372 break; 7373 } 7374 7375 case FCIO_GET_OTHER_ADAPTER_PORTS: { 7376 uint32_t index; 7377 char *tmpPath; 7378 fc_local_port_t *tmpPort; 7379 7380 if (fcio->fcio_olen < MAXPATHLEN || 7381 fcio->fcio_ilen != sizeof (uint32_t)) { 7382 rval = EINVAL; 7383 break; 7384 } 7385 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7386 rval = EFAULT; 7387 break; 7388 } 7389 7390 tmpPort = fctl_get_adapter_port_by_index(port, index); 7391 if (tmpPort == NULL) { 7392 FP_TRACE(FP_NHEAD1(9, 0), 7393 "User supplied index out of range"); 7394 fcio->fcio_errno = FC_BADPORT; 7395 rval = EFAULT; 7396 if (fp_fcio_copyout(fcio, data, mode)) { 7397 rval = EFAULT; 7398 } 7399 break; 7400 } 7401 7402 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7403 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath); 7404 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf, 7405 MAXPATHLEN, mode) == 0) { 7406 if (fp_fcio_copyout(fcio, data, mode)) { 7407 rval = EFAULT; 7408 } 7409 } else { 7410 rval = EFAULT; 7411 } 7412 kmem_free(tmpPath, MAXPATHLEN); 7413 break; 7414 } 7415 7416 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES: 7417 case FCIO_GET_ADAPTER_ATTRIBUTES: { 7418 fc_hba_adapter_attributes_t *val; 7419 fc_hba_adapter_attributes32_t *val32; 7420 7421 if (use32 == B_TRUE) { 7422 if (fcio->fcio_olen < sizeof (*val32) || 7423 fcio->fcio_xfer != FCIO_XFER_READ) { 7424 rval = EINVAL; 7425 break; 7426 } 7427 } else { 7428 if (fcio->fcio_olen < sizeof (*val) || 7429 fcio->fcio_xfer != FCIO_XFER_READ) { 7430 rval = EINVAL; 7431 break; 7432 } 7433 } 7434 7435 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7436 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; 7437 mutex_enter(&port->fp_mutex); 7438 bcopy(port->fp_hba_port_attrs.manufacturer, 7439 val->Manufacturer, 7440 sizeof (val->Manufacturer)); 7441 bcopy(port->fp_hba_port_attrs.serial_number, 7442 val->SerialNumber, 7443 sizeof (val->SerialNumber)); 7444 bcopy(port->fp_hba_port_attrs.model, 7445 val->Model, 7446 sizeof (val->Model)); 7447 bcopy(port->fp_hba_port_attrs.model_description, 7448 val->ModelDescription, 7449 sizeof (val->ModelDescription)); 7450 bcopy(port->fp_sym_node_name, val->NodeSymbolicName, 7451 port->fp_sym_node_namelen); 7452 bcopy(port->fp_hba_port_attrs.hardware_version, 7453 val->HardwareVersion, 7454 sizeof (val->HardwareVersion)); 7455 bcopy(port->fp_hba_port_attrs.option_rom_version, 7456 val->OptionROMVersion, 7457 sizeof (val->OptionROMVersion)); 7458 bcopy(port->fp_hba_port_attrs.firmware_version, 7459 val->FirmwareVersion, 7460 sizeof (val->FirmwareVersion)); 7461 val->VendorSpecificID = 7462 port->fp_hba_port_attrs.vendor_specific_id; 7463 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7464 &val->NodeWWN.raw_wwn, 7465 sizeof (val->NodeWWN.raw_wwn)); 7466 7467 7468 bcopy(port->fp_hba_port_attrs.driver_name, 7469 val->DriverName, 7470 sizeof (val->DriverName)); 7471 bcopy(port->fp_hba_port_attrs.driver_version, 7472 val->DriverVersion, 7473 sizeof (val->DriverVersion)); 7474 mutex_exit(&port->fp_mutex); 7475 7476 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) { 7477 val->NumberOfPorts = fctl_count_fru_ports(port, 0); 7478 } else { 7479 val->NumberOfPorts = fctl_count_fru_ports(port, 1); 7480 } 7481 7482 if (use32 == B_TRUE) { 7483 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7484 val32->version = val->version; 7485 bcopy(val->Manufacturer, val32->Manufacturer, 7486 sizeof (val->Manufacturer)); 7487 bcopy(val->SerialNumber, val32->SerialNumber, 7488 sizeof (val->SerialNumber)); 7489 bcopy(val->Model, val32->Model, 7490 sizeof (val->Model)); 7491 bcopy(val->ModelDescription, val32->ModelDescription, 7492 sizeof (val->ModelDescription)); 7493 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName, 7494 sizeof (val->NodeSymbolicName)); 7495 bcopy(val->HardwareVersion, val32->HardwareVersion, 7496 sizeof (val->HardwareVersion)); 7497 bcopy(val->OptionROMVersion, val32->OptionROMVersion, 7498 sizeof (val->OptionROMVersion)); 7499 bcopy(val->FirmwareVersion, val32->FirmwareVersion, 7500 sizeof (val->FirmwareVersion)); 7501 val32->VendorSpecificID = val->VendorSpecificID; 7502 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7503 sizeof (val->NodeWWN.raw_wwn)); 7504 bcopy(val->DriverName, val32->DriverName, 7505 sizeof (val->DriverName)); 7506 bcopy(val->DriverVersion, val32->DriverVersion, 7507 sizeof (val->DriverVersion)); 7508 7509 val32->NumberOfPorts = val->NumberOfPorts; 7510 7511 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7512 fcio->fcio_olen, mode) == 0) { 7513 if (fp_fcio_copyout(fcio, data, mode)) { 7514 rval = EFAULT; 7515 } 7516 } else { 7517 rval = EFAULT; 7518 } 7519 7520 kmem_free(val32, sizeof (*val32)); 7521 } else { 7522 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7523 fcio->fcio_olen, mode) == 0) { 7524 if (fp_fcio_copyout(fcio, data, mode)) { 7525 rval = EFAULT; 7526 } 7527 } else { 7528 rval = EFAULT; 7529 } 7530 } 7531 7532 kmem_free(val, sizeof (*val)); 7533 break; 7534 } 7535 7536 case FCIO_GET_NPIV_ATTRIBUTES: { 7537 fc_hba_npiv_attributes_t *attrs; 7538 7539 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP); 7540 mutex_enter(&port->fp_mutex); 7541 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7542 &attrs->NodeWWN.raw_wwn, 7543 sizeof (attrs->NodeWWN.raw_wwn)); 7544 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7545 &attrs->PortWWN.raw_wwn, 7546 sizeof (attrs->PortWWN.raw_wwn)); 7547 mutex_exit(&port->fp_mutex); 7548 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf, 7549 fcio->fcio_olen, mode) == 0) { 7550 if (fp_fcio_copyout(fcio, data, mode)) { 7551 rval = EFAULT; 7552 } 7553 } else { 7554 rval = EFAULT; 7555 } 7556 kmem_free(attrs, sizeof (*attrs)); 7557 break; 7558 } 7559 7560 case FCIO_DELETE_NPIV_PORT: { 7561 fc_local_port_t *tmpport; 7562 char ww_pname[17]; 7563 la_wwn_t vwwn[1]; 7564 7565 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port"); 7566 if (ddi_copyin(fcio->fcio_ibuf, 7567 &vwwn, sizeof (la_wwn_t), mode)) { 7568 rval = EFAULT; 7569 break; 7570 } 7571 7572 fc_wwn_to_str(&vwwn[0], ww_pname); 7573 FP_TRACE(FP_NHEAD1(3, 0), 7574 "Delete NPIV Port %s", ww_pname); 7575 tmpport = fc_delete_npiv_port(port, &vwwn[0]); 7576 if (tmpport == NULL) { 7577 FP_TRACE(FP_NHEAD1(3, 0), 7578 "Delete NPIV Port : no found"); 7579 rval = EFAULT; 7580 } else { 7581 fc_local_port_t *nextport = tmpport->fp_port_next; 7582 fc_local_port_t *prevport = tmpport->fp_port_prev; 7583 int portlen, portindex, ret; 7584 7585 portlen = sizeof (portindex); 7586 ret = ddi_prop_op(DDI_DEV_T_ANY, 7587 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF, 7588 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 7589 (caddr_t)&portindex, &portlen); 7590 if (ret != DDI_SUCCESS) { 7591 rval = EFAULT; 7592 break; 7593 } 7594 if (ndi_devi_offline(tmpport->fp_port_dip, 7595 NDI_DEVI_REMOVE) != DDI_SUCCESS) { 7596 FP_TRACE(FP_NHEAD1(1, 0), 7597 "Delete NPIV Port failed"); 7598 mutex_enter(&port->fp_mutex); 7599 tmpport->fp_npiv_state = 0; 7600 mutex_exit(&port->fp_mutex); 7601 rval = EFAULT; 7602 } else { 7603 mutex_enter(&port->fp_mutex); 7604 nextport->fp_port_prev = prevport; 7605 prevport->fp_port_next = nextport; 7606 if (port == port->fp_port_next) { 7607 port->fp_port_next = 7608 port->fp_port_prev = NULL; 7609 } 7610 port->fp_npiv_portnum--; 7611 FP_TRACE(FP_NHEAD1(3, 0), 7612 "Delete NPIV Port %d", portindex); 7613 port->fp_npiv_portindex[portindex-1] = 0; 7614 mutex_exit(&port->fp_mutex); 7615 } 7616 } 7617 break; 7618 } 7619 7620 case FCIO_CREATE_NPIV_PORT: { 7621 char ww_nname[17], ww_pname[17]; 7622 la_npiv_create_entry_t entrybuf; 7623 uint32_t vportindex = 0; 7624 int npiv_ret = 0; 7625 char *portname, *fcaname; 7626 7627 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7628 (void) ddi_pathname(port->fp_port_dip, portname); 7629 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7630 (void) ddi_pathname(port->fp_fca_dip, fcaname); 7631 FP_TRACE(FP_NHEAD1(1, 0), 7632 "Create NPIV port %s %s %s", portname, fcaname, 7633 ddi_driver_name(port->fp_fca_dip)); 7634 kmem_free(portname, MAXPATHLEN); 7635 kmem_free(fcaname, MAXPATHLEN); 7636 if (ddi_copyin(fcio->fcio_ibuf, 7637 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) { 7638 rval = EFAULT; 7639 break; 7640 } 7641 7642 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname); 7643 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname); 7644 vportindex = entrybuf.vindex; 7645 FP_TRACE(FP_NHEAD1(3, 0), 7646 "Create NPIV Port %s %s %d", 7647 ww_nname, ww_pname, vportindex); 7648 7649 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) { 7650 rval = EFAULT; 7651 break; 7652 } 7653 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip, 7654 port->fp_port_dip, ww_nname, ww_pname, &vportindex); 7655 if (npiv_ret == NDI_SUCCESS) { 7656 mutex_enter(&port->fp_mutex); 7657 port->fp_npiv_portnum++; 7658 mutex_exit(&port->fp_mutex); 7659 if (fp_copyout((void *)&vportindex, 7660 (void *)fcio->fcio_obuf, 7661 fcio->fcio_olen, mode) == 0) { 7662 if (fp_fcio_copyout(fcio, data, mode)) { 7663 rval = EFAULT; 7664 } 7665 } else { 7666 rval = EFAULT; 7667 } 7668 } else { 7669 rval = EFAULT; 7670 } 7671 FP_TRACE(FP_NHEAD1(3, 0), 7672 "Create NPIV Port %d %d", npiv_ret, vportindex); 7673 break; 7674 } 7675 7676 case FCIO_GET_NPIV_PORT_LIST: { 7677 fc_hba_npiv_port_list_t *list; 7678 int count; 7679 7680 if ((fcio->fcio_xfer != FCIO_XFER_READ) || 7681 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { 7682 rval = EINVAL; 7683 break; 7684 } 7685 7686 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 7687 list->version = FC_HBA_LIST_VERSION; 7688 7689 count = (fcio->fcio_olen - 7690 (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN + 1; 7691 if (port->fp_npiv_portnum > count) { 7692 list->numAdapters = port->fp_npiv_portnum; 7693 } else { 7694 /* build npiv port list */ 7695 count = fc_ulp_get_npiv_port_list(port, 7696 (char *)list->hbaPaths); 7697 if (count < 0) { 7698 rval = ENXIO; 7699 FP_TRACE(FP_NHEAD1(1, 0), 7700 "Build NPIV Port List error"); 7701 kmem_free(list, fcio->fcio_olen); 7702 break; 7703 } 7704 list->numAdapters = count; 7705 } 7706 7707 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf, 7708 fcio->fcio_olen, mode) == 0) { 7709 if (fp_fcio_copyout(fcio, data, mode)) { 7710 FP_TRACE(FP_NHEAD1(1, 0), 7711 "Copy NPIV Port data error"); 7712 rval = EFAULT; 7713 } 7714 } else { 7715 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error"); 7716 rval = EFAULT; 7717 } 7718 kmem_free(list, fcio->fcio_olen); 7719 break; 7720 } 7721 7722 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: { 7723 fc_hba_port_npiv_attributes_t *val; 7724 7725 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7726 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION; 7727 7728 mutex_enter(&port->fp_mutex); 7729 val->npivflag = port->fp_npiv_flag; 7730 val->lastChange = port->fp_last_change; 7731 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7732 &val->PortWWN.raw_wwn, 7733 sizeof (val->PortWWN.raw_wwn)); 7734 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7735 &val->NodeWWN.raw_wwn, 7736 sizeof (val->NodeWWN.raw_wwn)); 7737 mutex_exit(&port->fp_mutex); 7738 7739 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port); 7740 if (port->fp_npiv_type != FC_NPIV_PORT) { 7741 val->MaxNumberOfNPIVPorts = 7742 port->fp_fca_tran->fca_num_npivports; 7743 } else { 7744 val->MaxNumberOfNPIVPorts = 0; 7745 } 7746 7747 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7748 fcio->fcio_olen, mode) == 0) { 7749 if (fp_fcio_copyout(fcio, data, mode)) { 7750 rval = EFAULT; 7751 } 7752 } else { 7753 rval = EFAULT; 7754 } 7755 kmem_free(val, sizeof (*val)); 7756 break; 7757 } 7758 7759 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: { 7760 fc_hba_port_attributes_t *val; 7761 fc_hba_port_attributes32_t *val32; 7762 7763 if (use32 == B_TRUE) { 7764 if (fcio->fcio_olen < sizeof (*val32) || 7765 fcio->fcio_xfer != FCIO_XFER_READ) { 7766 rval = EINVAL; 7767 break; 7768 } 7769 } else { 7770 if (fcio->fcio_olen < sizeof (*val) || 7771 fcio->fcio_xfer != FCIO_XFER_READ) { 7772 rval = EINVAL; 7773 break; 7774 } 7775 } 7776 7777 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7778 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7779 mutex_enter(&port->fp_mutex); 7780 val->lastChange = port->fp_last_change; 7781 val->fp_minor = port->fp_instance; 7782 7783 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7784 &val->PortWWN.raw_wwn, 7785 sizeof (val->PortWWN.raw_wwn)); 7786 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7787 &val->NodeWWN.raw_wwn, 7788 sizeof (val->NodeWWN.raw_wwn)); 7789 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn, 7790 sizeof (val->FabricName.raw_wwn)); 7791 7792 val->PortFcId = port->fp_port_id.port_id; 7793 7794 switch (FC_PORT_STATE_MASK(port->fp_state)) { 7795 case FC_STATE_OFFLINE: 7796 val->PortState = FC_HBA_PORTSTATE_OFFLINE; 7797 break; 7798 case FC_STATE_ONLINE: 7799 case FC_STATE_LOOP: 7800 case FC_STATE_NAMESERVICE: 7801 val->PortState = FC_HBA_PORTSTATE_ONLINE; 7802 break; 7803 default: 7804 val->PortState = FC_HBA_PORTSTATE_UNKNOWN; 7805 break; 7806 } 7807 7808 /* Translate from LV to FC-HBA port type codes */ 7809 switch (port->fp_port_type.port_type) { 7810 case FC_NS_PORT_N: 7811 val->PortType = FC_HBA_PORTTYPE_NPORT; 7812 break; 7813 case FC_NS_PORT_NL: 7814 /* Actually means loop for us */ 7815 val->PortType = FC_HBA_PORTTYPE_LPORT; 7816 break; 7817 case FC_NS_PORT_F: 7818 val->PortType = FC_HBA_PORTTYPE_FPORT; 7819 break; 7820 case FC_NS_PORT_FL: 7821 val->PortType = FC_HBA_PORTTYPE_FLPORT; 7822 break; 7823 case FC_NS_PORT_E: 7824 val->PortType = FC_HBA_PORTTYPE_EPORT; 7825 break; 7826 default: 7827 val->PortType = FC_HBA_PORTTYPE_OTHER; 7828 break; 7829 } 7830 7831 7832 /* 7833 * If fp has decided that the topology is public loop, 7834 * we will indicate that using the appropriate 7835 * FC HBA API constant. 7836 */ 7837 switch (port->fp_topology) { 7838 case FC_TOP_PUBLIC_LOOP: 7839 val->PortType = FC_HBA_PORTTYPE_NLPORT; 7840 break; 7841 7842 case FC_TOP_PT_PT: 7843 val->PortType = FC_HBA_PORTTYPE_PTP; 7844 break; 7845 7846 case FC_TOP_UNKNOWN: 7847 /* 7848 * This should cover the case where nothing is connected 7849 * to the port. Crystal+ is p'bly an exception here. 7850 * For Crystal+, port 0 will come up as private loop 7851 * (i.e fp_bind_state will be FC_STATE_LOOP) even when 7852 * nothing is connected to it. 7853 * Current plan is to let userland handle this. 7854 */ 7855 if (port->fp_bind_state == FC_STATE_OFFLINE) { 7856 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7857 } 7858 break; 7859 7860 default: 7861 /* 7862 * Do Nothing. 7863 * Unused: 7864 * val->PortType = FC_HBA_PORTTYPE_GPORT; 7865 */ 7866 break; 7867 } 7868 7869 val->PortSupportedClassofService = 7870 port->fp_hba_port_attrs.supported_cos; 7871 val->PortSupportedFc4Types[0] = 0; 7872 bcopy(port->fp_fc4_types, val->PortActiveFc4Types, 7873 sizeof (val->PortActiveFc4Types)); 7874 bcopy(port->fp_sym_port_name, val->PortSymbolicName, 7875 port->fp_sym_port_namelen); 7876 val->PortSupportedSpeed = 7877 port->fp_hba_port_attrs.supported_speed; 7878 7879 switch (FC_PORT_SPEED_MASK(port->fp_state)) { 7880 case FC_STATE_1GBIT_SPEED: 7881 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT; 7882 break; 7883 case FC_STATE_2GBIT_SPEED: 7884 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT; 7885 break; 7886 case FC_STATE_4GBIT_SPEED: 7887 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT; 7888 break; 7889 case FC_STATE_8GBIT_SPEED: 7890 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT; 7891 break; 7892 case FC_STATE_10GBIT_SPEED: 7893 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT; 7894 break; 7895 case FC_STATE_16GBIT_SPEED: 7896 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT; 7897 break; 7898 default: 7899 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7900 break; 7901 } 7902 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size; 7903 val->NumberofDiscoveredPorts = port->fp_dev_count; 7904 mutex_exit(&port->fp_mutex); 7905 7906 if (use32 == B_TRUE) { 7907 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7908 val32->version = val->version; 7909 val32->lastChange = val->lastChange; 7910 val32->fp_minor = val->fp_minor; 7911 7912 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn, 7913 sizeof (val->PortWWN.raw_wwn)); 7914 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7915 sizeof (val->NodeWWN.raw_wwn)); 7916 val32->PortFcId = val->PortFcId; 7917 val32->PortState = val->PortState; 7918 val32->PortType = val->PortType; 7919 7920 val32->PortSupportedClassofService = 7921 val->PortSupportedClassofService; 7922 bcopy(val->PortActiveFc4Types, 7923 val32->PortActiveFc4Types, 7924 sizeof (val->PortActiveFc4Types)); 7925 bcopy(val->PortSymbolicName, val32->PortSymbolicName, 7926 sizeof (val->PortSymbolicName)); 7927 bcopy(&val->FabricName, &val32->FabricName, 7928 sizeof (val->FabricName.raw_wwn)); 7929 val32->PortSupportedSpeed = val->PortSupportedSpeed; 7930 val32->PortSpeed = val->PortSpeed; 7931 7932 val32->PortMaxFrameSize = val->PortMaxFrameSize; 7933 val32->NumberofDiscoveredPorts = 7934 val->NumberofDiscoveredPorts; 7935 7936 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7937 fcio->fcio_olen, mode) == 0) { 7938 if (fp_fcio_copyout(fcio, data, mode)) { 7939 rval = EFAULT; 7940 } 7941 } else { 7942 rval = EFAULT; 7943 } 7944 7945 kmem_free(val32, sizeof (*val32)); 7946 } else { 7947 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7948 fcio->fcio_olen, mode) == 0) { 7949 if (fp_fcio_copyout(fcio, data, mode)) { 7950 rval = EFAULT; 7951 } 7952 } else { 7953 rval = EFAULT; 7954 } 7955 } 7956 7957 kmem_free(val, sizeof (*val)); 7958 break; 7959 } 7960 7961 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: { 7962 fc_hba_port_attributes_t *val; 7963 fc_hba_port_attributes32_t *val32; 7964 uint32_t index = 0; 7965 fc_remote_port_t *tmp_pd; 7966 7967 if (use32 == B_TRUE) { 7968 if (fcio->fcio_olen < sizeof (*val32) || 7969 fcio->fcio_xfer != FCIO_XFER_READ) { 7970 rval = EINVAL; 7971 break; 7972 } 7973 } else { 7974 if (fcio->fcio_olen < sizeof (*val) || 7975 fcio->fcio_xfer != FCIO_XFER_READ) { 7976 rval = EINVAL; 7977 break; 7978 } 7979 } 7980 7981 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7982 rval = EFAULT; 7983 break; 7984 } 7985 7986 if (index >= port->fp_dev_count) { 7987 FP_TRACE(FP_NHEAD1(9, 0), 7988 "User supplied index out of range"); 7989 fcio->fcio_errno = FC_OUTOFBOUNDS; 7990 rval = EINVAL; 7991 if (fp_fcio_copyout(fcio, data, mode)) { 7992 rval = EFAULT; 7993 } 7994 break; 7995 } 7996 7997 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7998 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7999 8000 mutex_enter(&port->fp_mutex); 8001 tmp_pd = fctl_lookup_pd_by_index(port, index); 8002 8003 if (tmp_pd == NULL) { 8004 fcio->fcio_errno = FC_BADPORT; 8005 rval = EINVAL; 8006 } else { 8007 val->lastChange = port->fp_last_change; 8008 val->fp_minor = port->fp_instance; 8009 8010 mutex_enter(&tmp_pd->pd_mutex); 8011 bcopy(&tmp_pd->pd_port_name.raw_wwn, 8012 &val->PortWWN.raw_wwn, 8013 sizeof (val->PortWWN.raw_wwn)); 8014 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 8015 &val->NodeWWN.raw_wwn, 8016 sizeof (val->NodeWWN.raw_wwn)); 8017 val->PortFcId = tmp_pd->pd_port_id.port_id; 8018 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 8019 tmp_pd->pd_spn_len); 8020 val->PortSupportedClassofService = tmp_pd->pd_cos; 8021 /* 8022 * we will assume the sizeof these pd_fc4types and 8023 * portActiveFc4Types will remain the same. we could 8024 * add in a check for it, but we decided it was unneeded 8025 */ 8026 bcopy((caddr_t)tmp_pd->pd_fc4types, 8027 val->PortActiveFc4Types, 8028 sizeof (tmp_pd->pd_fc4types)); 8029 val->PortState = 8030 fp_map_remote_port_state(tmp_pd->pd_state); 8031 mutex_exit(&tmp_pd->pd_mutex); 8032 8033 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 8034 val->PortSupportedFc4Types[0] = 0; 8035 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8036 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8037 val->PortMaxFrameSize = 0; 8038 val->NumberofDiscoveredPorts = 0; 8039 8040 if (use32 == B_TRUE) { 8041 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 8042 val32->version = val->version; 8043 val32->lastChange = val->lastChange; 8044 val32->fp_minor = val->fp_minor; 8045 8046 bcopy(&val->PortWWN.raw_wwn, 8047 &val32->PortWWN.raw_wwn, 8048 sizeof (val->PortWWN.raw_wwn)); 8049 bcopy(&val->NodeWWN.raw_wwn, 8050 &val32->NodeWWN.raw_wwn, 8051 sizeof (val->NodeWWN.raw_wwn)); 8052 val32->PortFcId = val->PortFcId; 8053 bcopy(val->PortSymbolicName, 8054 val32->PortSymbolicName, 8055 sizeof (val->PortSymbolicName)); 8056 val32->PortSupportedClassofService = 8057 val->PortSupportedClassofService; 8058 bcopy(val->PortActiveFc4Types, 8059 val32->PortActiveFc4Types, 8060 sizeof (tmp_pd->pd_fc4types)); 8061 8062 val32->PortType = val->PortType; 8063 val32->PortState = val->PortState; 8064 val32->PortSupportedFc4Types[0] = 8065 val->PortSupportedFc4Types[0]; 8066 val32->PortSupportedSpeed = 8067 val->PortSupportedSpeed; 8068 val32->PortSpeed = val->PortSpeed; 8069 val32->PortMaxFrameSize = 8070 val->PortMaxFrameSize; 8071 val32->NumberofDiscoveredPorts = 8072 val->NumberofDiscoveredPorts; 8073 8074 if (fp_copyout((void *)val32, 8075 (void *)fcio->fcio_obuf, 8076 fcio->fcio_olen, mode) == 0) { 8077 if (fp_fcio_copyout(fcio, 8078 data, mode)) { 8079 rval = EFAULT; 8080 } 8081 } else { 8082 rval = EFAULT; 8083 } 8084 8085 kmem_free(val32, sizeof (*val32)); 8086 } else { 8087 if (fp_copyout((void *)val, 8088 (void *)fcio->fcio_obuf, 8089 fcio->fcio_olen, mode) == 0) { 8090 if (fp_fcio_copyout(fcio, data, mode)) { 8091 rval = EFAULT; 8092 } 8093 } else { 8094 rval = EFAULT; 8095 } 8096 } 8097 } 8098 8099 mutex_exit(&port->fp_mutex); 8100 kmem_free(val, sizeof (*val)); 8101 break; 8102 } 8103 8104 case FCIO_GET_PORT_ATTRIBUTES: { 8105 fc_hba_port_attributes_t *val; 8106 fc_hba_port_attributes32_t *val32; 8107 la_wwn_t wwn; 8108 fc_remote_port_t *tmp_pd; 8109 8110 if (use32 == B_TRUE) { 8111 if (fcio->fcio_olen < sizeof (*val32) || 8112 fcio->fcio_xfer != FCIO_XFER_READ) { 8113 rval = EINVAL; 8114 break; 8115 } 8116 } else { 8117 if (fcio->fcio_olen < sizeof (*val) || 8118 fcio->fcio_xfer != FCIO_XFER_READ) { 8119 rval = EINVAL; 8120 break; 8121 } 8122 } 8123 8124 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) { 8125 rval = EFAULT; 8126 break; 8127 } 8128 8129 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 8130 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 8131 8132 mutex_enter(&port->fp_mutex); 8133 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn); 8134 val->lastChange = port->fp_last_change; 8135 val->fp_minor = port->fp_instance; 8136 mutex_exit(&port->fp_mutex); 8137 8138 if (tmp_pd == NULL) { 8139 fcio->fcio_errno = FC_BADWWN; 8140 rval = EINVAL; 8141 } else { 8142 mutex_enter(&tmp_pd->pd_mutex); 8143 bcopy(&tmp_pd->pd_port_name.raw_wwn, 8144 &val->PortWWN.raw_wwn, 8145 sizeof (val->PortWWN.raw_wwn)); 8146 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 8147 &val->NodeWWN.raw_wwn, 8148 sizeof (val->NodeWWN.raw_wwn)); 8149 val->PortFcId = tmp_pd->pd_port_id.port_id; 8150 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 8151 tmp_pd->pd_spn_len); 8152 val->PortSupportedClassofService = tmp_pd->pd_cos; 8153 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 8154 val->PortState = 8155 fp_map_remote_port_state(tmp_pd->pd_state); 8156 val->PortSupportedFc4Types[0] = 0; 8157 /* 8158 * we will assume the sizeof these pd_fc4types and 8159 * portActiveFc4Types will remain the same. we could 8160 * add in a check for it, but we decided it was unneeded 8161 */ 8162 bcopy((caddr_t)tmp_pd->pd_fc4types, 8163 val->PortActiveFc4Types, 8164 sizeof (tmp_pd->pd_fc4types)); 8165 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8166 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8167 val->PortMaxFrameSize = 0; 8168 val->NumberofDiscoveredPorts = 0; 8169 mutex_exit(&tmp_pd->pd_mutex); 8170 8171 if (use32 == B_TRUE) { 8172 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 8173 val32->version = val->version; 8174 val32->lastChange = val->lastChange; 8175 val32->fp_minor = val->fp_minor; 8176 bcopy(&val->PortWWN.raw_wwn, 8177 &val32->PortWWN.raw_wwn, 8178 sizeof (val->PortWWN.raw_wwn)); 8179 bcopy(&val->NodeWWN.raw_wwn, 8180 &val32->NodeWWN.raw_wwn, 8181 sizeof (val->NodeWWN.raw_wwn)); 8182 val32->PortFcId = val->PortFcId; 8183 bcopy(val->PortSymbolicName, 8184 val32->PortSymbolicName, 8185 sizeof (val->PortSymbolicName)); 8186 val32->PortSupportedClassofService = 8187 val->PortSupportedClassofService; 8188 val32->PortType = val->PortType; 8189 val32->PortState = val->PortState; 8190 val32->PortSupportedFc4Types[0] = 8191 val->PortSupportedFc4Types[0]; 8192 bcopy(val->PortActiveFc4Types, 8193 val32->PortActiveFc4Types, 8194 sizeof (tmp_pd->pd_fc4types)); 8195 val32->PortSupportedSpeed = 8196 val->PortSupportedSpeed; 8197 val32->PortSpeed = val->PortSpeed; 8198 val32->PortMaxFrameSize = val->PortMaxFrameSize; 8199 val32->NumberofDiscoveredPorts = 8200 val->NumberofDiscoveredPorts; 8201 8202 if (fp_copyout((void *)val32, 8203 (void *)fcio->fcio_obuf, 8204 fcio->fcio_olen, mode) == 0) { 8205 if (fp_fcio_copyout(fcio, data, mode)) { 8206 rval = EFAULT; 8207 } 8208 } else { 8209 rval = EFAULT; 8210 } 8211 8212 kmem_free(val32, sizeof (*val32)); 8213 } else { 8214 if (fp_copyout((void *)val, 8215 (void *)fcio->fcio_obuf, 8216 fcio->fcio_olen, mode) == 0) { 8217 if (fp_fcio_copyout(fcio, data, mode)) { 8218 rval = EFAULT; 8219 } 8220 } else { 8221 rval = EFAULT; 8222 } 8223 } 8224 } 8225 kmem_free(val, sizeof (*val)); 8226 break; 8227 } 8228 8229 case FCIO_GET_NUM_DEVS: { 8230 int num_devices; 8231 8232 if (fcio->fcio_olen != sizeof (num_devices) || 8233 fcio->fcio_xfer != FCIO_XFER_READ) { 8234 rval = EINVAL; 8235 break; 8236 } 8237 8238 mutex_enter(&port->fp_mutex); 8239 switch (port->fp_topology) { 8240 case FC_TOP_PRIVATE_LOOP: 8241 case FC_TOP_PT_PT: 8242 num_devices = port->fp_total_devices; 8243 fcio->fcio_errno = FC_SUCCESS; 8244 break; 8245 8246 case FC_TOP_PUBLIC_LOOP: 8247 case FC_TOP_FABRIC: 8248 mutex_exit(&port->fp_mutex); 8249 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, 8250 NULL, KM_SLEEP); 8251 ASSERT(job != NULL); 8252 8253 /* 8254 * In FC-GS-2 the Name Server doesn't send out 8255 * RSCNs for any Name Server Database updates 8256 * When it is finally fixed there is no need 8257 * to probe as below and should be removed. 8258 */ 8259 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 8260 fctl_dealloc_job(job); 8261 8262 mutex_enter(&port->fp_mutex); 8263 num_devices = port->fp_total_devices; 8264 fcio->fcio_errno = FC_SUCCESS; 8265 break; 8266 8267 case FC_TOP_NO_NS: 8268 /* FALLTHROUGH */ 8269 case FC_TOP_UNKNOWN: 8270 /* FALLTHROUGH */ 8271 default: 8272 num_devices = 0; 8273 fcio->fcio_errno = FC_SUCCESS; 8274 break; 8275 } 8276 mutex_exit(&port->fp_mutex); 8277 8278 if (fp_copyout((void *)&num_devices, 8279 (void *)fcio->fcio_obuf, fcio->fcio_olen, 8280 mode) == 0) { 8281 if (fp_fcio_copyout(fcio, data, mode)) { 8282 rval = EFAULT; 8283 } 8284 } else { 8285 rval = EFAULT; 8286 } 8287 break; 8288 } 8289 8290 case FCIO_GET_DEV_LIST: { 8291 int num_devices; 8292 int new_count; 8293 int map_size; 8294 8295 if (fcio->fcio_xfer != FCIO_XFER_READ || 8296 fcio->fcio_alen != sizeof (new_count)) { 8297 rval = EINVAL; 8298 break; 8299 } 8300 8301 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 8302 8303 mutex_enter(&port->fp_mutex); 8304 if (num_devices < port->fp_total_devices) { 8305 fcio->fcio_errno = FC_TOOMANY; 8306 new_count = port->fp_total_devices; 8307 mutex_exit(&port->fp_mutex); 8308 8309 if (fp_copyout((void *)&new_count, 8310 (void *)fcio->fcio_abuf, 8311 sizeof (new_count), mode)) { 8312 rval = EFAULT; 8313 break; 8314 } 8315 8316 if (fp_fcio_copyout(fcio, data, mode)) { 8317 rval = EFAULT; 8318 break; 8319 } 8320 rval = EINVAL; 8321 break; 8322 } 8323 8324 if (port->fp_total_devices <= 0) { 8325 fcio->fcio_errno = FC_NO_MAP; 8326 new_count = port->fp_total_devices; 8327 mutex_exit(&port->fp_mutex); 8328 8329 if (fp_copyout((void *)&new_count, 8330 (void *)fcio->fcio_abuf, 8331 sizeof (new_count), mode)) { 8332 rval = EFAULT; 8333 break; 8334 } 8335 8336 if (fp_fcio_copyout(fcio, data, mode)) { 8337 rval = EFAULT; 8338 break; 8339 } 8340 rval = EINVAL; 8341 break; 8342 } 8343 8344 switch (port->fp_topology) { 8345 case FC_TOP_PRIVATE_LOOP: 8346 if (fp_fillout_loopmap(port, fcio, 8347 mode) != FC_SUCCESS) { 8348 rval = EFAULT; 8349 break; 8350 } 8351 if (fp_fcio_copyout(fcio, data, mode)) { 8352 rval = EFAULT; 8353 } 8354 break; 8355 8356 case FC_TOP_PT_PT: 8357 if (fp_fillout_p2pmap(port, fcio, 8358 mode) != FC_SUCCESS) { 8359 rval = EFAULT; 8360 break; 8361 } 8362 if (fp_fcio_copyout(fcio, data, mode)) { 8363 rval = EFAULT; 8364 } 8365 break; 8366 8367 case FC_TOP_PUBLIC_LOOP: 8368 case FC_TOP_FABRIC: { 8369 fctl_ns_req_t *ns_cmd; 8370 8371 map_size = 8372 sizeof (fc_port_dev_t) * port->fp_total_devices; 8373 8374 mutex_exit(&port->fp_mutex); 8375 8376 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 8377 sizeof (ns_resp_gan_t), map_size, 8378 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND), 8379 KM_SLEEP); 8380 ASSERT(ns_cmd != NULL); 8381 8382 ns_cmd->ns_gan_index = 0; 8383 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 8384 ns_cmd->ns_cmd_code = NS_GA_NXT; 8385 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t); 8386 8387 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, 8388 NULL, KM_SLEEP); 8389 ASSERT(job != NULL); 8390 8391 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 8392 8393 if (ret != FC_SUCCESS || 8394 job->job_result != FC_SUCCESS) { 8395 fctl_free_ns_cmd(ns_cmd); 8396 8397 fcio->fcio_errno = job->job_result; 8398 new_count = 0; 8399 if (fp_copyout((void *)&new_count, 8400 (void *)fcio->fcio_abuf, 8401 sizeof (new_count), mode)) { 8402 fctl_dealloc_job(job); 8403 mutex_enter(&port->fp_mutex); 8404 rval = EFAULT; 8405 break; 8406 } 8407 8408 if (fp_fcio_copyout(fcio, data, mode)) { 8409 fctl_dealloc_job(job); 8410 mutex_enter(&port->fp_mutex); 8411 rval = EFAULT; 8412 break; 8413 } 8414 rval = EIO; 8415 mutex_enter(&port->fp_mutex); 8416 break; 8417 } 8418 fctl_dealloc_job(job); 8419 8420 new_count = ns_cmd->ns_gan_index; 8421 if (fp_copyout((void *)&new_count, 8422 (void *)fcio->fcio_abuf, sizeof (new_count), 8423 mode)) { 8424 rval = EFAULT; 8425 fctl_free_ns_cmd(ns_cmd); 8426 mutex_enter(&port->fp_mutex); 8427 break; 8428 } 8429 8430 if (fp_copyout((void *)ns_cmd->ns_data_buf, 8431 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) * 8432 ns_cmd->ns_gan_index, mode)) { 8433 rval = EFAULT; 8434 fctl_free_ns_cmd(ns_cmd); 8435 mutex_enter(&port->fp_mutex); 8436 break; 8437 } 8438 fctl_free_ns_cmd(ns_cmd); 8439 8440 if (fp_fcio_copyout(fcio, data, mode)) { 8441 rval = EFAULT; 8442 } 8443 mutex_enter(&port->fp_mutex); 8444 break; 8445 } 8446 8447 case FC_TOP_NO_NS: 8448 /* FALLTHROUGH */ 8449 case FC_TOP_UNKNOWN: 8450 /* FALLTHROUGH */ 8451 default: 8452 fcio->fcio_errno = FC_NO_MAP; 8453 num_devices = port->fp_total_devices; 8454 8455 if (fp_copyout((void *)&new_count, 8456 (void *)fcio->fcio_abuf, 8457 sizeof (new_count), mode)) { 8458 rval = EFAULT; 8459 break; 8460 } 8461 8462 if (fp_fcio_copyout(fcio, data, mode)) { 8463 rval = EFAULT; 8464 break; 8465 } 8466 rval = EINVAL; 8467 break; 8468 } 8469 mutex_exit(&port->fp_mutex); 8470 break; 8471 } 8472 8473 case FCIO_GET_SYM_PNAME: { 8474 rval = ENOTSUP; 8475 break; 8476 } 8477 8478 case FCIO_GET_SYM_NNAME: { 8479 rval = ENOTSUP; 8480 break; 8481 } 8482 8483 case FCIO_SET_SYM_PNAME: { 8484 rval = ENOTSUP; 8485 break; 8486 } 8487 8488 case FCIO_SET_SYM_NNAME: { 8489 rval = ENOTSUP; 8490 break; 8491 } 8492 8493 case FCIO_GET_LOGI_PARAMS: { 8494 la_wwn_t pwwn; 8495 la_wwn_t *my_pwwn; 8496 la_els_logi_t *params; 8497 la_els_logi32_t *params32; 8498 fc_remote_node_t *node; 8499 fc_remote_port_t *pd; 8500 8501 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8502 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || 8503 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { 8504 rval = EINVAL; 8505 break; 8506 } 8507 8508 if (use32 == B_TRUE) { 8509 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) { 8510 rval = EINVAL; 8511 break; 8512 } 8513 } else { 8514 if (fcio->fcio_olen != sizeof (la_els_logi_t)) { 8515 rval = EINVAL; 8516 break; 8517 } 8518 } 8519 8520 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8521 rval = EFAULT; 8522 break; 8523 } 8524 8525 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8526 if (pd == NULL) { 8527 mutex_enter(&port->fp_mutex); 8528 my_pwwn = &port->fp_service_params.nport_ww_name; 8529 mutex_exit(&port->fp_mutex); 8530 8531 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) { 8532 rval = ENXIO; 8533 break; 8534 } 8535 8536 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8537 mutex_enter(&port->fp_mutex); 8538 *params = port->fp_service_params; 8539 mutex_exit(&port->fp_mutex); 8540 } else { 8541 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8542 8543 mutex_enter(&pd->pd_mutex); 8544 params->ls_code.mbz = params->ls_code.ls_code = 0; 8545 params->common_service = pd->pd_csp; 8546 params->nport_ww_name = pd->pd_port_name; 8547 params->class_1 = pd->pd_clsp1; 8548 params->class_2 = pd->pd_clsp2; 8549 params->class_3 = pd->pd_clsp3; 8550 node = pd->pd_remote_nodep; 8551 mutex_exit(&pd->pd_mutex); 8552 8553 bzero(params->reserved, sizeof (params->reserved)); 8554 8555 mutex_enter(&node->fd_mutex); 8556 bcopy(node->fd_vv, params->vendor_version, 8557 sizeof (node->fd_vv)); 8558 params->node_ww_name = node->fd_node_name; 8559 mutex_exit(&node->fd_mutex); 8560 8561 fctl_release_remote_port(pd); 8562 } 8563 8564 if (use32 == B_TRUE) { 8565 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP); 8566 8567 params32->ls_code.mbz = params->ls_code.mbz; 8568 params32->common_service = params->common_service; 8569 params32->nport_ww_name = params->nport_ww_name; 8570 params32->class_1 = params->class_1; 8571 params32->class_2 = params->class_2; 8572 params32->class_3 = params->class_3; 8573 bzero(params32->reserved, sizeof (params32->reserved)); 8574 bcopy(params->vendor_version, params32->vendor_version, 8575 sizeof (node->fd_vv)); 8576 params32->node_ww_name = params->node_ww_name; 8577 8578 if (ddi_copyout((void *)params32, 8579 (void *)fcio->fcio_obuf, 8580 sizeof (*params32), mode)) { 8581 rval = EFAULT; 8582 } 8583 8584 kmem_free(params32, sizeof (*params32)); 8585 } else { 8586 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf, 8587 sizeof (*params), mode)) { 8588 rval = EFAULT; 8589 } 8590 } 8591 8592 kmem_free(params, sizeof (*params)); 8593 if (fp_fcio_copyout(fcio, data, mode)) { 8594 rval = EFAULT; 8595 } 8596 break; 8597 } 8598 8599 case FCIO_DEV_LOGOUT: 8600 case FCIO_DEV_LOGIN: 8601 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8602 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8603 rval = EINVAL; 8604 8605 if (fp_fcio_copyout(fcio, data, mode)) { 8606 rval = EFAULT; 8607 } 8608 break; 8609 } 8610 8611 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) { 8612 jcode = JOB_FCIO_LOGIN; 8613 } else { 8614 jcode = JOB_FCIO_LOGOUT; 8615 } 8616 8617 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP); 8618 bcopy(fcio, kfcio, sizeof (*fcio)); 8619 8620 if (kfcio->fcio_ilen) { 8621 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen, 8622 KM_SLEEP); 8623 8624 if (ddi_copyin((void *)fcio->fcio_ibuf, 8625 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen, 8626 mode)) { 8627 rval = EFAULT; 8628 8629 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8630 kmem_free(kfcio, sizeof (*kfcio)); 8631 fcio->fcio_errno = job->job_result; 8632 if (fp_fcio_copyout(fcio, data, mode)) { 8633 rval = EFAULT; 8634 } 8635 break; 8636 } 8637 } 8638 8639 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP); 8640 job->job_private = kfcio; 8641 8642 fctl_enque_job(port, job); 8643 fctl_jobwait(job); 8644 8645 rval = job->job_result; 8646 8647 fcio->fcio_errno = kfcio->fcio_errno; 8648 if (fp_fcio_copyout(fcio, data, mode)) { 8649 rval = EFAULT; 8650 } 8651 8652 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8653 kmem_free(kfcio, sizeof (*kfcio)); 8654 fctl_dealloc_job(job); 8655 break; 8656 8657 case FCIO_GET_STATE: { 8658 la_wwn_t pwwn; 8659 uint32_t state; 8660 fc_remote_port_t *pd; 8661 fctl_ns_req_t *ns_cmd; 8662 8663 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8664 fcio->fcio_olen != sizeof (state) || 8665 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 || 8666 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { 8667 rval = EINVAL; 8668 break; 8669 } 8670 8671 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8672 rval = EFAULT; 8673 break; 8674 } 8675 fcio->fcio_errno = 0; 8676 8677 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8678 if (pd == NULL) { 8679 mutex_enter(&port->fp_mutex); 8680 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 8681 mutex_exit(&port->fp_mutex); 8682 job = fctl_alloc_job(JOB_PLOGI_ONE, 0, 8683 NULL, NULL, KM_SLEEP); 8684 8685 job->job_counter = 1; 8686 job->job_result = FC_SUCCESS; 8687 8688 ns_cmd = fctl_alloc_ns_cmd( 8689 sizeof (ns_req_gid_pn_t), 8690 sizeof (ns_resp_gid_pn_t), 8691 sizeof (ns_resp_gid_pn_t), 8692 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 8693 ASSERT(ns_cmd != NULL); 8694 8695 ns_cmd->ns_cmd_code = NS_GID_PN; 8696 ((ns_req_gid_pn_t *) 8697 (ns_cmd->ns_cmd_buf))->pwwn = pwwn; 8698 8699 ret = fp_ns_query(port, ns_cmd, job, 8700 1, KM_SLEEP); 8701 8702 if (ret != FC_SUCCESS || job->job_result != 8703 FC_SUCCESS) { 8704 if (ret != FC_SUCCESS) { 8705 fcio->fcio_errno = ret; 8706 } else { 8707 fcio->fcio_errno = 8708 job->job_result; 8709 } 8710 rval = EIO; 8711 } else { 8712 state = PORT_DEVICE_INVALID; 8713 } 8714 fctl_free_ns_cmd(ns_cmd); 8715 fctl_dealloc_job(job); 8716 } else { 8717 mutex_exit(&port->fp_mutex); 8718 fcio->fcio_errno = FC_BADWWN; 8719 rval = ENXIO; 8720 } 8721 } else { 8722 mutex_enter(&pd->pd_mutex); 8723 state = pd->pd_state; 8724 mutex_exit(&pd->pd_mutex); 8725 8726 fctl_release_remote_port(pd); 8727 } 8728 8729 if (!rval) { 8730 if (ddi_copyout((void *)&state, 8731 (void *)fcio->fcio_obuf, sizeof (state), 8732 mode)) { 8733 rval = EFAULT; 8734 } 8735 } 8736 if (fp_fcio_copyout(fcio, data, mode)) { 8737 rval = EFAULT; 8738 } 8739 break; 8740 } 8741 8742 case FCIO_DEV_REMOVE: { 8743 la_wwn_t pwwn; 8744 fc_portmap_t *changelist; 8745 fc_remote_port_t *pd; 8746 8747 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8748 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8749 rval = EINVAL; 8750 break; 8751 } 8752 8753 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8754 rval = EFAULT; 8755 break; 8756 } 8757 8758 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8759 if (pd == NULL) { 8760 rval = ENXIO; 8761 fcio->fcio_errno = FC_BADWWN; 8762 if (fp_fcio_copyout(fcio, data, mode)) { 8763 rval = EFAULT; 8764 } 8765 break; 8766 } 8767 8768 mutex_enter(&pd->pd_mutex); 8769 if (pd->pd_ref_count > 1) { 8770 mutex_exit(&pd->pd_mutex); 8771 8772 rval = EBUSY; 8773 fcio->fcio_errno = FC_FAILURE; 8774 fctl_release_remote_port(pd); 8775 8776 if (fp_fcio_copyout(fcio, data, mode)) { 8777 rval = EFAULT; 8778 } 8779 break; 8780 } 8781 mutex_exit(&pd->pd_mutex); 8782 8783 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 8784 8785 fctl_copy_portmap(changelist, pd); 8786 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 8787 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 8788 8789 fctl_release_remote_port(pd); 8790 break; 8791 } 8792 8793 case FCIO_GET_FCODE_REV: { 8794 caddr_t fcode_rev; 8795 fc_fca_pm_t pm; 8796 8797 if (fcio->fcio_olen < FC_FCODE_REV_SIZE || 8798 fcio->fcio_xfer != FCIO_XFER_READ) { 8799 rval = EINVAL; 8800 break; 8801 } 8802 bzero((caddr_t)&pm, sizeof (pm)); 8803 8804 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8805 8806 pm.pm_cmd_flags = FC_FCA_PM_READ; 8807 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV; 8808 pm.pm_data_len = fcio->fcio_olen; 8809 pm.pm_data_buf = fcode_rev; 8810 8811 ret = port->fp_fca_tran->fca_port_manage( 8812 port->fp_fca_handle, &pm); 8813 8814 if (ret == FC_SUCCESS) { 8815 if (ddi_copyout((void *)fcode_rev, 8816 (void *)fcio->fcio_obuf, 8817 fcio->fcio_olen, mode) == 0) { 8818 if (fp_fcio_copyout(fcio, data, mode)) { 8819 rval = EFAULT; 8820 } 8821 } else { 8822 rval = EFAULT; 8823 } 8824 } else { 8825 /* 8826 * check if buffer was not large enough to obtain 8827 * FCODE version. 8828 */ 8829 if (pm.pm_data_len > fcio->fcio_olen) { 8830 rval = ENOMEM; 8831 } else { 8832 rval = EIO; 8833 } 8834 fcio->fcio_errno = ret; 8835 if (fp_fcio_copyout(fcio, data, mode)) { 8836 rval = EFAULT; 8837 } 8838 } 8839 kmem_free(fcode_rev, fcio->fcio_olen); 8840 break; 8841 } 8842 8843 case FCIO_GET_FW_REV: { 8844 caddr_t fw_rev; 8845 fc_fca_pm_t pm; 8846 8847 if (fcio->fcio_olen < FC_FW_REV_SIZE || 8848 fcio->fcio_xfer != FCIO_XFER_READ) { 8849 rval = EINVAL; 8850 break; 8851 } 8852 bzero((caddr_t)&pm, sizeof (pm)); 8853 8854 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8855 8856 pm.pm_cmd_flags = FC_FCA_PM_READ; 8857 pm.pm_cmd_code = FC_PORT_GET_FW_REV; 8858 pm.pm_data_len = fcio->fcio_olen; 8859 pm.pm_data_buf = fw_rev; 8860 8861 ret = port->fp_fca_tran->fca_port_manage( 8862 port->fp_fca_handle, &pm); 8863 8864 if (ret == FC_SUCCESS) { 8865 if (ddi_copyout((void *)fw_rev, 8866 (void *)fcio->fcio_obuf, 8867 fcio->fcio_olen, mode) == 0) { 8868 if (fp_fcio_copyout(fcio, data, mode)) { 8869 rval = EFAULT; 8870 } 8871 } else { 8872 rval = EFAULT; 8873 } 8874 } else { 8875 if (fp_fcio_copyout(fcio, data, mode)) { 8876 rval = EFAULT; 8877 } 8878 rval = EIO; 8879 } 8880 kmem_free(fw_rev, fcio->fcio_olen); 8881 break; 8882 } 8883 8884 case FCIO_GET_DUMP_SIZE: { 8885 uint32_t dump_size; 8886 fc_fca_pm_t pm; 8887 8888 if (fcio->fcio_olen != sizeof (dump_size) || 8889 fcio->fcio_xfer != FCIO_XFER_READ) { 8890 rval = EINVAL; 8891 break; 8892 } 8893 bzero((caddr_t)&pm, sizeof (pm)); 8894 pm.pm_cmd_flags = FC_FCA_PM_READ; 8895 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8896 pm.pm_data_len = sizeof (dump_size); 8897 pm.pm_data_buf = (caddr_t)&dump_size; 8898 8899 ret = port->fp_fca_tran->fca_port_manage( 8900 port->fp_fca_handle, &pm); 8901 8902 if (ret == FC_SUCCESS) { 8903 if (ddi_copyout((void *)&dump_size, 8904 (void *)fcio->fcio_obuf, sizeof (dump_size), 8905 mode) == 0) { 8906 if (fp_fcio_copyout(fcio, data, mode)) { 8907 rval = EFAULT; 8908 } 8909 } else { 8910 rval = EFAULT; 8911 } 8912 } else { 8913 fcio->fcio_errno = ret; 8914 rval = EIO; 8915 if (fp_fcio_copyout(fcio, data, mode)) { 8916 rval = EFAULT; 8917 } 8918 } 8919 break; 8920 } 8921 8922 case FCIO_DOWNLOAD_FW: { 8923 caddr_t firmware; 8924 fc_fca_pm_t pm; 8925 8926 if (fcio->fcio_ilen <= 0 || 8927 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8928 rval = EINVAL; 8929 break; 8930 } 8931 8932 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8933 if (ddi_copyin(fcio->fcio_ibuf, firmware, 8934 fcio->fcio_ilen, mode)) { 8935 rval = EFAULT; 8936 kmem_free(firmware, fcio->fcio_ilen); 8937 break; 8938 } 8939 8940 bzero((caddr_t)&pm, sizeof (pm)); 8941 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8942 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW; 8943 pm.pm_data_len = fcio->fcio_ilen; 8944 pm.pm_data_buf = firmware; 8945 8946 ret = port->fp_fca_tran->fca_port_manage( 8947 port->fp_fca_handle, &pm); 8948 8949 kmem_free(firmware, fcio->fcio_ilen); 8950 8951 if (ret != FC_SUCCESS) { 8952 fcio->fcio_errno = ret; 8953 rval = EIO; 8954 if (fp_fcio_copyout(fcio, data, mode)) { 8955 rval = EFAULT; 8956 } 8957 } 8958 break; 8959 } 8960 8961 case FCIO_DOWNLOAD_FCODE: { 8962 caddr_t fcode; 8963 fc_fca_pm_t pm; 8964 8965 if (fcio->fcio_ilen <= 0 || 8966 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8967 rval = EINVAL; 8968 break; 8969 } 8970 8971 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8972 if (ddi_copyin(fcio->fcio_ibuf, fcode, 8973 fcio->fcio_ilen, mode)) { 8974 rval = EFAULT; 8975 kmem_free(fcode, fcio->fcio_ilen); 8976 break; 8977 } 8978 8979 bzero((caddr_t)&pm, sizeof (pm)); 8980 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8981 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE; 8982 pm.pm_data_len = fcio->fcio_ilen; 8983 pm.pm_data_buf = fcode; 8984 8985 ret = port->fp_fca_tran->fca_port_manage( 8986 port->fp_fca_handle, &pm); 8987 8988 kmem_free(fcode, fcio->fcio_ilen); 8989 8990 if (ret != FC_SUCCESS) { 8991 fcio->fcio_errno = ret; 8992 rval = EIO; 8993 if (fp_fcio_copyout(fcio, data, mode)) { 8994 rval = EFAULT; 8995 } 8996 } 8997 break; 8998 } 8999 9000 case FCIO_FORCE_DUMP: 9001 ret = port->fp_fca_tran->fca_reset( 9002 port->fp_fca_handle, FC_FCA_CORE); 9003 9004 if (ret != FC_SUCCESS) { 9005 fcio->fcio_errno = ret; 9006 rval = EIO; 9007 if (fp_fcio_copyout(fcio, data, mode)) { 9008 rval = EFAULT; 9009 } 9010 } 9011 break; 9012 9013 case FCIO_GET_DUMP: { 9014 caddr_t dump; 9015 uint32_t dump_size; 9016 fc_fca_pm_t pm; 9017 9018 if (fcio->fcio_xfer != FCIO_XFER_READ) { 9019 rval = EINVAL; 9020 break; 9021 } 9022 bzero((caddr_t)&pm, sizeof (pm)); 9023 9024 pm.pm_cmd_flags = FC_FCA_PM_READ; 9025 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 9026 pm.pm_data_len = sizeof (dump_size); 9027 pm.pm_data_buf = (caddr_t)&dump_size; 9028 9029 ret = port->fp_fca_tran->fca_port_manage( 9030 port->fp_fca_handle, &pm); 9031 9032 if (ret != FC_SUCCESS) { 9033 fcio->fcio_errno = ret; 9034 rval = EIO; 9035 if (fp_fcio_copyout(fcio, data, mode)) { 9036 rval = EFAULT; 9037 } 9038 break; 9039 } 9040 if (fcio->fcio_olen != dump_size) { 9041 fcio->fcio_errno = FC_NOMEM; 9042 rval = EINVAL; 9043 if (fp_fcio_copyout(fcio, data, mode)) { 9044 rval = EFAULT; 9045 } 9046 break; 9047 } 9048 9049 dump = kmem_zalloc(dump_size, KM_SLEEP); 9050 9051 bzero((caddr_t)&pm, sizeof (pm)); 9052 pm.pm_cmd_flags = FC_FCA_PM_READ; 9053 pm.pm_cmd_code = FC_PORT_GET_DUMP; 9054 pm.pm_data_len = dump_size; 9055 pm.pm_data_buf = dump; 9056 9057 ret = port->fp_fca_tran->fca_port_manage( 9058 port->fp_fca_handle, &pm); 9059 9060 if (ret == FC_SUCCESS) { 9061 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf, 9062 dump_size, mode) == 0) { 9063 if (fp_fcio_copyout(fcio, data, mode)) { 9064 rval = EFAULT; 9065 } 9066 } else { 9067 rval = EFAULT; 9068 } 9069 } else { 9070 fcio->fcio_errno = ret; 9071 rval = EIO; 9072 if (fp_fcio_copyout(fcio, data, mode)) { 9073 rval = EFAULT; 9074 } 9075 } 9076 kmem_free(dump, dump_size); 9077 break; 9078 } 9079 9080 case FCIO_GET_TOPOLOGY: { 9081 uint32_t user_topology; 9082 9083 if (fcio->fcio_xfer != FCIO_XFER_READ || 9084 fcio->fcio_olen != sizeof (user_topology)) { 9085 rval = EINVAL; 9086 break; 9087 } 9088 9089 mutex_enter(&port->fp_mutex); 9090 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 9091 user_topology = FC_TOP_UNKNOWN; 9092 } else { 9093 user_topology = port->fp_topology; 9094 } 9095 mutex_exit(&port->fp_mutex); 9096 9097 if (ddi_copyout((void *)&user_topology, 9098 (void *)fcio->fcio_obuf, sizeof (user_topology), 9099 mode)) { 9100 rval = EFAULT; 9101 } 9102 break; 9103 } 9104 9105 case FCIO_RESET_LINK: { 9106 la_wwn_t pwwn; 9107 9108 /* 9109 * Look at the output buffer field; if this field has zero 9110 * bytes then attempt to reset the local link/loop. If the 9111 * fcio_ibuf field points to a WWN, see if it's an NL_Port, 9112 * and if yes, determine the LFA and reset the remote LIP 9113 * by LINIT ELS. 9114 */ 9115 9116 if (fcio->fcio_xfer != FCIO_XFER_WRITE || 9117 fcio->fcio_ilen != sizeof (pwwn)) { 9118 rval = EINVAL; 9119 break; 9120 } 9121 9122 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9123 sizeof (pwwn), mode)) { 9124 rval = EFAULT; 9125 break; 9126 } 9127 9128 mutex_enter(&port->fp_mutex); 9129 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 9130 mutex_exit(&port->fp_mutex); 9131 break; 9132 } 9133 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 9134 mutex_exit(&port->fp_mutex); 9135 9136 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP); 9137 if (job == NULL) { 9138 rval = ENOMEM; 9139 break; 9140 } 9141 job->job_counter = 1; 9142 job->job_private = (void *)&pwwn; 9143 9144 fctl_enque_job(port, job); 9145 fctl_jobwait(job); 9146 9147 mutex_enter(&port->fp_mutex); 9148 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 9149 mutex_exit(&port->fp_mutex); 9150 9151 if (job->job_result != FC_SUCCESS) { 9152 fcio->fcio_errno = job->job_result; 9153 rval = EIO; 9154 if (fp_fcio_copyout(fcio, data, mode)) { 9155 rval = EFAULT; 9156 } 9157 } 9158 fctl_dealloc_job(job); 9159 break; 9160 } 9161 9162 case FCIO_RESET_HARD: 9163 ret = port->fp_fca_tran->fca_reset( 9164 port->fp_fca_handle, FC_FCA_RESET); 9165 if (ret != FC_SUCCESS) { 9166 fcio->fcio_errno = ret; 9167 rval = EIO; 9168 if (fp_fcio_copyout(fcio, data, mode)) { 9169 rval = EFAULT; 9170 } 9171 } 9172 break; 9173 9174 case FCIO_RESET_HARD_CORE: 9175 ret = port->fp_fca_tran->fca_reset( 9176 port->fp_fca_handle, FC_FCA_RESET_CORE); 9177 if (ret != FC_SUCCESS) { 9178 rval = EIO; 9179 fcio->fcio_errno = ret; 9180 if (fp_fcio_copyout(fcio, data, mode)) { 9181 rval = EFAULT; 9182 } 9183 } 9184 break; 9185 9186 case FCIO_DIAG: { 9187 fc_fca_pm_t pm; 9188 9189 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); 9190 9191 /* Validate user buffer from ioctl call. */ 9192 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) || 9193 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) || 9194 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) || 9195 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) || 9196 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) || 9197 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) { 9198 rval = EFAULT; 9199 break; 9200 } 9201 9202 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) { 9203 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 9204 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf, 9205 fcio->fcio_ilen, mode)) { 9206 rval = EFAULT; 9207 goto fp_fcio_diag_cleanup; 9208 } 9209 } 9210 9211 if ((pm.pm_data_len = fcio->fcio_alen) > 0) { 9212 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP); 9213 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf, 9214 fcio->fcio_alen, mode)) { 9215 rval = EFAULT; 9216 goto fp_fcio_diag_cleanup; 9217 } 9218 } 9219 9220 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) { 9221 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 9222 } 9223 9224 pm.pm_cmd_code = FC_PORT_DIAG; 9225 pm.pm_cmd_flags = fcio->fcio_cmd_flags; 9226 9227 ret = port->fp_fca_tran->fca_port_manage( 9228 port->fp_fca_handle, &pm); 9229 9230 if (ret != FC_SUCCESS) { 9231 if (ret == FC_INVALID_REQUEST) { 9232 rval = ENOTTY; 9233 } else { 9234 rval = EIO; 9235 } 9236 9237 fcio->fcio_errno = ret; 9238 if (fp_fcio_copyout(fcio, data, mode)) { 9239 rval = EFAULT; 9240 } 9241 goto fp_fcio_diag_cleanup; 9242 } 9243 9244 /* 9245 * pm_stat_len will contain the number of status bytes 9246 * an FCA driver requires to return the complete status 9247 * of the requested diag operation. If the user buffer 9248 * is not large enough to hold the entire status, We 9249 * copy only the portion of data the fits in the buffer and 9250 * return a ENOMEM to the user application. 9251 */ 9252 if (pm.pm_stat_len > fcio->fcio_olen) { 9253 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 9254 "fp:FCIO_DIAG:status buffer too small\n"); 9255 9256 rval = ENOMEM; 9257 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9258 fcio->fcio_olen, mode)) { 9259 rval = EFAULT; 9260 goto fp_fcio_diag_cleanup; 9261 } 9262 } else { 9263 /* 9264 * Copy only data pm_stat_len bytes of data 9265 */ 9266 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9267 pm.pm_stat_len, mode)) { 9268 rval = EFAULT; 9269 goto fp_fcio_diag_cleanup; 9270 } 9271 } 9272 9273 if (fp_fcio_copyout(fcio, data, mode)) { 9274 rval = EFAULT; 9275 } 9276 9277 fp_fcio_diag_cleanup: 9278 if (pm.pm_cmd_buf != NULL) { 9279 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen); 9280 } 9281 if (pm.pm_data_buf != NULL) { 9282 kmem_free(pm.pm_data_buf, fcio->fcio_alen); 9283 } 9284 if (pm.pm_stat_buf != NULL) { 9285 kmem_free(pm.pm_stat_buf, fcio->fcio_olen); 9286 } 9287 9288 break; 9289 } 9290 9291 case FCIO_GET_NODE_ID: { 9292 /* validate parameters */ 9293 if (fcio->fcio_xfer != FCIO_XFER_READ || 9294 fcio->fcio_olen < sizeof (fc_rnid_t)) { 9295 rval = EINVAL; 9296 break; 9297 } 9298 9299 rval = fp_get_rnid(port, data, mode, fcio); 9300 9301 /* ioctl handling is over */ 9302 break; 9303 } 9304 9305 case FCIO_SEND_NODE_ID: { 9306 la_wwn_t pwwn; 9307 9308 /* validate parameters */ 9309 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 9310 fcio->fcio_xfer != FCIO_XFER_READ) { 9311 rval = EINVAL; 9312 break; 9313 } 9314 9315 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9316 sizeof (la_wwn_t), mode)) { 9317 rval = EFAULT; 9318 break; 9319 } 9320 9321 rval = fp_send_rnid(port, data, mode, fcio, &pwwn); 9322 9323 /* ioctl handling is over */ 9324 break; 9325 } 9326 9327 case FCIO_SET_NODE_ID: { 9328 if (fcio->fcio_ilen != sizeof (fc_rnid_t) || 9329 (fcio->fcio_xfer != FCIO_XFER_WRITE)) { 9330 rval = EINVAL; 9331 break; 9332 } 9333 9334 rval = fp_set_rnid(port, data, mode, fcio); 9335 break; 9336 } 9337 9338 case FCIO_LINK_STATUS: { 9339 fc_portid_t rls_req; 9340 fc_rls_acc_t *rls_acc; 9341 fc_fca_pm_t pm; 9342 uint32_t dest, src_id; 9343 fp_cmd_t *cmd; 9344 fc_remote_port_t *pd; 9345 uchar_t pd_flags; 9346 9347 /* validate parameters */ 9348 if (fcio->fcio_ilen != sizeof (fc_portid_t) || 9349 fcio->fcio_olen != sizeof (fc_rls_acc_t) || 9350 fcio->fcio_xfer != FCIO_XFER_RW) { 9351 rval = EINVAL; 9352 break; 9353 } 9354 9355 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && 9356 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { 9357 rval = EINVAL; 9358 break; 9359 } 9360 9361 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req, 9362 sizeof (fc_portid_t), mode)) { 9363 rval = EFAULT; 9364 break; 9365 } 9366 9367 9368 /* Determine the destination of the RLS frame */ 9369 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) { 9370 dest = FS_FABRIC_F_PORT; 9371 } else { 9372 dest = rls_req.port_id; 9373 } 9374 9375 mutex_enter(&port->fp_mutex); 9376 src_id = port->fp_port_id.port_id; 9377 mutex_exit(&port->fp_mutex); 9378 9379 /* If dest is zero OR same as FCA ID, then use port_manage() */ 9380 if (dest == 0 || dest == src_id) { 9381 9382 /* Allocate memory for link error status block */ 9383 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9384 ASSERT(rls_acc != NULL); 9385 9386 /* Prepare the port management structure */ 9387 bzero((caddr_t)&pm, sizeof (pm)); 9388 9389 pm.pm_cmd_flags = FC_FCA_PM_READ; 9390 pm.pm_cmd_code = FC_PORT_RLS; 9391 pm.pm_data_len = sizeof (*rls_acc); 9392 pm.pm_data_buf = (caddr_t)rls_acc; 9393 9394 /* Get the adapter's link error status block */ 9395 ret = port->fp_fca_tran->fca_port_manage( 9396 port->fp_fca_handle, &pm); 9397 9398 if (ret == FC_SUCCESS) { 9399 /* xfer link status block to userland */ 9400 if (ddi_copyout((void *)rls_acc, 9401 (void *)fcio->fcio_obuf, 9402 sizeof (*rls_acc), mode) == 0) { 9403 if (fp_fcio_copyout(fcio, data, 9404 mode)) { 9405 rval = EFAULT; 9406 } 9407 } else { 9408 rval = EFAULT; 9409 } 9410 } else { 9411 rval = EIO; 9412 fcio->fcio_errno = ret; 9413 if (fp_fcio_copyout(fcio, data, mode)) { 9414 rval = EFAULT; 9415 } 9416 } 9417 9418 kmem_free(rls_acc, sizeof (*rls_acc)); 9419 9420 /* ioctl handling is over */ 9421 break; 9422 } 9423 9424 /* 9425 * Send RLS to the destination port. 9426 * Having RLS frame destination is as FPORT is not yet 9427 * supported and will be implemented in future, if needed. 9428 * Following call to get "pd" will fail if dest is FPORT 9429 */ 9430 pd = fctl_hold_remote_port_by_did(port, dest); 9431 if (pd == NULL) { 9432 fcio->fcio_errno = FC_BADOBJECT; 9433 rval = ENXIO; 9434 if (fp_fcio_copyout(fcio, data, mode)) { 9435 rval = EFAULT; 9436 } 9437 break; 9438 } 9439 9440 mutex_enter(&pd->pd_mutex); 9441 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 9442 mutex_exit(&pd->pd_mutex); 9443 fctl_release_remote_port(pd); 9444 9445 fcio->fcio_errno = FC_LOGINREQ; 9446 rval = EINVAL; 9447 if (fp_fcio_copyout(fcio, data, mode)) { 9448 rval = EFAULT; 9449 } 9450 break; 9451 } 9452 ASSERT(pd->pd_login_count >= 1); 9453 mutex_exit(&pd->pd_mutex); 9454 9455 /* 9456 * Allocate job structure and set job_code as DUMMY, 9457 * because we will not go through the job thread. 9458 * Instead fp_sendcmd() is called directly here. 9459 */ 9460 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9461 NULL, NULL, KM_SLEEP); 9462 ASSERT(job != NULL); 9463 9464 job->job_counter = 1; 9465 9466 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t), 9467 sizeof (la_els_rls_acc_t), KM_SLEEP, pd); 9468 if (cmd == NULL) { 9469 fcio->fcio_errno = FC_NOMEM; 9470 rval = ENOMEM; 9471 9472 fctl_release_remote_port(pd); 9473 9474 fctl_dealloc_job(job); 9475 if (fp_fcio_copyout(fcio, data, mode)) { 9476 rval = EFAULT; 9477 } 9478 break; 9479 } 9480 9481 /* Allocate memory for link error status block */ 9482 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9483 9484 mutex_enter(&port->fp_mutex); 9485 mutex_enter(&pd->pd_mutex); 9486 9487 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9488 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9489 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9490 cmd->cmd_retry_count = 1; 9491 cmd->cmd_ulp_pkt = NULL; 9492 9493 fp_rls_init(cmd, job); 9494 9495 job->job_private = (void *)rls_acc; 9496 9497 pd_flags = pd->pd_flags; 9498 pd->pd_flags = PD_ELS_IN_PROGRESS; 9499 9500 mutex_exit(&pd->pd_mutex); 9501 mutex_exit(&port->fp_mutex); 9502 9503 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9504 fctl_jobwait(job); 9505 9506 fcio->fcio_errno = job->job_result; 9507 if (job->job_result == FC_SUCCESS) { 9508 ASSERT(pd != NULL); 9509 /* 9510 * link error status block is now available. 9511 * Copy it to userland 9512 */ 9513 ASSERT(job->job_private == (void *)rls_acc); 9514 if (ddi_copyout((void *)rls_acc, 9515 (void *)fcio->fcio_obuf, 9516 sizeof (*rls_acc), mode) == 0) { 9517 if (fp_fcio_copyout(fcio, data, 9518 mode)) { 9519 rval = EFAULT; 9520 } 9521 } else { 9522 rval = EFAULT; 9523 } 9524 } else { 9525 rval = EIO; 9526 } 9527 } else { 9528 rval = EIO; 9529 fp_free_pkt(cmd); 9530 } 9531 9532 if (rval) { 9533 mutex_enter(&port->fp_mutex); 9534 mutex_enter(&pd->pd_mutex); 9535 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 9536 pd->pd_flags = pd_flags; 9537 } 9538 mutex_exit(&pd->pd_mutex); 9539 mutex_exit(&port->fp_mutex); 9540 } 9541 9542 fctl_release_remote_port(pd); 9543 fctl_dealloc_job(job); 9544 kmem_free(rls_acc, sizeof (*rls_acc)); 9545 9546 if (fp_fcio_copyout(fcio, data, mode)) { 9547 rval = EFAULT; 9548 } 9549 break; 9550 } 9551 9552 case FCIO_NS: { 9553 fc_ns_cmd_t *ns_req; 9554 fc_ns_cmd32_t *ns_req32; 9555 fctl_ns_req_t *ns_cmd; 9556 9557 if (use32 == B_TRUE) { 9558 if (fcio->fcio_ilen != sizeof (*ns_req32)) { 9559 rval = EINVAL; 9560 break; 9561 } 9562 9563 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9564 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP); 9565 9566 if (ddi_copyin(fcio->fcio_ibuf, ns_req32, 9567 sizeof (*ns_req32), mode)) { 9568 rval = EFAULT; 9569 kmem_free(ns_req, sizeof (*ns_req)); 9570 kmem_free(ns_req32, sizeof (*ns_req32)); 9571 break; 9572 } 9573 9574 ns_req->ns_flags = ns_req32->ns_flags; 9575 ns_req->ns_cmd = ns_req32->ns_cmd; 9576 ns_req->ns_req_len = ns_req32->ns_req_len; 9577 ns_req->ns_req_payload = ns_req32->ns_req_payload; 9578 ns_req->ns_resp_len = ns_req32->ns_resp_len; 9579 ns_req->ns_resp_payload = ns_req32->ns_resp_payload; 9580 ns_req->ns_fctl_private = ns_req32->ns_fctl_private; 9581 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr; 9582 9583 kmem_free(ns_req32, sizeof (*ns_req32)); 9584 } else { 9585 if (fcio->fcio_ilen != sizeof (*ns_req)) { 9586 rval = EINVAL; 9587 break; 9588 } 9589 9590 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9591 9592 if (ddi_copyin(fcio->fcio_ibuf, ns_req, 9593 sizeof (fc_ns_cmd_t), mode)) { 9594 rval = EFAULT; 9595 kmem_free(ns_req, sizeof (*ns_req)); 9596 break; 9597 } 9598 } 9599 9600 if (ns_req->ns_req_len <= 0) { 9601 rval = EINVAL; 9602 kmem_free(ns_req, sizeof (*ns_req)); 9603 break; 9604 } 9605 9606 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 9607 ASSERT(job != NULL); 9608 9609 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 9610 ns_req->ns_resp_len, ns_req->ns_resp_len, 9611 FCTL_NS_FILL_NS_MAP, KM_SLEEP); 9612 ASSERT(ns_cmd != NULL); 9613 ns_cmd->ns_cmd_code = ns_req->ns_cmd; 9614 9615 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 9616 ns_cmd->ns_gan_max = 1; 9617 ns_cmd->ns_gan_index = 0; 9618 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 9619 } 9620 9621 if (ddi_copyin(ns_req->ns_req_payload, 9622 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) { 9623 rval = EFAULT; 9624 fctl_free_ns_cmd(ns_cmd); 9625 fctl_dealloc_job(job); 9626 kmem_free(ns_req, sizeof (*ns_req)); 9627 break; 9628 } 9629 9630 job->job_private = (void *)ns_cmd; 9631 fctl_enque_job(port, job); 9632 fctl_jobwait(job); 9633 rval = job->job_result; 9634 9635 if (rval == FC_SUCCESS) { 9636 if (ns_req->ns_resp_len) { 9637 if (ddi_copyout(ns_cmd->ns_data_buf, 9638 ns_req->ns_resp_payload, 9639 ns_cmd->ns_data_len, mode)) { 9640 rval = EFAULT; 9641 fctl_free_ns_cmd(ns_cmd); 9642 fctl_dealloc_job(job); 9643 kmem_free(ns_req, sizeof (*ns_req)); 9644 break; 9645 } 9646 } 9647 } else { 9648 rval = EIO; 9649 } 9650 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr; 9651 fctl_free_ns_cmd(ns_cmd); 9652 fctl_dealloc_job(job); 9653 kmem_free(ns_req, sizeof (*ns_req)); 9654 9655 if (fp_fcio_copyout(fcio, data, mode)) { 9656 rval = EFAULT; 9657 } 9658 break; 9659 } 9660 9661 default: 9662 rval = ENOTTY; 9663 break; 9664 } 9665 9666 /* 9667 * If set, reset the EXCL busy bit to 9668 * receive other exclusive access commands 9669 */ 9670 mutex_enter(&port->fp_mutex); 9671 if (port->fp_flag & FP_EXCL_BUSY) { 9672 port->fp_flag &= ~FP_EXCL_BUSY; 9673 } 9674 mutex_exit(&port->fp_mutex); 9675 9676 return (rval); 9677 } 9678 9679 9680 /* 9681 * This function assumes that the response length 9682 * is same regardless of data model (LP32 or LP64) 9683 * which is true for all the ioctls currently 9684 * supported. 9685 */ 9686 static int 9687 fp_copyout(void *from, void *to, size_t len, int mode) 9688 { 9689 return (ddi_copyout(from, to, len, mode)); 9690 } 9691 9692 /* 9693 * This function does the set rnid 9694 */ 9695 static int 9696 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9697 { 9698 int rval = 0; 9699 fc_rnid_t *rnid; 9700 fc_fca_pm_t pm; 9701 9702 /* Allocate memory for node id block */ 9703 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9704 9705 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) { 9706 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT); 9707 kmem_free(rnid, sizeof (fc_rnid_t)); 9708 return (EFAULT); 9709 } 9710 9711 /* Prepare the port management structure */ 9712 bzero((caddr_t)&pm, sizeof (pm)); 9713 9714 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 9715 pm.pm_cmd_code = FC_PORT_SET_NODE_ID; 9716 pm.pm_data_len = sizeof (*rnid); 9717 pm.pm_data_buf = (caddr_t)rnid; 9718 9719 /* Get the adapter's node data */ 9720 rval = port->fp_fca_tran->fca_port_manage( 9721 port->fp_fca_handle, &pm); 9722 9723 if (rval != FC_SUCCESS) { 9724 fcio->fcio_errno = rval; 9725 rval = EIO; 9726 if (fp_fcio_copyout(fcio, data, mode)) { 9727 rval = EFAULT; 9728 } 9729 } else { 9730 mutex_enter(&port->fp_mutex); 9731 /* copy to the port structure */ 9732 bcopy(rnid, &port->fp_rnid_params, 9733 sizeof (port->fp_rnid_params)); 9734 mutex_exit(&port->fp_mutex); 9735 } 9736 9737 kmem_free(rnid, sizeof (fc_rnid_t)); 9738 9739 if (rval != FC_SUCCESS) { 9740 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval); 9741 } 9742 9743 return (rval); 9744 } 9745 9746 /* 9747 * This function does the local pwwn get rnid 9748 */ 9749 static int 9750 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9751 { 9752 fc_rnid_t *rnid; 9753 fc_fca_pm_t pm; 9754 int rval = 0; 9755 uint32_t ret; 9756 9757 /* Allocate memory for rnid data block */ 9758 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9759 9760 mutex_enter(&port->fp_mutex); 9761 if (port->fp_rnid_init == 1) { 9762 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t)); 9763 mutex_exit(&port->fp_mutex); 9764 /* xfer node info to userland */ 9765 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf, 9766 sizeof (*rnid), mode) == 0) { 9767 if (fp_fcio_copyout(fcio, data, mode)) { 9768 rval = EFAULT; 9769 } 9770 } else { 9771 rval = EFAULT; 9772 } 9773 9774 kmem_free(rnid, sizeof (fc_rnid_t)); 9775 9776 if (rval != FC_SUCCESS) { 9777 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", 9778 rval); 9779 } 9780 9781 return (rval); 9782 } 9783 mutex_exit(&port->fp_mutex); 9784 9785 /* Prepare the port management structure */ 9786 bzero((caddr_t)&pm, sizeof (pm)); 9787 9788 pm.pm_cmd_flags = FC_FCA_PM_READ; 9789 pm.pm_cmd_code = FC_PORT_GET_NODE_ID; 9790 pm.pm_data_len = sizeof (fc_rnid_t); 9791 pm.pm_data_buf = (caddr_t)rnid; 9792 9793 /* Get the adapter's node data */ 9794 ret = port->fp_fca_tran->fca_port_manage( 9795 port->fp_fca_handle, 9796 &pm); 9797 9798 if (ret == FC_SUCCESS) { 9799 /* initialize in the port_info */ 9800 mutex_enter(&port->fp_mutex); 9801 port->fp_rnid_init = 1; 9802 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid)); 9803 mutex_exit(&port->fp_mutex); 9804 9805 /* xfer node info to userland */ 9806 if (ddi_copyout((void *)rnid, 9807 (void *)fcio->fcio_obuf, 9808 sizeof (*rnid), mode) == 0) { 9809 if (fp_fcio_copyout(fcio, data, 9810 mode)) { 9811 rval = EFAULT; 9812 } 9813 } else { 9814 rval = EFAULT; 9815 } 9816 } else { 9817 rval = EIO; 9818 fcio->fcio_errno = ret; 9819 if (fp_fcio_copyout(fcio, data, mode)) { 9820 rval = EFAULT; 9821 } 9822 } 9823 9824 kmem_free(rnid, sizeof (fc_rnid_t)); 9825 9826 if (rval != FC_SUCCESS) { 9827 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval); 9828 } 9829 9830 return (rval); 9831 } 9832 9833 static int 9834 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio, 9835 la_wwn_t *pwwn) 9836 { 9837 int rval = 0; 9838 fc_remote_port_t *pd; 9839 fp_cmd_t *cmd; 9840 job_request_t *job; 9841 la_els_rnid_acc_t *rnid_acc; 9842 9843 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 9844 if (pd == NULL) { 9845 /* 9846 * We can safely assume that the destination port 9847 * is logged in. Either the user land will explicitly 9848 * login before issuing RNID ioctl or the device would 9849 * have been configured, meaning already logged in. 9850 */ 9851 9852 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO); 9853 9854 return (ENXIO); 9855 } 9856 /* 9857 * Allocate job structure and set job_code as DUMMY, 9858 * because we will not go thorugh the job thread. 9859 * Instead fp_sendcmd() is called directly here. 9860 */ 9861 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9862 NULL, NULL, KM_SLEEP); 9863 9864 ASSERT(job != NULL); 9865 9866 job->job_counter = 1; 9867 9868 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t), 9869 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd); 9870 if (cmd == NULL) { 9871 fcio->fcio_errno = FC_NOMEM; 9872 rval = ENOMEM; 9873 9874 fctl_dealloc_job(job); 9875 if (fp_fcio_copyout(fcio, data, mode)) { 9876 rval = EFAULT; 9877 } 9878 9879 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9880 9881 return (rval); 9882 } 9883 9884 /* Allocate memory for node id accept block */ 9885 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP); 9886 9887 mutex_enter(&port->fp_mutex); 9888 mutex_enter(&pd->pd_mutex); 9889 9890 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9891 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9892 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9893 cmd->cmd_retry_count = 1; 9894 cmd->cmd_ulp_pkt = NULL; 9895 9896 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job); 9897 9898 job->job_private = (void *)rnid_acc; 9899 9900 pd->pd_flags = PD_ELS_IN_PROGRESS; 9901 9902 mutex_exit(&pd->pd_mutex); 9903 mutex_exit(&port->fp_mutex); 9904 9905 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9906 fctl_jobwait(job); 9907 fcio->fcio_errno = job->job_result; 9908 if (job->job_result == FC_SUCCESS) { 9909 int rnid_cnt; 9910 ASSERT(pd != NULL); 9911 /* 9912 * node id block is now available. 9913 * Copy it to userland 9914 */ 9915 ASSERT(job->job_private == (void *)rnid_acc); 9916 9917 /* get the response length */ 9918 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) + 9919 rnid_acc->hdr.cmn_len + 9920 rnid_acc->hdr.specific_len; 9921 9922 if (fcio->fcio_olen < rnid_cnt) { 9923 rval = EINVAL; 9924 } else if (ddi_copyout((void *)rnid_acc, 9925 (void *)fcio->fcio_obuf, 9926 rnid_cnt, mode) == 0) { 9927 if (fp_fcio_copyout(fcio, data, 9928 mode)) { 9929 rval = EFAULT; 9930 } 9931 } else { 9932 rval = EFAULT; 9933 } 9934 } else { 9935 rval = EIO; 9936 } 9937 } else { 9938 rval = EIO; 9939 if (pd) { 9940 mutex_enter(&pd->pd_mutex); 9941 pd->pd_flags = PD_IDLE; 9942 mutex_exit(&pd->pd_mutex); 9943 } 9944 fp_free_pkt(cmd); 9945 } 9946 9947 fctl_dealloc_job(job); 9948 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t)); 9949 9950 if (fp_fcio_copyout(fcio, data, mode)) { 9951 rval = EFAULT; 9952 } 9953 9954 if (rval != FC_SUCCESS) { 9955 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9956 } 9957 9958 return (rval); 9959 } 9960 9961 /* 9962 * Copy out to userland 9963 */ 9964 static int 9965 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode) 9966 { 9967 int rval; 9968 9969 #ifdef _MULTI_DATAMODEL 9970 switch (ddi_model_convert_from(mode & FMODELS)) { 9971 case DDI_MODEL_ILP32: { 9972 struct fcio32 fcio32; 9973 9974 fcio32.fcio_xfer = fcio->fcio_xfer; 9975 fcio32.fcio_cmd = fcio->fcio_cmd; 9976 fcio32.fcio_flags = fcio->fcio_flags; 9977 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags; 9978 fcio32.fcio_ilen = fcio->fcio_ilen; 9979 fcio32.fcio_ibuf = 9980 (caddr32_t)(uintptr_t)fcio->fcio_ibuf; 9981 fcio32.fcio_olen = fcio->fcio_olen; 9982 fcio32.fcio_obuf = 9983 (caddr32_t)(uintptr_t)fcio->fcio_obuf; 9984 fcio32.fcio_alen = fcio->fcio_alen; 9985 fcio32.fcio_abuf = 9986 (caddr32_t)(uintptr_t)fcio->fcio_abuf; 9987 fcio32.fcio_errno = fcio->fcio_errno; 9988 9989 rval = ddi_copyout((void *)&fcio32, (void *)data, 9990 sizeof (struct fcio32), mode); 9991 break; 9992 } 9993 case DDI_MODEL_NONE: 9994 rval = ddi_copyout((void *)fcio, (void *)data, 9995 sizeof (fcio_t), mode); 9996 break; 9997 } 9998 #else 9999 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode); 10000 #endif 10001 10002 return (rval); 10003 } 10004 10005 10006 static void 10007 fp_p2p_online(fc_local_port_t *port, job_request_t *job) 10008 { 10009 uint32_t listlen; 10010 fc_portmap_t *changelist; 10011 10012 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10013 ASSERT(port->fp_topology == FC_TOP_PT_PT); 10014 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 10015 10016 listlen = 0; 10017 changelist = NULL; 10018 10019 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10020 if (port->fp_statec_busy > 1) { 10021 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10022 } 10023 } 10024 mutex_exit(&port->fp_mutex); 10025 10026 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10027 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10028 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10029 listlen, listlen, KM_SLEEP); 10030 10031 mutex_enter(&port->fp_mutex); 10032 } else { 10033 ASSERT(changelist == NULL && listlen == 0); 10034 mutex_enter(&port->fp_mutex); 10035 if (--port->fp_statec_busy == 0) { 10036 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10037 } 10038 } 10039 } 10040 10041 static int 10042 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10043 { 10044 int rval; 10045 int count; 10046 int index; 10047 int num_devices; 10048 fc_remote_node_t *node; 10049 fc_port_dev_t *devlist; 10050 struct pwwn_hash *head; 10051 fc_remote_port_t *pd; 10052 10053 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10054 10055 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10056 10057 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP); 10058 10059 for (count = index = 0; index < pwwn_table_size; index++) { 10060 head = &port->fp_pwwn_table[index]; 10061 pd = head->pwwn_head; 10062 while (pd != NULL) { 10063 mutex_enter(&pd->pd_mutex); 10064 if (pd->pd_state == PORT_DEVICE_INVALID) { 10065 mutex_exit(&pd->pd_mutex); 10066 pd = pd->pd_wwn_hnext; 10067 continue; 10068 } 10069 10070 devlist[count].dev_state = pd->pd_state; 10071 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10072 devlist[count].dev_did = pd->pd_port_id; 10073 devlist[count].dev_did.priv_lilp_posit = 10074 (uint8_t)(index & 0xff); 10075 bcopy((caddr_t)pd->pd_fc4types, 10076 (caddr_t)devlist[count].dev_type, 10077 sizeof (pd->pd_fc4types)); 10078 10079 bcopy((caddr_t)&pd->pd_port_name, 10080 (caddr_t)&devlist[count].dev_pwwn, 10081 sizeof (la_wwn_t)); 10082 10083 node = pd->pd_remote_nodep; 10084 mutex_exit(&pd->pd_mutex); 10085 10086 if (node) { 10087 mutex_enter(&node->fd_mutex); 10088 bcopy((caddr_t)&node->fd_node_name, 10089 (caddr_t)&devlist[count].dev_nwwn, 10090 sizeof (la_wwn_t)); 10091 mutex_exit(&node->fd_mutex); 10092 } 10093 count++; 10094 if (count >= num_devices) { 10095 goto found; 10096 } 10097 } 10098 } 10099 found: 10100 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10101 sizeof (count), mode)) { 10102 rval = FC_FAILURE; 10103 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10104 sizeof (fc_port_dev_t) * num_devices, mode)) { 10105 rval = FC_FAILURE; 10106 } else { 10107 rval = FC_SUCCESS; 10108 } 10109 10110 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices); 10111 10112 return (rval); 10113 } 10114 10115 10116 /* 10117 * Handle Fabric ONLINE 10118 */ 10119 static void 10120 fp_fabric_online(fc_local_port_t *port, job_request_t *job) 10121 { 10122 int index; 10123 int rval; 10124 int dbg_count; 10125 int count = 0; 10126 char ww_name[17]; 10127 uint32_t d_id; 10128 uint32_t listlen; 10129 fctl_ns_req_t *ns_cmd; 10130 struct pwwn_hash *head; 10131 fc_remote_port_t *pd; 10132 fc_remote_port_t *npd; 10133 fc_portmap_t *changelist; 10134 10135 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10136 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 10137 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 10138 10139 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 10140 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 10141 0, KM_SLEEP); 10142 10143 ASSERT(ns_cmd != NULL); 10144 10145 ns_cmd->ns_cmd_code = NS_GID_PN; 10146 10147 /* 10148 * Check if orphans are showing up now 10149 */ 10150 if (port->fp_orphan_count) { 10151 fc_orphan_t *orp; 10152 fc_orphan_t *norp = NULL; 10153 fc_orphan_t *prev = NULL; 10154 10155 for (orp = port->fp_orphan_list; orp; orp = norp) { 10156 norp = orp->orp_next; 10157 mutex_exit(&port->fp_mutex); 10158 orp->orp_nscan++; 10159 10160 job->job_counter = 1; 10161 job->job_result = FC_SUCCESS; 10162 10163 ((ns_req_gid_pn_t *) 10164 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn; 10165 ((ns_resp_gid_pn_t *) 10166 ns_cmd->ns_data_buf)->pid.port_id = 0; 10167 ((ns_resp_gid_pn_t *) 10168 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 10169 10170 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10171 if (rval == FC_SUCCESS) { 10172 d_id = 10173 BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10174 pd = fp_create_remote_port_by_ns(port, 10175 d_id, KM_SLEEP); 10176 10177 if (pd != NULL) { 10178 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10179 10180 fp_printf(port, CE_WARN, FP_LOG_ONLY, 10181 0, NULL, "N_x Port with D_ID=%x," 10182 " PWWN=%s reappeared in fabric", 10183 d_id, ww_name); 10184 10185 mutex_enter(&port->fp_mutex); 10186 if (prev) { 10187 prev->orp_next = orp->orp_next; 10188 } else { 10189 ASSERT(orp == 10190 port->fp_orphan_list); 10191 port->fp_orphan_list = 10192 orp->orp_next; 10193 } 10194 port->fp_orphan_count--; 10195 mutex_exit(&port->fp_mutex); 10196 kmem_free(orp, sizeof (*orp)); 10197 count++; 10198 10199 mutex_enter(&pd->pd_mutex); 10200 pd->pd_flags = PD_ELS_MARK; 10201 10202 mutex_exit(&pd->pd_mutex); 10203 } else { 10204 prev = orp; 10205 } 10206 } else { 10207 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) { 10208 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10209 10210 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, 10211 NULL, 10212 " Port WWN %s removed from orphan" 10213 " list after %d scans", ww_name, 10214 orp->orp_nscan); 10215 10216 mutex_enter(&port->fp_mutex); 10217 if (prev) { 10218 prev->orp_next = orp->orp_next; 10219 } else { 10220 ASSERT(orp == 10221 port->fp_orphan_list); 10222 port->fp_orphan_list = 10223 orp->orp_next; 10224 } 10225 port->fp_orphan_count--; 10226 mutex_exit(&port->fp_mutex); 10227 10228 kmem_free(orp, sizeof (*orp)); 10229 } else { 10230 prev = orp; 10231 } 10232 } 10233 mutex_enter(&port->fp_mutex); 10234 } 10235 } 10236 10237 /* 10238 * Walk the Port WWN hash table, reestablish LOGIN 10239 * if a LOGIN is already performed on a particular 10240 * device; Any failure to LOGIN should mark the 10241 * port device OLD. 10242 */ 10243 for (index = 0; index < pwwn_table_size; index++) { 10244 head = &port->fp_pwwn_table[index]; 10245 npd = head->pwwn_head; 10246 10247 while ((pd = npd) != NULL) { 10248 la_wwn_t *pwwn; 10249 10250 npd = pd->pd_wwn_hnext; 10251 10252 /* 10253 * Don't count in the port devices that are new 10254 * unless the total number of devices visible 10255 * through this port is less than FP_MAX_DEVICES 10256 */ 10257 mutex_enter(&pd->pd_mutex); 10258 if (port->fp_dev_count >= FP_MAX_DEVICES || 10259 (port->fp_options & FP_TARGET_MODE)) { 10260 if (pd->pd_type == PORT_DEVICE_NEW || 10261 pd->pd_flags == PD_ELS_MARK || 10262 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10263 mutex_exit(&pd->pd_mutex); 10264 continue; 10265 } 10266 } else { 10267 if (pd->pd_flags == PD_ELS_MARK || 10268 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10269 mutex_exit(&pd->pd_mutex); 10270 continue; 10271 } 10272 pd->pd_type = PORT_DEVICE_OLD; 10273 } 10274 count++; 10275 10276 /* 10277 * Consult with the name server about D_ID changes 10278 */ 10279 job->job_counter = 1; 10280 job->job_result = FC_SUCCESS; 10281 10282 ((ns_req_gid_pn_t *) 10283 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name; 10284 ((ns_resp_gid_pn_t *) 10285 ns_cmd->ns_data_buf)->pid.port_id = 0; 10286 10287 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)-> 10288 pid.priv_lilp_posit = 0; 10289 10290 pwwn = &pd->pd_port_name; 10291 pd->pd_flags = PD_ELS_MARK; 10292 10293 mutex_exit(&pd->pd_mutex); 10294 mutex_exit(&port->fp_mutex); 10295 10296 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10297 if (rval != FC_SUCCESS) { 10298 fc_wwn_to_str(pwwn, ww_name); 10299 10300 mutex_enter(&pd->pd_mutex); 10301 d_id = pd->pd_port_id.port_id; 10302 pd->pd_type = PORT_DEVICE_DELETE; 10303 mutex_exit(&pd->pd_mutex); 10304 10305 FP_TRACE(FP_NHEAD1(3, 0), 10306 "fp_fabric_online: PD " 10307 "disappeared; d_id=%x, PWWN=%s", 10308 d_id, ww_name); 10309 10310 FP_TRACE(FP_NHEAD2(9, 0), 10311 "N_x Port with D_ID=%x, PWWN=%s" 10312 " disappeared from fabric", d_id, 10313 ww_name); 10314 10315 mutex_enter(&port->fp_mutex); 10316 continue; 10317 } 10318 10319 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10320 10321 mutex_enter(&port->fp_mutex); 10322 mutex_enter(&pd->pd_mutex); 10323 if (d_id != pd->pd_port_id.port_id) { 10324 fctl_delist_did_table(port, pd); 10325 fc_wwn_to_str(pwwn, ww_name); 10326 10327 FP_TRACE(FP_NHEAD2(9, 0), 10328 "D_ID of a device with PWWN %s changed." 10329 " New D_ID = %x, OLD D_ID = %x", ww_name, 10330 d_id, pd->pd_port_id.port_id); 10331 10332 pd->pd_port_id.port_id = BE_32(d_id); 10333 pd->pd_type = PORT_DEVICE_CHANGED; 10334 fctl_enlist_did_table(port, pd); 10335 } 10336 mutex_exit(&pd->pd_mutex); 10337 10338 } 10339 } 10340 10341 if (ns_cmd) { 10342 fctl_free_ns_cmd(ns_cmd); 10343 } 10344 10345 listlen = 0; 10346 changelist = NULL; 10347 if (count) { 10348 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 10349 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 10350 mutex_exit(&port->fp_mutex); 10351 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000)); 10352 mutex_enter(&port->fp_mutex); 10353 } 10354 10355 dbg_count = 0; 10356 10357 job->job_counter = count; 10358 10359 for (index = 0; index < pwwn_table_size; index++) { 10360 head = &port->fp_pwwn_table[index]; 10361 npd = head->pwwn_head; 10362 10363 while ((pd = npd) != NULL) { 10364 npd = pd->pd_wwn_hnext; 10365 10366 mutex_enter(&pd->pd_mutex); 10367 if (pd->pd_flags != PD_ELS_MARK) { 10368 mutex_exit(&pd->pd_mutex); 10369 continue; 10370 } 10371 10372 dbg_count++; 10373 10374 /* 10375 * If it is already marked deletion, nothing 10376 * else to do. 10377 */ 10378 if (pd->pd_type == PORT_DEVICE_DELETE) { 10379 pd->pd_type = PORT_DEVICE_OLD; 10380 10381 mutex_exit(&pd->pd_mutex); 10382 mutex_exit(&port->fp_mutex); 10383 fp_jobdone(job); 10384 mutex_enter(&port->fp_mutex); 10385 10386 continue; 10387 } 10388 10389 /* 10390 * If it is freshly discovered out of 10391 * the orphan list, nothing else to do 10392 */ 10393 if (pd->pd_type == PORT_DEVICE_NEW) { 10394 pd->pd_flags = PD_IDLE; 10395 10396 mutex_exit(&pd->pd_mutex); 10397 mutex_exit(&port->fp_mutex); 10398 fp_jobdone(job); 10399 mutex_enter(&port->fp_mutex); 10400 10401 continue; 10402 } 10403 10404 pd->pd_flags = PD_IDLE; 10405 d_id = pd->pd_port_id.port_id; 10406 10407 /* 10408 * Explicitly mark all devices OLD; successful 10409 * PLOGI should reset this to either NO_CHANGE 10410 * or CHANGED. 10411 */ 10412 if (pd->pd_type != PORT_DEVICE_CHANGED) { 10413 pd->pd_type = PORT_DEVICE_OLD; 10414 } 10415 10416 mutex_exit(&pd->pd_mutex); 10417 mutex_exit(&port->fp_mutex); 10418 10419 rval = fp_port_login(port, d_id, job, 10420 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 10421 10422 if (rval != FC_SUCCESS) { 10423 fp_jobdone(job); 10424 } 10425 mutex_enter(&port->fp_mutex); 10426 } 10427 } 10428 mutex_exit(&port->fp_mutex); 10429 10430 ASSERT(dbg_count == count); 10431 fp_jobwait(job); 10432 10433 mutex_enter(&port->fp_mutex); 10434 10435 ASSERT(port->fp_statec_busy > 0); 10436 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10437 if (port->fp_statec_busy > 1) { 10438 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10439 } 10440 } 10441 mutex_exit(&port->fp_mutex); 10442 } else { 10443 ASSERT(port->fp_statec_busy > 0); 10444 if (port->fp_statec_busy > 1) { 10445 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10446 } 10447 mutex_exit(&port->fp_mutex); 10448 } 10449 10450 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10451 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10452 10453 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10454 listlen, listlen, KM_SLEEP); 10455 10456 mutex_enter(&port->fp_mutex); 10457 } else { 10458 ASSERT(changelist == NULL && listlen == 0); 10459 mutex_enter(&port->fp_mutex); 10460 if (--port->fp_statec_busy == 0) { 10461 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10462 } 10463 } 10464 } 10465 10466 10467 /* 10468 * Fill out device list for userland ioctl in private loop 10469 */ 10470 static int 10471 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10472 { 10473 int rval; 10474 int count; 10475 int index; 10476 int num_devices; 10477 fc_remote_node_t *node; 10478 fc_port_dev_t *devlist; 10479 int lilp_device_count; 10480 fc_lilpmap_t *lilp_map; 10481 uchar_t *alpa_list; 10482 10483 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10484 10485 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10486 if (port->fp_total_devices > port->fp_dev_count && 10487 num_devices >= port->fp_total_devices) { 10488 job_request_t *job; 10489 10490 mutex_exit(&port->fp_mutex); 10491 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP); 10492 job->job_counter = 1; 10493 10494 mutex_enter(&port->fp_mutex); 10495 fp_get_loopmap(port, job); 10496 mutex_exit(&port->fp_mutex); 10497 10498 fp_jobwait(job); 10499 fctl_dealloc_job(job); 10500 } else { 10501 mutex_exit(&port->fp_mutex); 10502 } 10503 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP); 10504 10505 mutex_enter(&port->fp_mutex); 10506 10507 /* 10508 * Applications are accustomed to getting the device list in 10509 * LILP map order. The HBA firmware usually returns the device 10510 * map in the LILP map order and diagnostic applications would 10511 * prefer to receive in the device list in that order too 10512 */ 10513 lilp_map = &port->fp_lilp_map; 10514 alpa_list = &lilp_map->lilp_alpalist[0]; 10515 10516 /* 10517 * the length field corresponds to the offset in the LILP frame 10518 * which begins with 1. The thing to note here is that the 10519 * lilp_device_count is 1 more than fp->fp_total_devices since 10520 * the host adapter's alpa also shows up in the lilp map. We 10521 * don't however return details of the host adapter since 10522 * fctl_get_remote_port_by_did fails for the host adapter's ALPA 10523 * and applications are required to issue the FCIO_GET_HOST_PARAMS 10524 * ioctl to obtain details about the host adapter port. 10525 */ 10526 lilp_device_count = lilp_map->lilp_length; 10527 10528 for (count = index = 0; index < lilp_device_count && 10529 count < num_devices; index++) { 10530 uint32_t d_id; 10531 fc_remote_port_t *pd; 10532 10533 d_id = alpa_list[index]; 10534 10535 mutex_exit(&port->fp_mutex); 10536 pd = fctl_get_remote_port_by_did(port, d_id); 10537 mutex_enter(&port->fp_mutex); 10538 10539 if (pd != NULL) { 10540 mutex_enter(&pd->pd_mutex); 10541 10542 if (pd->pd_state == PORT_DEVICE_INVALID) { 10543 mutex_exit(&pd->pd_mutex); 10544 continue; 10545 } 10546 10547 devlist[count].dev_state = pd->pd_state; 10548 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10549 devlist[count].dev_did = pd->pd_port_id; 10550 devlist[count].dev_did.priv_lilp_posit = 10551 (uint8_t)(index & 0xff); 10552 bcopy((caddr_t)pd->pd_fc4types, 10553 (caddr_t)devlist[count].dev_type, 10554 sizeof (pd->pd_fc4types)); 10555 10556 bcopy((caddr_t)&pd->pd_port_name, 10557 (caddr_t)&devlist[count].dev_pwwn, 10558 sizeof (la_wwn_t)); 10559 10560 node = pd->pd_remote_nodep; 10561 mutex_exit(&pd->pd_mutex); 10562 10563 if (node) { 10564 mutex_enter(&node->fd_mutex); 10565 bcopy((caddr_t)&node->fd_node_name, 10566 (caddr_t)&devlist[count].dev_nwwn, 10567 sizeof (la_wwn_t)); 10568 mutex_exit(&node->fd_mutex); 10569 } 10570 count++; 10571 } 10572 } 10573 10574 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10575 sizeof (count), mode)) { 10576 rval = FC_FAILURE; 10577 } 10578 10579 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10580 sizeof (fc_port_dev_t) * num_devices, mode)) { 10581 rval = FC_FAILURE; 10582 } else { 10583 rval = FC_SUCCESS; 10584 } 10585 10586 kmem_free(devlist, sizeof (*devlist) * num_devices); 10587 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10588 10589 return (rval); 10590 } 10591 10592 10593 /* 10594 * Completion function for responses to unsolicited commands 10595 */ 10596 static void 10597 fp_unsol_intr(fc_packet_t *pkt) 10598 { 10599 fp_cmd_t *cmd; 10600 fc_local_port_t *port; 10601 10602 cmd = pkt->pkt_ulp_private; 10603 port = cmd->cmd_port; 10604 10605 mutex_enter(&port->fp_mutex); 10606 port->fp_out_fpcmds--; 10607 mutex_exit(&port->fp_mutex); 10608 10609 if (pkt->pkt_state != FC_PKT_SUCCESS) { 10610 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt, 10611 "couldn't post response to unsolicited request;" 10612 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id, 10613 pkt->pkt_resp_fhdr.rx_id); 10614 } 10615 10616 if (cmd == port->fp_els_resp_pkt) { 10617 mutex_enter(&port->fp_mutex); 10618 port->fp_els_resp_pkt_busy = 0; 10619 mutex_exit(&port->fp_mutex); 10620 return; 10621 } 10622 10623 fp_free_pkt(cmd); 10624 } 10625 10626 10627 /* 10628 * solicited LINIT ELS completion function 10629 */ 10630 static void 10631 fp_linit_intr(fc_packet_t *pkt) 10632 { 10633 fp_cmd_t *cmd; 10634 job_request_t *job; 10635 fc_linit_resp_t acc; 10636 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 10637 10638 cmd = (fp_cmd_t *)pkt->pkt_ulp_private; 10639 10640 mutex_enter(&cmd->cmd_port->fp_mutex); 10641 cmd->cmd_port->fp_out_fpcmds--; 10642 mutex_exit(&cmd->cmd_port->fp_mutex); 10643 10644 if (FP_IS_PKT_ERROR(pkt)) { 10645 (void) fp_common_intr(pkt, 1); 10646 return; 10647 } 10648 10649 job = cmd->cmd_job; 10650 10651 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc, 10652 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR); 10653 if (acc.status != FC_LINIT_SUCCESS) { 10654 job->job_result = FC_FAILURE; 10655 } else { 10656 job->job_result = FC_SUCCESS; 10657 } 10658 10659 fp_iodone(cmd); 10660 } 10661 10662 10663 /* 10664 * Decode the unsolicited request; For FC-4 Device and Link data frames 10665 * notify the registered ULP of this FC-4 type right here. For Unsolicited 10666 * ELS requests, submit a request to the job_handler thread to work on it. 10667 * The intent is to act quickly on the FC-4 unsolicited link and data frames 10668 * and save much of the interrupt time processing of unsolicited ELS requests 10669 * and hand it off to the job_handler thread. 10670 */ 10671 static void 10672 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type) 10673 { 10674 uchar_t r_ctl; 10675 uchar_t ls_code; 10676 uint32_t s_id; 10677 uint32_t rscn_count = FC_INVALID_RSCN_COUNT; 10678 uint32_t cb_arg; 10679 fp_cmd_t *cmd; 10680 fc_local_port_t *port; 10681 job_request_t *job; 10682 fc_remote_port_t *pd; 10683 10684 port = port_handle; 10685 10686 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x," 10687 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x" 10688 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x" 10689 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10690 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl, 10691 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt, 10692 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro, 10693 buf->ub_buffer[0]); 10694 10695 if (type & 0x80000000) { 10696 /* 10697 * Huh ? Nothing much can be done without 10698 * a valid buffer. So just exit. 10699 */ 10700 return; 10701 } 10702 /* 10703 * If the unsolicited interrupts arrive while it isn't 10704 * safe to handle unsolicited callbacks; Drop them, yes, 10705 * drop them on the floor 10706 */ 10707 mutex_enter(&port->fp_mutex); 10708 port->fp_active_ubs++; 10709 if ((port->fp_soft_state & 10710 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 10711 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 10712 10713 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is " 10714 "not ONLINE. s_id=%x, d_id=%x, type=%x, " 10715 "seq_id=%x, ox_id=%x, rx_id=%x" 10716 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10717 buf->ub_frame.type, buf->ub_frame.seq_id, 10718 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 10719 10720 ASSERT(port->fp_active_ubs > 0); 10721 if (--(port->fp_active_ubs) == 0) { 10722 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10723 } 10724 10725 mutex_exit(&port->fp_mutex); 10726 10727 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10728 1, &buf->ub_token); 10729 10730 return; 10731 } 10732 10733 r_ctl = buf->ub_frame.r_ctl; 10734 s_id = buf->ub_frame.s_id; 10735 if (port->fp_active_ubs == 1) { 10736 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB; 10737 } 10738 10739 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO && 10740 port->fp_statec_busy) { 10741 mutex_exit(&port->fp_mutex); 10742 pd = fctl_get_remote_port_by_did(port, s_id); 10743 if (pd) { 10744 mutex_enter(&pd->pd_mutex); 10745 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10746 FP_TRACE(FP_NHEAD1(3, 0), 10747 "LOGO for LOGGED IN D_ID %x", 10748 buf->ub_frame.s_id); 10749 pd->pd_state = PORT_DEVICE_VALID; 10750 } 10751 mutex_exit(&pd->pd_mutex); 10752 } 10753 10754 mutex_enter(&port->fp_mutex); 10755 ASSERT(port->fp_active_ubs > 0); 10756 if (--(port->fp_active_ubs) == 0) { 10757 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10758 } 10759 mutex_exit(&port->fp_mutex); 10760 10761 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10762 1, &buf->ub_token); 10763 10764 FP_TRACE(FP_NHEAD1(3, 0), 10765 "fp_unsol_cb() bailing out LOGO for D_ID %x", 10766 buf->ub_frame.s_id); 10767 return; 10768 } 10769 10770 if (port->fp_els_resp_pkt_busy == 0) { 10771 if (r_ctl == R_CTL_ELS_REQ) { 10772 ls_code = buf->ub_buffer[0]; 10773 10774 switch (ls_code) { 10775 case LA_ELS_PLOGI: 10776 case LA_ELS_FLOGI: 10777 port->fp_els_resp_pkt_busy = 1; 10778 mutex_exit(&port->fp_mutex); 10779 fp_i_handle_unsol_els(port, buf); 10780 10781 mutex_enter(&port->fp_mutex); 10782 ASSERT(port->fp_active_ubs > 0); 10783 if (--(port->fp_active_ubs) == 0) { 10784 port->fp_soft_state &= 10785 ~FP_SOFT_IN_UNSOL_CB; 10786 } 10787 mutex_exit(&port->fp_mutex); 10788 port->fp_fca_tran->fca_ub_release( 10789 port->fp_fca_handle, 1, &buf->ub_token); 10790 10791 return; 10792 case LA_ELS_RSCN: 10793 if (++(port)->fp_rscn_count == 10794 FC_INVALID_RSCN_COUNT) { 10795 ++(port)->fp_rscn_count; 10796 } 10797 rscn_count = port->fp_rscn_count; 10798 break; 10799 10800 default: 10801 break; 10802 } 10803 } 10804 } else if ((r_ctl == R_CTL_ELS_REQ) && 10805 (buf->ub_buffer[0] == LA_ELS_RSCN)) { 10806 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10807 ++port->fp_rscn_count; 10808 } 10809 rscn_count = port->fp_rscn_count; 10810 } 10811 10812 mutex_exit(&port->fp_mutex); 10813 10814 switch (r_ctl & R_CTL_ROUTING) { 10815 case R_CTL_DEVICE_DATA: 10816 /* 10817 * If the unsolicited buffer is a CT IU, 10818 * have the job_handler thread work on it. 10819 */ 10820 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 10821 break; 10822 } 10823 /* FALLTHROUGH */ 10824 10825 case R_CTL_FC4_SVC: { 10826 int sendup = 0; 10827 10828 /* 10829 * If a LOGIN isn't performed before this request 10830 * shut the door on this port with a reply that a 10831 * LOGIN is required. We make an exception however 10832 * for IP broadcast packets and pass them through 10833 * to the IP ULP(s) to handle broadcast requests. 10834 * This is not a problem for private loop devices 10835 * but for fabric topologies we don't log into the 10836 * remote ports during port initialization and 10837 * the ULPs need to log into requesting ports on 10838 * demand. 10839 */ 10840 pd = fctl_get_remote_port_by_did(port, s_id); 10841 if (pd) { 10842 mutex_enter(&pd->pd_mutex); 10843 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10844 sendup++; 10845 } 10846 mutex_exit(&pd->pd_mutex); 10847 } else if ((pd == NULL) && 10848 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) && 10849 (buf->ub_frame.d_id == 0xffffff || 10850 buf->ub_frame.d_id == 0x00)) { 10851 /* brodacst IP frame - so sendup via job thread */ 10852 break; 10853 } 10854 10855 /* 10856 * Send all FC4 services via job thread too 10857 */ 10858 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) { 10859 break; 10860 } 10861 10862 if (sendup || !FC_IS_REAL_DEVICE(s_id)) { 10863 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type); 10864 return; 10865 } 10866 10867 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10868 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10869 0, KM_NOSLEEP, pd); 10870 if (cmd != NULL) { 10871 fp_els_rjt_init(port, cmd, buf, 10872 FC_ACTION_NON_RETRYABLE, 10873 FC_REASON_LOGIN_REQUIRED, NULL); 10874 10875 if (fp_sendcmd(port, cmd, 10876 port->fp_fca_handle) != FC_SUCCESS) { 10877 fp_free_pkt(cmd); 10878 } 10879 } 10880 } 10881 10882 mutex_enter(&port->fp_mutex); 10883 ASSERT(port->fp_active_ubs > 0); 10884 if (--(port->fp_active_ubs) == 0) { 10885 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10886 } 10887 mutex_exit(&port->fp_mutex); 10888 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10889 1, &buf->ub_token); 10890 10891 return; 10892 } 10893 10894 default: 10895 break; 10896 } 10897 10898 /* 10899 * Submit a Request to the job_handler thread to work 10900 * on the unsolicited request. The potential side effect 10901 * of this is that the unsolicited buffer takes a little 10902 * longer to get released but we save interrupt time in 10903 * the bargain. 10904 */ 10905 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? 0 : rscn_count; 10906 10907 /* 10908 * One way that the rscn_count will get used is described below : 10909 * 10910 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count. 10911 * 2. Before mutex is released, a copy of it is stored in rscn_count. 10912 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below) 10913 * by overloading the job_cb_arg to pass the rscn_count 10914 * 4. When one of the routines processing the RSCN picks it up (ex: 10915 * fp_validate_rscn_page()), it passes this count in the map 10916 * structure (as part of the map_rscn_info structure member) to the 10917 * ULPs. 10918 * 5. When ULPs make calls back to the transport (example interfaces for 10919 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they 10920 * can now pass back this count as part of the fc_packet's 10921 * pkt_ulp_rscn_count member. fcp does this currently. 10922 * 6. When transport gets a call to transport a command on the wire, it 10923 * will check to see if there is a valid pkt_ulp_rsvd1 field in the 10924 * fc_packet. If there is, it will match that info with the current 10925 * rscn_count on that instance of the port. If they don't match up 10926 * then there was a newer RSCN. The ULP gets back an error code which 10927 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN. 10928 * 7. At this point the ULP is free to make up its own mind as to how to 10929 * handle this. Currently, fcp will reset its retry counters and keep 10930 * retrying the operation it was doing in anticipation of getting a 10931 * new state change call back for the new RSCN. 10932 */ 10933 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL, 10934 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP); 10935 if (job == NULL) { 10936 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() " 10937 "couldn't submit a job to the thread, failing.."); 10938 10939 mutex_enter(&port->fp_mutex); 10940 10941 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10942 --port->fp_rscn_count; 10943 } 10944 10945 ASSERT(port->fp_active_ubs > 0); 10946 if (--(port->fp_active_ubs) == 0) { 10947 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10948 } 10949 10950 mutex_exit(&port->fp_mutex); 10951 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10952 1, &buf->ub_token); 10953 10954 return; 10955 } 10956 job->job_private = (void *)buf; 10957 fctl_enque_job(port, job); 10958 } 10959 10960 10961 /* 10962 * Handle unsolicited requests 10963 */ 10964 static void 10965 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf, 10966 job_request_t *job) 10967 { 10968 uchar_t r_ctl; 10969 uchar_t ls_code; 10970 uint32_t s_id; 10971 fp_cmd_t *cmd; 10972 fc_remote_port_t *pd; 10973 fp_unsol_spec_t *ub_spec; 10974 10975 r_ctl = buf->ub_frame.r_ctl; 10976 s_id = buf->ub_frame.s_id; 10977 10978 switch (r_ctl & R_CTL_ROUTING) { 10979 case R_CTL_EXTENDED_SVC: 10980 if (r_ctl != R_CTL_ELS_REQ) { 10981 break; 10982 } 10983 10984 ls_code = buf->ub_buffer[0]; 10985 switch (ls_code) { 10986 case LA_ELS_LOGO: 10987 case LA_ELS_ADISC: 10988 case LA_ELS_PRLO: 10989 pd = fctl_get_remote_port_by_did(port, s_id); 10990 if (pd == NULL) { 10991 if (!FC_IS_REAL_DEVICE(s_id)) { 10992 break; 10993 } 10994 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10995 break; 10996 } 10997 if ((cmd = fp_alloc_pkt(port, 10998 sizeof (la_els_rjt_t), 0, KM_SLEEP, 10999 NULL)) == NULL) { 11000 /* 11001 * Can this actually fail when 11002 * given KM_SLEEP? (Could be used 11003 * this way in a number of places.) 11004 */ 11005 break; 11006 } 11007 11008 fp_els_rjt_init(port, cmd, buf, 11009 FC_ACTION_NON_RETRYABLE, 11010 FC_REASON_INVALID_LINK_CTRL, job); 11011 11012 if (fp_sendcmd(port, cmd, 11013 port->fp_fca_handle) != FC_SUCCESS) { 11014 fp_free_pkt(cmd); 11015 } 11016 11017 break; 11018 } 11019 if (ls_code == LA_ELS_LOGO) { 11020 fp_handle_unsol_logo(port, buf, pd, job); 11021 } else if (ls_code == LA_ELS_ADISC) { 11022 fp_handle_unsol_adisc(port, buf, pd, job); 11023 } else { 11024 fp_handle_unsol_prlo(port, buf, pd, job); 11025 } 11026 break; 11027 11028 case LA_ELS_PLOGI: 11029 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP); 11030 break; 11031 11032 case LA_ELS_FLOGI: 11033 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP); 11034 break; 11035 11036 case LA_ELS_RSCN: 11037 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP); 11038 break; 11039 11040 default: 11041 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 11042 ub_spec->port = port; 11043 ub_spec->buf = buf; 11044 11045 (void) taskq_dispatch(port->fp_taskq, 11046 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 11047 return; 11048 } 11049 break; 11050 11051 case R_CTL_BASIC_SVC: 11052 /* 11053 * The unsolicited basic link services could be ABTS 11054 * and RMC (Or even a NOP). Just BA_RJT them until 11055 * such time there arises a need to handle them more 11056 * carefully. 11057 */ 11058 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11059 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t), 11060 0, KM_SLEEP, NULL); 11061 if (cmd != NULL) { 11062 fp_ba_rjt_init(port, cmd, buf, job); 11063 if (fp_sendcmd(port, cmd, 11064 port->fp_fca_handle) != FC_SUCCESS) { 11065 fp_free_pkt(cmd); 11066 } 11067 } 11068 } 11069 break; 11070 11071 case R_CTL_DEVICE_DATA: 11072 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 11073 /* 11074 * Mostly this is of type FC_TYPE_FC_SERVICES. 11075 * As we don't like any Unsolicited FC services 11076 * requests, we would do well to RJT them as 11077 * well. 11078 */ 11079 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11080 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11081 0, KM_SLEEP, NULL); 11082 if (cmd != NULL) { 11083 fp_els_rjt_init(port, cmd, buf, 11084 FC_ACTION_NON_RETRYABLE, 11085 FC_REASON_INVALID_LINK_CTRL, job); 11086 11087 if (fp_sendcmd(port, cmd, 11088 port->fp_fca_handle) != 11089 FC_SUCCESS) { 11090 fp_free_pkt(cmd); 11091 } 11092 } 11093 } 11094 break; 11095 } 11096 /* FALLTHROUGH */ 11097 11098 case R_CTL_FC4_SVC: 11099 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 11100 ub_spec->port = port; 11101 ub_spec->buf = buf; 11102 11103 (void) taskq_dispatch(port->fp_taskq, 11104 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 11105 return; 11106 11107 case R_CTL_LINK_CTL: 11108 /* 11109 * Turn deaf ear on unsolicited link control frames. 11110 * Typical unsolicited link control Frame is an LCR 11111 * (to reset End to End credit to the default login 11112 * value and abort current sequences for all classes) 11113 * An intelligent microcode/firmware should handle 11114 * this transparently at its level and not pass all 11115 * the way up here. 11116 * 11117 * Possible responses to LCR are R_RDY, F_RJT, P_RJT 11118 * or F_BSY. P_RJT is chosen to be the most appropriate 11119 * at this time. 11120 */ 11121 /* FALLTHROUGH */ 11122 11123 default: 11124 /* 11125 * Just reject everything else as an invalid request. 11126 */ 11127 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11128 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11129 0, KM_SLEEP, NULL); 11130 if (cmd != NULL) { 11131 fp_els_rjt_init(port, cmd, buf, 11132 FC_ACTION_NON_RETRYABLE, 11133 FC_REASON_INVALID_LINK_CTRL, job); 11134 11135 if (fp_sendcmd(port, cmd, 11136 port->fp_fca_handle) != FC_SUCCESS) { 11137 fp_free_pkt(cmd); 11138 } 11139 } 11140 } 11141 break; 11142 } 11143 11144 mutex_enter(&port->fp_mutex); 11145 ASSERT(port->fp_active_ubs > 0); 11146 if (--(port->fp_active_ubs) == 0) { 11147 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 11148 } 11149 mutex_exit(&port->fp_mutex); 11150 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 11151 1, &buf->ub_token); 11152 } 11153 11154 11155 /* 11156 * Prepare a BA_RJT and send it over. 11157 */ 11158 static void 11159 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11160 job_request_t *job) 11161 { 11162 fc_packet_t *pkt; 11163 la_ba_rjt_t payload; 11164 11165 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11166 11167 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11168 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11169 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11170 cmd->cmd_retry_count = 1; 11171 cmd->cmd_ulp_pkt = NULL; 11172 11173 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11174 cmd->cmd_job = job; 11175 11176 pkt = &cmd->cmd_pkt; 11177 11178 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS); 11179 11180 payload.reserved = 0; 11181 payload.reason_code = FC_REASON_CMD_UNSUPPORTED; 11182 payload.explanation = FC_EXPLN_NONE; 11183 payload.vendor = 0; 11184 11185 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11186 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11187 } 11188 11189 11190 /* 11191 * Prepare an LS_RJT and send it over 11192 */ 11193 static void 11194 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11195 uchar_t action, uchar_t reason, job_request_t *job) 11196 { 11197 fc_packet_t *pkt; 11198 la_els_rjt_t payload; 11199 11200 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11201 11202 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11203 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11204 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11205 cmd->cmd_retry_count = 1; 11206 cmd->cmd_ulp_pkt = NULL; 11207 11208 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11209 cmd->cmd_job = job; 11210 11211 pkt = &cmd->cmd_pkt; 11212 11213 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11214 11215 payload.ls_code.ls_code = LA_ELS_RJT; 11216 payload.ls_code.mbz = 0; 11217 payload.action = action; 11218 payload.reason = reason; 11219 payload.reserved = 0; 11220 payload.vu = 0; 11221 11222 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11223 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11224 } 11225 11226 /* 11227 * Function: fp_prlo_acc_init 11228 * 11229 * Description: Initializes an Link Service Accept for a PRLO. 11230 * 11231 * Arguments: *port Local port through which the PRLO was 11232 * received. 11233 * cmd Command that will carry the accept. 11234 * *buf Unsolicited buffer containing the PRLO 11235 * request. 11236 * job Job request. 11237 * sleep Allocation mode. 11238 * 11239 * Return Value: *cmd Command containing the response. 11240 * 11241 * Context: Depends on the parameter sleep. 11242 */ 11243 fp_cmd_t * 11244 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd, 11245 fc_unsol_buf_t *buf, job_request_t *job, int sleep) 11246 { 11247 fp_cmd_t *cmd; 11248 fc_packet_t *pkt; 11249 la_els_prlo_t *req; 11250 size_t len; 11251 uint16_t flags; 11252 11253 req = (la_els_prlo_t *)buf->ub_buffer; 11254 len = (size_t)ntohs(req->payload_length); 11255 11256 /* 11257 * The payload of the accept to a PRLO has to be the exact match of 11258 * the payload of the request (at the exception of the code). 11259 */ 11260 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd); 11261 11262 if (cmd) { 11263 /* 11264 * The fp command was successfully allocated. 11265 */ 11266 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11267 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11268 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11269 cmd->cmd_retry_count = 1; 11270 cmd->cmd_ulp_pkt = NULL; 11271 11272 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11273 cmd->cmd_job = job; 11274 11275 pkt = &cmd->cmd_pkt; 11276 11277 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, 11278 FC_TYPE_EXTENDED_LS); 11279 11280 /* The code is overwritten for the copy. */ 11281 req->ls_code = LA_ELS_ACC; 11282 /* Response code is set. */ 11283 flags = ntohs(req->flags); 11284 flags &= ~SP_RESP_CODE_MASK; 11285 flags |= SP_RESP_CODE_REQ_EXECUTED; 11286 req->flags = htons(flags); 11287 11288 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req, 11289 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR); 11290 } 11291 return (cmd); 11292 } 11293 11294 /* 11295 * Prepare an ACC response to an ELS request 11296 */ 11297 static void 11298 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11299 job_request_t *job) 11300 { 11301 fc_packet_t *pkt; 11302 ls_code_t payload; 11303 11304 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11305 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11306 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11307 cmd->cmd_retry_count = 1; 11308 cmd->cmd_ulp_pkt = NULL; 11309 11310 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11311 cmd->cmd_job = job; 11312 11313 pkt = &cmd->cmd_pkt; 11314 11315 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11316 11317 payload.ls_code = LA_ELS_ACC; 11318 payload.mbz = 0; 11319 11320 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11321 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11322 } 11323 11324 /* 11325 * Unsolicited PRLO handler 11326 * 11327 * A Process Logout should be handled by the ULP that established it. However, 11328 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens 11329 * when a device implicitly logs out an initiator (for whatever reason) and 11330 * tries to get that initiator to restablish the connection (PLOGI and PRLI). 11331 * The logical thing to do for the device would be to send a LOGO in response 11332 * to any FC4 frame sent by the initiator. Some devices choose, however, to send 11333 * a PRLO instead. 11334 * 11335 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to 11336 * think that the Port Login has been lost. If we follow the Fibre Channel 11337 * protocol to the letter a PRLI should be sent after accepting the PRLO. If 11338 * the Port Login has also been lost, the remote port will reject the PRLI 11339 * indicating that we must PLOGI first. The initiator will then turn around and 11340 * send a PLOGI. The way Leadville is layered and the way the ULP interface 11341 * is defined doesn't allow this scenario to be followed easily. If FCP were to 11342 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is 11343 * needed would be received by FCP. FCP would have, then, to tell the transport 11344 * (fp) to PLOGI. The problem is, the transport would still think the Port 11345 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even 11346 * if you think it's not necessary". To work around that difficulty, the PRLO 11347 * is treated by the transport as a LOGO. The downside to it is a Port Login 11348 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that 11349 * has nothing to do with the PRLO) may be impacted. However, this is a 11350 * scenario very unlikely to happen. As of today the only ULP in Leadville 11351 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be 11352 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very 11353 * unlikely). 11354 */ 11355 static void 11356 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11357 fc_remote_port_t *pd, job_request_t *job) 11358 { 11359 int busy; 11360 int rval; 11361 int retain; 11362 fp_cmd_t *cmd; 11363 fc_portmap_t *listptr; 11364 boolean_t tolerance; 11365 la_els_prlo_t *req; 11366 11367 req = (la_els_prlo_t *)buf->ub_buffer; 11368 11369 if ((ntohs(req->payload_length) != 11370 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) || 11371 (req->page_length != sizeof (service_parameter_page_t))) { 11372 /* 11373 * We are being very restrictive. Only on page per 11374 * payload. If it is not the case we reject the ELS although 11375 * we should reply indicating we handle only single page 11376 * per PRLO. 11377 */ 11378 goto fp_reject_prlo; 11379 } 11380 11381 if (ntohs(req->payload_length) > buf->ub_bufsize) { 11382 /* 11383 * This is in case the payload advertizes a size bigger than 11384 * what it really is. 11385 */ 11386 goto fp_reject_prlo; 11387 } 11388 11389 mutex_enter(&port->fp_mutex); 11390 busy = port->fp_statec_busy; 11391 mutex_exit(&port->fp_mutex); 11392 11393 mutex_enter(&pd->pd_mutex); 11394 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11395 if (!busy) { 11396 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11397 pd->pd_state == PORT_DEVICE_INVALID || 11398 pd->pd_flags == PD_ELS_IN_PROGRESS || 11399 pd->pd_type == PORT_DEVICE_OLD) { 11400 busy++; 11401 } 11402 } 11403 11404 if (busy) { 11405 mutex_exit(&pd->pd_mutex); 11406 11407 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11408 "pd=%p - busy", 11409 pd->pd_port_id.port_id, pd); 11410 11411 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11412 goto fp_reject_prlo; 11413 } 11414 } else { 11415 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11416 11417 if (tolerance) { 11418 fctl_tc_reset(&pd->pd_logo_tc); 11419 retain = 0; 11420 pd->pd_state = PORT_DEVICE_INVALID; 11421 } 11422 11423 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11424 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11425 tolerance, retain); 11426 11427 pd->pd_aux_flags |= PD_LOGGED_OUT; 11428 mutex_exit(&pd->pd_mutex); 11429 11430 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP); 11431 if (cmd == NULL) { 11432 return; 11433 } 11434 11435 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11436 if (rval != FC_SUCCESS) { 11437 fp_free_pkt(cmd); 11438 return; 11439 } 11440 11441 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11442 11443 if (retain) { 11444 fp_unregister_login(pd); 11445 fctl_copy_portmap(listptr, pd); 11446 } else { 11447 uint32_t d_id; 11448 char ww_name[17]; 11449 11450 mutex_enter(&pd->pd_mutex); 11451 d_id = pd->pd_port_id.port_id; 11452 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11453 mutex_exit(&pd->pd_mutex); 11454 11455 FP_TRACE(FP_NHEAD2(9, 0), 11456 "N_x Port with D_ID=%x, PWWN=%s logged out" 11457 " %d times in %d us; Giving up", d_id, ww_name, 11458 FC_LOGO_TOLERANCE_LIMIT, 11459 FC_LOGO_TOLERANCE_TIME_LIMIT); 11460 11461 fp_fillout_old_map(listptr, pd, 0); 11462 listptr->map_type = PORT_DEVICE_OLD; 11463 } 11464 11465 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11466 return; 11467 } 11468 11469 fp_reject_prlo: 11470 11471 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd); 11472 if (cmd != NULL) { 11473 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE, 11474 FC_REASON_INVALID_LINK_CTRL, job); 11475 11476 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11477 fp_free_pkt(cmd); 11478 } 11479 } 11480 } 11481 11482 /* 11483 * Unsolicited LOGO handler 11484 */ 11485 static void 11486 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11487 fc_remote_port_t *pd, job_request_t *job) 11488 { 11489 int busy; 11490 int rval; 11491 int retain; 11492 fp_cmd_t *cmd; 11493 fc_portmap_t *listptr; 11494 boolean_t tolerance; 11495 11496 mutex_enter(&port->fp_mutex); 11497 busy = port->fp_statec_busy; 11498 mutex_exit(&port->fp_mutex); 11499 11500 mutex_enter(&pd->pd_mutex); 11501 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11502 if (!busy) { 11503 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11504 pd->pd_state == PORT_DEVICE_INVALID || 11505 pd->pd_flags == PD_ELS_IN_PROGRESS || 11506 pd->pd_type == PORT_DEVICE_OLD) { 11507 busy++; 11508 } 11509 } 11510 11511 if (busy) { 11512 mutex_exit(&pd->pd_mutex); 11513 11514 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11515 "pd=%p - busy", 11516 pd->pd_port_id.port_id, pd); 11517 11518 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11519 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11520 0, KM_SLEEP, pd); 11521 if (cmd != NULL) { 11522 fp_els_rjt_init(port, cmd, buf, 11523 FC_ACTION_NON_RETRYABLE, 11524 FC_REASON_INVALID_LINK_CTRL, job); 11525 11526 if (fp_sendcmd(port, cmd, 11527 port->fp_fca_handle) != FC_SUCCESS) { 11528 fp_free_pkt(cmd); 11529 } 11530 } 11531 } 11532 } else { 11533 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11534 11535 if (tolerance) { 11536 fctl_tc_reset(&pd->pd_logo_tc); 11537 retain = 0; 11538 pd->pd_state = PORT_DEVICE_INVALID; 11539 } 11540 11541 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11542 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11543 tolerance, retain); 11544 11545 pd->pd_aux_flags |= PD_LOGGED_OUT; 11546 mutex_exit(&pd->pd_mutex); 11547 11548 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, 11549 KM_SLEEP, pd); 11550 if (cmd == NULL) { 11551 return; 11552 } 11553 11554 fp_els_acc_init(port, cmd, buf, job); 11555 11556 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11557 if (rval != FC_SUCCESS) { 11558 fp_free_pkt(cmd); 11559 return; 11560 } 11561 11562 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11563 11564 if (retain) { 11565 job_request_t *job; 11566 fctl_ns_req_t *ns_cmd; 11567 11568 /* 11569 * when get LOGO, first try to get PID from nameserver 11570 * if failed, then we do not need 11571 * send PLOGI to that remote port 11572 */ 11573 job = fctl_alloc_job( 11574 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP); 11575 11576 if (job != NULL) { 11577 ns_cmd = fctl_alloc_ns_cmd( 11578 sizeof (ns_req_gid_pn_t), 11579 sizeof (ns_resp_gid_pn_t), 11580 sizeof (ns_resp_gid_pn_t), 11581 0, KM_SLEEP); 11582 if (ns_cmd != NULL) { 11583 int ret; 11584 job->job_result = FC_SUCCESS; 11585 ns_cmd->ns_cmd_code = NS_GID_PN; 11586 ((ns_req_gid_pn_t *) 11587 (ns_cmd->ns_cmd_buf))->pwwn = 11588 pd->pd_port_name; 11589 ret = fp_ns_query( 11590 port, ns_cmd, job, 1, KM_SLEEP); 11591 if ((ret != FC_SUCCESS) || 11592 (job->job_result != FC_SUCCESS)) { 11593 fctl_free_ns_cmd(ns_cmd); 11594 fctl_dealloc_job(job); 11595 FP_TRACE(FP_NHEAD2(9, 0), 11596 "NS query failed,", 11597 " delete pd"); 11598 goto delete_pd; 11599 } 11600 fctl_free_ns_cmd(ns_cmd); 11601 } 11602 fctl_dealloc_job(job); 11603 } 11604 fp_unregister_login(pd); 11605 fctl_copy_portmap(listptr, pd); 11606 } else { 11607 uint32_t d_id; 11608 char ww_name[17]; 11609 11610 delete_pd: 11611 mutex_enter(&pd->pd_mutex); 11612 d_id = pd->pd_port_id.port_id; 11613 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11614 mutex_exit(&pd->pd_mutex); 11615 11616 FP_TRACE(FP_NHEAD2(9, 0), 11617 "N_x Port with D_ID=%x, PWWN=%s logged out" 11618 " %d times in %d us; Giving up", d_id, ww_name, 11619 FC_LOGO_TOLERANCE_LIMIT, 11620 FC_LOGO_TOLERANCE_TIME_LIMIT); 11621 11622 fp_fillout_old_map(listptr, pd, 0); 11623 listptr->map_type = PORT_DEVICE_OLD; 11624 } 11625 11626 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11627 } 11628 } 11629 11630 11631 /* 11632 * Perform general purpose preparation of a response to an unsolicited request 11633 */ 11634 static void 11635 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf, 11636 uchar_t r_ctl, uchar_t type) 11637 { 11638 pkt->pkt_cmd_fhdr.r_ctl = r_ctl; 11639 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id; 11640 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id; 11641 pkt->pkt_cmd_fhdr.type = type; 11642 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT; 11643 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id; 11644 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl; 11645 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt; 11646 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id; 11647 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id; 11648 pkt->pkt_cmd_fhdr.ro = 0; 11649 pkt->pkt_cmd_fhdr.rsvd = 0; 11650 pkt->pkt_comp = fp_unsol_intr; 11651 pkt->pkt_timeout = FP_ELS_TIMEOUT; 11652 pkt->pkt_ub_resp_token = (opaque_t)buf; 11653 } 11654 11655 /* 11656 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the 11657 * early development days of public loop soc+ firmware, numerous problems 11658 * were encountered (the details are undocumented and history now) which 11659 * led to the birth of this function. 11660 * 11661 * If a pre-allocated unsolicited response packet is free, send out an 11662 * immediate response, otherwise submit the request to the port thread 11663 * to do the deferred processing. 11664 */ 11665 static void 11666 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf) 11667 { 11668 int sent; 11669 int f_port; 11670 int do_acc; 11671 fp_cmd_t *cmd; 11672 la_els_logi_t *payload; 11673 fc_remote_port_t *pd; 11674 char dww_name[17]; 11675 11676 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11677 11678 cmd = port->fp_els_resp_pkt; 11679 11680 mutex_enter(&port->fp_mutex); 11681 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11682 mutex_exit(&port->fp_mutex); 11683 11684 switch (buf->ub_buffer[0]) { 11685 case LA_ELS_PLOGI: { 11686 int small; 11687 11688 payload = (la_els_logi_t *)buf->ub_buffer; 11689 11690 f_port = FP_IS_F_PORT(payload-> 11691 common_service.cmn_features) ? 1 : 0; 11692 11693 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 11694 &payload->nport_ww_name); 11695 pd = fctl_get_remote_port_by_pwwn(port, 11696 &payload->nport_ww_name); 11697 if (pd) { 11698 mutex_enter(&pd->pd_mutex); 11699 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11700 /* 11701 * Most likely this means a cross login is in 11702 * progress or a device about to be yanked out. 11703 * Only accept the plogi if my wwn is smaller. 11704 */ 11705 if (pd->pd_type == PORT_DEVICE_OLD) { 11706 sent = 1; 11707 } 11708 /* 11709 * Stop plogi request (if any) 11710 * attempt from local side to speedup 11711 * the discovery progress. 11712 * Mark the pd as PD_PLOGI_RECEPIENT. 11713 */ 11714 if (f_port == 0 && small < 0) { 11715 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11716 } 11717 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11718 11719 mutex_exit(&pd->pd_mutex); 11720 11721 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: " 11722 "Unsol PLOGI received. PD still exists in the " 11723 "PWWN list. pd=%p PWWN=%s, sent=%x", 11724 pd, dww_name, sent); 11725 11726 if (f_port == 0 && small < 0) { 11727 FP_TRACE(FP_NHEAD1(3, 0), 11728 "fp_i_handle_unsol_els: Mark the pd" 11729 " as plogi recipient, pd=%p, PWWN=%s" 11730 ", sent=%x", 11731 pd, dww_name, sent); 11732 } 11733 } else { 11734 sent = 0; 11735 } 11736 11737 /* 11738 * To avoid Login collisions, accept only if my WWN 11739 * is smaller than the requester (A curious side note 11740 * would be that this rule may not satisfy the PLOGIs 11741 * initiated by the switch from not-so-well known 11742 * ports such as 0xFFFC41) 11743 */ 11744 if ((f_port == 0 && small < 0) || 11745 (((small > 0 && do_acc) || 11746 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11747 if (fp_is_class_supported(port->fp_cos, 11748 buf->ub_class) == FC_FAILURE) { 11749 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11750 cmd->cmd_pkt.pkt_cmdlen = 11751 sizeof (la_els_rjt_t); 11752 cmd->cmd_pkt.pkt_rsplen = 0; 11753 fp_els_rjt_init(port, cmd, buf, 11754 FC_ACTION_NON_RETRYABLE, 11755 FC_REASON_CLASS_NOT_SUPP, NULL); 11756 FP_TRACE(FP_NHEAD1(3, 0), 11757 "fp_i_handle_unsol_els: " 11758 "Unsupported class. " 11759 "Rejecting PLOGI"); 11760 11761 } else { 11762 mutex_enter(&port->fp_mutex); 11763 port->fp_els_resp_pkt_busy = 0; 11764 mutex_exit(&port->fp_mutex); 11765 return; 11766 } 11767 } else { 11768 cmd->cmd_pkt.pkt_cmdlen = 11769 sizeof (la_els_logi_t); 11770 cmd->cmd_pkt.pkt_rsplen = 0; 11771 11772 /* 11773 * If fp_port_id is zero and topology is 11774 * Point-to-Point, get the local port id from 11775 * the d_id in the PLOGI request. 11776 * If the outgoing FLOGI hasn't been accepted, 11777 * the topology will be unknown here. But it's 11778 * still safe to save the d_id to fp_port_id, 11779 * just because it will be overwritten later 11780 * if the topology is not Point-to-Point. 11781 */ 11782 mutex_enter(&port->fp_mutex); 11783 if ((port->fp_port_id.port_id == 0) && 11784 (port->fp_topology == FC_TOP_PT_PT || 11785 port->fp_topology == FC_TOP_UNKNOWN)) { 11786 port->fp_port_id.port_id = 11787 buf->ub_frame.d_id; 11788 } 11789 mutex_exit(&port->fp_mutex); 11790 11791 /* 11792 * Sometime later, we should validate 11793 * the service parameters instead of 11794 * just accepting it. 11795 */ 11796 fp_login_acc_init(port, cmd, buf, NULL, 11797 KM_NOSLEEP); 11798 FP_TRACE(FP_NHEAD1(3, 0), 11799 "fp_i_handle_unsol_els: Accepting PLOGI," 11800 " f_port=%d, small=%d, do_acc=%d," 11801 " sent=%d.", f_port, small, do_acc, 11802 sent); 11803 } 11804 } else { 11805 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 11806 port->fp_options & FP_SEND_RJT) { 11807 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11808 cmd->cmd_pkt.pkt_rsplen = 0; 11809 fp_els_rjt_init(port, cmd, buf, 11810 FC_ACTION_NON_RETRYABLE, 11811 FC_REASON_LOGICAL_BSY, NULL); 11812 FP_TRACE(FP_NHEAD1(3, 0), 11813 "fp_i_handle_unsol_els: " 11814 "Rejecting PLOGI with Logical Busy." 11815 "Possible Login collision."); 11816 } else { 11817 mutex_enter(&port->fp_mutex); 11818 port->fp_els_resp_pkt_busy = 0; 11819 mutex_exit(&port->fp_mutex); 11820 return; 11821 } 11822 } 11823 break; 11824 } 11825 11826 case LA_ELS_FLOGI: 11827 if (fp_is_class_supported(port->fp_cos, 11828 buf->ub_class) == FC_FAILURE) { 11829 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11830 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11831 cmd->cmd_pkt.pkt_rsplen = 0; 11832 fp_els_rjt_init(port, cmd, buf, 11833 FC_ACTION_NON_RETRYABLE, 11834 FC_REASON_CLASS_NOT_SUPP, NULL); 11835 FP_TRACE(FP_NHEAD1(3, 0), 11836 "fp_i_handle_unsol_els: " 11837 "Unsupported Class. Rejecting FLOGI."); 11838 } else { 11839 mutex_enter(&port->fp_mutex); 11840 port->fp_els_resp_pkt_busy = 0; 11841 mutex_exit(&port->fp_mutex); 11842 return; 11843 } 11844 } else { 11845 mutex_enter(&port->fp_mutex); 11846 if (FC_PORT_STATE_MASK(port->fp_state) != 11847 FC_STATE_ONLINE || (port->fp_port_id.port_id && 11848 buf->ub_frame.s_id == port->fp_port_id.port_id)) { 11849 mutex_exit(&port->fp_mutex); 11850 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11851 cmd->cmd_pkt.pkt_cmdlen = 11852 sizeof (la_els_rjt_t); 11853 cmd->cmd_pkt.pkt_rsplen = 0; 11854 fp_els_rjt_init(port, cmd, buf, 11855 FC_ACTION_NON_RETRYABLE, 11856 FC_REASON_INVALID_LINK_CTRL, 11857 NULL); 11858 FP_TRACE(FP_NHEAD1(3, 0), 11859 "fp_i_handle_unsol_els: " 11860 "Invalid Link Ctrl. " 11861 "Rejecting FLOGI."); 11862 } else { 11863 mutex_enter(&port->fp_mutex); 11864 port->fp_els_resp_pkt_busy = 0; 11865 mutex_exit(&port->fp_mutex); 11866 return; 11867 } 11868 } else { 11869 mutex_exit(&port->fp_mutex); 11870 cmd->cmd_pkt.pkt_cmdlen = 11871 sizeof (la_els_logi_t); 11872 cmd->cmd_pkt.pkt_rsplen = 0; 11873 /* 11874 * Let's not aggressively validate the N_Port's 11875 * service parameters until PLOGI. Suffice it 11876 * to give a hint that we are an N_Port and we 11877 * are game to some serious stuff here. 11878 */ 11879 fp_login_acc_init(port, cmd, buf, 11880 NULL, KM_NOSLEEP); 11881 FP_TRACE(FP_NHEAD1(3, 0), 11882 "fp_i_handle_unsol_els: " 11883 "Accepting FLOGI."); 11884 } 11885 } 11886 break; 11887 11888 default: 11889 return; 11890 } 11891 11892 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) { 11893 mutex_enter(&port->fp_mutex); 11894 port->fp_els_resp_pkt_busy = 0; 11895 mutex_exit(&port->fp_mutex); 11896 } 11897 } 11898 11899 11900 /* 11901 * Handle unsolicited PLOGI request 11902 */ 11903 static void 11904 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 11905 job_request_t *job, int sleep) 11906 { 11907 int sent; 11908 int small; 11909 int f_port; 11910 int do_acc; 11911 fp_cmd_t *cmd; 11912 la_wwn_t *swwn; 11913 la_wwn_t *dwwn; 11914 la_els_logi_t *payload; 11915 fc_remote_port_t *pd; 11916 char dww_name[17]; 11917 11918 payload = (la_els_logi_t *)buf->ub_buffer; 11919 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0; 11920 11921 mutex_enter(&port->fp_mutex); 11922 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11923 mutex_exit(&port->fp_mutex); 11924 11925 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x," 11926 "type=%x, f_ctl=%x" 11927 " seq_id=%x, ox_id=%x, rx_id=%x" 11928 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 11929 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 11930 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 11931 11932 swwn = &port->fp_service_params.nport_ww_name; 11933 dwwn = &payload->nport_ww_name; 11934 small = fctl_wwn_cmp(swwn, dwwn); 11935 pd = fctl_get_remote_port_by_pwwn(port, dwwn); 11936 if (pd) { 11937 mutex_enter(&pd->pd_mutex); 11938 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11939 /* 11940 * Most likely this means a cross login is in 11941 * progress or a device about to be yanked out. 11942 * Only accept the plogi if my wwn is smaller. 11943 */ 11944 11945 if (pd->pd_type == PORT_DEVICE_OLD) { 11946 sent = 1; 11947 } 11948 /* 11949 * Stop plogi request (if any) 11950 * attempt from local side to speedup 11951 * the discovery progress. 11952 * Mark the pd as PD_PLOGI_RECEPIENT. 11953 */ 11954 if (f_port == 0 && small < 0) { 11955 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11956 } 11957 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11958 11959 mutex_exit(&pd->pd_mutex); 11960 11961 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI" 11962 " received. PD still exists in the PWWN list. pd=%p " 11963 "PWWN=%s, sent=%x", pd, dww_name, sent); 11964 11965 if (f_port == 0 && small < 0) { 11966 FP_TRACE(FP_NHEAD1(3, 0), 11967 "fp_handle_unsol_plogi: Mark the pd" 11968 " as plogi recipient, pd=%p, PWWN=%s" 11969 ", sent=%x", 11970 pd, dww_name, sent); 11971 } 11972 } else { 11973 sent = 0; 11974 } 11975 11976 /* 11977 * Avoid Login collisions by accepting only if my WWN is smaller. 11978 * 11979 * A side note: There is no need to start a PLOGI from this end in 11980 * this context if login isn't going to be accepted for the 11981 * above reason as either a LIP (in private loop), RSCN (in 11982 * fabric topology), or an FLOGI (in point to point - Huh ? 11983 * check FC-PH) would normally drive the PLOGI from this end. 11984 * At this point of time there is no need for an inbound PLOGI 11985 * to kick an outbound PLOGI when it is going to be rejected 11986 * for the reason of WWN being smaller. However it isn't hard 11987 * to do that either (when such a need arises, start a timer 11988 * for a duration that extends beyond a normal device discovery 11989 * time and check if an outbound PLOGI did go before that, if 11990 * none fire one) 11991 * 11992 * Unfortunately, as it turned out, during booting, it is possible 11993 * to miss another initiator in the same loop as port driver 11994 * instances are serially attached. While preserving the above 11995 * comments for belly laughs, please kick an outbound PLOGI in 11996 * a non-switch environment (which is a pt pt between N_Ports or 11997 * a private loop) 11998 * 11999 * While preserving the above comments for amusement, send an 12000 * ACC if the PLOGI is going to be rejected for WWN being smaller 12001 * when no discovery is in progress at this end. Turn around 12002 * and make the port device as the PLOGI initiator, so that 12003 * during subsequent link/loop initialization, this end drives 12004 * the PLOGI (In fact both ends do in this particular case, but 12005 * only one wins) 12006 * 12007 * Make sure the PLOGIs initiated by the switch from not-so-well-known 12008 * ports (such as 0xFFFC41) are accepted too. 12009 */ 12010 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) || 12011 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 12012 if (fp_is_class_supported(port->fp_cos, 12013 buf->ub_class) == FC_FAILURE) { 12014 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12015 cmd = fp_alloc_pkt(port, 12016 sizeof (la_els_logi_t), 0, sleep, pd); 12017 if (cmd == NULL) { 12018 return; 12019 } 12020 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 12021 cmd->cmd_pkt.pkt_rsplen = 0; 12022 fp_els_rjt_init(port, cmd, buf, 12023 FC_ACTION_NON_RETRYABLE, 12024 FC_REASON_CLASS_NOT_SUPP, job); 12025 FP_TRACE(FP_NHEAD1(3, 0), 12026 "fp_handle_unsol_plogi: " 12027 "Unsupported class. rejecting PLOGI"); 12028 } 12029 } else { 12030 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12031 0, sleep, pd); 12032 if (cmd == NULL) { 12033 return; 12034 } 12035 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t); 12036 cmd->cmd_pkt.pkt_rsplen = 0; 12037 12038 /* 12039 * Sometime later, we should validate the service 12040 * parameters instead of just accepting it. 12041 */ 12042 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 12043 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 12044 "Accepting PLOGI, f_port=%d, small=%d, " 12045 "do_acc=%d, sent=%d.", f_port, small, do_acc, 12046 sent); 12047 12048 /* 12049 * If fp_port_id is zero and topology is 12050 * Point-to-Point, get the local port id from 12051 * the d_id in the PLOGI request. 12052 * If the outgoing FLOGI hasn't been accepted, 12053 * the topology will be unknown here. But it's 12054 * still safe to save the d_id to fp_port_id, 12055 * just because it will be overwritten later 12056 * if the topology is not Point-to-Point. 12057 */ 12058 mutex_enter(&port->fp_mutex); 12059 if ((port->fp_port_id.port_id == 0) && 12060 (port->fp_topology == FC_TOP_PT_PT || 12061 port->fp_topology == FC_TOP_UNKNOWN)) { 12062 port->fp_port_id.port_id = 12063 buf->ub_frame.d_id; 12064 } 12065 mutex_exit(&port->fp_mutex); 12066 } 12067 } else { 12068 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 12069 port->fp_options & FP_SEND_RJT) { 12070 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12071 0, sleep, pd); 12072 if (cmd == NULL) { 12073 return; 12074 } 12075 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 12076 cmd->cmd_pkt.pkt_rsplen = 0; 12077 /* 12078 * Send out Logical busy to indicate 12079 * the detection of PLOGI collision 12080 */ 12081 fp_els_rjt_init(port, cmd, buf, 12082 FC_ACTION_NON_RETRYABLE, 12083 FC_REASON_LOGICAL_BSY, job); 12084 12085 fc_wwn_to_str(dwwn, dww_name); 12086 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 12087 "Rejecting Unsol PLOGI with Logical Busy." 12088 "possible PLOGI collision. PWWN=%s, sent=%x", 12089 dww_name, sent); 12090 } else { 12091 return; 12092 } 12093 } 12094 12095 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12096 fp_free_pkt(cmd); 12097 } 12098 } 12099 12100 12101 /* 12102 * Handle mischievous turning over of our own FLOGI requests back to 12103 * us by the SOC+ microcode. In other words, look at the class of such 12104 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them 12105 * on the floor 12106 */ 12107 static void 12108 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 12109 job_request_t *job, int sleep) 12110 { 12111 uint32_t state; 12112 uint32_t s_id; 12113 fp_cmd_t *cmd; 12114 12115 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) { 12116 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12117 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12118 0, sleep, NULL); 12119 if (cmd == NULL) { 12120 return; 12121 } 12122 fp_els_rjt_init(port, cmd, buf, 12123 FC_ACTION_NON_RETRYABLE, 12124 FC_REASON_CLASS_NOT_SUPP, job); 12125 } else { 12126 return; 12127 } 12128 } else { 12129 12130 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:" 12131 " s_id=%x, d_id=%x, type=%x, f_ctl=%x" 12132 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x", 12133 buf->ub_frame.s_id, buf->ub_frame.d_id, 12134 buf->ub_frame.type, buf->ub_frame.f_ctl, 12135 buf->ub_frame.seq_id, buf->ub_frame.ox_id, 12136 buf->ub_frame.rx_id, buf->ub_frame.ro); 12137 12138 mutex_enter(&port->fp_mutex); 12139 state = FC_PORT_STATE_MASK(port->fp_state); 12140 s_id = port->fp_port_id.port_id; 12141 mutex_exit(&port->fp_mutex); 12142 12143 if (state != FC_STATE_ONLINE || 12144 (s_id && buf->ub_frame.s_id == s_id)) { 12145 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12146 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12147 0, sleep, NULL); 12148 if (cmd == NULL) { 12149 return; 12150 } 12151 fp_els_rjt_init(port, cmd, buf, 12152 FC_ACTION_NON_RETRYABLE, 12153 FC_REASON_INVALID_LINK_CTRL, job); 12154 FP_TRACE(FP_NHEAD1(3, 0), 12155 "fp_handle_unsol_flogi: " 12156 "Rejecting PLOGI. Invalid Link CTRL"); 12157 } else { 12158 return; 12159 } 12160 } else { 12161 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12162 0, sleep, NULL); 12163 if (cmd == NULL) { 12164 return; 12165 } 12166 /* 12167 * Let's not aggressively validate the N_Port's 12168 * service parameters until PLOGI. Suffice it 12169 * to give a hint that we are an N_Port and we 12170 * are game to some serious stuff here. 12171 */ 12172 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 12173 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: " 12174 "Accepting PLOGI"); 12175 } 12176 } 12177 12178 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12179 fp_free_pkt(cmd); 12180 } 12181 } 12182 12183 12184 /* 12185 * Perform PLOGI accept 12186 */ 12187 static void 12188 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 12189 job_request_t *job, int sleep) 12190 { 12191 fc_packet_t *pkt; 12192 fc_portmap_t *listptr; 12193 la_els_logi_t payload; 12194 12195 ASSERT(buf != NULL); 12196 12197 /* 12198 * If we are sending ACC to PLOGI and we haven't already 12199 * create port and node device handles, let's create them 12200 * here. 12201 */ 12202 if (buf->ub_buffer[0] == LA_ELS_PLOGI && 12203 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) { 12204 int small; 12205 int do_acc; 12206 fc_remote_port_t *pd; 12207 la_els_logi_t *req; 12208 12209 req = (la_els_logi_t *)buf->ub_buffer; 12210 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 12211 &req->nport_ww_name); 12212 12213 mutex_enter(&port->fp_mutex); 12214 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 12215 mutex_exit(&port->fp_mutex); 12216 12217 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x", 12218 port->fp_port_id.port_id, buf->ub_frame.s_id); 12219 pd = fctl_create_remote_port(port, &req->node_ww_name, 12220 &req->nport_ww_name, buf->ub_frame.s_id, 12221 PD_PLOGI_RECEPIENT, sleep); 12222 if (pd == NULL) { 12223 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: " 12224 "Couldn't create port device for d_id:0x%x", 12225 buf->ub_frame.s_id); 12226 12227 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 12228 "couldn't create port device d_id=%x", 12229 buf->ub_frame.s_id); 12230 } else { 12231 /* 12232 * usoc currently returns PLOGIs inline and 12233 * the maximum buffer size is 60 bytes or so. 12234 * So attempt not to look beyond what is in 12235 * the unsolicited buffer 12236 * 12237 * JNI also traverses this path sometimes 12238 */ 12239 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) { 12240 fp_register_login(NULL, pd, req, buf->ub_class); 12241 } else { 12242 mutex_enter(&pd->pd_mutex); 12243 if (pd->pd_login_count == 0) { 12244 pd->pd_login_count++; 12245 } 12246 pd->pd_state = PORT_DEVICE_LOGGED_IN; 12247 pd->pd_login_class = buf->ub_class; 12248 mutex_exit(&pd->pd_mutex); 12249 } 12250 12251 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep); 12252 if (listptr != NULL) { 12253 fctl_copy_portmap(listptr, pd); 12254 (void) fp_ulp_devc_cb(port, listptr, 12255 1, 1, sleep, 0); 12256 } 12257 12258 if (small > 0 && do_acc) { 12259 mutex_enter(&pd->pd_mutex); 12260 pd->pd_recepient = PD_PLOGI_INITIATOR; 12261 mutex_exit(&pd->pd_mutex); 12262 } 12263 } 12264 } 12265 12266 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 12267 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 12268 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12269 cmd->cmd_retry_count = 1; 12270 cmd->cmd_ulp_pkt = NULL; 12271 12272 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12273 cmd->cmd_job = job; 12274 12275 pkt = &cmd->cmd_pkt; 12276 12277 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 12278 12279 payload = port->fp_service_params; 12280 payload.ls_code.ls_code = LA_ELS_ACC; 12281 12282 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12283 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12284 12285 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x " 12286 "bufsize:0x%x sizeof (la_els_logi):0x%x " 12287 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x " 12288 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id, 12289 buf->ub_bufsize, sizeof (la_els_logi_t), 12290 port->fp_service_params.nport_ww_name.w.naa_id, 12291 port->fp_service_params.nport_ww_name.w.nport_id, 12292 port->fp_service_params.nport_ww_name.w.wwn_hi, 12293 port->fp_service_params.nport_ww_name.w.wwn_lo, 12294 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id, 12295 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id, 12296 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi, 12297 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo, 12298 port->fp_statec_busy); 12299 } 12300 12301 12302 #define RSCN_EVENT_NAME_LEN 256 12303 12304 /* 12305 * Handle RSCNs 12306 */ 12307 static void 12308 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf, 12309 job_request_t *job, int sleep) 12310 { 12311 uint32_t mask; 12312 fp_cmd_t *cmd; 12313 uint32_t count; 12314 int listindex; 12315 int16_t len; 12316 fc_rscn_t *payload; 12317 fc_portmap_t *listptr; 12318 fctl_ns_req_t *ns_cmd; 12319 fc_affected_id_t *page; 12320 caddr_t nvname; 12321 nvlist_t *attr_list = NULL; 12322 12323 mutex_enter(&port->fp_mutex); 12324 if (!FC_IS_TOP_SWITCH(port->fp_topology)) { 12325 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12326 --port->fp_rscn_count; 12327 } 12328 mutex_exit(&port->fp_mutex); 12329 return; 12330 } 12331 mutex_exit(&port->fp_mutex); 12332 12333 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL); 12334 if (cmd != NULL) { 12335 fp_els_acc_init(port, cmd, buf, job); 12336 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12337 fp_free_pkt(cmd); 12338 } 12339 } 12340 12341 payload = (fc_rscn_t *)buf->ub_buffer; 12342 ASSERT(payload->rscn_code == LA_ELS_RSCN); 12343 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN); 12344 12345 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN; 12346 12347 if (len <= 0) { 12348 mutex_enter(&port->fp_mutex); 12349 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12350 --port->fp_rscn_count; 12351 } 12352 mutex_exit(&port->fp_mutex); 12353 12354 return; 12355 } 12356 12357 ASSERT((len & 0x3) == 0); /* Must be power of 4 */ 12358 count = (len >> 2) << 1; /* number of pages multiplied by 2 */ 12359 12360 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 12361 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t)); 12362 12363 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12364 12365 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t), 12366 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t), 12367 0, sleep); 12368 if (ns_cmd == NULL) { 12369 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12370 12371 mutex_enter(&port->fp_mutex); 12372 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12373 --port->fp_rscn_count; 12374 } 12375 mutex_exit(&port->fp_mutex); 12376 12377 return; 12378 } 12379 12380 ns_cmd->ns_cmd_code = NS_GPN_ID; 12381 12382 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x," 12383 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x" 12384 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 12385 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 12386 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 12387 12388 /* Only proceed if we can allocate nvname and the nvlist */ 12389 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL && 12390 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 12391 KM_NOSLEEP) == DDI_SUCCESS) { 12392 if (!(attr_list && nvlist_add_uint32(attr_list, "instance", 12393 port->fp_instance) == DDI_SUCCESS && 12394 nvlist_add_byte_array(attr_list, "port-wwn", 12395 port->fp_service_params.nport_ww_name.raw_wwn, 12396 sizeof (la_wwn_t)) == DDI_SUCCESS)) { 12397 nvlist_free(attr_list); 12398 attr_list = NULL; 12399 } 12400 } 12401 12402 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) { 12403 /* Add affected page to the event payload */ 12404 if (attr_list != NULL) { 12405 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN, 12406 "affected_page_%d", listindex); 12407 if (attr_list && nvlist_add_uint32(attr_list, nvname, 12408 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) { 12409 /* We don't send a partial event, so dump it */ 12410 nvlist_free(attr_list); 12411 attr_list = NULL; 12412 } 12413 } 12414 /* 12415 * Query the NS to get the Port WWN for this 12416 * affected D_ID. 12417 */ 12418 mask = 0; 12419 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) { 12420 case FC_RSCN_PORT_ADDRESS: 12421 fp_validate_rscn_page(port, page, job, ns_cmd, 12422 listptr, &listindex, sleep); 12423 12424 if (listindex == 0) { 12425 /* 12426 * We essentially did not process this RSCN. So, 12427 * ULPs are not going to be called and so we 12428 * decrement the rscn_count 12429 */ 12430 mutex_enter(&port->fp_mutex); 12431 if (--port->fp_rscn_count == 12432 FC_INVALID_RSCN_COUNT) { 12433 --port->fp_rscn_count; 12434 } 12435 mutex_exit(&port->fp_mutex); 12436 } 12437 break; 12438 12439 case FC_RSCN_AREA_ADDRESS: 12440 mask = 0xFFFF00; 12441 /* FALLTHROUGH */ 12442 12443 case FC_RSCN_DOMAIN_ADDRESS: 12444 if (!mask) { 12445 mask = 0xFF0000; 12446 } 12447 fp_validate_area_domain(port, page->aff_d_id, mask, 12448 job, sleep); 12449 break; 12450 12451 case FC_RSCN_FABRIC_ADDRESS: 12452 /* 12453 * We need to discover all the devices on this 12454 * port. 12455 */ 12456 fp_validate_area_domain(port, 0, 0, job, sleep); 12457 break; 12458 12459 default: 12460 break; 12461 } 12462 } 12463 if (attr_list != NULL) { 12464 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, 12465 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list, 12466 NULL, DDI_SLEEP); 12467 nvlist_free(attr_list); 12468 } else { 12469 FP_TRACE(FP_NHEAD1(9, 0), 12470 "RSCN handled, but event not sent to userland"); 12471 } 12472 if (nvname != NULL) { 12473 kmem_free(nvname, RSCN_EVENT_NAME_LEN); 12474 } 12475 12476 if (ns_cmd) { 12477 fctl_free_ns_cmd(ns_cmd); 12478 } 12479 12480 if (listindex) { 12481 #ifdef DEBUG 12482 page = (fc_affected_id_t *)(buf->ub_buffer + 12483 sizeof (fc_rscn_t)); 12484 12485 if (listptr->map_did.port_id != page->aff_d_id) { 12486 FP_TRACE(FP_NHEAD1(9, 0), 12487 "PORT RSCN: processed=%x, reporting=%x", 12488 listptr->map_did.port_id, page->aff_d_id); 12489 } 12490 #endif 12491 12492 (void) fp_ulp_devc_cb(port, listptr, listindex, count, 12493 sleep, 0); 12494 } else { 12495 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12496 } 12497 } 12498 12499 12500 /* 12501 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held 12502 */ 12503 static void 12504 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12505 { 12506 int is_switch; 12507 int initiator; 12508 fc_local_port_t *port; 12509 12510 port = pd->pd_port; 12511 12512 /* This function has the following bunch of assumptions */ 12513 ASSERT(port != NULL); 12514 ASSERT(MUTEX_HELD(&port->fp_mutex)); 12515 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex)); 12516 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12517 12518 pd->pd_state = PORT_DEVICE_INVALID; 12519 pd->pd_type = PORT_DEVICE_OLD; 12520 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12521 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12522 12523 fctl_delist_did_table(port, pd); 12524 fctl_delist_pwwn_table(port, pd); 12525 12526 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x" 12527 " removed the PD=%p from DID and PWWN tables", 12528 port, pd->pd_port_id.port_id, pd); 12529 12530 if ((!flag) && port && initiator && is_switch) { 12531 (void) fctl_add_orphan_held(port, pd); 12532 } 12533 fctl_copy_portmap_held(map, pd); 12534 map->map_pd = pd; 12535 } 12536 12537 /* 12538 * Fill out old map for ULPs 12539 */ 12540 static void 12541 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12542 { 12543 int is_switch; 12544 int initiator; 12545 fc_local_port_t *port; 12546 12547 mutex_enter(&pd->pd_mutex); 12548 port = pd->pd_port; 12549 mutex_exit(&pd->pd_mutex); 12550 12551 mutex_enter(&port->fp_mutex); 12552 mutex_enter(&pd->pd_mutex); 12553 12554 pd->pd_state = PORT_DEVICE_INVALID; 12555 pd->pd_type = PORT_DEVICE_OLD; 12556 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12557 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12558 12559 fctl_delist_did_table(port, pd); 12560 fctl_delist_pwwn_table(port, pd); 12561 12562 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x" 12563 " removed the PD=%p from DID and PWWN tables", 12564 port, pd->pd_port_id.port_id, pd); 12565 12566 mutex_exit(&pd->pd_mutex); 12567 mutex_exit(&port->fp_mutex); 12568 12569 ASSERT(port != NULL); 12570 if ((!flag) && port && initiator && is_switch) { 12571 (void) fctl_add_orphan(port, pd, KM_NOSLEEP); 12572 } 12573 fctl_copy_portmap(map, pd); 12574 map->map_pd = pd; 12575 } 12576 12577 12578 /* 12579 * Fillout Changed Map for ULPs 12580 */ 12581 static void 12582 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd, 12583 uint32_t *new_did, la_wwn_t *new_pwwn) 12584 { 12585 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12586 12587 pd->pd_type = PORT_DEVICE_CHANGED; 12588 if (new_did) { 12589 pd->pd_port_id.port_id = *new_did; 12590 } 12591 if (new_pwwn) { 12592 pd->pd_port_name = *new_pwwn; 12593 } 12594 mutex_exit(&pd->pd_mutex); 12595 12596 fctl_copy_portmap(map, pd); 12597 12598 mutex_enter(&pd->pd_mutex); 12599 pd->pd_type = PORT_DEVICE_NOCHANGE; 12600 } 12601 12602 12603 /* 12604 * Fillout New Name Server map 12605 */ 12606 static void 12607 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle, 12608 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id) 12609 { 12610 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12611 12612 if (handle) { 12613 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn, 12614 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn), 12615 DDI_DEV_AUTOINCR); 12616 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn, 12617 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn), 12618 DDI_DEV_AUTOINCR); 12619 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types, 12620 (uint8_t *)gan_resp->gan_fc4types, 12621 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR); 12622 } else { 12623 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn, 12624 sizeof (gan_resp->gan_pwwn)); 12625 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn, 12626 sizeof (gan_resp->gan_nwwn)); 12627 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types, 12628 sizeof (gan_resp->gan_fc4types)); 12629 } 12630 port_map->map_did.port_id = d_id; 12631 port_map->map_did.priv_lilp_posit = 0; 12632 port_map->map_hard_addr.hard_addr = 0; 12633 port_map->map_hard_addr.rsvd = 0; 12634 port_map->map_state = PORT_DEVICE_INVALID; 12635 port_map->map_type = PORT_DEVICE_NEW; 12636 port_map->map_flags = 0; 12637 port_map->map_pd = NULL; 12638 12639 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn); 12640 12641 ASSERT(port != NULL); 12642 } 12643 12644 12645 /* 12646 * Perform LINIT ELS 12647 */ 12648 static int 12649 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep, 12650 job_request_t *job) 12651 { 12652 int rval; 12653 uint32_t d_id; 12654 uint32_t s_id; 12655 uint32_t lfa; 12656 uchar_t class; 12657 uint32_t ret; 12658 fp_cmd_t *cmd; 12659 fc_porttype_t ptype; 12660 fc_packet_t *pkt; 12661 fc_linit_req_t payload; 12662 fc_remote_port_t *pd; 12663 12664 rval = 0; 12665 12666 ASSERT(job != NULL); 12667 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12668 12669 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 12670 if (pd == NULL) { 12671 fctl_ns_req_t *ns_cmd; 12672 12673 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 12674 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 12675 0, sleep); 12676 12677 if (ns_cmd == NULL) { 12678 return (FC_NOMEM); 12679 } 12680 job->job_result = FC_SUCCESS; 12681 ns_cmd->ns_cmd_code = NS_GID_PN; 12682 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 12683 12684 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12685 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12686 fctl_free_ns_cmd(ns_cmd); 12687 return (FC_FAILURE); 12688 } 12689 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id)); 12690 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 12691 12692 fctl_free_ns_cmd(ns_cmd); 12693 lfa = d_id & 0xFFFF00; 12694 12695 /* 12696 * Given this D_ID, get the port type to see if 12697 * we can do LINIT on the LFA 12698 */ 12699 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t), 12700 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t), 12701 0, sleep); 12702 12703 if (ns_cmd == NULL) { 12704 return (FC_NOMEM); 12705 } 12706 12707 job->job_result = FC_SUCCESS; 12708 ns_cmd->ns_cmd_code = NS_GPT_ID; 12709 12710 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id; 12711 ((ns_req_gpt_id_t *) 12712 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 12713 12714 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12715 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12716 fctl_free_ns_cmd(ns_cmd); 12717 return (FC_FAILURE); 12718 } 12719 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype)); 12720 12721 fctl_free_ns_cmd(ns_cmd); 12722 12723 switch (ptype.port_type) { 12724 case FC_NS_PORT_NL: 12725 case FC_NS_PORT_F_NL: 12726 case FC_NS_PORT_FL: 12727 break; 12728 12729 default: 12730 return (FC_FAILURE); 12731 } 12732 } else { 12733 mutex_enter(&pd->pd_mutex); 12734 ptype = pd->pd_porttype; 12735 12736 switch (pd->pd_porttype.port_type) { 12737 case FC_NS_PORT_NL: 12738 case FC_NS_PORT_F_NL: 12739 case FC_NS_PORT_FL: 12740 lfa = pd->pd_port_id.port_id & 0xFFFF00; 12741 break; 12742 12743 default: 12744 mutex_exit(&pd->pd_mutex); 12745 return (FC_FAILURE); 12746 } 12747 mutex_exit(&pd->pd_mutex); 12748 } 12749 12750 mutex_enter(&port->fp_mutex); 12751 s_id = port->fp_port_id.port_id; 12752 class = port->fp_ns_login_class; 12753 mutex_exit(&port->fp_mutex); 12754 12755 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t), 12756 sizeof (fc_linit_resp_t), sleep, pd); 12757 if (cmd == NULL) { 12758 return (FC_NOMEM); 12759 } 12760 12761 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12762 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12763 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12764 cmd->cmd_retry_count = fp_retry_count; 12765 cmd->cmd_ulp_pkt = NULL; 12766 12767 pkt = &cmd->cmd_pkt; 12768 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12769 12770 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job); 12771 12772 /* 12773 * How does LIP work by the way ? 12774 * If the L_Port receives three consecutive identical ordered 12775 * sets whose first two characters (fully decoded) are equal to 12776 * the values shown in Table 3 of FC-AL-2 then the L_Port shall 12777 * recognize a Loop Initialization Primitive sequence. The 12778 * character 3 determines the type of lip: 12779 * LIP(F7) Normal LIP 12780 * LIP(F8) Loop Failure LIP 12781 * 12782 * The possible combination for the 3rd and 4th bytes are: 12783 * F7, F7 Normal Lip - No valid AL_PA 12784 * F8, F8 Loop Failure - No valid AL_PA 12785 * F7, AL_PS Normal Lip - Valid source AL_PA 12786 * F8, AL_PS Loop Failure - Valid source AL_PA 12787 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS 12788 * And Normal Lip for all other loop members 12789 * 0xFF AL_PS Vendor specific reset of all loop members 12790 * 12791 * Now, it may not always be that we, at the source, may have an 12792 * AL_PS (AL_PA of source) for 4th character slot, so we decide 12793 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT 12794 * payload we are going to set: 12795 * lip_b3 = 0xF7; Normal LIP 12796 * lip_b4 = 0xF7; No valid source AL_PA 12797 */ 12798 payload.ls_code.ls_code = LA_ELS_LINIT; 12799 payload.ls_code.mbz = 0; 12800 payload.rsvd = 0; 12801 payload.func = 0; /* Let Fabric determine the best way */ 12802 payload.lip_b3 = 0xF7; /* Normal LIP */ 12803 payload.lip_b4 = 0xF7; /* No valid source AL_PA */ 12804 12805 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12806 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12807 12808 job->job_counter = 1; 12809 12810 ret = fp_sendcmd(port, cmd, port->fp_fca_handle); 12811 if (ret == FC_SUCCESS) { 12812 fp_jobwait(job); 12813 rval = job->job_result; 12814 } else { 12815 rval = FC_FAILURE; 12816 fp_free_pkt(cmd); 12817 } 12818 12819 return (rval); 12820 } 12821 12822 12823 /* 12824 * Fill out the device handles with GAN response 12825 */ 12826 static void 12827 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 12828 ns_resp_gan_t *gan_resp) 12829 { 12830 fc_remote_node_t *node; 12831 fc_porttype_t type; 12832 fc_local_port_t *port; 12833 12834 ASSERT(pd != NULL); 12835 ASSERT(handle != NULL); 12836 12837 port = pd->pd_port; 12838 12839 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p," 12840 " port_id=%x, sym_len=%d fc4-type=%x", 12841 pd, gan_resp->gan_type_id.rsvd, 12842 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]); 12843 12844 mutex_enter(&pd->pd_mutex); 12845 12846 FC_GET_RSP(port, *handle, (uint8_t *)&type, 12847 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR); 12848 12849 pd->pd_porttype.port_type = type.port_type; 12850 pd->pd_porttype.rsvd = 0; 12851 12852 pd->pd_spn_len = gan_resp->gan_spnlen; 12853 if (pd->pd_spn_len) { 12854 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn, 12855 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len, 12856 DDI_DEV_AUTOINCR); 12857 } 12858 12859 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr, 12860 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr), 12861 DDI_DEV_AUTOINCR); 12862 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos, 12863 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos), 12864 DDI_DEV_AUTOINCR); 12865 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types, 12866 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types), 12867 DDI_DEV_AUTOINCR); 12868 12869 node = pd->pd_remote_nodep; 12870 mutex_exit(&pd->pd_mutex); 12871 12872 mutex_enter(&node->fd_mutex); 12873 12874 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa, 12875 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa), 12876 DDI_DEV_AUTOINCR); 12877 12878 node->fd_snn_len = gan_resp->gan_snnlen; 12879 if (node->fd_snn_len) { 12880 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn, 12881 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len, 12882 DDI_DEV_AUTOINCR); 12883 } 12884 12885 mutex_exit(&node->fd_mutex); 12886 } 12887 12888 12889 /* 12890 * Handles all NS Queries (also means that this function 12891 * doesn't handle NS object registration) 12892 */ 12893 static int 12894 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job, 12895 int polled, int sleep) 12896 { 12897 int rval; 12898 fp_cmd_t *cmd; 12899 12900 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12901 12902 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 12903 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x", 12904 port->fp_port_id.port_id, ns_cmd->ns_gan_sid); 12905 } 12906 12907 if (ns_cmd->ns_cmd_size == 0) { 12908 return (FC_FAILURE); 12909 } 12910 12911 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 12912 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) + 12913 ns_cmd->ns_resp_size, sleep, NULL); 12914 if (cmd == NULL) { 12915 return (FC_NOMEM); 12916 } 12917 12918 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf, 12919 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job); 12920 12921 if (polled) { 12922 job->job_counter = 1; 12923 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12924 } 12925 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 12926 if (rval != FC_SUCCESS) { 12927 job->job_result = rval; 12928 fp_iodone(cmd); 12929 if (polled == 0) { 12930 /* 12931 * Return FC_SUCCESS to indicate that 12932 * fp_iodone is performed already. 12933 */ 12934 rval = FC_SUCCESS; 12935 } 12936 } 12937 12938 if (polled) { 12939 fp_jobwait(job); 12940 rval = job->job_result; 12941 } 12942 12943 return (rval); 12944 } 12945 12946 12947 /* 12948 * Initialize Common Transport request 12949 */ 12950 static void 12951 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd, 12952 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len, 12953 uint16_t resp_len, job_request_t *job) 12954 { 12955 uint32_t s_id; 12956 uchar_t class; 12957 fc_packet_t *pkt; 12958 fc_ct_header_t ct; 12959 12960 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12961 12962 mutex_enter(&port->fp_mutex); 12963 s_id = port->fp_port_id.port_id; 12964 class = port->fp_ns_login_class; 12965 mutex_exit(&port->fp_mutex); 12966 12967 cmd->cmd_job = job; 12968 cmd->cmd_private = ns_cmd; 12969 pkt = &cmd->cmd_pkt; 12970 12971 ct.ct_rev = CT_REV; 12972 ct.ct_inid = 0; 12973 ct.ct_fcstype = FCSTYPE_DIRECTORY; 12974 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER; 12975 ct.ct_options = 0; 12976 ct.ct_reserved1 = 0; 12977 ct.ct_cmdrsp = cmd_code; 12978 ct.ct_aiusize = resp_len >> 2; 12979 ct.ct_reserved2 = 0; 12980 ct.ct_reason = 0; 12981 ct.ct_expln = 0; 12982 ct.ct_vendor = 0; 12983 12984 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct, 12985 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR); 12986 12987 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 12988 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC; 12989 pkt->pkt_cmd_fhdr.s_id = s_id; 12990 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 12991 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | 12992 F_CTL_FIRST_SEQ | F_CTL_END_SEQ; 12993 pkt->pkt_cmd_fhdr.seq_id = 0; 12994 pkt->pkt_cmd_fhdr.df_ctl = 0; 12995 pkt->pkt_cmd_fhdr.seq_cnt = 0; 12996 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 12997 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 12998 pkt->pkt_cmd_fhdr.ro = 0; 12999 pkt->pkt_cmd_fhdr.rsvd = 0; 13000 13001 pkt->pkt_comp = fp_ns_intr; 13002 pkt->pkt_ulp_private = (opaque_t)cmd; 13003 pkt->pkt_timeout = FP_NS_TIMEOUT; 13004 13005 if (cmd_buf) { 13006 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf, 13007 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13008 cmd_len, DDI_DEV_AUTOINCR); 13009 } 13010 13011 cmd->cmd_transport = port->fp_fca_tran->fca_transport; 13012 13013 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 13014 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13015 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 13016 cmd->cmd_retry_count = fp_retry_count; 13017 cmd->cmd_ulp_pkt = NULL; 13018 } 13019 13020 13021 /* 13022 * Name Server request interrupt routine 13023 */ 13024 static void 13025 fp_ns_intr(fc_packet_t *pkt) 13026 { 13027 fp_cmd_t *cmd; 13028 fc_local_port_t *port; 13029 fc_ct_header_t resp_hdr; 13030 fc_ct_header_t cmd_hdr; 13031 fctl_ns_req_t *ns_cmd; 13032 13033 cmd = pkt->pkt_ulp_private; 13034 port = cmd->cmd_port; 13035 13036 mutex_enter(&port->fp_mutex); 13037 port->fp_out_fpcmds--; 13038 mutex_exit(&port->fp_mutex); 13039 13040 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr, 13041 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR); 13042 ns_cmd = (fctl_ns_req_t *) 13043 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private); 13044 if (!FP_IS_PKT_ERROR(pkt)) { 13045 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr, 13046 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr), 13047 DDI_DEV_AUTOINCR); 13048 13049 /* 13050 * On x86 architectures, make sure the resp_hdr is big endian. 13051 * This macro is a NOP on sparc architectures mainly because 13052 * we don't want to end up wasting time since the end result 13053 * is going to be the same. 13054 */ 13055 MAKE_BE_32(&resp_hdr); 13056 13057 if (ns_cmd) { 13058 /* 13059 * Always copy out the response CT_HDR 13060 */ 13061 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr, 13062 sizeof (resp_hdr)); 13063 } 13064 13065 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) { 13066 pkt->pkt_state = FC_PKT_FS_RJT; 13067 pkt->pkt_reason = resp_hdr.ct_reason; 13068 pkt->pkt_expln = resp_hdr.ct_expln; 13069 } 13070 } 13071 13072 if (FP_IS_PKT_ERROR(pkt)) { 13073 if (ns_cmd) { 13074 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13075 ASSERT(ns_cmd->ns_pd != NULL); 13076 13077 /* Mark it OLD if not already done */ 13078 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13079 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD; 13080 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13081 } 13082 13083 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13084 fctl_free_ns_cmd(ns_cmd); 13085 ((fp_cmd_t *) 13086 (pkt->pkt_ulp_private))->cmd_private = NULL; 13087 } 13088 13089 } 13090 13091 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x " 13092 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X", 13093 port->fp_port_id.port_id, pkt->pkt_state, 13094 pkt->pkt_reason, pkt->pkt_expln, 13095 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp); 13096 13097 (void) fp_common_intr(pkt, 1); 13098 13099 return; 13100 } 13101 13102 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) { 13103 uint32_t d_id; 13104 fc_local_port_t *port; 13105 fp_cmd_t *cmd; 13106 13107 d_id = pkt->pkt_cmd_fhdr.d_id; 13108 cmd = pkt->pkt_ulp_private; 13109 port = cmd->cmd_port; 13110 FP_TRACE(FP_NHEAD2(9, 0), 13111 "Bogus NS response received for D_ID=%x", d_id); 13112 } 13113 13114 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) { 13115 fp_gan_handler(pkt, ns_cmd); 13116 return; 13117 } 13118 13119 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID && 13120 cmd_hdr.ct_cmdrsp <= NS_GID_PT) { 13121 if (ns_cmd) { 13122 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) { 13123 fp_ns_query_handler(pkt, ns_cmd); 13124 return; 13125 } 13126 } 13127 } 13128 13129 fp_iodone(pkt->pkt_ulp_private); 13130 } 13131 13132 13133 /* 13134 * Process NS_GAN response 13135 */ 13136 static void 13137 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13138 { 13139 int my_did; 13140 fc_portid_t d_id; 13141 fp_cmd_t *cmd; 13142 fc_local_port_t *port; 13143 fc_remote_port_t *pd; 13144 ns_req_gan_t gan_req; 13145 ns_resp_gan_t *gan_resp; 13146 13147 ASSERT(ns_cmd != NULL); 13148 13149 cmd = pkt->pkt_ulp_private; 13150 port = cmd->cmd_port; 13151 13152 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t)); 13153 13154 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id, 13155 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR); 13156 13157 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id); 13158 13159 /* 13160 * In this case the priv_lilp_posit field in reality 13161 * is actually represents the relative position on a private loop. 13162 * So zero it while dealing with Port Identifiers. 13163 */ 13164 d_id.priv_lilp_posit = 0; 13165 pd = fctl_get_remote_port_by_did(port, d_id.port_id); 13166 if (ns_cmd->ns_gan_sid == d_id.port_id) { 13167 /* 13168 * We've come a full circle; time to get out. 13169 */ 13170 fp_iodone(cmd); 13171 return; 13172 } 13173 13174 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) { 13175 ns_cmd->ns_gan_sid = d_id.port_id; 13176 } 13177 13178 mutex_enter(&port->fp_mutex); 13179 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0; 13180 mutex_exit(&port->fp_mutex); 13181 13182 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port, 13183 port->fp_port_id.port_id, d_id.port_id); 13184 if (my_did == 0) { 13185 la_wwn_t pwwn; 13186 la_wwn_t nwwn; 13187 13188 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; " 13189 "port=%p, d_id=%x, type_id=%x, " 13190 "pwwn=%x %x %x %x %x %x %x %x, " 13191 "nwwn=%x %x %x %x %x %x %x %x", 13192 port, d_id.port_id, gan_resp->gan_type_id, 13193 13194 gan_resp->gan_pwwn.raw_wwn[0], 13195 gan_resp->gan_pwwn.raw_wwn[1], 13196 gan_resp->gan_pwwn.raw_wwn[2], 13197 gan_resp->gan_pwwn.raw_wwn[3], 13198 gan_resp->gan_pwwn.raw_wwn[4], 13199 gan_resp->gan_pwwn.raw_wwn[5], 13200 gan_resp->gan_pwwn.raw_wwn[6], 13201 gan_resp->gan_pwwn.raw_wwn[7], 13202 13203 gan_resp->gan_nwwn.raw_wwn[0], 13204 gan_resp->gan_nwwn.raw_wwn[1], 13205 gan_resp->gan_nwwn.raw_wwn[2], 13206 gan_resp->gan_nwwn.raw_wwn[3], 13207 gan_resp->gan_nwwn.raw_wwn[4], 13208 gan_resp->gan_nwwn.raw_wwn[5], 13209 gan_resp->gan_nwwn.raw_wwn[6], 13210 gan_resp->gan_nwwn.raw_wwn[7]); 13211 13212 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 13213 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn), 13214 DDI_DEV_AUTOINCR); 13215 13216 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 13217 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn), 13218 DDI_DEV_AUTOINCR); 13219 13220 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) { 13221 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create" 13222 "pd %x", port->fp_port_id.port_id, d_id.port_id); 13223 pd = fctl_create_remote_port(port, &nwwn, &pwwn, 13224 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); 13225 } 13226 if (pd != NULL) { 13227 fp_stuff_device_with_gan(&pkt->pkt_resp_acc, 13228 pd, gan_resp); 13229 } 13230 13231 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) { 13232 *((int *)ns_cmd->ns_data_buf) += 1; 13233 } 13234 13235 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) { 13236 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0); 13237 13238 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) { 13239 fc_port_dev_t *userbuf; 13240 13241 userbuf = ((fc_port_dev_t *) 13242 ns_cmd->ns_data_buf) + 13243 ns_cmd->ns_gan_index++; 13244 13245 userbuf->dev_did = d_id; 13246 13247 FC_GET_RSP(port, pkt->pkt_resp_acc, 13248 (uint8_t *)userbuf->dev_type, 13249 (uint8_t *)gan_resp->gan_fc4types, 13250 sizeof (userbuf->dev_type), 13251 DDI_DEV_AUTOINCR); 13252 13253 userbuf->dev_nwwn = nwwn; 13254 userbuf->dev_pwwn = pwwn; 13255 13256 if (pd != NULL) { 13257 mutex_enter(&pd->pd_mutex); 13258 userbuf->dev_state = pd->pd_state; 13259 userbuf->dev_hard_addr = 13260 pd->pd_hard_addr; 13261 mutex_exit(&pd->pd_mutex); 13262 } else { 13263 userbuf->dev_state = 13264 PORT_DEVICE_INVALID; 13265 } 13266 } else if (ns_cmd->ns_flags & 13267 FCTL_NS_BUF_IS_FC_PORTMAP) { 13268 fc_portmap_t *map; 13269 13270 map = ((fc_portmap_t *) 13271 ns_cmd->ns_data_buf) + 13272 ns_cmd->ns_gan_index++; 13273 13274 /* 13275 * First fill it like any new map 13276 * and update the port device info 13277 * below. 13278 */ 13279 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc, 13280 map, gan_resp, d_id.port_id); 13281 if (pd != NULL) { 13282 fctl_copy_portmap(map, pd); 13283 } else { 13284 map->map_state = PORT_DEVICE_INVALID; 13285 map->map_type = PORT_DEVICE_NOCHANGE; 13286 } 13287 } else { 13288 caddr_t dst_ptr; 13289 13290 dst_ptr = ns_cmd->ns_data_buf + 13291 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++; 13292 13293 FC_GET_RSP(port, pkt->pkt_resp_acc, 13294 (uint8_t *)dst_ptr, (uint8_t *)gan_resp, 13295 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR); 13296 } 13297 } else { 13298 ns_cmd->ns_gan_index++; 13299 } 13300 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) { 13301 fp_iodone(cmd); 13302 return; 13303 } 13304 } 13305 13306 gan_req.pid = d_id; 13307 13308 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req, 13309 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13310 sizeof (gan_req), DDI_DEV_AUTOINCR); 13311 13312 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) { 13313 pkt->pkt_state = FC_PKT_TRAN_ERROR; 13314 fp_iodone(cmd); 13315 } else { 13316 mutex_enter(&port->fp_mutex); 13317 port->fp_out_fpcmds++; 13318 mutex_exit(&port->fp_mutex); 13319 } 13320 } 13321 13322 13323 /* 13324 * Handle NS Query interrupt 13325 */ 13326 static void 13327 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13328 { 13329 fp_cmd_t *cmd; 13330 fc_local_port_t *port; 13331 caddr_t src_ptr; 13332 uint32_t xfer_len; 13333 13334 cmd = pkt->pkt_ulp_private; 13335 port = cmd->cmd_port; 13336 13337 xfer_len = ns_cmd->ns_resp_size; 13338 13339 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x", 13340 ns_cmd->ns_cmd_code, xfer_len); 13341 13342 if (ns_cmd->ns_cmd_code == NS_GPN_ID) { 13343 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13344 13345 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x", 13346 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]); 13347 } 13348 13349 if (xfer_len <= ns_cmd->ns_data_len) { 13350 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13351 FC_GET_RSP(port, pkt->pkt_resp_acc, 13352 (uint8_t *)ns_cmd->ns_data_buf, 13353 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR); 13354 } 13355 13356 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13357 ASSERT(ns_cmd->ns_pd != NULL); 13358 13359 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13360 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) { 13361 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE; 13362 } 13363 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13364 } 13365 13366 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13367 fctl_free_ns_cmd(ns_cmd); 13368 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL; 13369 } 13370 fp_iodone(cmd); 13371 } 13372 13373 13374 /* 13375 * Handle unsolicited ADISC ELS request 13376 */ 13377 static void 13378 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf, 13379 fc_remote_port_t *pd, job_request_t *job) 13380 { 13381 int rval; 13382 fp_cmd_t *cmd; 13383 13384 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p", 13385 port, pd->pd_port_id.port_id, pd->pd_state, pd); 13386 mutex_enter(&pd->pd_mutex); 13387 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 13388 mutex_exit(&pd->pd_mutex); 13389 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 13390 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 13391 0, KM_SLEEP, pd); 13392 if (cmd != NULL) { 13393 fp_els_rjt_init(port, cmd, buf, 13394 FC_ACTION_NON_RETRYABLE, 13395 FC_REASON_INVALID_LINK_CTRL, job); 13396 13397 if (fp_sendcmd(port, cmd, 13398 port->fp_fca_handle) != FC_SUCCESS) { 13399 fp_free_pkt(cmd); 13400 } 13401 } 13402 } 13403 } else { 13404 mutex_exit(&pd->pd_mutex); 13405 /* 13406 * Yes, yes, we don't have a hard address. But we 13407 * we should still respond. Huh ? Visit 21.19.2 13408 * of FC-PH-2 which essentially says that if an 13409 * NL_Port doesn't have a hard address, or if a port 13410 * does not have FC-AL capability, it shall report 13411 * zeroes in this field. 13412 */ 13413 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 13414 0, KM_SLEEP, pd); 13415 if (cmd == NULL) { 13416 return; 13417 } 13418 fp_adisc_acc_init(port, cmd, buf, job); 13419 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13420 if (rval != FC_SUCCESS) { 13421 fp_free_pkt(cmd); 13422 } 13423 } 13424 } 13425 13426 13427 /* 13428 * Initialize ADISC response. 13429 */ 13430 static void 13431 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 13432 job_request_t *job) 13433 { 13434 fc_packet_t *pkt; 13435 la_els_adisc_t payload; 13436 13437 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 13438 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 13439 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 13440 cmd->cmd_retry_count = 1; 13441 cmd->cmd_ulp_pkt = NULL; 13442 13443 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 13444 cmd->cmd_job = job; 13445 13446 pkt = &cmd->cmd_pkt; 13447 13448 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 13449 13450 payload.ls_code.ls_code = LA_ELS_ACC; 13451 payload.ls_code.mbz = 0; 13452 13453 mutex_enter(&port->fp_mutex); 13454 payload.nport_id = port->fp_port_id; 13455 payload.hard_addr = port->fp_hard_addr; 13456 mutex_exit(&port->fp_mutex); 13457 13458 payload.port_wwn = port->fp_service_params.nport_ww_name; 13459 payload.node_wwn = port->fp_service_params.node_ww_name; 13460 13461 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 13462 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 13463 } 13464 13465 13466 /* 13467 * Hold and Install the requested ULP drivers 13468 */ 13469 static void 13470 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port) 13471 { 13472 int len; 13473 int count; 13474 int data_len; 13475 major_t ulp_major; 13476 caddr_t ulp_name; 13477 caddr_t data_ptr; 13478 caddr_t data_buf; 13479 13480 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13481 13482 data_buf = NULL; 13483 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 13484 DDI_PROP_DONTPASS, "load-ulp-list", 13485 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) { 13486 return; 13487 } 13488 13489 len = strlen(data_buf); 13490 port->fp_ulp_nload = fctl_atoi(data_buf, 10); 13491 13492 data_ptr = data_buf + len + 1; 13493 for (count = 0; count < port->fp_ulp_nload; count++) { 13494 len = strlen(data_ptr) + 1; 13495 ulp_name = kmem_zalloc(len, KM_SLEEP); 13496 bcopy(data_ptr, ulp_name, len); 13497 13498 ulp_major = ddi_name_to_major(ulp_name); 13499 13500 if (ulp_major != (major_t)-1) { 13501 if (modload("drv", ulp_name) < 0) { 13502 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 13503 0, NULL, "failed to load %s", 13504 ulp_name); 13505 } 13506 } else { 13507 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 13508 "%s isn't a valid driver", ulp_name); 13509 } 13510 13511 kmem_free(ulp_name, len); 13512 data_ptr += len; /* Skip to next field */ 13513 } 13514 13515 /* 13516 * Free the memory allocated by DDI 13517 */ 13518 if (data_buf != NULL) { 13519 kmem_free(data_buf, data_len); 13520 } 13521 } 13522 13523 13524 /* 13525 * Perform LOGO operation 13526 */ 13527 static int 13528 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job) 13529 { 13530 int rval; 13531 fp_cmd_t *cmd; 13532 13533 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13534 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 13535 13536 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 13537 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 13538 13539 mutex_enter(&port->fp_mutex); 13540 mutex_enter(&pd->pd_mutex); 13541 13542 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN); 13543 ASSERT(pd->pd_login_count == 1); 13544 13545 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 13546 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13547 cmd->cmd_flags = 0; 13548 cmd->cmd_retry_count = 1; 13549 cmd->cmd_ulp_pkt = NULL; 13550 13551 fp_logo_init(pd, cmd, job); 13552 13553 mutex_exit(&pd->pd_mutex); 13554 mutex_exit(&port->fp_mutex); 13555 13556 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13557 if (rval != FC_SUCCESS) { 13558 fp_iodone(cmd); 13559 } 13560 13561 return (rval); 13562 } 13563 13564 13565 /* 13566 * Perform Port attach callbacks to registered ULPs 13567 */ 13568 static void 13569 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd) 13570 { 13571 fp_soft_attach_t *att; 13572 13573 att = kmem_zalloc(sizeof (*att), KM_SLEEP); 13574 att->att_cmd = cmd; 13575 att->att_port = port; 13576 13577 /* 13578 * We need to remember whether or not fctl_busy_port 13579 * succeeded so we know whether or not to call 13580 * fctl_idle_port when the task is complete. 13581 */ 13582 13583 if (fctl_busy_port(port) == 0) { 13584 att->att_need_pm_idle = B_TRUE; 13585 } else { 13586 att->att_need_pm_idle = B_FALSE; 13587 } 13588 13589 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach, 13590 att, KM_SLEEP); 13591 } 13592 13593 13594 /* 13595 * Forward state change notifications on to interested ULPs. 13596 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the 13597 * real work. 13598 */ 13599 static int 13600 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep) 13601 { 13602 fc_port_clist_t *clist; 13603 13604 clist = kmem_zalloc(sizeof (*clist), sleep); 13605 if (clist == NULL) { 13606 return (FC_NOMEM); 13607 } 13608 13609 clist->clist_state = statec; 13610 13611 mutex_enter(&port->fp_mutex); 13612 clist->clist_flags = port->fp_topology; 13613 mutex_exit(&port->fp_mutex); 13614 13615 clist->clist_port = (opaque_t)port; 13616 clist->clist_len = 0; 13617 clist->clist_size = 0; 13618 clist->clist_map = NULL; 13619 13620 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 13621 clist, KM_SLEEP); 13622 13623 return (FC_SUCCESS); 13624 } 13625 13626 13627 /* 13628 * Get name server map 13629 */ 13630 static int 13631 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map, 13632 uint32_t *len, uint32_t sid) 13633 { 13634 int ret; 13635 fctl_ns_req_t *ns_cmd; 13636 13637 /* 13638 * Don't let the allocator do anything for response; 13639 * we have have buffer ready to fillout. 13640 */ 13641 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13642 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP | 13643 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP); 13644 13645 ns_cmd->ns_data_len = sizeof (**map) * (*len); 13646 ns_cmd->ns_data_buf = (caddr_t)*map; 13647 13648 ASSERT(ns_cmd != NULL); 13649 13650 ns_cmd->ns_gan_index = 0; 13651 ns_cmd->ns_gan_sid = sid; 13652 ns_cmd->ns_cmd_code = NS_GA_NXT; 13653 ns_cmd->ns_gan_max = *len; 13654 13655 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13656 13657 if (ns_cmd->ns_gan_index != *len) { 13658 *len = ns_cmd->ns_gan_index; 13659 } 13660 ns_cmd->ns_data_len = 0; 13661 ns_cmd->ns_data_buf = NULL; 13662 fctl_free_ns_cmd(ns_cmd); 13663 13664 return (ret); 13665 } 13666 13667 13668 /* 13669 * Create a remote port in Fabric topology by using NS services 13670 */ 13671 static fc_remote_port_t * 13672 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep) 13673 { 13674 int rval; 13675 job_request_t *job; 13676 fctl_ns_req_t *ns_cmd; 13677 fc_remote_port_t *pd; 13678 13679 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13680 13681 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x", 13682 port, d_id); 13683 13684 #ifdef DEBUG 13685 mutex_enter(&port->fp_mutex); 13686 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 13687 mutex_exit(&port->fp_mutex); 13688 #endif 13689 13690 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep); 13691 if (job == NULL) { 13692 return (NULL); 13693 } 13694 13695 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13696 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE | 13697 FCTL_NS_NO_DATA_BUF), sleep); 13698 if (ns_cmd == NULL) { 13699 return (NULL); 13700 } 13701 13702 job->job_result = FC_SUCCESS; 13703 ns_cmd->ns_gan_max = 1; 13704 ns_cmd->ns_cmd_code = NS_GA_NXT; 13705 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 13706 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 13707 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 13708 13709 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 13710 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13711 fctl_free_ns_cmd(ns_cmd); 13712 13713 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) { 13714 fctl_dealloc_job(job); 13715 return (NULL); 13716 } 13717 fctl_dealloc_job(job); 13718 13719 pd = fctl_get_remote_port_by_did(port, d_id); 13720 13721 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p", 13722 port, d_id, pd); 13723 13724 return (pd); 13725 } 13726 13727 13728 /* 13729 * Check for the permissions on an ioctl command. If it is required to have an 13730 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If 13731 * the ioctl command isn't in one of the list built, shut the door on that too. 13732 * 13733 * Certain ioctls perform hardware accesses in FCA drivers, and it needs 13734 * to be made sure that users open the port for an exclusive access while 13735 * performing those operations. 13736 * 13737 * This can prevent a casual user from inflicting damage on the port by 13738 * sending these ioctls from multiple processes/threads (there is no good 13739 * reason why one would need to do that) without actually realizing how 13740 * expensive such commands could turn out to be. 13741 * 13742 * It is also important to note that, even with an exclusive access, 13743 * multiple threads can share the same file descriptor and fire down 13744 * commands in parallel. To prevent that the driver needs to make sure 13745 * that such commands aren't in progress already. This is taken care of 13746 * in the FP_EXCL_BUSY bit of fp_flag. 13747 */ 13748 static int 13749 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd) 13750 { 13751 int ret = FC_FAILURE; 13752 int count; 13753 13754 for (count = 0; 13755 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]); 13756 count++) { 13757 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) { 13758 if (fp_perm_list[count].fp_open_flag & open_flag) { 13759 ret = FC_SUCCESS; 13760 } 13761 break; 13762 } 13763 } 13764 13765 return (ret); 13766 } 13767 13768 13769 /* 13770 * Bind Port driver's unsolicited, state change callbacks 13771 */ 13772 static int 13773 fp_bind_callbacks(fc_local_port_t *port) 13774 { 13775 fc_fca_bind_info_t bind_info = {0}; 13776 fc_fca_port_info_t *port_info; 13777 int rval = DDI_SUCCESS; 13778 uint16_t class; 13779 int node_namelen, port_namelen; 13780 char *nname = NULL, *pname = NULL; 13781 13782 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13783 13784 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13785 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13786 "node-name", &nname) != DDI_PROP_SUCCESS) { 13787 FP_TRACE(FP_NHEAD1(1, 0), 13788 "fp_bind_callback fail to get node-name"); 13789 } 13790 if (nname) { 13791 fc_str_to_wwn(nname, &(bind_info.port_nwwn)); 13792 } 13793 13794 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13795 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13796 "port-name", &pname) != DDI_PROP_SUCCESS) { 13797 FP_TRACE(FP_NHEAD1(1, 0), 13798 "fp_bind_callback fail to get port-name"); 13799 } 13800 if (pname) { 13801 fc_str_to_wwn(pname, &(bind_info.port_pwwn)); 13802 } 13803 13804 if (port->fp_npiv_type == FC_NPIV_PORT) { 13805 bind_info.port_npiv = 1; 13806 } 13807 13808 /* 13809 * fca_bind_port returns the FCA driver's handle for the local 13810 * port instance. If the port number isn't supported it returns NULL. 13811 * It also sets up callback in the FCA for various 13812 * things like state change, ELS etc.. 13813 */ 13814 bind_info.port_statec_cb = fp_statec_cb; 13815 bind_info.port_unsol_cb = fp_unsol_cb; 13816 bind_info.port_num = port->fp_port_num; 13817 bind_info.port_handle = (opaque_t)port; 13818 13819 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP); 13820 13821 /* 13822 * Hold the port driver mutex as the callbacks are bound until the 13823 * service parameters are properly filled in (in order to be able to 13824 * properly respond to unsolicited ELS requests) 13825 */ 13826 mutex_enter(&port->fp_mutex); 13827 13828 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port( 13829 port->fp_fca_dip, port_info, &bind_info); 13830 13831 if (port->fp_fca_handle == NULL) { 13832 rval = DDI_FAILURE; 13833 goto exit; 13834 } 13835 13836 /* 13837 * Only fcoei will set this bit 13838 */ 13839 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) { 13840 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA; 13841 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA); 13842 } 13843 13844 port->fp_bind_state = port->fp_state = port_info->pi_port_state; 13845 port->fp_service_params = port_info->pi_login_params; 13846 port->fp_hard_addr = port_info->pi_hard_addr; 13847 13848 /* Copy from the FCA structure to the FP structure */ 13849 port->fp_hba_port_attrs = port_info->pi_attrs; 13850 13851 if (port_info->pi_rnid_params.status == FC_SUCCESS) { 13852 port->fp_rnid_init = 1; 13853 bcopy(&port_info->pi_rnid_params.params, 13854 &port->fp_rnid_params, 13855 sizeof (port->fp_rnid_params)); 13856 } else { 13857 port->fp_rnid_init = 0; 13858 } 13859 13860 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name); 13861 if (node_namelen) { 13862 bcopy(&port_info->pi_attrs.sym_node_name, 13863 &port->fp_sym_node_name, 13864 node_namelen); 13865 port->fp_sym_node_namelen = node_namelen; 13866 } 13867 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name); 13868 if (port_namelen) { 13869 bcopy(&port_info->pi_attrs.sym_port_name, 13870 &port->fp_sym_port_name, 13871 port_namelen); 13872 port->fp_sym_port_namelen = port_namelen; 13873 } 13874 13875 /* zero out the normally unused fields right away */ 13876 port->fp_service_params.ls_code.mbz = 0; 13877 port->fp_service_params.ls_code.ls_code = 0; 13878 bzero(&port->fp_service_params.reserved, 13879 sizeof (port->fp_service_params.reserved)); 13880 13881 class = port_info->pi_login_params.class_1.class_opt; 13882 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0; 13883 13884 class = port_info->pi_login_params.class_2.class_opt; 13885 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0; 13886 13887 class = port_info->pi_login_params.class_3.class_opt; 13888 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0; 13889 13890 exit: 13891 if (nname) { 13892 ddi_prop_free(nname); 13893 } 13894 if (pname) { 13895 ddi_prop_free(pname); 13896 } 13897 mutex_exit(&port->fp_mutex); 13898 kmem_free(port_info, sizeof (*port_info)); 13899 13900 return (rval); 13901 } 13902 13903 13904 /* 13905 * Retrieve FCA capabilities 13906 */ 13907 static void 13908 fp_retrieve_caps(fc_local_port_t *port) 13909 { 13910 int rval; 13911 int ub_count; 13912 fc_fcp_dma_t fcp_dma; 13913 fc_reset_action_t action; 13914 fc_dma_behavior_t dma_behavior; 13915 13916 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13917 13918 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13919 FC_CAP_UNSOL_BUF, &ub_count); 13920 13921 switch (rval) { 13922 case FC_CAP_FOUND: 13923 case FC_CAP_SETTABLE: 13924 switch (ub_count) { 13925 case 0: 13926 break; 13927 13928 case -1: 13929 ub_count = fp_unsol_buf_count; 13930 break; 13931 13932 default: 13933 /* 1/4th of total buffers is my share */ 13934 ub_count = 13935 (ub_count / port->fp_fca_tran->fca_numports) >> 2; 13936 break; 13937 } 13938 break; 13939 13940 default: 13941 ub_count = 0; 13942 break; 13943 } 13944 13945 mutex_enter(&port->fp_mutex); 13946 port->fp_ub_count = ub_count; 13947 mutex_exit(&port->fp_mutex); 13948 13949 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13950 FC_CAP_POST_RESET_BEHAVIOR, &action); 13951 13952 switch (rval) { 13953 case FC_CAP_FOUND: 13954 case FC_CAP_SETTABLE: 13955 switch (action) { 13956 case FC_RESET_RETURN_NONE: 13957 case FC_RESET_RETURN_ALL: 13958 case FC_RESET_RETURN_OUTSTANDING: 13959 break; 13960 13961 default: 13962 action = FC_RESET_RETURN_NONE; 13963 break; 13964 } 13965 break; 13966 13967 default: 13968 action = FC_RESET_RETURN_NONE; 13969 break; 13970 } 13971 mutex_enter(&port->fp_mutex); 13972 port->fp_reset_action = action; 13973 mutex_exit(&port->fp_mutex); 13974 13975 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13976 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior); 13977 13978 switch (rval) { 13979 case FC_CAP_FOUND: 13980 switch (dma_behavior) { 13981 case FC_ALLOW_STREAMING: 13982 /* FALLTHROUGH */ 13983 case FC_NO_STREAMING: 13984 break; 13985 13986 default: 13987 /* 13988 * If capability was found and the value 13989 * was incorrect assume the worst 13990 */ 13991 dma_behavior = FC_NO_STREAMING; 13992 break; 13993 } 13994 break; 13995 13996 default: 13997 /* 13998 * If capability was not defined - allow streaming; existing 13999 * FCAs should not be affected. 14000 */ 14001 dma_behavior = FC_ALLOW_STREAMING; 14002 break; 14003 } 14004 mutex_enter(&port->fp_mutex); 14005 port->fp_dma_behavior = dma_behavior; 14006 mutex_exit(&port->fp_mutex); 14007 14008 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 14009 FC_CAP_FCP_DMA, &fcp_dma); 14010 14011 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE && 14012 fcp_dma != FC_DVMA_SPACE)) { 14013 fcp_dma = FC_DVMA_SPACE; 14014 } 14015 14016 mutex_enter(&port->fp_mutex); 14017 port->fp_fcp_dma = fcp_dma; 14018 mutex_exit(&port->fp_mutex); 14019 } 14020 14021 14022 /* 14023 * Handle Domain, Area changes in the Fabric. 14024 */ 14025 static void 14026 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask, 14027 job_request_t *job, int sleep) 14028 { 14029 #ifdef DEBUG 14030 uint32_t dcnt; 14031 #endif 14032 int rval; 14033 int send; 14034 int index; 14035 int listindex; 14036 int login; 14037 int job_flags; 14038 char ww_name[17]; 14039 uint32_t d_id; 14040 uint32_t count; 14041 fctl_ns_req_t *ns_cmd; 14042 fc_portmap_t *list; 14043 fc_orphan_t *orp; 14044 fc_orphan_t *norp; 14045 fc_orphan_t *prev; 14046 fc_remote_port_t *pd; 14047 fc_remote_port_t *npd; 14048 struct pwwn_hash *head; 14049 14050 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14051 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14052 0, sleep); 14053 if (ns_cmd == NULL) { 14054 mutex_enter(&port->fp_mutex); 14055 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14056 --port->fp_rscn_count; 14057 } 14058 mutex_exit(&port->fp_mutex); 14059 14060 return; 14061 } 14062 ns_cmd->ns_cmd_code = NS_GID_PN; 14063 14064 /* 14065 * We need to get a new count of devices from the 14066 * name server, which will also create any new devices 14067 * as needed. 14068 */ 14069 14070 (void) fp_ns_get_devcount(port, job, 1, sleep); 14071 14072 FP_TRACE(FP_NHEAD1(3, 0), 14073 "fp_validate_area_domain: get_devcount found %d devices", 14074 port->fp_total_devices); 14075 14076 mutex_enter(&port->fp_mutex); 14077 14078 for (count = index = 0; index < pwwn_table_size; index++) { 14079 head = &port->fp_pwwn_table[index]; 14080 pd = head->pwwn_head; 14081 while (pd != NULL) { 14082 mutex_enter(&pd->pd_mutex); 14083 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14084 if ((pd->pd_port_id.port_id & mask) == id && 14085 pd->pd_recepient == PD_PLOGI_INITIATOR) { 14086 count++; 14087 pd->pd_type = PORT_DEVICE_OLD; 14088 pd->pd_flags = PD_ELS_MARK; 14089 } 14090 } 14091 mutex_exit(&pd->pd_mutex); 14092 pd = pd->pd_wwn_hnext; 14093 } 14094 } 14095 14096 #ifdef DEBUG 14097 dcnt = count; 14098 #endif /* DEBUG */ 14099 14100 /* 14101 * Since port->fp_orphan_count is declared an 'int' it is 14102 * theoretically possible that the count could go negative. 14103 * 14104 * This would be bad and if that happens we really do want 14105 * to know. 14106 */ 14107 14108 ASSERT(port->fp_orphan_count >= 0); 14109 14110 count += port->fp_orphan_count; 14111 14112 /* 14113 * We add the port->fp_total_devices value to the count 14114 * in the case where our port is newly attached. This is 14115 * because we haven't done any discovery and we don't have 14116 * any orphans in the port's orphan list. If we do not do 14117 * this addition to count then we won't alloc enough kmem 14118 * to do discovery with. 14119 */ 14120 14121 if (count == 0) { 14122 count += port->fp_total_devices; 14123 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: " 14124 "0x%x orphans found, using 0x%x", 14125 port->fp_orphan_count, count); 14126 } 14127 14128 mutex_exit(&port->fp_mutex); 14129 14130 /* 14131 * Allocate the change list 14132 */ 14133 14134 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 14135 if (list == NULL) { 14136 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 14137 " Not enough memory to service RSCNs" 14138 " for %d ports, continuing...", count); 14139 14140 fctl_free_ns_cmd(ns_cmd); 14141 14142 mutex_enter(&port->fp_mutex); 14143 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14144 --port->fp_rscn_count; 14145 } 14146 mutex_exit(&port->fp_mutex); 14147 14148 return; 14149 } 14150 14151 /* 14152 * Attempt to validate or invalidate the devices that were 14153 * already in the pwwn hash table. 14154 */ 14155 14156 mutex_enter(&port->fp_mutex); 14157 for (listindex = 0, index = 0; index < pwwn_table_size; index++) { 14158 head = &port->fp_pwwn_table[index]; 14159 npd = head->pwwn_head; 14160 14161 while ((pd = npd) != NULL) { 14162 npd = pd->pd_wwn_hnext; 14163 14164 mutex_enter(&pd->pd_mutex); 14165 if ((pd->pd_port_id.port_id & mask) == id && 14166 pd->pd_flags == PD_ELS_MARK) { 14167 la_wwn_t *pwwn; 14168 14169 job->job_result = FC_SUCCESS; 14170 14171 ((ns_req_gid_pn_t *) 14172 (ns_cmd->ns_cmd_buf))->pwwn = 14173 pd->pd_port_name; 14174 14175 pwwn = &pd->pd_port_name; 14176 d_id = pd->pd_port_id.port_id; 14177 14178 mutex_exit(&pd->pd_mutex); 14179 mutex_exit(&port->fp_mutex); 14180 14181 rval = fp_ns_query(port, ns_cmd, job, 1, 14182 sleep); 14183 if (rval != FC_SUCCESS) { 14184 fc_wwn_to_str(pwwn, ww_name); 14185 14186 FP_TRACE(FP_NHEAD1(3, 0), 14187 "AREA RSCN: PD disappeared; " 14188 "d_id=%x, PWWN=%s", d_id, ww_name); 14189 14190 FP_TRACE(FP_NHEAD2(9, 0), 14191 "N_x Port with D_ID=%x," 14192 " PWWN=%s disappeared from fabric", 14193 d_id, ww_name); 14194 14195 fp_fillout_old_map(list + listindex++, 14196 pd, 1); 14197 } else { 14198 fctl_copy_portmap(list + listindex++, 14199 pd); 14200 14201 mutex_enter(&pd->pd_mutex); 14202 pd->pd_flags = PD_ELS_IN_PROGRESS; 14203 mutex_exit(&pd->pd_mutex); 14204 } 14205 14206 mutex_enter(&port->fp_mutex); 14207 } else { 14208 mutex_exit(&pd->pd_mutex); 14209 } 14210 } 14211 } 14212 14213 mutex_exit(&port->fp_mutex); 14214 14215 ASSERT(listindex == dcnt); 14216 14217 job->job_counter = listindex; 14218 job_flags = job->job_flags; 14219 job->job_flags |= JOB_TYPE_FP_ASYNC; 14220 14221 /* 14222 * Login (if we were the initiator) or validate devices in the 14223 * port map. 14224 */ 14225 14226 for (index = 0; index < listindex; index++) { 14227 pd = list[index].map_pd; 14228 14229 mutex_enter(&pd->pd_mutex); 14230 ASSERT((pd->pd_port_id.port_id & mask) == id); 14231 14232 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14233 ASSERT(pd->pd_type == PORT_DEVICE_OLD); 14234 mutex_exit(&pd->pd_mutex); 14235 fp_jobdone(job); 14236 continue; 14237 } 14238 14239 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0; 14240 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 14241 d_id = pd->pd_port_id.port_id; 14242 mutex_exit(&pd->pd_mutex); 14243 14244 if ((d_id & mask) == id && send) { 14245 if (login) { 14246 FP_TRACE(FP_NHEAD1(6, 0), 14247 "RSCN and PLOGI request;" 14248 " pd=%p, job=%p d_id=%x, index=%d", pd, 14249 job, d_id, index); 14250 14251 rval = fp_port_login(port, d_id, job, 14252 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL); 14253 if (rval != FC_SUCCESS) { 14254 mutex_enter(&pd->pd_mutex); 14255 pd->pd_flags = PD_IDLE; 14256 mutex_exit(&pd->pd_mutex); 14257 14258 job->job_result = rval; 14259 fp_jobdone(job); 14260 } 14261 FP_TRACE(FP_NHEAD1(1, 0), 14262 "PLOGI succeeded:no skip(1) for " 14263 "D_ID %x", d_id); 14264 list[index].map_flags |= 14265 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14266 } else { 14267 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;" 14268 " pd=%p, job=%p d_id=%x, index=%d", pd, 14269 job, d_id, index); 14270 14271 rval = fp_ns_validate_device(port, pd, job, 14272 0, sleep); 14273 if (rval != FC_SUCCESS) { 14274 fp_jobdone(job); 14275 } 14276 mutex_enter(&pd->pd_mutex); 14277 pd->pd_flags = PD_IDLE; 14278 mutex_exit(&pd->pd_mutex); 14279 } 14280 } else { 14281 FP_TRACE(FP_NHEAD1(6, 0), 14282 "RSCN and NO request sent; pd=%p," 14283 " d_id=%x, index=%d", pd, d_id, index); 14284 14285 mutex_enter(&pd->pd_mutex); 14286 pd->pd_flags = PD_IDLE; 14287 mutex_exit(&pd->pd_mutex); 14288 14289 fp_jobdone(job); 14290 } 14291 } 14292 14293 if (listindex) { 14294 fctl_jobwait(job); 14295 } 14296 job->job_flags = job_flags; 14297 14298 /* 14299 * Orphan list validation. 14300 */ 14301 mutex_enter(&port->fp_mutex); 14302 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count && 14303 orp != NULL; orp = norp) { 14304 norp = orp->orp_next; 14305 mutex_exit(&port->fp_mutex); 14306 14307 job->job_counter = 1; 14308 job->job_result = FC_SUCCESS; 14309 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 14310 14311 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn; 14312 14313 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14314 ((ns_resp_gid_pn_t *) 14315 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14316 14317 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 14318 if (rval == FC_SUCCESS) { 14319 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 14320 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 14321 if (pd != NULL) { 14322 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 14323 14324 FP_TRACE(FP_NHEAD1(6, 0), 14325 "RSCN and ORPHAN list " 14326 "success; d_id=%x, PWWN=%s", d_id, ww_name); 14327 14328 FP_TRACE(FP_NHEAD2(6, 0), 14329 "N_x Port with D_ID=%x, PWWN=%s reappeared" 14330 " in fabric", d_id, ww_name); 14331 14332 mutex_enter(&port->fp_mutex); 14333 if (prev) { 14334 prev->orp_next = orp->orp_next; 14335 } else { 14336 ASSERT(orp == port->fp_orphan_list); 14337 port->fp_orphan_list = orp->orp_next; 14338 } 14339 port->fp_orphan_count--; 14340 mutex_exit(&port->fp_mutex); 14341 14342 kmem_free(orp, sizeof (*orp)); 14343 fctl_copy_portmap(list + listindex++, pd); 14344 } else { 14345 prev = orp; 14346 } 14347 } else { 14348 prev = orp; 14349 } 14350 mutex_enter(&port->fp_mutex); 14351 } 14352 mutex_exit(&port->fp_mutex); 14353 14354 /* 14355 * One more pass through the list to delist old devices from 14356 * the d_id and pwwn tables and possibly add to the orphan list. 14357 */ 14358 14359 for (index = 0; index < listindex; index++) { 14360 pd = list[index].map_pd; 14361 ASSERT(pd != NULL); 14362 14363 /* 14364 * Update PLOGI results; For NS validation 14365 * of orphan list, it is redundant 14366 * 14367 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if 14368 * appropriate as fctl_copy_portmap() will clear map_flags. 14369 */ 14370 if (list[index].map_flags & 14371 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) { 14372 fctl_copy_portmap(list + index, pd); 14373 list[index].map_flags |= 14374 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14375 } else { 14376 fctl_copy_portmap(list + index, pd); 14377 } 14378 14379 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14380 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x", 14381 pd, pd->pd_port_id.port_id, 14382 pd->pd_port_name.raw_wwn[0], 14383 pd->pd_port_name.raw_wwn[1], 14384 pd->pd_port_name.raw_wwn[2], 14385 pd->pd_port_name.raw_wwn[3], 14386 pd->pd_port_name.raw_wwn[4], 14387 pd->pd_port_name.raw_wwn[5], 14388 pd->pd_port_name.raw_wwn[6], 14389 pd->pd_port_name.raw_wwn[7]); 14390 14391 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14392 "results continued, pd=%p type=%x, flags=%x, state=%x", 14393 pd, pd->pd_type, pd->pd_flags, pd->pd_state); 14394 14395 mutex_enter(&pd->pd_mutex); 14396 if (pd->pd_type == PORT_DEVICE_OLD) { 14397 int initiator; 14398 14399 pd->pd_flags = PD_IDLE; 14400 initiator = (pd->pd_recepient == 14401 PD_PLOGI_INITIATOR) ? 1 : 0; 14402 14403 mutex_exit(&pd->pd_mutex); 14404 14405 mutex_enter(&port->fp_mutex); 14406 mutex_enter(&pd->pd_mutex); 14407 14408 pd->pd_state = PORT_DEVICE_INVALID; 14409 fctl_delist_did_table(port, pd); 14410 fctl_delist_pwwn_table(port, pd); 14411 14412 mutex_exit(&pd->pd_mutex); 14413 mutex_exit(&port->fp_mutex); 14414 14415 if (initiator) { 14416 (void) fctl_add_orphan(port, pd, sleep); 14417 } 14418 list[index].map_pd = pd; 14419 } else { 14420 ASSERT(pd->pd_flags == PD_IDLE); 14421 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 14422 /* 14423 * Reset LOGO tolerance to zero 14424 */ 14425 fctl_tc_reset(&pd->pd_logo_tc); 14426 } 14427 mutex_exit(&pd->pd_mutex); 14428 } 14429 } 14430 14431 if (ns_cmd) { 14432 fctl_free_ns_cmd(ns_cmd); 14433 } 14434 if (listindex) { 14435 (void) fp_ulp_devc_cb(port, list, listindex, count, 14436 sleep, 0); 14437 } else { 14438 kmem_free(list, sizeof (*list) * count); 14439 14440 mutex_enter(&port->fp_mutex); 14441 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14442 --port->fp_rscn_count; 14443 } 14444 mutex_exit(&port->fp_mutex); 14445 } 14446 } 14447 14448 14449 /* 14450 * Work hard to make sense out of an RSCN page. 14451 */ 14452 static void 14453 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page, 14454 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr, 14455 int *listindex, int sleep) 14456 { 14457 int rval; 14458 char ww_name[17]; 14459 la_wwn_t *pwwn; 14460 fc_remote_port_t *pwwn_pd; 14461 fc_remote_port_t *did_pd; 14462 14463 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id); 14464 14465 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; " 14466 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id, 14467 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg); 14468 14469 if (did_pd != NULL) { 14470 mutex_enter(&did_pd->pd_mutex); 14471 if (did_pd->pd_flags != PD_IDLE) { 14472 mutex_exit(&did_pd->pd_mutex); 14473 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: " 14474 "PD is BUSY; port=%p, d_id=%x, pd=%p", 14475 port, page->aff_d_id, did_pd); 14476 return; 14477 } 14478 did_pd->pd_flags = PD_ELS_IN_PROGRESS; 14479 mutex_exit(&did_pd->pd_mutex); 14480 } 14481 14482 job->job_counter = 1; 14483 14484 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn; 14485 14486 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id; 14487 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0; 14488 14489 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t)); 14490 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 14491 14492 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x," 14493 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x", 14494 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid, 14495 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason, 14496 ns_cmd->ns_resp_hdr.ct_expln); 14497 14498 job->job_counter = 1; 14499 14500 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) { 14501 /* 14502 * What this means is that the D_ID 14503 * disappeared from the Fabric. 14504 */ 14505 if (did_pd == NULL) { 14506 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;" 14507 " NULL PD disappeared, rval=%x", rval); 14508 return; 14509 } 14510 14511 fc_wwn_to_str(&did_pd->pd_port_name, ww_name); 14512 14513 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14514 (uint32_t)(uintptr_t)job->job_cb_arg; 14515 14516 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14517 14518 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; " 14519 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name); 14520 14521 FP_TRACE(FP_NHEAD2(9, 0), 14522 "GPN_ID for D_ID=%x failed", page->aff_d_id); 14523 14524 FP_TRACE(FP_NHEAD2(9, 0), 14525 "N_x Port with D_ID=%x, PWWN=%s disappeared from" 14526 " fabric", page->aff_d_id, ww_name); 14527 14528 mutex_enter(&did_pd->pd_mutex); 14529 did_pd->pd_flags = PD_IDLE; 14530 mutex_exit(&did_pd->pd_mutex); 14531 14532 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; " 14533 "PD disappeared, pd=%p", page->aff_d_id, did_pd); 14534 14535 return; 14536 } 14537 14538 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn); 14539 14540 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) { 14541 /* 14542 * There is no change. Do PLOGI again and add it to 14543 * ULP portmap baggage and return. Note: When RSCNs 14544 * arrive with per page states, the need for PLOGI 14545 * can be determined correctly. 14546 */ 14547 mutex_enter(&pwwn_pd->pd_mutex); 14548 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE; 14549 mutex_exit(&pwwn_pd->pd_mutex); 14550 14551 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14552 (uint32_t)(uintptr_t)job->job_cb_arg; 14553 14554 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14555 14556 mutex_enter(&pwwn_pd->pd_mutex); 14557 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14558 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14559 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14560 mutex_exit(&pwwn_pd->pd_mutex); 14561 14562 rval = fp_port_login(port, page->aff_d_id, job, 14563 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14564 if (rval == FC_SUCCESS) { 14565 fp_jobwait(job); 14566 rval = job->job_result; 14567 14568 /* 14569 * Reset LOGO tolerance to zero 14570 * Also we are the PLOGI initiator now. 14571 */ 14572 mutex_enter(&pwwn_pd->pd_mutex); 14573 fctl_tc_reset(&pwwn_pd->pd_logo_tc); 14574 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR; 14575 mutex_exit(&pwwn_pd->pd_mutex); 14576 } 14577 14578 if (rval == FC_SUCCESS) { 14579 struct fc_portmap *map = 14580 listptr + *listindex - 1; 14581 14582 FP_TRACE(FP_NHEAD1(1, 0), 14583 "PLOGI succeeded: no skip(2)" 14584 " for D_ID %x", page->aff_d_id); 14585 map->map_flags |= 14586 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14587 } else { 14588 FP_TRACE(FP_NHEAD2(9, rval), 14589 "PLOGI to D_ID=%x failed", page->aff_d_id); 14590 14591 FP_TRACE(FP_NHEAD2(9, 0), 14592 "N_x Port with D_ID=%x, PWWN=%s" 14593 " disappeared from fabric", 14594 page->aff_d_id, ww_name); 14595 14596 fp_fillout_old_map(listptr + 14597 *listindex - 1, pwwn_pd, 0); 14598 } 14599 } else { 14600 mutex_exit(&pwwn_pd->pd_mutex); 14601 } 14602 14603 mutex_enter(&did_pd->pd_mutex); 14604 did_pd->pd_flags = PD_IDLE; 14605 mutex_exit(&did_pd->pd_mutex); 14606 14607 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14608 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval, 14609 job->job_result, pwwn_pd); 14610 14611 return; 14612 } 14613 14614 if (did_pd == NULL && pwwn_pd == NULL) { 14615 14616 fc_orphan_t *orp = NULL; 14617 fc_orphan_t *norp = NULL; 14618 fc_orphan_t *prev = NULL; 14619 14620 /* 14621 * Hunt down the orphan list before giving up. 14622 */ 14623 14624 mutex_enter(&port->fp_mutex); 14625 if (port->fp_orphan_count) { 14626 14627 for (orp = port->fp_orphan_list; orp; orp = norp) { 14628 norp = orp->orp_next; 14629 14630 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) { 14631 prev = orp; 14632 continue; 14633 } 14634 14635 if (prev) { 14636 prev->orp_next = orp->orp_next; 14637 } else { 14638 ASSERT(orp == 14639 port->fp_orphan_list); 14640 port->fp_orphan_list = 14641 orp->orp_next; 14642 } 14643 port->fp_orphan_count--; 14644 break; 14645 } 14646 } 14647 14648 mutex_exit(&port->fp_mutex); 14649 pwwn_pd = fp_create_remote_port_by_ns(port, 14650 page->aff_d_id, sleep); 14651 14652 if (pwwn_pd != NULL) { 14653 14654 if (orp) { 14655 fc_wwn_to_str(&orp->orp_pwwn, 14656 ww_name); 14657 14658 FP_TRACE(FP_NHEAD2(9, 0), 14659 "N_x Port with D_ID=%x," 14660 " PWWN=%s reappeared in fabric", 14661 page->aff_d_id, ww_name); 14662 14663 kmem_free(orp, sizeof (*orp)); 14664 } 14665 14666 (listptr + *listindex)-> 14667 map_rscn_info.ulp_rscn_count = 14668 (uint32_t)(uintptr_t)job->job_cb_arg; 14669 14670 fctl_copy_portmap(listptr + 14671 (*listindex)++, pwwn_pd); 14672 } 14673 14674 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14675 "Case TWO", page->aff_d_id); 14676 14677 return; 14678 } 14679 14680 if (pwwn_pd != NULL && did_pd == NULL) { 14681 uint32_t old_d_id; 14682 uint32_t d_id = page->aff_d_id; 14683 14684 /* 14685 * What this means is there is a new D_ID for this 14686 * Port WWN. Take out the port device off D_ID 14687 * list and put it back with a new D_ID. Perform 14688 * PLOGI if already logged in. 14689 */ 14690 mutex_enter(&port->fp_mutex); 14691 mutex_enter(&pwwn_pd->pd_mutex); 14692 14693 old_d_id = pwwn_pd->pd_port_id.port_id; 14694 14695 fctl_delist_did_table(port, pwwn_pd); 14696 14697 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14698 (uint32_t)(uintptr_t)job->job_cb_arg; 14699 14700 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd, 14701 &d_id, NULL); 14702 fctl_enlist_did_table(port, pwwn_pd); 14703 14704 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;" 14705 " Case THREE, pd=%p," 14706 " state=%x", pwwn_pd, pwwn_pd->pd_state); 14707 14708 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14709 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14710 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14711 14712 mutex_exit(&pwwn_pd->pd_mutex); 14713 mutex_exit(&port->fp_mutex); 14714 14715 FP_TRACE(FP_NHEAD2(9, 0), 14716 "N_x Port with D_ID=%x, PWWN=%s has a new" 14717 " D_ID=%x now", old_d_id, ww_name, d_id); 14718 14719 rval = fp_port_login(port, page->aff_d_id, job, 14720 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14721 if (rval == FC_SUCCESS) { 14722 fp_jobwait(job); 14723 rval = job->job_result; 14724 } 14725 14726 if (rval != FC_SUCCESS) { 14727 fp_fillout_old_map(listptr + 14728 *listindex - 1, pwwn_pd, 0); 14729 } 14730 } else { 14731 mutex_exit(&pwwn_pd->pd_mutex); 14732 mutex_exit(&port->fp_mutex); 14733 } 14734 14735 return; 14736 } 14737 14738 if (pwwn_pd == NULL && did_pd != NULL) { 14739 fc_portmap_t *ptr; 14740 uint32_t len = 1; 14741 char old_ww_name[17]; 14742 14743 mutex_enter(&did_pd->pd_mutex); 14744 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name); 14745 mutex_exit(&did_pd->pd_mutex); 14746 14747 fc_wwn_to_str(pwwn, ww_name); 14748 14749 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14750 (uint32_t)(uintptr_t)job->job_cb_arg; 14751 14752 /* 14753 * What this means is that there is a new Port WWN for 14754 * this D_ID; Mark the Port device as old and provide 14755 * the new PWWN and D_ID combination as new. 14756 */ 14757 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14758 14759 FP_TRACE(FP_NHEAD2(9, 0), 14760 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now", 14761 page->aff_d_id, old_ww_name, ww_name); 14762 14763 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14764 (uint32_t)(uintptr_t)job->job_cb_arg; 14765 14766 ptr = listptr + (*listindex)++; 14767 14768 job->job_counter = 1; 14769 14770 if (fp_ns_getmap(port, job, &ptr, &len, 14771 page->aff_d_id - 1) != FC_SUCCESS) { 14772 (*listindex)--; 14773 } 14774 14775 mutex_enter(&did_pd->pd_mutex); 14776 did_pd->pd_flags = PD_IDLE; 14777 mutex_exit(&did_pd->pd_mutex); 14778 14779 return; 14780 } 14781 14782 /* 14783 * A weird case of Port WWN and D_ID existence but not matching up 14784 * between them. Trust your instincts - Take the port device handle 14785 * off Port WWN list, fix it with new Port WWN and put it back, In 14786 * the mean time mark the port device corresponding to the old port 14787 * WWN as OLD. 14788 */ 14789 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p," 14790 " did_pd=%p", pwwn_pd, did_pd); 14791 14792 mutex_enter(&port->fp_mutex); 14793 mutex_enter(&pwwn_pd->pd_mutex); 14794 14795 pwwn_pd->pd_type = PORT_DEVICE_OLD; 14796 pwwn_pd->pd_state = PORT_DEVICE_INVALID; 14797 fctl_delist_did_table(port, pwwn_pd); 14798 fctl_delist_pwwn_table(port, pwwn_pd); 14799 14800 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14801 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x", 14802 pwwn_pd->pd_port_id.port_id, 14803 14804 pwwn_pd->pd_port_name.raw_wwn[0], 14805 pwwn_pd->pd_port_name.raw_wwn[1], 14806 pwwn_pd->pd_port_name.raw_wwn[2], 14807 pwwn_pd->pd_port_name.raw_wwn[3], 14808 pwwn_pd->pd_port_name.raw_wwn[4], 14809 pwwn_pd->pd_port_name.raw_wwn[5], 14810 pwwn_pd->pd_port_name.raw_wwn[6], 14811 pwwn_pd->pd_port_name.raw_wwn[7]); 14812 14813 mutex_exit(&pwwn_pd->pd_mutex); 14814 mutex_exit(&port->fp_mutex); 14815 14816 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14817 (uint32_t)(uintptr_t)job->job_cb_arg; 14818 14819 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14820 14821 mutex_enter(&port->fp_mutex); 14822 mutex_enter(&did_pd->pd_mutex); 14823 14824 fctl_delist_pwwn_table(port, did_pd); 14825 14826 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14827 (uint32_t)(uintptr_t)job->job_cb_arg; 14828 14829 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn); 14830 fctl_enlist_pwwn_table(port, did_pd); 14831 14832 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14833 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x", 14834 did_pd->pd_port_id.port_id, did_pd->pd_state, 14835 14836 did_pd->pd_port_name.raw_wwn[0], 14837 did_pd->pd_port_name.raw_wwn[1], 14838 did_pd->pd_port_name.raw_wwn[2], 14839 did_pd->pd_port_name.raw_wwn[3], 14840 did_pd->pd_port_name.raw_wwn[4], 14841 did_pd->pd_port_name.raw_wwn[5], 14842 did_pd->pd_port_name.raw_wwn[6], 14843 did_pd->pd_port_name.raw_wwn[7]); 14844 14845 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14846 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14847 mutex_exit(&did_pd->pd_mutex); 14848 mutex_exit(&port->fp_mutex); 14849 14850 rval = fp_port_login(port, page->aff_d_id, job, 14851 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL); 14852 if (rval == FC_SUCCESS) { 14853 fp_jobwait(job); 14854 if (job->job_result != FC_SUCCESS) { 14855 fp_fillout_old_map(listptr + 14856 *listindex - 1, did_pd, 0); 14857 } 14858 } else { 14859 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0); 14860 } 14861 } else { 14862 mutex_exit(&did_pd->pd_mutex); 14863 mutex_exit(&port->fp_mutex); 14864 } 14865 14866 mutex_enter(&did_pd->pd_mutex); 14867 did_pd->pd_flags = PD_IDLE; 14868 mutex_exit(&did_pd->pd_mutex); 14869 } 14870 14871 14872 /* 14873 * Check with NS for the presence of this port WWN 14874 */ 14875 static int 14876 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd, 14877 job_request_t *job, int polled, int sleep) 14878 { 14879 la_wwn_t pwwn; 14880 uint32_t flags; 14881 fctl_ns_req_t *ns_cmd; 14882 14883 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST); 14884 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14885 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14886 flags, sleep); 14887 if (ns_cmd == NULL) { 14888 return (FC_NOMEM); 14889 } 14890 14891 mutex_enter(&pd->pd_mutex); 14892 pwwn = pd->pd_port_name; 14893 mutex_exit(&pd->pd_mutex); 14894 14895 ns_cmd->ns_cmd_code = NS_GID_PN; 14896 ns_cmd->ns_pd = pd; 14897 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn; 14898 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14899 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14900 14901 return (fp_ns_query(port, ns_cmd, job, polled, sleep)); 14902 } 14903 14904 14905 /* 14906 * Sanity check the LILP map returned by FCA 14907 */ 14908 static int 14909 fp_validate_lilp_map(fc_lilpmap_t *lilp_map) 14910 { 14911 int count; 14912 14913 if (lilp_map->lilp_length == 0) { 14914 return (FC_FAILURE); 14915 } 14916 14917 for (count = 0; count < lilp_map->lilp_length; count++) { 14918 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) != 14919 FC_SUCCESS) { 14920 return (FC_FAILURE); 14921 } 14922 } 14923 14924 return (FC_SUCCESS); 14925 } 14926 14927 14928 /* 14929 * Sanity check if the AL_PA is a valid address 14930 */ 14931 static int 14932 fp_is_valid_alpa(uchar_t al_pa) 14933 { 14934 int count; 14935 14936 for (count = 0; count < sizeof (fp_valid_alpas); count++) { 14937 if (al_pa == fp_valid_alpas[count] || al_pa == 0) { 14938 return (FC_SUCCESS); 14939 } 14940 } 14941 14942 return (FC_FAILURE); 14943 } 14944 14945 14946 /* 14947 * Post unsolicited callbacks to ULPs 14948 */ 14949 static void 14950 fp_ulp_unsol_cb(void *arg) 14951 { 14952 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg; 14953 14954 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf, 14955 ub_spec->buf->ub_frame.type); 14956 kmem_free(ub_spec, sizeof (*ub_spec)); 14957 } 14958 14959 14960 /* 14961 * Perform message reporting in a consistent manner. Unless there is 14962 * a strong reason NOT to use this function (which is very very rare) 14963 * all message reporting should go through this. 14964 */ 14965 static void 14966 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno, 14967 fc_packet_t *pkt, const char *fmt, ...) 14968 { 14969 caddr_t buf; 14970 va_list ap; 14971 14972 switch (level) { 14973 case CE_NOTE: 14974 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) { 14975 return; 14976 } 14977 break; 14978 14979 case CE_WARN: 14980 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) { 14981 return; 14982 } 14983 break; 14984 } 14985 14986 buf = kmem_zalloc(256, KM_NOSLEEP); 14987 if (buf == NULL) { 14988 return; 14989 } 14990 14991 (void) sprintf(buf, "fp(%d): ", port->fp_instance); 14992 14993 va_start(ap, fmt); 14994 (void) vsprintf(buf + strlen(buf), fmt, ap); 14995 va_end(ap); 14996 14997 if (fc_errno) { 14998 char *errmsg; 14999 15000 (void) fc_ulp_error(fc_errno, &errmsg); 15001 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg); 15002 } else { 15003 if (pkt) { 15004 caddr_t state, reason, action, expln; 15005 15006 (void) fc_ulp_pkt_error(pkt, &state, &reason, 15007 &action, &expln); 15008 15009 (void) sprintf(buf + strlen(buf), 15010 " state=%s, reason=%s", state, reason); 15011 15012 if (pkt->pkt_resp_resid) { 15013 (void) sprintf(buf + strlen(buf), 15014 " resp resid=%x\n", pkt->pkt_resp_resid); 15015 } 15016 } 15017 } 15018 15019 switch (dest) { 15020 case FP_CONSOLE_ONLY: 15021 cmn_err(level, "^%s", buf); 15022 break; 15023 15024 case FP_LOG_ONLY: 15025 cmn_err(level, "!%s", buf); 15026 break; 15027 15028 default: 15029 cmn_err(level, "%s", buf); 15030 break; 15031 } 15032 15033 kmem_free(buf, 256); 15034 } 15035 15036 static int 15037 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 15038 { 15039 int ret; 15040 uint32_t d_id; 15041 la_wwn_t pwwn; 15042 fc_remote_port_t *pd = NULL; 15043 fc_remote_port_t *held_pd = NULL; 15044 fctl_ns_req_t *ns_cmd; 15045 fc_portmap_t *changelist; 15046 15047 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 15048 15049 mutex_enter(&port->fp_mutex); 15050 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 15051 mutex_exit(&port->fp_mutex); 15052 job->job_counter = 1; 15053 15054 job->job_result = FC_SUCCESS; 15055 15056 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 15057 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 15058 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 15059 15060 ASSERT(ns_cmd != NULL); 15061 15062 ns_cmd->ns_cmd_code = NS_GID_PN; 15063 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn; 15064 15065 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 15066 15067 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 15068 if (ret != FC_SUCCESS) { 15069 fcio->fcio_errno = ret; 15070 } else { 15071 fcio->fcio_errno = job->job_result; 15072 } 15073 fctl_free_ns_cmd(ns_cmd); 15074 return (EIO); 15075 } 15076 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 15077 fctl_free_ns_cmd(ns_cmd); 15078 } else { 15079 mutex_exit(&port->fp_mutex); 15080 15081 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15082 if (held_pd == NULL) { 15083 fcio->fcio_errno = FC_BADWWN; 15084 return (EIO); 15085 } 15086 pd = held_pd; 15087 15088 mutex_enter(&pd->pd_mutex); 15089 d_id = pd->pd_port_id.port_id; 15090 mutex_exit(&pd->pd_mutex); 15091 } 15092 15093 job->job_counter = 1; 15094 15095 pd = fctl_get_remote_port_by_did(port, d_id); 15096 15097 if (pd) { 15098 mutex_enter(&pd->pd_mutex); 15099 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 15100 pd->pd_login_count++; 15101 mutex_exit(&pd->pd_mutex); 15102 15103 fcio->fcio_errno = FC_SUCCESS; 15104 if (held_pd) { 15105 fctl_release_remote_port(held_pd); 15106 } 15107 15108 return (0); 15109 } 15110 mutex_exit(&pd->pd_mutex); 15111 } else { 15112 mutex_enter(&port->fp_mutex); 15113 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 15114 mutex_exit(&port->fp_mutex); 15115 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 15116 if (pd == NULL) { 15117 fcio->fcio_errno = FC_FAILURE; 15118 if (held_pd) { 15119 fctl_release_remote_port(held_pd); 15120 } 15121 return (EIO); 15122 } 15123 } else { 15124 mutex_exit(&port->fp_mutex); 15125 } 15126 } 15127 15128 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 15129 job->job_counter = 1; 15130 15131 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN, 15132 KM_SLEEP, pd, NULL); 15133 15134 if (ret != FC_SUCCESS) { 15135 fcio->fcio_errno = ret; 15136 if (held_pd) { 15137 fctl_release_remote_port(held_pd); 15138 } 15139 return (EIO); 15140 } 15141 fp_jobwait(job); 15142 15143 fcio->fcio_errno = job->job_result; 15144 15145 if (held_pd) { 15146 fctl_release_remote_port(held_pd); 15147 } 15148 15149 if (job->job_result != FC_SUCCESS) { 15150 return (EIO); 15151 } 15152 15153 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15154 if (pd == NULL) { 15155 fcio->fcio_errno = FC_BADDEV; 15156 return (ENODEV); 15157 } 15158 15159 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15160 15161 fctl_copy_portmap(changelist, pd); 15162 changelist->map_type = PORT_DEVICE_USER_LOGIN; 15163 15164 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15165 15166 mutex_enter(&pd->pd_mutex); 15167 pd->pd_type = PORT_DEVICE_NOCHANGE; 15168 mutex_exit(&pd->pd_mutex); 15169 15170 fctl_release_remote_port(pd); 15171 15172 return (0); 15173 } 15174 15175 15176 static int 15177 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 15178 { 15179 la_wwn_t pwwn; 15180 fp_cmd_t *cmd; 15181 fc_portmap_t *changelist; 15182 fc_remote_port_t *pd; 15183 15184 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 15185 15186 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15187 if (pd == NULL) { 15188 fcio->fcio_errno = FC_BADWWN; 15189 return (ENXIO); 15190 } 15191 15192 mutex_enter(&pd->pd_mutex); 15193 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 15194 fcio->fcio_errno = FC_LOGINREQ; 15195 mutex_exit(&pd->pd_mutex); 15196 15197 fctl_release_remote_port(pd); 15198 15199 return (EINVAL); 15200 } 15201 15202 ASSERT(pd->pd_login_count >= 1); 15203 15204 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 15205 fcio->fcio_errno = FC_FAILURE; 15206 mutex_exit(&pd->pd_mutex); 15207 15208 fctl_release_remote_port(pd); 15209 15210 return (EBUSY); 15211 } 15212 15213 if (pd->pd_login_count > 1) { 15214 pd->pd_login_count--; 15215 fcio->fcio_errno = FC_SUCCESS; 15216 mutex_exit(&pd->pd_mutex); 15217 15218 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15219 15220 fctl_copy_portmap(changelist, pd); 15221 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15222 15223 fctl_release_remote_port(pd); 15224 15225 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15226 15227 return (0); 15228 } 15229 15230 pd->pd_flags = PD_ELS_IN_PROGRESS; 15231 mutex_exit(&pd->pd_mutex); 15232 15233 job->job_counter = 1; 15234 15235 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 15236 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 15237 if (cmd == NULL) { 15238 fcio->fcio_errno = FC_NOMEM; 15239 fctl_release_remote_port(pd); 15240 15241 mutex_enter(&pd->pd_mutex); 15242 pd->pd_flags = PD_IDLE; 15243 mutex_exit(&pd->pd_mutex); 15244 15245 return (ENOMEM); 15246 } 15247 15248 mutex_enter(&port->fp_mutex); 15249 mutex_enter(&pd->pd_mutex); 15250 15251 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 15252 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 15253 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 15254 cmd->cmd_retry_count = 1; 15255 cmd->cmd_ulp_pkt = NULL; 15256 15257 fp_logo_init(pd, cmd, job); 15258 15259 mutex_exit(&pd->pd_mutex); 15260 mutex_exit(&port->fp_mutex); 15261 15262 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 15263 mutex_enter(&pd->pd_mutex); 15264 pd->pd_flags = PD_IDLE; 15265 mutex_exit(&pd->pd_mutex); 15266 15267 fp_free_pkt(cmd); 15268 fctl_release_remote_port(pd); 15269 15270 return (EIO); 15271 } 15272 15273 fp_jobwait(job); 15274 15275 fcio->fcio_errno = job->job_result; 15276 if (job->job_result != FC_SUCCESS) { 15277 mutex_enter(&pd->pd_mutex); 15278 pd->pd_flags = PD_IDLE; 15279 mutex_exit(&pd->pd_mutex); 15280 15281 fctl_release_remote_port(pd); 15282 15283 return (EIO); 15284 } 15285 15286 ASSERT(pd != NULL); 15287 15288 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15289 15290 fctl_copy_portmap(changelist, pd); 15291 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15292 changelist->map_state = PORT_DEVICE_INVALID; 15293 15294 mutex_enter(&port->fp_mutex); 15295 mutex_enter(&pd->pd_mutex); 15296 15297 fctl_delist_did_table(port, pd); 15298 fctl_delist_pwwn_table(port, pd); 15299 pd->pd_flags = PD_IDLE; 15300 15301 mutex_exit(&pd->pd_mutex); 15302 mutex_exit(&port->fp_mutex); 15303 15304 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15305 15306 fctl_release_remote_port(pd); 15307 15308 return (0); 15309 } 15310 15311 15312 15313 /* 15314 * Send a syslog event for adapter port level events. 15315 */ 15316 static void 15317 fp_log_port_event(fc_local_port_t *port, char *subclass) 15318 { 15319 nvlist_t *attr_list; 15320 15321 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15322 KM_SLEEP) != DDI_SUCCESS) { 15323 goto alloc_failed; 15324 } 15325 15326 if (nvlist_add_uint32(attr_list, "instance", 15327 port->fp_instance) != DDI_SUCCESS) { 15328 goto error; 15329 } 15330 15331 if (nvlist_add_byte_array(attr_list, "port-wwn", 15332 port->fp_service_params.nport_ww_name.raw_wwn, 15333 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15334 goto error; 15335 } 15336 15337 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15338 subclass, attr_list, NULL, DDI_SLEEP); 15339 15340 nvlist_free(attr_list); 15341 return; 15342 15343 error: 15344 nvlist_free(attr_list); 15345 alloc_failed: 15346 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15347 } 15348 15349 15350 static void 15351 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn, 15352 uint32_t port_id) 15353 { 15354 nvlist_t *attr_list; 15355 15356 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15357 KM_SLEEP) != DDI_SUCCESS) { 15358 goto alloc_failed; 15359 } 15360 15361 if (nvlist_add_uint32(attr_list, "instance", 15362 port->fp_instance) != DDI_SUCCESS) { 15363 goto error; 15364 } 15365 15366 if (nvlist_add_byte_array(attr_list, "port-wwn", 15367 port->fp_service_params.nport_ww_name.raw_wwn, 15368 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15369 goto error; 15370 } 15371 15372 if (nvlist_add_byte_array(attr_list, "target-port-wwn", 15373 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) { 15374 goto error; 15375 } 15376 15377 if (nvlist_add_uint32(attr_list, "target-port-id", 15378 port_id) != DDI_SUCCESS) { 15379 goto error; 15380 } 15381 15382 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15383 subclass, attr_list, NULL, DDI_SLEEP); 15384 15385 nvlist_free(attr_list); 15386 return; 15387 15388 error: 15389 nvlist_free(attr_list); 15390 alloc_failed: 15391 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15392 } 15393 15394 static uint32_t 15395 fp_map_remote_port_state(uint32_t rm_state) 15396 { 15397 switch (rm_state) { 15398 case PORT_DEVICE_LOGGED_IN: 15399 return (FC_HBA_PORTSTATE_ONLINE); 15400 case PORT_DEVICE_VALID: 15401 case PORT_DEVICE_INVALID: 15402 default: 15403 return (FC_HBA_PORTSTATE_UNKNOWN); 15404 } 15405 } 15406