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 } /* NULL terminated list of */ 111 }; 112 113 114 115 static uint16_t ns_reg_cmds[] = { 116 NS_RPN_ID, 117 NS_RNN_ID, 118 NS_RCS_ID, 119 NS_RFT_ID, 120 NS_RPT_ID, 121 NS_RSPN_ID, 122 NS_RSNN_NN 123 }; 124 125 struct fp_xlat { 126 uchar_t xlat_state; 127 int xlat_rval; 128 } fp_xlat [] = { 129 { FC_PKT_SUCCESS, FC_SUCCESS }, 130 { FC_PKT_REMOTE_STOP, FC_FAILURE }, 131 { FC_PKT_LOCAL_RJT, FC_FAILURE }, 132 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT }, 133 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT }, 134 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY }, 135 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY }, 136 { FC_PKT_NPORT_BSY, FC_PBUSY }, 137 { FC_PKT_FABRIC_BSY, FC_FBUSY }, 138 { FC_PKT_LS_RJT, FC_FAILURE }, 139 { FC_PKT_BA_RJT, FC_FAILURE }, 140 { FC_PKT_TIMEOUT, FC_FAILURE }, 141 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR }, 142 { FC_PKT_FAILURE, FC_FAILURE }, 143 { FC_PKT_PORT_OFFLINE, FC_OFFLINE } 144 }; 145 146 static uchar_t fp_valid_alpas[] = { 147 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 148 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 149 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 150 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 151 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 152 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 153 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, 154 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82, 155 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E, 156 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC, 157 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 158 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 159 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 160 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF 161 }; 162 163 static struct fp_perms { 164 uint16_t fp_ioctl_cmd; 165 uchar_t fp_open_flag; 166 } fp_perm_list [] = { 167 { FCIO_GET_NUM_DEVS, FP_OPEN }, 168 { FCIO_GET_DEV_LIST, FP_OPEN }, 169 { FCIO_GET_SYM_PNAME, FP_OPEN }, 170 { FCIO_GET_SYM_NNAME, FP_OPEN }, 171 { FCIO_SET_SYM_PNAME, FP_EXCL }, 172 { FCIO_SET_SYM_NNAME, FP_EXCL }, 173 { FCIO_GET_LOGI_PARAMS, FP_OPEN }, 174 { FCIO_DEV_LOGIN, FP_EXCL }, 175 { FCIO_DEV_LOGOUT, FP_EXCL }, 176 { FCIO_GET_STATE, FP_OPEN }, 177 { FCIO_DEV_REMOVE, FP_EXCL }, 178 { FCIO_GET_FCODE_REV, FP_OPEN }, 179 { FCIO_GET_FW_REV, FP_OPEN }, 180 { FCIO_GET_DUMP_SIZE, FP_OPEN }, 181 { FCIO_FORCE_DUMP, FP_EXCL }, 182 { FCIO_GET_DUMP, FP_OPEN }, 183 { FCIO_GET_TOPOLOGY, FP_OPEN }, 184 { FCIO_RESET_LINK, FP_EXCL }, 185 { FCIO_RESET_HARD, FP_EXCL }, 186 { FCIO_RESET_HARD_CORE, FP_EXCL }, 187 { FCIO_DIAG, FP_OPEN }, 188 { FCIO_NS, FP_EXCL }, 189 { FCIO_DOWNLOAD_FW, FP_EXCL }, 190 { FCIO_DOWNLOAD_FCODE, FP_EXCL }, 191 { FCIO_LINK_STATUS, FP_OPEN }, 192 { FCIO_GET_HOST_PARAMS, FP_OPEN }, 193 { FCIO_GET_NODE_ID, FP_OPEN }, 194 { FCIO_SET_NODE_ID, FP_EXCL }, 195 { FCIO_SEND_NODE_ID, FP_OPEN }, 196 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN }, 197 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN }, 198 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN }, 199 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN }, 200 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN }, 201 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN }, 202 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN }, 203 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN }, 204 { FCIO_DELETE_NPIV_PORT, FP_OPEN }, 205 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN }, 206 { FCIO_CREATE_NPIV_PORT, FP_OPEN }, 207 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN } 208 }; 209 210 static char *fp_pm_comps[] = { 211 "NAME=FC Port", 212 "0=Port Down", 213 "1=Port Up" 214 }; 215 216 217 #ifdef _LITTLE_ENDIAN 218 #define MAKE_BE_32(x) { \ 219 uint32_t *ptr1, i; \ 220 ptr1 = (uint32_t *)(x); \ 221 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \ 222 *ptr1 = BE_32(*ptr1); \ 223 ptr1++; \ 224 } \ 225 } 226 #else 227 #define MAKE_BE_32(x) 228 #endif 229 230 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES); 231 static uint32_t fp_options = 0; 232 233 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY; 234 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */ 235 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */ 236 unsigned int fp_offline_ticker; /* seconds */ 237 238 /* 239 * Driver global variable to anchor the list of soft state structs for 240 * all fp driver instances. Used with the Solaris DDI soft state functions. 241 */ 242 static void *fp_driver_softstate; 243 244 static clock_t fp_retry_ticks; 245 static clock_t fp_offline_ticks; 246 247 static int fp_retry_ticker; 248 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT; 249 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE; 250 251 static int fp_log_size = FP_LOG_SIZE; 252 static int fp_trace = FP_TRACE_DEFAULT; 253 static fc_trace_logq_t *fp_logq = NULL; 254 255 int fp_get_adapter_paths(char *pathList, int count); 256 static void fp_log_port_event(fc_local_port_t *port, char *subclass); 257 static void fp_log_target_event(fc_local_port_t *port, char *subclass, 258 la_wwn_t tgt_pwwn, uint32_t port_id); 259 static uint32_t fp_map_remote_port_state(uint32_t rm_state); 260 static void fp_init_symbolic_names(fc_local_port_t *port); 261 262 263 /* 264 * Perform global initialization 265 */ 266 int 267 _init(void) 268 { 269 int ret; 270 271 if ((ret = ddi_soft_state_init(&fp_driver_softstate, 272 sizeof (struct fc_local_port), 8)) != 0) { 273 return (ret); 274 } 275 276 if ((ret = scsi_hba_init(&modlinkage)) != 0) { 277 ddi_soft_state_fini(&fp_driver_softstate); 278 return (ret); 279 } 280 281 fp_logq = fc_trace_alloc_logq(fp_log_size); 282 283 if ((ret = mod_install(&modlinkage)) != 0) { 284 fc_trace_free_logq(fp_logq); 285 ddi_soft_state_fini(&fp_driver_softstate); 286 scsi_hba_fini(&modlinkage); 287 } 288 289 return (ret); 290 } 291 292 293 /* 294 * Prepare for driver unload 295 */ 296 int 297 _fini(void) 298 { 299 int ret; 300 301 if ((ret = mod_remove(&modlinkage)) == 0) { 302 fc_trace_free_logq(fp_logq); 303 ddi_soft_state_fini(&fp_driver_softstate); 304 scsi_hba_fini(&modlinkage); 305 } 306 307 return (ret); 308 } 309 310 311 /* 312 * Request mod_info() to handle all cases 313 */ 314 int 315 _info(struct modinfo *modinfo) 316 { 317 return (mod_info(&modlinkage, modinfo)); 318 } 319 320 321 /* 322 * fp_attach: 323 * 324 * The respective cmd handlers take care of performing 325 * ULP related invocations 326 */ 327 static int 328 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 329 { 330 int rval; 331 332 /* 333 * We check the value of fp_offline_ticker at this 334 * point. The variable is global for the driver and 335 * not specific to an instance. 336 * 337 * If there is no user-defined value found in /etc/system 338 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER). 339 * The minimum setting for this offline timeout according 340 * to the FC-FS2 standard (Fibre Channel Framing and 341 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec. 342 * 343 * We do not recommend setting the value to less than 10 344 * seconds (RA_TOV) or more than 90 seconds. If this 345 * variable is greater than 90 seconds then drivers above 346 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain. 347 */ 348 349 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY, 350 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker", 351 FP_OFFLINE_TICKER); 352 353 if ((fp_offline_ticker < 10) || 354 (fp_offline_ticker > 90)) { 355 cmn_err(CE_WARN, "Setting fp_offline_ticker to " 356 "%d second(s). This is outside the " 357 "recommended range of 10..90 seconds", 358 fp_offline_ticker); 359 } 360 361 /* 362 * Tick every second when there are commands to retry. 363 * It should tick at the least granular value of pkt_timeout 364 * (which is one second) 365 */ 366 fp_retry_ticker = 1; 367 368 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000); 369 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000); 370 371 switch (cmd) { 372 case DDI_ATTACH: 373 rval = fp_attach_handler(dip); 374 break; 375 376 case DDI_RESUME: 377 rval = fp_resume_handler(dip); 378 break; 379 380 default: 381 rval = DDI_FAILURE; 382 break; 383 } 384 return (rval); 385 } 386 387 388 /* 389 * fp_detach: 390 * 391 * If a ULP fails to handle cmd request converse of 392 * cmd is invoked for ULPs that previously succeeded 393 * cmd request. 394 */ 395 static int 396 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 397 { 398 int rval = DDI_FAILURE; 399 fc_local_port_t *port; 400 fc_attach_cmd_t converse; 401 uint8_t cnt; 402 403 if ((port = ddi_get_soft_state(fp_driver_softstate, 404 ddi_get_instance(dip))) == NULL) { 405 return (DDI_FAILURE); 406 } 407 408 mutex_enter(&port->fp_mutex); 409 410 if (port->fp_ulp_attach) { 411 mutex_exit(&port->fp_mutex); 412 return (DDI_FAILURE); 413 } 414 415 switch (cmd) { 416 case DDI_DETACH: 417 if (port->fp_task != FP_TASK_IDLE) { 418 mutex_exit(&port->fp_mutex); 419 return (DDI_FAILURE); 420 } 421 422 /* Let's attempt to quit the job handler gracefully */ 423 port->fp_soft_state |= FP_DETACH_INPROGRESS; 424 425 mutex_exit(&port->fp_mutex); 426 converse = FC_CMD_ATTACH; 427 if (fctl_detach_ulps(port, FC_CMD_DETACH, 428 &modlinkage) != FC_SUCCESS) { 429 mutex_enter(&port->fp_mutex); 430 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 431 mutex_exit(&port->fp_mutex); 432 rval = DDI_FAILURE; 433 break; 434 } 435 436 mutex_enter(&port->fp_mutex); 437 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt); 438 cnt++) { 439 mutex_exit(&port->fp_mutex); 440 delay(drv_usectohz(1000000)); 441 mutex_enter(&port->fp_mutex); 442 } 443 444 if (port->fp_job_head) { 445 mutex_exit(&port->fp_mutex); 446 rval = DDI_FAILURE; 447 break; 448 } 449 mutex_exit(&port->fp_mutex); 450 451 rval = fp_detach_handler(port); 452 break; 453 454 case DDI_SUSPEND: 455 mutex_exit(&port->fp_mutex); 456 converse = FC_CMD_RESUME; 457 if (fctl_detach_ulps(port, FC_CMD_SUSPEND, 458 &modlinkage) != FC_SUCCESS) { 459 rval = DDI_FAILURE; 460 break; 461 } 462 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) { 463 (void) callb_generic_cpr(&port->fp_cpr_info, 464 CB_CODE_CPR_RESUME); 465 } 466 break; 467 468 default: 469 mutex_exit(&port->fp_mutex); 470 break; 471 } 472 473 /* 474 * Use softint to perform reattach. Mark fp_ulp_attach so we 475 * don't attempt to do this repeatedly on behalf of some persistent 476 * caller. 477 */ 478 if (rval != DDI_SUCCESS) { 479 mutex_enter(&port->fp_mutex); 480 port->fp_ulp_attach = 1; 481 482 /* 483 * If the port is in the low power mode then there is 484 * possibility that fca too could be in low power mode. 485 * Try to raise the power before calling attach ulps. 486 */ 487 488 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 489 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 490 mutex_exit(&port->fp_mutex); 491 (void) pm_raise_power(port->fp_port_dip, 492 FP_PM_COMPONENT, FP_PM_PORT_UP); 493 } else { 494 mutex_exit(&port->fp_mutex); 495 } 496 497 498 fp_attach_ulps(port, converse); 499 500 mutex_enter(&port->fp_mutex); 501 while (port->fp_ulp_attach) { 502 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 503 } 504 505 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 506 507 /* 508 * Mark state as detach failed so asynchronous ULP attach 509 * events (downstream, not the ones we're initiating with 510 * the call to fp_attach_ulps) are not honored. We're 511 * really still in pending detach. 512 */ 513 port->fp_soft_state |= FP_DETACH_FAILED; 514 515 mutex_exit(&port->fp_mutex); 516 } 517 518 return (rval); 519 } 520 521 522 /* 523 * fp_getinfo: 524 * Given the device number, return either the 525 * dev_info_t pointer or the instance number. 526 */ 527 528 /* ARGSUSED */ 529 static int 530 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 531 { 532 int rval; 533 minor_t instance; 534 fc_local_port_t *port; 535 536 rval = DDI_SUCCESS; 537 instance = getminor((dev_t)arg); 538 539 switch (cmd) { 540 case DDI_INFO_DEVT2DEVINFO: 541 if ((port = ddi_get_soft_state(fp_driver_softstate, 542 instance)) == NULL) { 543 rval = DDI_FAILURE; 544 break; 545 } 546 *result = (void *)port->fp_port_dip; 547 break; 548 549 case DDI_INFO_DEVT2INSTANCE: 550 *result = (void *)(uintptr_t)instance; 551 break; 552 553 default: 554 rval = DDI_FAILURE; 555 break; 556 } 557 558 return (rval); 559 } 560 561 562 /* 563 * Entry point for power up and power down request from kernel 564 */ 565 static int 566 fp_power(dev_info_t *dip, int comp, int level) 567 { 568 int rval = DDI_FAILURE; 569 fc_local_port_t *port; 570 571 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 572 if (port == NULL || comp != FP_PM_COMPONENT) { 573 return (rval); 574 } 575 576 switch (level) { 577 case FP_PM_PORT_UP: 578 rval = DDI_SUCCESS; 579 580 /* 581 * If the port is DDI_SUSPENDed, let the DDI_RESUME 582 * code complete the rediscovery. 583 */ 584 mutex_enter(&port->fp_mutex); 585 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 586 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 587 port->fp_pm_level = FP_PM_PORT_UP; 588 mutex_exit(&port->fp_mutex); 589 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage); 590 break; 591 } 592 593 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 594 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 595 596 port->fp_pm_level = FP_PM_PORT_UP; 597 rval = fp_power_up(port); 598 if (rval != DDI_SUCCESS) { 599 port->fp_pm_level = FP_PM_PORT_DOWN; 600 } 601 } else { 602 port->fp_pm_level = FP_PM_PORT_UP; 603 } 604 mutex_exit(&port->fp_mutex); 605 break; 606 607 case FP_PM_PORT_DOWN: 608 mutex_enter(&port->fp_mutex); 609 610 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP)); 611 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 612 /* 613 * PM framework goofed up. We have don't 614 * have any PM components. Let's never go down. 615 */ 616 mutex_exit(&port->fp_mutex); 617 break; 618 619 } 620 621 if (port->fp_ulp_attach) { 622 /* We shouldn't let the power go down */ 623 mutex_exit(&port->fp_mutex); 624 break; 625 } 626 627 /* 628 * Not a whole lot to do if we are detaching 629 */ 630 if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 631 port->fp_pm_level = FP_PM_PORT_DOWN; 632 mutex_exit(&port->fp_mutex); 633 rval = DDI_SUCCESS; 634 break; 635 } 636 637 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) { 638 port->fp_pm_level = FP_PM_PORT_DOWN; 639 640 rval = fp_power_down(port); 641 if (rval != DDI_SUCCESS) { 642 port->fp_pm_level = FP_PM_PORT_UP; 643 ASSERT(!(port->fp_soft_state & 644 FP_SOFT_POWER_DOWN)); 645 } else { 646 ASSERT(port->fp_soft_state & 647 FP_SOFT_POWER_DOWN); 648 } 649 } 650 mutex_exit(&port->fp_mutex); 651 break; 652 653 default: 654 break; 655 } 656 657 return (rval); 658 } 659 660 661 /* 662 * Open FC port devctl node 663 */ 664 static int 665 fp_open(dev_t *devp, int flag, int otype, cred_t *credp) 666 { 667 int instance; 668 fc_local_port_t *port; 669 670 if (otype != OTYP_CHR) { 671 return (EINVAL); 672 } 673 674 /* 675 * This is not a toy to play with. Allow only powerful 676 * users (hopefully knowledgeable) to access the port 677 * (A hacker potentially could download a sick binary 678 * file into FCA) 679 */ 680 if (drv_priv(credp)) { 681 return (EPERM); 682 } 683 684 instance = (int)getminor(*devp); 685 686 port = ddi_get_soft_state(fp_driver_softstate, instance); 687 if (port == NULL) { 688 return (ENXIO); 689 } 690 691 mutex_enter(&port->fp_mutex); 692 if (port->fp_flag & FP_EXCL) { 693 /* 694 * It is already open for exclusive access. 695 * So shut the door on this caller. 696 */ 697 mutex_exit(&port->fp_mutex); 698 return (EBUSY); 699 } 700 701 if (flag & FEXCL) { 702 if (port->fp_flag & FP_OPEN) { 703 /* 704 * Exclusive operation not possible 705 * as it is already opened 706 */ 707 mutex_exit(&port->fp_mutex); 708 return (EBUSY); 709 } 710 port->fp_flag |= FP_EXCL; 711 } 712 port->fp_flag |= FP_OPEN; 713 mutex_exit(&port->fp_mutex); 714 715 return (0); 716 } 717 718 719 /* 720 * The driver close entry point is called on the last close() 721 * of a device. So it is perfectly alright to just clobber the 722 * open flag and reset it to idle (instead of having to reset 723 * each flag bits). For any confusion, check out close(9E). 724 */ 725 726 /* ARGSUSED */ 727 static int 728 fp_close(dev_t dev, int flag, int otype, cred_t *credp) 729 { 730 int instance; 731 fc_local_port_t *port; 732 733 if (otype != OTYP_CHR) { 734 return (EINVAL); 735 } 736 737 instance = (int)getminor(dev); 738 739 port = ddi_get_soft_state(fp_driver_softstate, instance); 740 if (port == NULL) { 741 return (ENXIO); 742 } 743 744 mutex_enter(&port->fp_mutex); 745 if ((port->fp_flag & FP_OPEN) == 0) { 746 mutex_exit(&port->fp_mutex); 747 return (ENODEV); 748 } 749 port->fp_flag = FP_IDLE; 750 mutex_exit(&port->fp_mutex); 751 752 return (0); 753 } 754 755 /* 756 * Handle IOCTL requests 757 */ 758 759 /* ARGSUSED */ 760 static int 761 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval) 762 { 763 int instance; 764 int ret = 0; 765 fcio_t fcio; 766 fc_local_port_t *port; 767 768 instance = (int)getminor(dev); 769 770 port = ddi_get_soft_state(fp_driver_softstate, instance); 771 if (port == NULL) { 772 return (ENXIO); 773 } 774 775 mutex_enter(&port->fp_mutex); 776 if ((port->fp_flag & FP_OPEN) == 0) { 777 mutex_exit(&port->fp_mutex); 778 return (ENXIO); 779 } 780 781 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 782 mutex_exit(&port->fp_mutex); 783 return (ENXIO); 784 } 785 786 mutex_exit(&port->fp_mutex); 787 788 /* this will raise power if necessary */ 789 ret = fctl_busy_port(port); 790 if (ret != 0) { 791 return (ret); 792 } 793 794 ASSERT(port->fp_pm_level == FP_PM_PORT_UP); 795 796 797 switch (cmd) { 798 case FCIO_CMD: { 799 #ifdef _MULTI_DATAMODEL 800 switch (ddi_model_convert_from(mode & FMODELS)) { 801 case DDI_MODEL_ILP32: { 802 struct fcio32 fcio32; 803 804 if (ddi_copyin((void *)data, (void *)&fcio32, 805 sizeof (struct fcio32), mode)) { 806 ret = EFAULT; 807 break; 808 } 809 fcio.fcio_xfer = fcio32.fcio_xfer; 810 fcio.fcio_cmd = fcio32.fcio_cmd; 811 fcio.fcio_flags = fcio32.fcio_flags; 812 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags; 813 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen; 814 fcio.fcio_ibuf = 815 (caddr_t)(uintptr_t)fcio32.fcio_ibuf; 816 fcio.fcio_olen = (size_t)fcio32.fcio_olen; 817 fcio.fcio_obuf = 818 (caddr_t)(uintptr_t)fcio32.fcio_obuf; 819 fcio.fcio_alen = (size_t)fcio32.fcio_alen; 820 fcio.fcio_abuf = 821 (caddr_t)(uintptr_t)fcio32.fcio_abuf; 822 fcio.fcio_errno = fcio32.fcio_errno; 823 break; 824 } 825 826 case DDI_MODEL_NONE: 827 if (ddi_copyin((void *)data, (void *)&fcio, 828 sizeof (fcio_t), mode)) { 829 ret = EFAULT; 830 } 831 break; 832 } 833 #else /* _MULTI_DATAMODEL */ 834 if (ddi_copyin((void *)data, (void *)&fcio, 835 sizeof (fcio_t), mode)) { 836 ret = EFAULT; 837 break; 838 } 839 #endif /* _MULTI_DATAMODEL */ 840 if (!ret) { 841 ret = fp_fciocmd(port, data, mode, &fcio); 842 } 843 break; 844 } 845 846 default: 847 ret = fctl_ulp_port_ioctl(port, dev, cmd, data, 848 mode, credp, rval); 849 } 850 851 fctl_idle_port(port); 852 853 return (ret); 854 } 855 856 857 /* 858 * Init Symbolic Port Name and Node Name 859 * LV will try to get symbolic names from FCA driver 860 * and register these to name server, 861 * if LV fails to get these, 862 * LV will register its default symbolic names to name server. 863 * The Default symbolic node name format is : 864 * <hostname>:<hba driver name>(instance) 865 * The Default symbolic port name format is : 866 * <fp path name> 867 */ 868 static void 869 fp_init_symbolic_names(fc_local_port_t *port) 870 { 871 const char *vendorname = ddi_driver_name(port->fp_fca_dip); 872 char *sym_name; 873 char fcaname[50] = {0}; 874 int hostnlen, fcanlen; 875 876 if (port->fp_sym_node_namelen == 0) { 877 hostnlen = strlen(utsname.nodename); 878 (void) snprintf(fcaname, sizeof (fcaname), 879 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip)); 880 fcanlen = strlen(fcaname); 881 882 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP); 883 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname); 884 port->fp_sym_node_namelen = strlen(sym_name); 885 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) { 886 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN; 887 } 888 (void) strncpy(port->fp_sym_node_name, sym_name, 889 port->fp_sym_node_namelen); 890 kmem_free(sym_name, hostnlen + fcanlen + 2); 891 } 892 893 if (port->fp_sym_port_namelen == 0) { 894 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 895 896 (void) ddi_pathname(port->fp_port_dip, pathname); 897 port->fp_sym_port_namelen = strlen(pathname); 898 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) { 899 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN; 900 } 901 (void) strncpy(port->fp_sym_port_name, pathname, 902 port->fp_sym_port_namelen); 903 kmem_free(pathname, MAXPATHLEN); 904 } 905 } 906 907 908 /* 909 * Perform port attach 910 */ 911 static int 912 fp_attach_handler(dev_info_t *dip) 913 { 914 int rval; 915 int instance; 916 int port_num; 917 int port_len; 918 char name[30]; 919 char i_pwwn[17]; 920 fp_cmd_t *pkt; 921 uint32_t ub_count; 922 fc_local_port_t *port; 923 job_request_t *job; 924 fc_local_port_t *phyport = NULL; 925 int portpro1; 926 char pwwn[17], nwwn[17]; 927 928 instance = ddi_get_instance(dip); 929 port_len = sizeof (port_num); 930 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 931 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 932 (caddr_t)&port_num, &port_len); 933 if (rval != DDI_SUCCESS) { 934 cmn_err(CE_WARN, "fp(%d): No port property in devinfo", 935 instance); 936 return (DDI_FAILURE); 937 } 938 939 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 940 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 941 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node", 942 instance); 943 return (DDI_FAILURE); 944 } 945 946 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance, 947 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 948 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment" 949 " point minor node", instance); 950 ddi_remove_minor_node(dip, NULL); 951 return (DDI_FAILURE); 952 } 953 954 if (ddi_soft_state_zalloc(fp_driver_softstate, instance) 955 != DDI_SUCCESS) { 956 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state", 957 instance); 958 ddi_remove_minor_node(dip, NULL); 959 return (DDI_FAILURE); 960 } 961 port = ddi_get_soft_state(fp_driver_softstate, instance); 962 963 (void) sprintf(port->fp_ibuf, "fp(%d)", instance); 964 965 port->fp_instance = instance; 966 port->fp_ulp_attach = 1; 967 port->fp_port_num = port_num; 968 port->fp_verbose = fp_verbosity; 969 port->fp_options = fp_options; 970 971 port->fp_fca_dip = ddi_get_parent(dip); 972 port->fp_port_dip = dip; 973 port->fp_fca_tran = (fc_fca_tran_t *) 974 ddi_get_driver_private(port->fp_fca_dip); 975 976 port->fp_task = port->fp_last_task = FP_TASK_IDLE; 977 978 /* 979 * Init the starting value of fp_rscn_count. Note that if 980 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the 981 * actual # of RSCNs will be (fp_rscn_count - 1) 982 */ 983 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1; 984 985 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL); 986 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL); 987 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL); 988 989 (void) sprintf(name, "fp%d_cache", instance); 990 991 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY, 992 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 993 "phyport-instance", -1)) != -1) { 994 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1); 995 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn); 996 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn); 997 port->fp_npiv_type = FC_NPIV_PORT; 998 } 999 1000 /* 1001 * Allocate the pool of fc_packet_t structs to be used with 1002 * this fp instance. 1003 */ 1004 port->fp_pkt_cache = kmem_cache_create(name, 1005 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8, 1006 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port, 1007 NULL, 0); 1008 port->fp_out_fpcmds = 0; 1009 if (port->fp_pkt_cache == NULL) { 1010 goto cache_alloc_failed; 1011 } 1012 1013 1014 /* 1015 * Allocate the d_id and pwwn hash tables for all remote ports 1016 * connected to this local port. 1017 */ 1018 port->fp_did_table = kmem_zalloc(did_table_size * 1019 sizeof (struct d_id_hash), KM_SLEEP); 1020 1021 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size * 1022 sizeof (struct pwwn_hash), KM_SLEEP); 1023 1024 port->fp_taskq = taskq_create("fp_ulp_callback", 1, 1025 MINCLSYSPRI, 1, 16, 0); 1026 1027 /* Indicate that don't have the pm components yet */ 1028 port->fp_soft_state |= FP_SOFT_NO_PMCOMP; 1029 1030 /* 1031 * Bind the callbacks with the FCA driver. This will open the gate 1032 * for asynchronous callbacks, so after this call the fp_mutex 1033 * must be held when updating the fc_local_port_t struct. 1034 * 1035 * This is done _before_ setting up the job thread so we can avoid 1036 * cleaning up after the thread_create() in the error path. This 1037 * also means fp will be operating with fp_els_resp_pkt set to NULL. 1038 */ 1039 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1040 goto bind_callbacks_failed; 1041 } 1042 1043 if (phyport) { 1044 mutex_enter(&phyport->fp_mutex); 1045 if (phyport->fp_port_next) { 1046 phyport->fp_port_next->fp_port_prev = port; 1047 port->fp_port_next = phyport->fp_port_next; 1048 phyport->fp_port_next = port; 1049 port->fp_port_prev = phyport; 1050 } else { 1051 phyport->fp_port_next = port; 1052 phyport->fp_port_prev = port; 1053 port->fp_port_next = phyport; 1054 port->fp_port_prev = phyport; 1055 } 1056 mutex_exit(&phyport->fp_mutex); 1057 } 1058 1059 /* 1060 * Init Symbolic Names 1061 */ 1062 fp_init_symbolic_names(port); 1063 1064 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t), 1065 KM_SLEEP, NULL); 1066 1067 if (pkt == NULL) { 1068 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet", 1069 instance); 1070 goto alloc_els_packet_failed; 1071 } 1072 1073 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN, 1074 v.v_maxsyspri - 2); 1075 1076 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn); 1077 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port", 1078 i_pwwn) != DDI_PROP_SUCCESS) { 1079 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1080 "fp(%d): Updating 'initiator-port' property" 1081 " on fp dev_info node failed", instance); 1082 } 1083 1084 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn); 1085 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node", 1086 i_pwwn) != DDI_PROP_SUCCESS) { 1087 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1088 "fp(%d): Updating 'initiator-node' property" 1089 " on fp dev_info node failed", instance); 1090 } 1091 1092 mutex_enter(&port->fp_mutex); 1093 port->fp_els_resp_pkt = pkt; 1094 mutex_exit(&port->fp_mutex); 1095 1096 /* 1097 * Determine the count of unsolicited buffers this FCA can support 1098 */ 1099 fp_retrieve_caps(port); 1100 1101 /* 1102 * Allocate unsolicited buffer tokens 1103 */ 1104 if (port->fp_ub_count) { 1105 ub_count = port->fp_ub_count; 1106 port->fp_ub_tokens = kmem_zalloc(ub_count * 1107 sizeof (*port->fp_ub_tokens), KM_SLEEP); 1108 /* 1109 * Do not fail the attach if unsolicited buffer allocation 1110 * fails; Just try to get along with whatever the FCA can do. 1111 */ 1112 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size, 1113 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) != 1114 FC_SUCCESS || ub_count != port->fp_ub_count) { 1115 cmn_err(CE_WARN, "fp(%d): failed to allocate " 1116 " Unsolicited buffers. proceeding with attach...", 1117 instance); 1118 kmem_free(port->fp_ub_tokens, 1119 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1120 port->fp_ub_tokens = NULL; 1121 } 1122 } 1123 1124 fp_load_ulp_modules(dip, port); 1125 1126 /* 1127 * Enable DDI_SUSPEND and DDI_RESUME for this instance. 1128 */ 1129 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 1130 "pm-hardware-state", "needs-suspend-resume", 1131 strlen("needs-suspend-resume") + 1); 1132 1133 /* 1134 * fctl maintains a list of all port handles, so 1135 * help fctl add this one to its list now. 1136 */ 1137 mutex_enter(&port->fp_mutex); 1138 fctl_add_port(port); 1139 1140 /* 1141 * If a state change is already in progress, set the bind state t 1142 * OFFLINE as well, so further state change callbacks into ULPs 1143 * will pass the appropriate states 1144 */ 1145 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE || 1146 port->fp_statec_busy) { 1147 port->fp_bind_state = FC_STATE_OFFLINE; 1148 mutex_exit(&port->fp_mutex); 1149 1150 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 1151 } else { 1152 /* 1153 * Without dropping the mutex, ensure that the port 1154 * startup happens ahead of state change callback 1155 * processing 1156 */ 1157 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL); 1158 1159 port->fp_last_task = port->fp_task; 1160 port->fp_task = FP_TASK_PORT_STARTUP; 1161 1162 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC, 1163 fp_startup_done, (opaque_t)port, KM_SLEEP); 1164 1165 port->fp_job_head = port->fp_job_tail = job; 1166 1167 cv_signal(&port->fp_cv); 1168 1169 mutex_exit(&port->fp_mutex); 1170 } 1171 1172 mutex_enter(&port->fp_mutex); 1173 while (port->fp_ulp_attach) { 1174 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 1175 } 1176 mutex_exit(&port->fp_mutex); 1177 1178 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1179 "pm-components", fp_pm_comps, 1180 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) != 1181 DDI_PROP_SUCCESS) { 1182 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM" 1183 " components property, PM disabled on this port."); 1184 mutex_enter(&port->fp_mutex); 1185 port->fp_pm_level = FP_PM_PORT_UP; 1186 mutex_exit(&port->fp_mutex); 1187 } else { 1188 if (pm_raise_power(dip, FP_PM_COMPONENT, 1189 FP_PM_PORT_UP) != DDI_SUCCESS) { 1190 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise" 1191 " power level"); 1192 mutex_enter(&port->fp_mutex); 1193 port->fp_pm_level = FP_PM_PORT_UP; 1194 mutex_exit(&port->fp_mutex); 1195 } 1196 1197 /* 1198 * Don't unset the FP_SOFT_NO_PMCOMP flag until after 1199 * the call to pm_raise_power. The PM framework can't 1200 * handle multiple threads calling into it during attach. 1201 */ 1202 1203 mutex_enter(&port->fp_mutex); 1204 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP; 1205 mutex_exit(&port->fp_mutex); 1206 } 1207 1208 ddi_report_dev(dip); 1209 1210 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH); 1211 1212 return (DDI_SUCCESS); 1213 1214 /* 1215 * Unwind any/all preceeding allocations in the event of an error. 1216 */ 1217 1218 alloc_els_packet_failed: 1219 1220 if (port->fp_fca_handle != NULL) { 1221 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1222 port->fp_fca_handle = NULL; 1223 } 1224 1225 if (port->fp_ub_tokens != NULL) { 1226 (void) fc_ulp_ubfree(port, port->fp_ub_count, 1227 port->fp_ub_tokens); 1228 kmem_free(port->fp_ub_tokens, 1229 port->fp_ub_count * sizeof (*port->fp_ub_tokens)); 1230 port->fp_ub_tokens = NULL; 1231 } 1232 1233 if (port->fp_els_resp_pkt != NULL) { 1234 fp_free_pkt(port->fp_els_resp_pkt); 1235 port->fp_els_resp_pkt = NULL; 1236 } 1237 1238 bind_callbacks_failed: 1239 1240 if (port->fp_taskq != NULL) { 1241 taskq_destroy(port->fp_taskq); 1242 } 1243 1244 if (port->fp_pwwn_table != NULL) { 1245 kmem_free(port->fp_pwwn_table, 1246 pwwn_table_size * sizeof (struct pwwn_hash)); 1247 port->fp_pwwn_table = NULL; 1248 } 1249 1250 if (port->fp_did_table != NULL) { 1251 kmem_free(port->fp_did_table, 1252 did_table_size * sizeof (struct d_id_hash)); 1253 port->fp_did_table = NULL; 1254 } 1255 1256 if (port->fp_pkt_cache != NULL) { 1257 kmem_cache_destroy(port->fp_pkt_cache); 1258 port->fp_pkt_cache = NULL; 1259 } 1260 1261 cache_alloc_failed: 1262 1263 cv_destroy(&port->fp_attach_cv); 1264 cv_destroy(&port->fp_cv); 1265 mutex_destroy(&port->fp_mutex); 1266 ddi_remove_minor_node(port->fp_port_dip, NULL); 1267 ddi_soft_state_free(fp_driver_softstate, instance); 1268 ddi_prop_remove_all(dip); 1269 1270 return (DDI_FAILURE); 1271 } 1272 1273 1274 /* 1275 * Handle DDI_RESUME request 1276 */ 1277 static int 1278 fp_resume_handler(dev_info_t *dip) 1279 { 1280 int rval; 1281 fc_local_port_t *port; 1282 1283 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 1284 1285 ASSERT(port != NULL); 1286 1287 #ifdef DEBUG 1288 mutex_enter(&port->fp_mutex); 1289 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND); 1290 mutex_exit(&port->fp_mutex); 1291 #endif 1292 1293 /* 1294 * If the port was power suspended, raise the power level 1295 */ 1296 mutex_enter(&port->fp_mutex); 1297 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 1298 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 1299 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 1300 1301 mutex_exit(&port->fp_mutex); 1302 if (pm_raise_power(dip, FP_PM_COMPONENT, 1303 FP_PM_PORT_UP) != DDI_SUCCESS) { 1304 FP_TRACE(FP_NHEAD2(9, 0), 1305 "Failed to raise the power level"); 1306 return (DDI_FAILURE); 1307 } 1308 mutex_enter(&port->fp_mutex); 1309 } 1310 port->fp_soft_state &= ~FP_SOFT_SUSPEND; 1311 mutex_exit(&port->fp_mutex); 1312 1313 /* 1314 * All the discovery is initiated and handled by per-port thread. 1315 * Further all the discovery is done in handled in callback mode 1316 * (not polled mode); In a specific case such as this, the discovery 1317 * is required to happen in polled mode. The easiest way out is 1318 * to bail out port thread and get started. Come back and fix this 1319 * to do on demand discovery initiated by ULPs. ULPs such as FCP 1320 * will do on-demand discovery during pre-power-up busctl handling 1321 * which will only be possible when SCSA provides a new HBA vector 1322 * for sending down the PM busctl requests. 1323 */ 1324 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME); 1325 1326 rval = fp_resume_all(port, FC_CMD_RESUME); 1327 if (rval != DDI_SUCCESS) { 1328 mutex_enter(&port->fp_mutex); 1329 port->fp_soft_state |= FP_SOFT_SUSPEND; 1330 mutex_exit(&port->fp_mutex); 1331 (void) callb_generic_cpr(&port->fp_cpr_info, 1332 CB_CODE_CPR_CHKPT); 1333 } 1334 1335 return (rval); 1336 } 1337 1338 /* 1339 * Perform FC Port power on initialization 1340 */ 1341 static int 1342 fp_power_up(fc_local_port_t *port) 1343 { 1344 int rval; 1345 1346 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1347 1348 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0); 1349 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN); 1350 1351 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1352 1353 mutex_exit(&port->fp_mutex); 1354 1355 rval = fp_resume_all(port, FC_CMD_POWER_UP); 1356 if (rval != DDI_SUCCESS) { 1357 mutex_enter(&port->fp_mutex); 1358 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1359 } else { 1360 mutex_enter(&port->fp_mutex); 1361 } 1362 1363 return (rval); 1364 } 1365 1366 1367 /* 1368 * It is important to note that the power may possibly be removed between 1369 * SUSPEND and the ensuing RESUME operation. In such a context the underlying 1370 * FC port hardware would have gone through an OFFLINE to ONLINE transition 1371 * (hardware state). In this case, the port driver may need to rediscover the 1372 * topology, perform LOGINs, register with the name server again and perform 1373 * any such port initialization procedures. To perform LOGINs, the driver could 1374 * use the port device handle to see if a LOGIN needs to be performed and use 1375 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured 1376 * or removed) which will be reflected in the map the ULPs will see. 1377 */ 1378 static int 1379 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd) 1380 { 1381 1382 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1383 1384 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1385 return (DDI_FAILURE); 1386 } 1387 1388 mutex_enter(&port->fp_mutex); 1389 1390 /* 1391 * If there are commands queued for delayed retry, instead of 1392 * working the hard way to figure out which ones are good for 1393 * restart and which ones not (ELSs are definitely not good 1394 * as the port will have to go through a new spin of rediscovery 1395 * now), so just flush them out. 1396 */ 1397 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) { 1398 fp_cmd_t *cmd; 1399 1400 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT; 1401 1402 mutex_exit(&port->fp_mutex); 1403 while ((cmd = fp_deque_cmd(port)) != NULL) { 1404 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 1405 fp_iodone(cmd); 1406 } 1407 mutex_enter(&port->fp_mutex); 1408 } 1409 1410 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) { 1411 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) || 1412 port->fp_dev_count) { 1413 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1414 port->fp_offline_tid = timeout(fp_offline_timeout, 1415 (caddr_t)port, fp_offline_ticks); 1416 } 1417 if (port->fp_job_head) { 1418 cv_signal(&port->fp_cv); 1419 } 1420 mutex_exit(&port->fp_mutex); 1421 fctl_attach_ulps(port, cmd, &modlinkage); 1422 } else { 1423 struct job_request *job; 1424 1425 /* 1426 * If an OFFLINE timer was running at the time of 1427 * suspending, there is no need to restart it as 1428 * the port is ONLINE now. 1429 */ 1430 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1431 if (port->fp_statec_busy == 0) { 1432 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 1433 } 1434 port->fp_statec_busy++; 1435 mutex_exit(&port->fp_mutex); 1436 1437 job = fctl_alloc_job(JOB_PORT_ONLINE, 1438 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP); 1439 fctl_enque_job(port, job); 1440 1441 fctl_jobwait(job); 1442 fctl_remove_oldies(port); 1443 1444 fctl_attach_ulps(port, cmd, &modlinkage); 1445 fctl_dealloc_job(job); 1446 } 1447 1448 return (DDI_SUCCESS); 1449 } 1450 1451 1452 /* 1453 * At this time, there shouldn't be any I/O requests on this port. 1454 * But the unsolicited callbacks from the underlying FCA port need 1455 * to be handled very carefully. The steps followed to handle the 1456 * DDI_DETACH are: 1457 * + Grab the port driver mutex, check if the unsolicited 1458 * callback is currently under processing. If true, fail 1459 * the DDI_DETACH request by printing a message; If false 1460 * mark the DDI_DETACH as under progress, so that any 1461 * further unsolicited callbacks get bounced. 1462 * + Perform PRLO/LOGO if necessary, cleanup all the data 1463 * structures. 1464 * + Get the job_handler thread to gracefully exit. 1465 * + Unregister callbacks with the FCA port. 1466 * + Now that some peace is found, notify all the ULPs of 1467 * DDI_DETACH request (using ulp_port_detach entry point) 1468 * + Free all mutexes, semaphores, conditional variables. 1469 * + Free the soft state, return success. 1470 * 1471 * Important considerations: 1472 * Port driver de-registers state change and unsolicited 1473 * callbacks before taking up the task of notifying ULPs 1474 * and performing PRLO and LOGOs. 1475 * 1476 * A port may go offline at the time PRLO/LOGO is being 1477 * requested. It is expected of all FCA drivers to fail 1478 * such requests either immediately with a FC_OFFLINE 1479 * return code to fc_fca_transport() or return the packet 1480 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE 1481 */ 1482 static int 1483 fp_detach_handler(fc_local_port_t *port) 1484 { 1485 job_request_t *job; 1486 uint32_t delay_count; 1487 fc_orphan_t *orp, *tmporp; 1488 1489 /* 1490 * In a Fabric topology with many host ports connected to 1491 * a switch, another detaching instance of fp might have 1492 * triggered a LOGO (which is an unsolicited request to 1493 * this instance). So in order to be able to successfully 1494 * detach by taking care of such cases a delay of about 1495 * 30 seconds is introduced. 1496 */ 1497 delay_count = 0; 1498 mutex_enter(&port->fp_mutex); 1499 if (port->fp_out_fpcmds != 0) { 1500 /* 1501 * At this time we can only check fp internal commands, because 1502 * sd/ssd/scsi_vhci should have finsihed all their commands, 1503 * fcp/fcip/fcsm should have finished all their commands. 1504 * 1505 * It seems that all fp internal commands are asynchronous now. 1506 */ 1507 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1508 mutex_exit(&port->fp_mutex); 1509 1510 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress" 1511 " Failing detach", port->fp_instance, port->fp_out_fpcmds); 1512 return (DDI_FAILURE); 1513 } 1514 1515 while ((port->fp_soft_state & 1516 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) && 1517 (delay_count < 30)) { 1518 mutex_exit(&port->fp_mutex); 1519 delay_count++; 1520 delay(drv_usectohz(1000000)); 1521 mutex_enter(&port->fp_mutex); 1522 } 1523 1524 if (port->fp_soft_state & 1525 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) { 1526 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1527 mutex_exit(&port->fp_mutex); 1528 1529 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1530 " Failing detach", port->fp_instance); 1531 return (DDI_FAILURE); 1532 } 1533 1534 port->fp_soft_state |= FP_SOFT_IN_DETACH; 1535 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1536 mutex_exit(&port->fp_mutex); 1537 1538 /* 1539 * If we're powered down, we need to raise power prior to submitting 1540 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never 1541 * process the shutdown job. 1542 */ 1543 if (fctl_busy_port(port) != 0) { 1544 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed", 1545 port->fp_instance); 1546 mutex_enter(&port->fp_mutex); 1547 port->fp_soft_state &= ~FP_SOFT_IN_DETACH; 1548 mutex_exit(&port->fp_mutex); 1549 return (DDI_FAILURE); 1550 } 1551 1552 /* 1553 * This will deallocate data structs and cause the "job" thread 1554 * to exit, in preparation for DDI_DETACH on the instance. 1555 * This can sleep for an arbitrary duration, since it waits for 1556 * commands over the wire, timeout(9F) callbacks, etc. 1557 * 1558 * CAUTION: There is still a race here, where the "job" thread 1559 * can still be executing code even tho the fctl_jobwait() call 1560 * below has returned to us. In theory the fp driver could even be 1561 * modunloaded even tho the job thread isn't done executing. 1562 * without creating the race condition. 1563 */ 1564 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL, 1565 (opaque_t)port, KM_SLEEP); 1566 fctl_enque_job(port, job); 1567 fctl_jobwait(job); 1568 fctl_dealloc_job(job); 1569 1570 1571 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT, 1572 FP_PM_PORT_DOWN); 1573 1574 if (port->fp_taskq) { 1575 taskq_destroy(port->fp_taskq); 1576 } 1577 1578 ddi_prop_remove_all(port->fp_port_dip); 1579 1580 ddi_remove_minor_node(port->fp_port_dip, NULL); 1581 1582 fctl_remove_port(port); 1583 1584 fp_free_pkt(port->fp_els_resp_pkt); 1585 1586 if (port->fp_ub_tokens) { 1587 if (fc_ulp_ubfree(port, port->fp_ub_count, 1588 port->fp_ub_tokens) != FC_SUCCESS) { 1589 cmn_err(CE_WARN, "fp(%d): couldn't free " 1590 " unsolicited buffers", port->fp_instance); 1591 } 1592 kmem_free(port->fp_ub_tokens, 1593 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1594 port->fp_ub_tokens = NULL; 1595 } 1596 1597 if (port->fp_pkt_cache != NULL) { 1598 kmem_cache_destroy(port->fp_pkt_cache); 1599 } 1600 1601 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1602 1603 mutex_enter(&port->fp_mutex); 1604 if (port->fp_did_table) { 1605 kmem_free(port->fp_did_table, did_table_size * 1606 sizeof (struct d_id_hash)); 1607 } 1608 1609 if (port->fp_pwwn_table) { 1610 kmem_free(port->fp_pwwn_table, pwwn_table_size * 1611 sizeof (struct pwwn_hash)); 1612 } 1613 orp = port->fp_orphan_list; 1614 while (orp) { 1615 tmporp = orp; 1616 orp = orp->orp_next; 1617 kmem_free(tmporp, sizeof (*orp)); 1618 } 1619 1620 mutex_exit(&port->fp_mutex); 1621 1622 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH); 1623 1624 mutex_destroy(&port->fp_mutex); 1625 cv_destroy(&port->fp_attach_cv); 1626 cv_destroy(&port->fp_cv); 1627 ddi_soft_state_free(fp_driver_softstate, port->fp_instance); 1628 1629 return (DDI_SUCCESS); 1630 } 1631 1632 1633 /* 1634 * Steps to perform DDI_SUSPEND operation on a FC port 1635 * 1636 * - If already suspended return DDI_FAILURE 1637 * - If already power-suspended return DDI_SUCCESS 1638 * - If an unsolicited callback or state change handling is in 1639 * in progress, throw a warning message, return DDI_FAILURE 1640 * - Cancel timeouts 1641 * - SUSPEND the job_handler thread (means do nothing as it is 1642 * taken care of by the CPR frame work) 1643 */ 1644 static int 1645 fp_suspend_handler(fc_local_port_t *port) 1646 { 1647 uint32_t delay_count; 1648 1649 mutex_enter(&port->fp_mutex); 1650 1651 /* 1652 * The following should never happen, but 1653 * let the driver be more defensive here 1654 */ 1655 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1656 mutex_exit(&port->fp_mutex); 1657 return (DDI_FAILURE); 1658 } 1659 1660 /* 1661 * If the port is already power suspended, there 1662 * is nothing else to do, So return DDI_SUCCESS, 1663 * but mark the SUSPEND bit in the soft state 1664 * before leaving. 1665 */ 1666 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1667 port->fp_soft_state |= FP_SOFT_SUSPEND; 1668 mutex_exit(&port->fp_mutex); 1669 return (DDI_SUCCESS); 1670 } 1671 1672 /* 1673 * Check if an unsolicited callback or state change handling is 1674 * in progress. If true, fail the suspend operation; also throw 1675 * a warning message notifying the failure. Note that Sun PCI 1676 * hotplug spec recommends messages in cases of failure (but 1677 * not flooding the console) 1678 * 1679 * Busy waiting for a short interval (500 millisecond ?) to see 1680 * if the callback processing completes may be another idea. Since 1681 * most of the callback processing involves a lot of work, it 1682 * is safe to just fail the SUSPEND operation. It is definitely 1683 * not bad to fail the SUSPEND operation if the driver is busy. 1684 */ 1685 delay_count = 0; 1686 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1687 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) { 1688 mutex_exit(&port->fp_mutex); 1689 delay_count++; 1690 delay(drv_usectohz(1000000)); 1691 mutex_enter(&port->fp_mutex); 1692 } 1693 1694 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1695 FP_SOFT_IN_UNSOL_CB)) { 1696 mutex_exit(&port->fp_mutex); 1697 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1698 " Failing suspend", port->fp_instance); 1699 return (DDI_FAILURE); 1700 } 1701 1702 /* 1703 * Check of FC port thread is busy 1704 */ 1705 if (port->fp_job_head) { 1706 mutex_exit(&port->fp_mutex); 1707 FP_TRACE(FP_NHEAD2(9, 0), 1708 "FC port thread is busy: Failing suspend"); 1709 return (DDI_FAILURE); 1710 } 1711 port->fp_soft_state |= FP_SOFT_SUSPEND; 1712 1713 fp_suspend_all(port); 1714 mutex_exit(&port->fp_mutex); 1715 1716 return (DDI_SUCCESS); 1717 } 1718 1719 1720 /* 1721 * Prepare for graceful power down of a FC port 1722 */ 1723 static int 1724 fp_power_down(fc_local_port_t *port) 1725 { 1726 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1727 1728 /* 1729 * Power down request followed by a DDI_SUSPEND should 1730 * never happen; If it does return DDI_SUCCESS 1731 */ 1732 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1733 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1734 return (DDI_SUCCESS); 1735 } 1736 1737 /* 1738 * If the port is already power suspended, there 1739 * is nothing else to do, So return DDI_SUCCESS, 1740 */ 1741 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1742 return (DDI_SUCCESS); 1743 } 1744 1745 /* 1746 * Check if an unsolicited callback or state change handling 1747 * is in progress. If true, fail the PM suspend operation. 1748 * But don't print a message unless the verbosity of the 1749 * driver desires otherwise. 1750 */ 1751 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) || 1752 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) { 1753 FP_TRACE(FP_NHEAD2(9, 0), 1754 "Unsolicited callback in progress: Failing power down"); 1755 return (DDI_FAILURE); 1756 } 1757 1758 /* 1759 * Check of FC port thread is busy 1760 */ 1761 if (port->fp_job_head) { 1762 FP_TRACE(FP_NHEAD2(9, 0), 1763 "FC port thread is busy: Failing power down"); 1764 return (DDI_FAILURE); 1765 } 1766 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1767 1768 /* 1769 * check if the ULPs are ready for power down 1770 */ 1771 mutex_exit(&port->fp_mutex); 1772 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN, 1773 &modlinkage) != FC_SUCCESS) { 1774 mutex_enter(&port->fp_mutex); 1775 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1776 mutex_exit(&port->fp_mutex); 1777 1778 /* 1779 * Power back up the obedient ULPs that went down 1780 */ 1781 fp_attach_ulps(port, FC_CMD_POWER_UP); 1782 1783 FP_TRACE(FP_NHEAD2(9, 0), 1784 "ULP(s) busy, detach_ulps failed. Failing power down"); 1785 mutex_enter(&port->fp_mutex); 1786 return (DDI_FAILURE); 1787 } 1788 mutex_enter(&port->fp_mutex); 1789 1790 fp_suspend_all(port); 1791 1792 return (DDI_SUCCESS); 1793 } 1794 1795 1796 /* 1797 * Suspend the entire FC port 1798 */ 1799 static void 1800 fp_suspend_all(fc_local_port_t *port) 1801 { 1802 int index; 1803 struct pwwn_hash *head; 1804 fc_remote_port_t *pd; 1805 1806 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1807 1808 if (port->fp_wait_tid != 0) { 1809 timeout_id_t tid; 1810 1811 tid = port->fp_wait_tid; 1812 port->fp_wait_tid = (timeout_id_t)NULL; 1813 mutex_exit(&port->fp_mutex); 1814 (void) untimeout(tid); 1815 mutex_enter(&port->fp_mutex); 1816 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT; 1817 } 1818 1819 if (port->fp_offline_tid) { 1820 timeout_id_t tid; 1821 1822 tid = port->fp_offline_tid; 1823 port->fp_offline_tid = (timeout_id_t)NULL; 1824 mutex_exit(&port->fp_mutex); 1825 (void) untimeout(tid); 1826 mutex_enter(&port->fp_mutex); 1827 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT; 1828 } 1829 mutex_exit(&port->fp_mutex); 1830 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1831 mutex_enter(&port->fp_mutex); 1832 1833 /* 1834 * Mark all devices as OLD, and reset the LOGIN state as well 1835 * (this will force the ULPs to perform a LOGIN after calling 1836 * fc_portgetmap() during RESUME/PM_RESUME) 1837 */ 1838 for (index = 0; index < pwwn_table_size; index++) { 1839 head = &port->fp_pwwn_table[index]; 1840 pd = head->pwwn_head; 1841 while (pd != NULL) { 1842 mutex_enter(&pd->pd_mutex); 1843 fp_remote_port_offline(pd); 1844 fctl_delist_did_table(port, pd); 1845 pd->pd_state = PORT_DEVICE_VALID; 1846 pd->pd_login_count = 0; 1847 mutex_exit(&pd->pd_mutex); 1848 pd = pd->pd_wwn_hnext; 1849 } 1850 } 1851 } 1852 1853 1854 /* 1855 * fp_cache_constructor: Constructor function for kmem_cache_create(9F). 1856 * Performs intializations for fc_packet_t structs. 1857 * Returns 0 for success or -1 for failure. 1858 * 1859 * This function allocates DMA handles for both command and responses. 1860 * Most of the ELSs used have both command and responses so it is strongly 1861 * desired to move them to cache constructor routine. 1862 * 1863 * Context: Can sleep iff called with KM_SLEEP flag. 1864 */ 1865 static int 1866 fp_cache_constructor(void *buf, void *cdarg, int kmflags) 1867 { 1868 int (*cb) (caddr_t); 1869 fc_packet_t *pkt; 1870 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1871 fc_local_port_t *port = (fc_local_port_t *)cdarg; 1872 1873 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1874 1875 cmd->cmd_next = NULL; 1876 cmd->cmd_flags = 0; 1877 cmd->cmd_dflags = 0; 1878 cmd->cmd_job = NULL; 1879 cmd->cmd_port = port; 1880 pkt = &cmd->cmd_pkt; 1881 1882 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 1883 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1884 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1885 &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 1886 return (-1); 1887 } 1888 1889 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1890 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1891 &pkt->pkt_resp_dma) != DDI_SUCCESS) { 1892 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1893 return (-1); 1894 } 1895 } else { 1896 pkt->pkt_cmd_dma = 0; 1897 pkt->pkt_resp_dma = 0; 1898 } 1899 1900 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL; 1901 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt = 1902 pkt->pkt_data_cookie_cnt = 0; 1903 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie = 1904 pkt->pkt_data_cookie = NULL; 1905 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t); 1906 1907 return (0); 1908 } 1909 1910 1911 /* 1912 * fp_cache_destructor: Destructor function for kmem_cache_create(). 1913 * Performs un-intializations for fc_packet_t structs. 1914 */ 1915 /* ARGSUSED */ 1916 static void 1917 fp_cache_destructor(void *buf, void *cdarg) 1918 { 1919 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1920 fc_packet_t *pkt; 1921 1922 pkt = &cmd->cmd_pkt; 1923 if (pkt->pkt_cmd_dma) { 1924 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1925 } 1926 1927 if (pkt->pkt_resp_dma) { 1928 ddi_dma_free_handle(&pkt->pkt_resp_dma); 1929 } 1930 } 1931 1932 1933 /* 1934 * Packet allocation for ELS and any other port driver commands 1935 * 1936 * Some ELSs like FLOGI and PLOGI are critical for topology and 1937 * device discovery and a system's inability to allocate memory 1938 * or DVMA resources while performing some of these critical ELSs 1939 * cause a lot of problem. While memory allocation failures are 1940 * rare, DVMA resource failures are common as the applications 1941 * are becoming more and more powerful on huge servers. So it 1942 * is desirable to have a framework support to reserve a fragment 1943 * of DVMA. So until this is fixed the correct way, the suffering 1944 * is huge whenever a LIP happens at a time DVMA resources are 1945 * drained out completely - So an attempt needs to be made to 1946 * KM_SLEEP while requesting for these resources, hoping that 1947 * the requests won't hang forever. 1948 * 1949 * The fc_remote_port_t argument is stored into the pkt_pd field in the 1950 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This 1951 * ensures that the pd_ref_count for the fc_remote_port_t is valid. 1952 * If there is no fc_remote_port_t associated with the fc_packet_t, then 1953 * fp_alloc_pkt() must be called with pd set to NULL. 1954 * 1955 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen, 1956 * actually, it's a design fault. But there's no problem for physical 1957 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei. 1958 * 1959 * For FCAs that don't support DMA, such as fcoei, we will use 1960 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len. 1961 */ 1962 1963 static fp_cmd_t * 1964 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags, 1965 fc_remote_port_t *pd) 1966 { 1967 int rval; 1968 ulong_t real_len; 1969 fp_cmd_t *cmd; 1970 fc_packet_t *pkt; 1971 int (*cb) (caddr_t); 1972 ddi_dma_cookie_t pkt_cookie; 1973 ddi_dma_cookie_t *cp; 1974 uint32_t cnt; 1975 1976 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1977 1978 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1979 1980 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags); 1981 if (cmd == NULL) { 1982 return (cmd); 1983 } 1984 1985 cmd->cmd_ulp_pkt = NULL; 1986 cmd->cmd_flags = 0; 1987 pkt = &cmd->cmd_pkt; 1988 ASSERT(cmd->cmd_dflags == 0); 1989 1990 pkt->pkt_datalen = 0; 1991 pkt->pkt_data = NULL; 1992 pkt->pkt_state = 0; 1993 pkt->pkt_action = 0; 1994 pkt->pkt_reason = 0; 1995 pkt->pkt_expln = 0; 1996 pkt->pkt_cmd = NULL; 1997 pkt->pkt_resp = NULL; 1998 pkt->pkt_fctl_rsvd1 = NULL; 1999 pkt->pkt_fctl_rsvd2 = NULL; 2000 2001 /* 2002 * Init pkt_pd with the given pointer; this must be done _before_ 2003 * the call to fc_ulp_init_packet(). 2004 */ 2005 pkt->pkt_pd = pd; 2006 2007 /* Now call the FCA driver to init its private, per-packet fields */ 2008 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) { 2009 goto alloc_pkt_failed; 2010 } 2011 2012 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2013 ASSERT(pkt->pkt_cmd_dma != NULL); 2014 2015 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len, 2016 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT, 2017 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len, 2018 &pkt->pkt_cmd_acc); 2019 2020 if (rval != DDI_SUCCESS) { 2021 goto alloc_pkt_failed; 2022 } 2023 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM; 2024 2025 if (real_len < cmd_len) { 2026 goto alloc_pkt_failed; 2027 } 2028 2029 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 2030 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | 2031 DDI_DMA_CONSISTENT, cb, NULL, 2032 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt); 2033 2034 if (rval != DDI_DMA_MAPPED) { 2035 goto alloc_pkt_failed; 2036 } 2037 2038 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND; 2039 2040 if (pkt->pkt_cmd_cookie_cnt > 2041 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2042 goto alloc_pkt_failed; 2043 } 2044 2045 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2046 2047 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2048 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie), 2049 KM_NOSLEEP); 2050 2051 if (cp == NULL) { 2052 goto alloc_pkt_failed; 2053 } 2054 2055 *cp = pkt_cookie; 2056 cp++; 2057 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) { 2058 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie); 2059 *cp = pkt_cookie; 2060 } 2061 } else if (cmd_len != 0) { 2062 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP); 2063 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len; 2064 } 2065 2066 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2067 ASSERT(pkt->pkt_resp_dma != NULL); 2068 2069 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len, 2070 port->fp_fca_tran->fca_acc_attr, 2071 DDI_DMA_CONSISTENT, cb, NULL, 2072 (caddr_t *)&pkt->pkt_resp, &real_len, 2073 &pkt->pkt_resp_acc); 2074 2075 if (rval != DDI_SUCCESS) { 2076 goto alloc_pkt_failed; 2077 } 2078 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM; 2079 2080 if (real_len < resp_len) { 2081 goto alloc_pkt_failed; 2082 } 2083 2084 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 2085 pkt->pkt_resp, real_len, DDI_DMA_READ | 2086 DDI_DMA_CONSISTENT, cb, NULL, 2087 &pkt_cookie, &pkt->pkt_resp_cookie_cnt); 2088 2089 if (rval != DDI_DMA_MAPPED) { 2090 goto alloc_pkt_failed; 2091 } 2092 2093 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND; 2094 2095 if (pkt->pkt_resp_cookie_cnt > 2096 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2097 goto alloc_pkt_failed; 2098 } 2099 2100 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2101 2102 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2103 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie), 2104 KM_NOSLEEP); 2105 2106 if (cp == NULL) { 2107 goto alloc_pkt_failed; 2108 } 2109 2110 *cp = pkt_cookie; 2111 cp++; 2112 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) { 2113 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie); 2114 *cp = pkt_cookie; 2115 } 2116 } else if (resp_len != 0) { 2117 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP); 2118 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len; 2119 } 2120 2121 pkt->pkt_cmdlen = cmd_len; 2122 pkt->pkt_rsplen = resp_len; 2123 pkt->pkt_ulp_private = cmd; 2124 2125 return (cmd); 2126 2127 alloc_pkt_failed: 2128 2129 fp_free_dma(cmd); 2130 2131 if (pkt->pkt_cmd_cookie != NULL) { 2132 kmem_free(pkt->pkt_cmd_cookie, 2133 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2134 pkt->pkt_cmd_cookie = NULL; 2135 } 2136 2137 if (pkt->pkt_resp_cookie != NULL) { 2138 kmem_free(pkt->pkt_resp_cookie, 2139 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2140 pkt->pkt_resp_cookie = NULL; 2141 } 2142 2143 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2144 if (pkt->pkt_cmd) { 2145 kmem_free(pkt->pkt_cmd, cmd_len); 2146 } 2147 2148 if (pkt->pkt_resp) { 2149 kmem_free(pkt->pkt_resp, resp_len); 2150 } 2151 } 2152 2153 kmem_cache_free(port->fp_pkt_cache, cmd); 2154 2155 return (NULL); 2156 } 2157 2158 2159 /* 2160 * Free FC packet 2161 */ 2162 static void 2163 fp_free_pkt(fp_cmd_t *cmd) 2164 { 2165 fc_local_port_t *port; 2166 fc_packet_t *pkt; 2167 2168 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex)); 2169 2170 cmd->cmd_next = NULL; 2171 cmd->cmd_job = NULL; 2172 pkt = &cmd->cmd_pkt; 2173 pkt->pkt_ulp_private = 0; 2174 pkt->pkt_tran_flags = 0; 2175 pkt->pkt_tran_type = 0; 2176 port = cmd->cmd_port; 2177 2178 if (pkt->pkt_cmd_cookie != NULL) { 2179 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt * 2180 sizeof (ddi_dma_cookie_t)); 2181 pkt->pkt_cmd_cookie = NULL; 2182 } 2183 2184 if (pkt->pkt_resp_cookie != NULL) { 2185 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt * 2186 sizeof (ddi_dma_cookie_t)); 2187 pkt->pkt_resp_cookie = NULL; 2188 } 2189 2190 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2191 if (pkt->pkt_cmd) { 2192 kmem_free(pkt->pkt_cmd, 2193 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1); 2194 } 2195 2196 if (pkt->pkt_resp) { 2197 kmem_free(pkt->pkt_resp, 2198 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2); 2199 } 2200 } 2201 2202 fp_free_dma(cmd); 2203 (void) fc_ulp_uninit_packet((opaque_t)port, pkt); 2204 kmem_cache_free(port->fp_pkt_cache, (void *)cmd); 2205 } 2206 2207 2208 /* 2209 * Release DVMA resources 2210 */ 2211 static void 2212 fp_free_dma(fp_cmd_t *cmd) 2213 { 2214 fc_packet_t *pkt = &cmd->cmd_pkt; 2215 2216 pkt->pkt_cmdlen = 0; 2217 pkt->pkt_rsplen = 0; 2218 pkt->pkt_tran_type = 0; 2219 pkt->pkt_tran_flags = 0; 2220 2221 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) { 2222 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 2223 } 2224 2225 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) { 2226 if (pkt->pkt_cmd_acc) { 2227 ddi_dma_mem_free(&pkt->pkt_cmd_acc); 2228 } 2229 } 2230 2231 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) { 2232 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 2233 } 2234 2235 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) { 2236 if (pkt->pkt_resp_acc) { 2237 ddi_dma_mem_free(&pkt->pkt_resp_acc); 2238 } 2239 } 2240 cmd->cmd_dflags = 0; 2241 } 2242 2243 2244 /* 2245 * Dedicated thread to perform various activities. One thread for 2246 * each fc_local_port_t (driver soft state) instance. 2247 * Note, this effectively works out to one thread for each local 2248 * port, but there are also some Solaris taskq threads in use on a per-local 2249 * port basis; these also need to be taken into consideration. 2250 */ 2251 static void 2252 fp_job_handler(fc_local_port_t *port) 2253 { 2254 int rval; 2255 uint32_t *d_id; 2256 fc_remote_port_t *pd; 2257 job_request_t *job; 2258 2259 #ifndef __lock_lint 2260 /* 2261 * Solaris-internal stuff for proper operation of kernel threads 2262 * with Solaris CPR. 2263 */ 2264 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex, 2265 callb_generic_cpr, "fp_job_handler"); 2266 #endif 2267 2268 2269 /* Loop forever waiting for work to do */ 2270 for (;;) { 2271 2272 mutex_enter(&port->fp_mutex); 2273 2274 /* 2275 * Sleep if no work to do right now, or if we want 2276 * to suspend or power-down. 2277 */ 2278 while (port->fp_job_head == NULL || 2279 (port->fp_soft_state & (FP_SOFT_POWER_DOWN | 2280 FP_SOFT_SUSPEND))) { 2281 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info); 2282 cv_wait(&port->fp_cv, &port->fp_mutex); 2283 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex); 2284 } 2285 2286 /* 2287 * OK, we've just been woken up, so retrieve the next entry 2288 * from the head of the job queue for this local port. 2289 */ 2290 job = fctl_deque_job(port); 2291 2292 /* 2293 * Handle all the fp driver's supported job codes here 2294 * in this big honkin' switch. 2295 */ 2296 switch (job->job_code) { 2297 case JOB_PORT_SHUTDOWN: 2298 /* 2299 * fp_port_shutdown() is only called from here. This 2300 * will prepare the local port instance (softstate) 2301 * for detaching. This cancels timeout callbacks, 2302 * executes LOGOs with remote ports, cleans up tables, 2303 * and deallocates data structs. 2304 */ 2305 fp_port_shutdown(port, job); 2306 2307 /* 2308 * This will exit the job thread. 2309 */ 2310 #ifndef __lock_lint 2311 CALLB_CPR_EXIT(&(port->fp_cpr_info)); 2312 #else 2313 mutex_exit(&port->fp_mutex); 2314 #endif 2315 fctl_jobdone(job); 2316 thread_exit(); 2317 2318 /* NOTREACHED */ 2319 2320 case JOB_ATTACH_ULP: { 2321 /* 2322 * This job is spawned in response to a ULP calling 2323 * fc_ulp_add(). 2324 */ 2325 2326 boolean_t do_attach_ulps = B_TRUE; 2327 2328 /* 2329 * If fp is detaching, we don't want to call 2330 * fp_startup_done as this asynchronous 2331 * notification may interfere with the re-attach. 2332 */ 2333 2334 if (port->fp_soft_state & (FP_DETACH_INPROGRESS | 2335 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) { 2336 do_attach_ulps = B_FALSE; 2337 } else { 2338 /* 2339 * We are going to force the transport 2340 * to attach to the ULPs, so set 2341 * fp_ulp_attach. This will keep any 2342 * potential detach from occurring until 2343 * we are done. 2344 */ 2345 port->fp_ulp_attach = 1; 2346 } 2347 2348 mutex_exit(&port->fp_mutex); 2349 2350 /* 2351 * NOTE: Since we just dropped the mutex, there is now 2352 * a race window where the fp_soft_state check above 2353 * could change here. This race is covered because an 2354 * additional check was added in the functions hidden 2355 * under fp_startup_done(). 2356 */ 2357 if (do_attach_ulps == B_TRUE) { 2358 /* 2359 * This goes thru a bit of a convoluted call 2360 * chain before spawning off a DDI taskq 2361 * request to perform the actual attach 2362 * operations. Blocking can occur at a number 2363 * of points. 2364 */ 2365 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 2366 } 2367 job->job_result = FC_SUCCESS; 2368 fctl_jobdone(job); 2369 break; 2370 } 2371 2372 case JOB_ULP_NOTIFY: { 2373 /* 2374 * Pass state change notifications up to any/all 2375 * registered ULPs. 2376 */ 2377 uint32_t statec; 2378 2379 statec = job->job_ulp_listlen; 2380 if (statec == FC_STATE_RESET_REQUESTED) { 2381 port->fp_last_task = port->fp_task; 2382 port->fp_task = FP_TASK_OFFLINE; 2383 fp_port_offline(port, 0); 2384 port->fp_task = port->fp_last_task; 2385 port->fp_last_task = FP_TASK_IDLE; 2386 } 2387 2388 if (--port->fp_statec_busy == 0) { 2389 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2390 } 2391 2392 mutex_exit(&port->fp_mutex); 2393 2394 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP); 2395 fctl_jobdone(job); 2396 break; 2397 } 2398 2399 case JOB_PLOGI_ONE: 2400 /* 2401 * Issue a PLOGI to a single remote port. Multiple 2402 * PLOGIs to different remote ports may occur in 2403 * parallel. 2404 * This can create the fc_remote_port_t if it does not 2405 * already exist. 2406 */ 2407 2408 mutex_exit(&port->fp_mutex); 2409 d_id = (uint32_t *)job->job_private; 2410 pd = fctl_get_remote_port_by_did(port, *d_id); 2411 2412 if (pd) { 2413 mutex_enter(&pd->pd_mutex); 2414 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 2415 pd->pd_login_count++; 2416 mutex_exit(&pd->pd_mutex); 2417 job->job_result = FC_SUCCESS; 2418 fctl_jobdone(job); 2419 break; 2420 } 2421 mutex_exit(&pd->pd_mutex); 2422 } else { 2423 mutex_enter(&port->fp_mutex); 2424 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2425 mutex_exit(&port->fp_mutex); 2426 pd = fp_create_remote_port_by_ns(port, 2427 *d_id, KM_SLEEP); 2428 if (pd == NULL) { 2429 job->job_result = FC_FAILURE; 2430 fctl_jobdone(job); 2431 break; 2432 } 2433 } else { 2434 mutex_exit(&port->fp_mutex); 2435 } 2436 } 2437 2438 job->job_flags |= JOB_TYPE_FP_ASYNC; 2439 job->job_counter = 1; 2440 2441 rval = fp_port_login(port, *d_id, job, 2442 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 2443 2444 if (rval != FC_SUCCESS) { 2445 job->job_result = rval; 2446 fctl_jobdone(job); 2447 } 2448 break; 2449 2450 case JOB_LOGO_ONE: { 2451 /* 2452 * Issue a PLOGO to a single remote port. Multiple 2453 * PLOGOs to different remote ports may occur in 2454 * parallel. 2455 */ 2456 fc_remote_port_t *pd; 2457 2458 #ifndef __lock_lint 2459 ASSERT(job->job_counter > 0); 2460 #endif 2461 2462 pd = (fc_remote_port_t *)job->job_ulp_pkts; 2463 2464 mutex_enter(&pd->pd_mutex); 2465 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 2466 mutex_exit(&pd->pd_mutex); 2467 job->job_result = FC_LOGINREQ; 2468 mutex_exit(&port->fp_mutex); 2469 fctl_jobdone(job); 2470 break; 2471 } 2472 if (pd->pd_login_count > 1) { 2473 pd->pd_login_count--; 2474 mutex_exit(&pd->pd_mutex); 2475 job->job_result = FC_SUCCESS; 2476 mutex_exit(&port->fp_mutex); 2477 fctl_jobdone(job); 2478 break; 2479 } 2480 mutex_exit(&pd->pd_mutex); 2481 mutex_exit(&port->fp_mutex); 2482 job->job_flags |= JOB_TYPE_FP_ASYNC; 2483 (void) fp_logout(port, pd, job); 2484 break; 2485 } 2486 2487 case JOB_FCIO_LOGIN: 2488 /* 2489 * PLOGI initiated at ioctl request. 2490 */ 2491 mutex_exit(&port->fp_mutex); 2492 job->job_result = 2493 fp_fcio_login(port, job->job_private, job); 2494 fctl_jobdone(job); 2495 break; 2496 2497 case JOB_FCIO_LOGOUT: 2498 /* 2499 * PLOGO initiated at ioctl request. 2500 */ 2501 mutex_exit(&port->fp_mutex); 2502 job->job_result = 2503 fp_fcio_logout(port, job->job_private, job); 2504 fctl_jobdone(job); 2505 break; 2506 2507 case JOB_PORT_GETMAP: 2508 case JOB_PORT_GETMAP_PLOGI_ALL: { 2509 port->fp_last_task = port->fp_task; 2510 port->fp_task = FP_TASK_GETMAP; 2511 2512 switch (port->fp_topology) { 2513 case FC_TOP_PRIVATE_LOOP: 2514 job->job_counter = 1; 2515 2516 fp_get_loopmap(port, job); 2517 mutex_exit(&port->fp_mutex); 2518 fp_jobwait(job); 2519 fctl_fillout_map(port, 2520 (fc_portmap_t **)job->job_private, 2521 (uint32_t *)job->job_arg, 1, 0, 0); 2522 fctl_jobdone(job); 2523 mutex_enter(&port->fp_mutex); 2524 break; 2525 2526 case FC_TOP_PUBLIC_LOOP: 2527 case FC_TOP_FABRIC: 2528 mutex_exit(&port->fp_mutex); 2529 job->job_counter = 1; 2530 2531 job->job_result = fp_ns_getmap(port, 2532 job, (fc_portmap_t **)job->job_private, 2533 (uint32_t *)job->job_arg, 2534 FCTL_GAN_START_ID); 2535 fctl_jobdone(job); 2536 mutex_enter(&port->fp_mutex); 2537 break; 2538 2539 case FC_TOP_PT_PT: 2540 mutex_exit(&port->fp_mutex); 2541 fctl_fillout_map(port, 2542 (fc_portmap_t **)job->job_private, 2543 (uint32_t *)job->job_arg, 1, 0, 0); 2544 fctl_jobdone(job); 2545 mutex_enter(&port->fp_mutex); 2546 break; 2547 2548 default: 2549 mutex_exit(&port->fp_mutex); 2550 fctl_jobdone(job); 2551 mutex_enter(&port->fp_mutex); 2552 break; 2553 } 2554 port->fp_task = port->fp_last_task; 2555 port->fp_last_task = FP_TASK_IDLE; 2556 mutex_exit(&port->fp_mutex); 2557 break; 2558 } 2559 2560 case JOB_PORT_OFFLINE: { 2561 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE); 2562 2563 port->fp_last_task = port->fp_task; 2564 port->fp_task = FP_TASK_OFFLINE; 2565 2566 if (port->fp_statec_busy > 2) { 2567 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2568 fp_port_offline(port, 0); 2569 if (--port->fp_statec_busy == 0) { 2570 port->fp_soft_state &= 2571 ~FP_SOFT_IN_STATEC_CB; 2572 } 2573 } else { 2574 fp_port_offline(port, 1); 2575 } 2576 2577 port->fp_task = port->fp_last_task; 2578 port->fp_last_task = FP_TASK_IDLE; 2579 2580 mutex_exit(&port->fp_mutex); 2581 2582 fctl_jobdone(job); 2583 break; 2584 } 2585 2586 case JOB_PORT_STARTUP: { 2587 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2588 if (port->fp_statec_busy > 1) { 2589 mutex_exit(&port->fp_mutex); 2590 break; 2591 } 2592 mutex_exit(&port->fp_mutex); 2593 2594 FP_TRACE(FP_NHEAD2(9, rval), 2595 "Topology discovery failed"); 2596 break; 2597 } 2598 2599 /* 2600 * Attempt building device handles in case 2601 * of private Loop. 2602 */ 2603 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) { 2604 job->job_counter = 1; 2605 2606 fp_get_loopmap(port, job); 2607 mutex_exit(&port->fp_mutex); 2608 fp_jobwait(job); 2609 mutex_enter(&port->fp_mutex); 2610 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 2611 ASSERT(port->fp_total_devices == 0); 2612 port->fp_total_devices = 2613 port->fp_dev_count; 2614 } 2615 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2616 /* 2617 * Hack to avoid state changes going up early 2618 */ 2619 port->fp_statec_busy++; 2620 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 2621 2622 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2623 fp_fabric_online(port, job); 2624 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION; 2625 } 2626 mutex_exit(&port->fp_mutex); 2627 fctl_jobdone(job); 2628 break; 2629 } 2630 2631 case JOB_PORT_ONLINE: { 2632 char *newtop; 2633 char *oldtop; 2634 uint32_t old_top; 2635 2636 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE); 2637 2638 /* 2639 * Bail out early if there are a lot of 2640 * state changes in the pipeline 2641 */ 2642 if (port->fp_statec_busy > 1) { 2643 --port->fp_statec_busy; 2644 mutex_exit(&port->fp_mutex); 2645 fctl_jobdone(job); 2646 break; 2647 } 2648 2649 switch (old_top = port->fp_topology) { 2650 case FC_TOP_PRIVATE_LOOP: 2651 oldtop = "Private Loop"; 2652 break; 2653 2654 case FC_TOP_PUBLIC_LOOP: 2655 oldtop = "Public Loop"; 2656 break; 2657 2658 case FC_TOP_PT_PT: 2659 oldtop = "Point to Point"; 2660 break; 2661 2662 case FC_TOP_FABRIC: 2663 oldtop = "Fabric"; 2664 break; 2665 2666 default: 2667 oldtop = NULL; 2668 break; 2669 } 2670 2671 port->fp_last_task = port->fp_task; 2672 port->fp_task = FP_TASK_ONLINE; 2673 2674 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2675 2676 port->fp_task = port->fp_last_task; 2677 port->fp_last_task = FP_TASK_IDLE; 2678 2679 if (port->fp_statec_busy > 1) { 2680 --port->fp_statec_busy; 2681 mutex_exit(&port->fp_mutex); 2682 break; 2683 } 2684 2685 port->fp_state = FC_STATE_OFFLINE; 2686 2687 FP_TRACE(FP_NHEAD2(9, rval), 2688 "Topology discovery failed"); 2689 2690 if (--port->fp_statec_busy == 0) { 2691 port->fp_soft_state &= 2692 ~FP_SOFT_IN_STATEC_CB; 2693 } 2694 2695 if (port->fp_offline_tid == NULL) { 2696 port->fp_offline_tid = 2697 timeout(fp_offline_timeout, 2698 (caddr_t)port, fp_offline_ticks); 2699 } 2700 2701 mutex_exit(&port->fp_mutex); 2702 break; 2703 } 2704 2705 switch (port->fp_topology) { 2706 case FC_TOP_PRIVATE_LOOP: 2707 newtop = "Private Loop"; 2708 break; 2709 2710 case FC_TOP_PUBLIC_LOOP: 2711 newtop = "Public Loop"; 2712 break; 2713 2714 case FC_TOP_PT_PT: 2715 newtop = "Point to Point"; 2716 break; 2717 2718 case FC_TOP_FABRIC: 2719 newtop = "Fabric"; 2720 break; 2721 2722 default: 2723 newtop = NULL; 2724 break; 2725 } 2726 2727 if (oldtop && newtop && strcmp(oldtop, newtop)) { 2728 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2729 "Change in FC Topology old = %s new = %s", 2730 oldtop, newtop); 2731 } 2732 2733 switch (port->fp_topology) { 2734 case FC_TOP_PRIVATE_LOOP: { 2735 int orphan = (old_top == FC_TOP_FABRIC || 2736 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0; 2737 2738 mutex_exit(&port->fp_mutex); 2739 fp_loop_online(port, job, orphan); 2740 break; 2741 } 2742 2743 case FC_TOP_PUBLIC_LOOP: 2744 /* FALLTHROUGH */ 2745 case FC_TOP_FABRIC: 2746 fp_fabric_online(port, job); 2747 mutex_exit(&port->fp_mutex); 2748 break; 2749 2750 case FC_TOP_PT_PT: 2751 fp_p2p_online(port, job); 2752 mutex_exit(&port->fp_mutex); 2753 break; 2754 2755 default: 2756 if (--port->fp_statec_busy != 0) { 2757 /* 2758 * Watch curiously at what the next 2759 * state transition can do. 2760 */ 2761 mutex_exit(&port->fp_mutex); 2762 break; 2763 } 2764 2765 FP_TRACE(FP_NHEAD2(9, 0), 2766 "Topology Unknown, Offlining the port.."); 2767 2768 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2769 port->fp_state = FC_STATE_OFFLINE; 2770 2771 if (port->fp_offline_tid == NULL) { 2772 port->fp_offline_tid = 2773 timeout(fp_offline_timeout, 2774 (caddr_t)port, fp_offline_ticks); 2775 } 2776 mutex_exit(&port->fp_mutex); 2777 break; 2778 } 2779 2780 mutex_enter(&port->fp_mutex); 2781 2782 port->fp_task = port->fp_last_task; 2783 port->fp_last_task = FP_TASK_IDLE; 2784 2785 mutex_exit(&port->fp_mutex); 2786 2787 fctl_jobdone(job); 2788 break; 2789 } 2790 2791 case JOB_PLOGI_GROUP: { 2792 mutex_exit(&port->fp_mutex); 2793 fp_plogi_group(port, job); 2794 break; 2795 } 2796 2797 case JOB_UNSOL_REQUEST: { 2798 mutex_exit(&port->fp_mutex); 2799 fp_handle_unsol_buf(port, 2800 (fc_unsol_buf_t *)job->job_private, job); 2801 fctl_dealloc_job(job); 2802 break; 2803 } 2804 2805 case JOB_NS_CMD: { 2806 fctl_ns_req_t *ns_cmd; 2807 2808 mutex_exit(&port->fp_mutex); 2809 2810 job->job_flags |= JOB_TYPE_FP_ASYNC; 2811 ns_cmd = (fctl_ns_req_t *)job->job_private; 2812 if (ns_cmd->ns_cmd_code < NS_GA_NXT || 2813 ns_cmd->ns_cmd_code > NS_DA_ID) { 2814 job->job_result = FC_BADCMD; 2815 fctl_jobdone(job); 2816 break; 2817 } 2818 2819 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) { 2820 if (ns_cmd->ns_pd != NULL) { 2821 job->job_result = FC_BADOBJECT; 2822 fctl_jobdone(job); 2823 break; 2824 } 2825 2826 job->job_counter = 1; 2827 2828 rval = fp_ns_reg(port, ns_cmd->ns_pd, 2829 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP); 2830 2831 if (rval != FC_SUCCESS) { 2832 job->job_result = rval; 2833 fctl_jobdone(job); 2834 } 2835 break; 2836 } 2837 job->job_result = FC_SUCCESS; 2838 job->job_counter = 1; 2839 2840 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP); 2841 if (rval != FC_SUCCESS) { 2842 fctl_jobdone(job); 2843 } 2844 break; 2845 } 2846 2847 case JOB_LINK_RESET: { 2848 la_wwn_t *pwwn; 2849 uint32_t topology; 2850 2851 pwwn = (la_wwn_t *)job->job_private; 2852 ASSERT(pwwn != NULL); 2853 2854 topology = port->fp_topology; 2855 mutex_exit(&port->fp_mutex); 2856 2857 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS || 2858 topology == FC_TOP_PRIVATE_LOOP) { 2859 job->job_flags |= JOB_TYPE_FP_ASYNC; 2860 rval = port->fp_fca_tran->fca_reset( 2861 port->fp_fca_handle, FC_FCA_LINK_RESET); 2862 job->job_result = rval; 2863 fp_jobdone(job); 2864 } else { 2865 ASSERT((job->job_flags & 2866 JOB_TYPE_FP_ASYNC) == 0); 2867 2868 if (FC_IS_TOP_SWITCH(topology)) { 2869 rval = fp_remote_lip(port, pwwn, 2870 KM_SLEEP, job); 2871 } else { 2872 rval = FC_FAILURE; 2873 } 2874 if (rval != FC_SUCCESS) { 2875 job->job_result = rval; 2876 } 2877 fctl_jobdone(job); 2878 } 2879 break; 2880 } 2881 2882 default: 2883 mutex_exit(&port->fp_mutex); 2884 job->job_result = FC_BADCMD; 2885 fctl_jobdone(job); 2886 break; 2887 } 2888 } 2889 /* NOTREACHED */ 2890 } 2891 2892 2893 /* 2894 * Perform FC port bring up initialization 2895 */ 2896 static int 2897 fp_port_startup(fc_local_port_t *port, job_request_t *job) 2898 { 2899 int rval; 2900 uint32_t state; 2901 uint32_t src_id; 2902 fc_lilpmap_t *lilp_map; 2903 2904 ASSERT(MUTEX_HELD(&port->fp_mutex)); 2905 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 2906 2907 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;" 2908 " port=%p, job=%p", port, job); 2909 2910 port->fp_topology = FC_TOP_UNKNOWN; 2911 port->fp_port_id.port_id = 0; 2912 state = FC_PORT_STATE_MASK(port->fp_state); 2913 2914 if (state == FC_STATE_OFFLINE) { 2915 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2916 job->job_result = FC_OFFLINE; 2917 mutex_exit(&port->fp_mutex); 2918 fctl_jobdone(job); 2919 mutex_enter(&port->fp_mutex); 2920 return (FC_OFFLINE); 2921 } 2922 2923 if (state == FC_STATE_LOOP) { 2924 port->fp_port_type.port_type = FC_NS_PORT_NL; 2925 mutex_exit(&port->fp_mutex); 2926 2927 lilp_map = &port->fp_lilp_map; 2928 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) { 2929 job->job_result = FC_FAILURE; 2930 fctl_jobdone(job); 2931 2932 FP_TRACE(FP_NHEAD1(9, rval), 2933 "LILP map Invalid or not present"); 2934 mutex_enter(&port->fp_mutex); 2935 return (FC_FAILURE); 2936 } 2937 2938 if (lilp_map->lilp_length == 0) { 2939 job->job_result = FC_NO_MAP; 2940 fctl_jobdone(job); 2941 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2942 "LILP map length zero"); 2943 mutex_enter(&port->fp_mutex); 2944 return (FC_NO_MAP); 2945 } 2946 src_id = lilp_map->lilp_myalpa & 0xFF; 2947 } else { 2948 fc_remote_port_t *pd; 2949 fc_fca_pm_t pm; 2950 fc_fca_p2p_info_t p2p_info; 2951 int pd_recepient; 2952 2953 /* 2954 * Get P2P remote port info if possible 2955 */ 2956 bzero((caddr_t)&pm, sizeof (pm)); 2957 2958 pm.pm_cmd_flags = FC_FCA_PM_READ; 2959 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO; 2960 pm.pm_data_len = sizeof (fc_fca_p2p_info_t); 2961 pm.pm_data_buf = (caddr_t)&p2p_info; 2962 2963 rval = port->fp_fca_tran->fca_port_manage( 2964 port->fp_fca_handle, &pm); 2965 2966 if (rval == FC_SUCCESS) { 2967 port->fp_port_id.port_id = p2p_info.fca_d_id; 2968 port->fp_port_type.port_type = FC_NS_PORT_N; 2969 port->fp_topology = FC_TOP_PT_PT; 2970 port->fp_total_devices = 1; 2971 pd_recepient = fctl_wwn_cmp( 2972 &port->fp_service_params.nport_ww_name, 2973 &p2p_info.pwwn) < 0 ? 2974 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR; 2975 mutex_exit(&port->fp_mutex); 2976 pd = fctl_create_remote_port(port, 2977 &p2p_info.nwwn, 2978 &p2p_info.pwwn, 2979 p2p_info.d_id, 2980 pd_recepient, KM_NOSLEEP); 2981 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;" 2982 " P2P port=%p pd=%p fp %x pd %x", port, pd, 2983 port->fp_port_id.port_id, p2p_info.d_id); 2984 mutex_enter(&port->fp_mutex); 2985 return (FC_SUCCESS); 2986 } 2987 port->fp_port_type.port_type = FC_NS_PORT_N; 2988 mutex_exit(&port->fp_mutex); 2989 src_id = 0; 2990 } 2991 2992 job->job_counter = 1; 2993 job->job_result = FC_SUCCESS; 2994 2995 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE, 2996 KM_SLEEP)) != FC_SUCCESS) { 2997 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2998 job->job_result = FC_FAILURE; 2999 fctl_jobdone(job); 3000 3001 mutex_enter(&port->fp_mutex); 3002 if (port->fp_statec_busy <= 1) { 3003 mutex_exit(&port->fp_mutex); 3004 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL, 3005 "Couldn't transport FLOGI"); 3006 mutex_enter(&port->fp_mutex); 3007 } 3008 return (FC_FAILURE); 3009 } 3010 3011 fp_jobwait(job); 3012 3013 mutex_enter(&port->fp_mutex); 3014 if (job->job_result == FC_SUCCESS) { 3015 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3016 mutex_exit(&port->fp_mutex); 3017 fp_ns_init(port, job, KM_SLEEP); 3018 mutex_enter(&port->fp_mutex); 3019 } 3020 } else { 3021 if (state == FC_STATE_LOOP) { 3022 port->fp_topology = FC_TOP_PRIVATE_LOOP; 3023 port->fp_port_id.port_id = 3024 port->fp_lilp_map.lilp_myalpa & 0xFF; 3025 } 3026 } 3027 3028 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p", 3029 port, job); 3030 3031 return (FC_SUCCESS); 3032 } 3033 3034 3035 /* 3036 * Perform ULP invocations following FC port startup 3037 */ 3038 /* ARGSUSED */ 3039 static void 3040 fp_startup_done(opaque_t arg, uchar_t result) 3041 { 3042 fc_local_port_t *port = arg; 3043 3044 fp_attach_ulps(port, FC_CMD_ATTACH); 3045 3046 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port); 3047 } 3048 3049 3050 /* 3051 * Perform ULP port attach 3052 */ 3053 static void 3054 fp_ulp_port_attach(void *arg) 3055 { 3056 fp_soft_attach_t *att = (fp_soft_attach_t *)arg; 3057 fc_local_port_t *port = att->att_port; 3058 3059 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3060 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd); 3061 3062 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage); 3063 3064 if (att->att_need_pm_idle == B_TRUE) { 3065 fctl_idle_port(port); 3066 } 3067 3068 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3069 " ULPs end; port=%p, cmd=%x", port, att->att_cmd); 3070 3071 mutex_enter(&att->att_port->fp_mutex); 3072 att->att_port->fp_ulp_attach = 0; 3073 3074 port->fp_task = port->fp_last_task; 3075 port->fp_last_task = FP_TASK_IDLE; 3076 3077 cv_signal(&att->att_port->fp_attach_cv); 3078 3079 mutex_exit(&att->att_port->fp_mutex); 3080 3081 kmem_free(att, sizeof (fp_soft_attach_t)); 3082 } 3083 3084 /* 3085 * Entry point to funnel all requests down to FCAs 3086 */ 3087 static int 3088 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle) 3089 { 3090 int rval; 3091 3092 mutex_enter(&port->fp_mutex); 3093 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL && 3094 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) == 3095 FC_STATE_OFFLINE))) { 3096 /* 3097 * This means there is more than one state change 3098 * at this point of time - Since they are processed 3099 * serially, any processing of the current one should 3100 * be failed, failed and move up in processing the next 3101 */ 3102 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS; 3103 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3104 if (cmd->cmd_job) { 3105 /* 3106 * A state change that is going to be invalidated 3107 * by another one already in the port driver's queue 3108 * need not go up to all ULPs. This will minimize 3109 * needless processing and ripples in ULP modules 3110 */ 3111 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3112 } 3113 mutex_exit(&port->fp_mutex); 3114 return (FC_STATEC_BUSY); 3115 } 3116 3117 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3118 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE; 3119 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3120 mutex_exit(&port->fp_mutex); 3121 3122 return (FC_OFFLINE); 3123 } 3124 mutex_exit(&port->fp_mutex); 3125 3126 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt); 3127 if (rval != FC_SUCCESS) { 3128 if (rval == FC_TRAN_BUSY) { 3129 cmd->cmd_retry_interval = fp_retry_delay; 3130 rval = fp_retry_cmd(&cmd->cmd_pkt); 3131 if (rval == FC_FAILURE) { 3132 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY; 3133 } 3134 } 3135 } else { 3136 mutex_enter(&port->fp_mutex); 3137 port->fp_out_fpcmds++; 3138 mutex_exit(&port->fp_mutex); 3139 } 3140 3141 return (rval); 3142 } 3143 3144 3145 /* 3146 * Each time a timeout kicks in, walk the wait queue, decrement the 3147 * the retry_interval, when the retry_interval becomes less than 3148 * or equal to zero, re-transport the command: If the re-transport 3149 * fails with BUSY, enqueue the command in the wait queue. 3150 * 3151 * In order to prevent looping forever because of commands enqueued 3152 * from within this function itself, save the current tail pointer 3153 * (in cur_tail) and exit the loop after serving this command. 3154 */ 3155 static void 3156 fp_resendcmd(void *port_handle) 3157 { 3158 int rval; 3159 fc_local_port_t *port; 3160 fp_cmd_t *cmd; 3161 fp_cmd_t *cur_tail; 3162 3163 port = port_handle; 3164 mutex_enter(&port->fp_mutex); 3165 cur_tail = port->fp_wait_tail; 3166 mutex_exit(&port->fp_mutex); 3167 3168 while ((cmd = fp_deque_cmd(port)) != NULL) { 3169 cmd->cmd_retry_interval -= fp_retry_ticker; 3170 /* Check if we are detaching */ 3171 if (port->fp_soft_state & 3172 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) { 3173 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 3174 cmd->cmd_pkt.pkt_reason = 0; 3175 fp_iodone(cmd); 3176 } else if (cmd->cmd_retry_interval <= 0) { 3177 rval = cmd->cmd_transport(port->fp_fca_handle, 3178 &cmd->cmd_pkt); 3179 3180 if (rval != FC_SUCCESS) { 3181 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) { 3182 if (--cmd->cmd_retry_count) { 3183 fp_enque_cmd(port, cmd); 3184 if (cmd == cur_tail) { 3185 break; 3186 } 3187 continue; 3188 } 3189 cmd->cmd_pkt.pkt_state = 3190 FC_PKT_TRAN_BSY; 3191 } else { 3192 cmd->cmd_pkt.pkt_state = 3193 FC_PKT_TRAN_ERROR; 3194 } 3195 cmd->cmd_pkt.pkt_reason = 0; 3196 fp_iodone(cmd); 3197 } else { 3198 mutex_enter(&port->fp_mutex); 3199 port->fp_out_fpcmds++; 3200 mutex_exit(&port->fp_mutex); 3201 } 3202 } else { 3203 fp_enque_cmd(port, cmd); 3204 } 3205 3206 if (cmd == cur_tail) { 3207 break; 3208 } 3209 } 3210 3211 mutex_enter(&port->fp_mutex); 3212 if (port->fp_wait_head) { 3213 timeout_id_t tid; 3214 3215 mutex_exit(&port->fp_mutex); 3216 tid = timeout(fp_resendcmd, (caddr_t)port, 3217 fp_retry_ticks); 3218 mutex_enter(&port->fp_mutex); 3219 port->fp_wait_tid = tid; 3220 } else { 3221 port->fp_wait_tid = NULL; 3222 } 3223 mutex_exit(&port->fp_mutex); 3224 } 3225 3226 3227 /* 3228 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here. 3229 * 3230 * Yes, as you can see below, cmd_retry_count is used here too. That means 3231 * the retries for BUSY are less if there were transport failures (transport 3232 * failure means fca_transport failure). The goal is not to exceed overall 3233 * retries set in the cmd_retry_count (whatever may be the reason for retry) 3234 * 3235 * Return Values: 3236 * FC_SUCCESS 3237 * FC_FAILURE 3238 */ 3239 static int 3240 fp_retry_cmd(fc_packet_t *pkt) 3241 { 3242 fp_cmd_t *cmd; 3243 3244 cmd = pkt->pkt_ulp_private; 3245 3246 if (--cmd->cmd_retry_count) { 3247 fp_enque_cmd(cmd->cmd_port, cmd); 3248 return (FC_SUCCESS); 3249 } else { 3250 return (FC_FAILURE); 3251 } 3252 } 3253 3254 3255 /* 3256 * Queue up FC packet for deferred retry 3257 */ 3258 static void 3259 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd) 3260 { 3261 timeout_id_t tid; 3262 3263 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3264 3265 #ifdef DEBUG 3266 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt, 3267 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id); 3268 #endif 3269 3270 mutex_enter(&port->fp_mutex); 3271 if (port->fp_wait_tail) { 3272 port->fp_wait_tail->cmd_next = cmd; 3273 port->fp_wait_tail = cmd; 3274 } else { 3275 ASSERT(port->fp_wait_head == NULL); 3276 port->fp_wait_head = port->fp_wait_tail = cmd; 3277 if (port->fp_wait_tid == NULL) { 3278 mutex_exit(&port->fp_mutex); 3279 tid = timeout(fp_resendcmd, (caddr_t)port, 3280 fp_retry_ticks); 3281 mutex_enter(&port->fp_mutex); 3282 port->fp_wait_tid = tid; 3283 } 3284 } 3285 mutex_exit(&port->fp_mutex); 3286 } 3287 3288 3289 /* 3290 * Handle all RJT codes 3291 */ 3292 static int 3293 fp_handle_reject(fc_packet_t *pkt) 3294 { 3295 int rval = FC_FAILURE; 3296 uchar_t next_class; 3297 fp_cmd_t *cmd; 3298 fc_local_port_t *port; 3299 3300 cmd = pkt->pkt_ulp_private; 3301 port = cmd->cmd_port; 3302 3303 switch (pkt->pkt_state) { 3304 case FC_PKT_FABRIC_RJT: 3305 case FC_PKT_NPORT_RJT: 3306 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) { 3307 next_class = fp_get_nextclass(cmd->cmd_port, 3308 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 3309 3310 if (next_class == FC_TRAN_CLASS_INVALID) { 3311 return (rval); 3312 } 3313 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class; 3314 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 3315 3316 rval = fp_sendcmd(cmd->cmd_port, cmd, 3317 cmd->cmd_port->fp_fca_handle); 3318 3319 if (rval != FC_SUCCESS) { 3320 pkt->pkt_state = FC_PKT_TRAN_ERROR; 3321 } 3322 } 3323 break; 3324 3325 case FC_PKT_LS_RJT: 3326 case FC_PKT_BA_RJT: 3327 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) || 3328 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) { 3329 cmd->cmd_retry_interval = fp_retry_delay; 3330 rval = fp_retry_cmd(pkt); 3331 } 3332 break; 3333 3334 case FC_PKT_FS_RJT: 3335 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) || 3336 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) && 3337 (pkt->pkt_expln == 0x00))) { 3338 cmd->cmd_retry_interval = fp_retry_delay; 3339 rval = fp_retry_cmd(pkt); 3340 } 3341 break; 3342 3343 case FC_PKT_LOCAL_RJT: 3344 if (pkt->pkt_reason == FC_REASON_QFULL) { 3345 cmd->cmd_retry_interval = fp_retry_delay; 3346 rval = fp_retry_cmd(pkt); 3347 } 3348 break; 3349 3350 default: 3351 FP_TRACE(FP_NHEAD1(1, 0), 3352 "fp_handle_reject(): Invalid pkt_state"); 3353 break; 3354 } 3355 3356 return (rval); 3357 } 3358 3359 3360 /* 3361 * Return the next class of service supported by the FCA 3362 */ 3363 static uchar_t 3364 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class) 3365 { 3366 uchar_t next_class; 3367 3368 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3369 3370 switch (cur_class) { 3371 case FC_TRAN_CLASS_INVALID: 3372 if (port->fp_cos & FC_NS_CLASS1) { 3373 next_class = FC_TRAN_CLASS1; 3374 break; 3375 } 3376 /* FALLTHROUGH */ 3377 3378 case FC_TRAN_CLASS1: 3379 if (port->fp_cos & FC_NS_CLASS2) { 3380 next_class = FC_TRAN_CLASS2; 3381 break; 3382 } 3383 /* FALLTHROUGH */ 3384 3385 case FC_TRAN_CLASS2: 3386 if (port->fp_cos & FC_NS_CLASS3) { 3387 next_class = FC_TRAN_CLASS3; 3388 break; 3389 } 3390 /* FALLTHROUGH */ 3391 3392 case FC_TRAN_CLASS3: 3393 default: 3394 next_class = FC_TRAN_CLASS_INVALID; 3395 break; 3396 } 3397 3398 return (next_class); 3399 } 3400 3401 3402 /* 3403 * Determine if a class of service is supported by the FCA 3404 */ 3405 static int 3406 fp_is_class_supported(uint32_t cos, uchar_t tran_class) 3407 { 3408 int rval; 3409 3410 switch (tran_class) { 3411 case FC_TRAN_CLASS1: 3412 if (cos & FC_NS_CLASS1) { 3413 rval = FC_SUCCESS; 3414 } else { 3415 rval = FC_FAILURE; 3416 } 3417 break; 3418 3419 case FC_TRAN_CLASS2: 3420 if (cos & FC_NS_CLASS2) { 3421 rval = FC_SUCCESS; 3422 } else { 3423 rval = FC_FAILURE; 3424 } 3425 break; 3426 3427 case FC_TRAN_CLASS3: 3428 if (cos & FC_NS_CLASS3) { 3429 rval = FC_SUCCESS; 3430 } else { 3431 rval = FC_FAILURE; 3432 } 3433 break; 3434 3435 default: 3436 rval = FC_FAILURE; 3437 break; 3438 } 3439 3440 return (rval); 3441 } 3442 3443 3444 /* 3445 * Dequeue FC packet for retry 3446 */ 3447 static fp_cmd_t * 3448 fp_deque_cmd(fc_local_port_t *port) 3449 { 3450 fp_cmd_t *cmd; 3451 3452 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3453 3454 mutex_enter(&port->fp_mutex); 3455 3456 if (port->fp_wait_head == NULL) { 3457 /* 3458 * To avoid races, NULL the fp_wait_tid as 3459 * we are about to exit the timeout thread. 3460 */ 3461 port->fp_wait_tid = NULL; 3462 mutex_exit(&port->fp_mutex); 3463 return (NULL); 3464 } 3465 3466 cmd = port->fp_wait_head; 3467 port->fp_wait_head = cmd->cmd_next; 3468 cmd->cmd_next = NULL; 3469 3470 if (port->fp_wait_head == NULL) { 3471 port->fp_wait_tail = NULL; 3472 } 3473 mutex_exit(&port->fp_mutex); 3474 3475 return (cmd); 3476 } 3477 3478 3479 /* 3480 * Wait for job completion 3481 */ 3482 static void 3483 fp_jobwait(job_request_t *job) 3484 { 3485 sema_p(&job->job_port_sema); 3486 } 3487 3488 3489 /* 3490 * Convert FC packet state to FC errno 3491 */ 3492 int 3493 fp_state_to_rval(uchar_t state) 3494 { 3495 int count; 3496 3497 for (count = 0; count < sizeof (fp_xlat) / 3498 sizeof (fp_xlat[0]); count++) { 3499 if (fp_xlat[count].xlat_state == state) { 3500 return (fp_xlat[count].xlat_rval); 3501 } 3502 } 3503 3504 return (FC_FAILURE); 3505 } 3506 3507 3508 /* 3509 * For Synchronous I/O requests, the caller is 3510 * expected to do fctl_jobdone(if necessary) 3511 * 3512 * We want to preserve at least one failure in the 3513 * job_result if it happens. 3514 * 3515 */ 3516 static void 3517 fp_iodone(fp_cmd_t *cmd) 3518 { 3519 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt; 3520 job_request_t *job = cmd->cmd_job; 3521 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd; 3522 3523 ASSERT(job != NULL); 3524 ASSERT(cmd->cmd_port != NULL); 3525 ASSERT(&cmd->cmd_pkt != NULL); 3526 3527 mutex_enter(&job->job_mutex); 3528 if (job->job_result == FC_SUCCESS) { 3529 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state); 3530 } 3531 mutex_exit(&job->job_mutex); 3532 3533 if (pd) { 3534 mutex_enter(&pd->pd_mutex); 3535 pd->pd_flags = PD_IDLE; 3536 mutex_exit(&pd->pd_mutex); 3537 } 3538 3539 if (ulp_pkt) { 3540 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR && 3541 FP_IS_PKT_ERROR(ulp_pkt)) { 3542 fc_local_port_t *port; 3543 fc_remote_node_t *node; 3544 3545 port = cmd->cmd_port; 3546 3547 mutex_enter(&pd->pd_mutex); 3548 pd->pd_state = PORT_DEVICE_INVALID; 3549 pd->pd_ref_count--; 3550 node = pd->pd_remote_nodep; 3551 mutex_exit(&pd->pd_mutex); 3552 3553 ASSERT(node != NULL); 3554 ASSERT(port != NULL); 3555 3556 if (fctl_destroy_remote_port(port, pd) == 0) { 3557 fctl_destroy_remote_node(node); 3558 } 3559 3560 ulp_pkt->pkt_pd = NULL; 3561 } 3562 3563 ulp_pkt->pkt_comp(ulp_pkt); 3564 } 3565 3566 fp_free_pkt(cmd); 3567 fp_jobdone(job); 3568 } 3569 3570 3571 /* 3572 * Job completion handler 3573 */ 3574 static void 3575 fp_jobdone(job_request_t *job) 3576 { 3577 mutex_enter(&job->job_mutex); 3578 ASSERT(job->job_counter > 0); 3579 3580 if (--job->job_counter != 0) { 3581 mutex_exit(&job->job_mutex); 3582 return; 3583 } 3584 3585 if (job->job_ulp_pkts) { 3586 ASSERT(job->job_ulp_listlen > 0); 3587 kmem_free(job->job_ulp_pkts, 3588 sizeof (fc_packet_t *) * job->job_ulp_listlen); 3589 } 3590 3591 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3592 mutex_exit(&job->job_mutex); 3593 fctl_jobdone(job); 3594 } else { 3595 mutex_exit(&job->job_mutex); 3596 sema_v(&job->job_port_sema); 3597 } 3598 } 3599 3600 3601 /* 3602 * Try to perform shutdown of a port during a detach. No return 3603 * value since the detach should not fail because the port shutdown 3604 * failed. 3605 */ 3606 static void 3607 fp_port_shutdown(fc_local_port_t *port, job_request_t *job) 3608 { 3609 int index; 3610 int count; 3611 int flags; 3612 fp_cmd_t *cmd; 3613 struct pwwn_hash *head; 3614 fc_remote_port_t *pd; 3615 3616 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3617 3618 job->job_result = FC_SUCCESS; 3619 3620 if (port->fp_taskq) { 3621 /* 3622 * We must release the mutex here to ensure that other 3623 * potential jobs can complete their processing. Many 3624 * also need this mutex. 3625 */ 3626 mutex_exit(&port->fp_mutex); 3627 taskq_wait(port->fp_taskq); 3628 mutex_enter(&port->fp_mutex); 3629 } 3630 3631 if (port->fp_offline_tid) { 3632 timeout_id_t tid; 3633 3634 tid = port->fp_offline_tid; 3635 port->fp_offline_tid = NULL; 3636 mutex_exit(&port->fp_mutex); 3637 (void) untimeout(tid); 3638 mutex_enter(&port->fp_mutex); 3639 } 3640 3641 if (port->fp_wait_tid) { 3642 timeout_id_t tid; 3643 3644 tid = port->fp_wait_tid; 3645 port->fp_wait_tid = NULL; 3646 mutex_exit(&port->fp_mutex); 3647 (void) untimeout(tid); 3648 } else { 3649 mutex_exit(&port->fp_mutex); 3650 } 3651 3652 /* 3653 * While we cancel the timeout, let's also return the 3654 * the outstanding requests back to the callers. 3655 */ 3656 while ((cmd = fp_deque_cmd(port)) != NULL) { 3657 ASSERT(cmd->cmd_job != NULL); 3658 cmd->cmd_job->job_result = FC_OFFLINE; 3659 fp_iodone(cmd); 3660 } 3661 3662 /* 3663 * Gracefully LOGO with all the devices logged in. 3664 */ 3665 mutex_enter(&port->fp_mutex); 3666 3667 for (count = index = 0; index < pwwn_table_size; index++) { 3668 head = &port->fp_pwwn_table[index]; 3669 pd = head->pwwn_head; 3670 while (pd != NULL) { 3671 mutex_enter(&pd->pd_mutex); 3672 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3673 count++; 3674 } 3675 mutex_exit(&pd->pd_mutex); 3676 pd = pd->pd_wwn_hnext; 3677 } 3678 } 3679 3680 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3681 flags = job->job_flags; 3682 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 3683 } else { 3684 flags = 0; 3685 } 3686 if (count) { 3687 job->job_counter = count; 3688 3689 for (index = 0; index < pwwn_table_size; index++) { 3690 head = &port->fp_pwwn_table[index]; 3691 pd = head->pwwn_head; 3692 while (pd != NULL) { 3693 mutex_enter(&pd->pd_mutex); 3694 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3695 ASSERT(pd->pd_login_count > 0); 3696 /* 3697 * Force the counter to ONE in order 3698 * for us to really send LOGO els. 3699 */ 3700 pd->pd_login_count = 1; 3701 mutex_exit(&pd->pd_mutex); 3702 mutex_exit(&port->fp_mutex); 3703 (void) fp_logout(port, pd, job); 3704 mutex_enter(&port->fp_mutex); 3705 } else { 3706 mutex_exit(&pd->pd_mutex); 3707 } 3708 pd = pd->pd_wwn_hnext; 3709 } 3710 } 3711 mutex_exit(&port->fp_mutex); 3712 fp_jobwait(job); 3713 } else { 3714 mutex_exit(&port->fp_mutex); 3715 } 3716 3717 if (job->job_result != FC_SUCCESS) { 3718 FP_TRACE(FP_NHEAD1(9, 0), 3719 "Can't logout all devices. Proceeding with" 3720 " port shutdown"); 3721 job->job_result = FC_SUCCESS; 3722 } 3723 3724 fctl_destroy_all_remote_ports(port); 3725 3726 mutex_enter(&port->fp_mutex); 3727 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3728 mutex_exit(&port->fp_mutex); 3729 fp_ns_fini(port, job); 3730 } else { 3731 mutex_exit(&port->fp_mutex); 3732 } 3733 3734 if (flags) { 3735 job->job_flags = flags; 3736 } 3737 3738 mutex_enter(&port->fp_mutex); 3739 3740 } 3741 3742 3743 /* 3744 * Build the port driver's data structures based on the AL_PA list 3745 */ 3746 static void 3747 fp_get_loopmap(fc_local_port_t *port, job_request_t *job) 3748 { 3749 int rval; 3750 int flag; 3751 int count; 3752 uint32_t d_id; 3753 fc_remote_port_t *pd; 3754 fc_lilpmap_t *lilp_map; 3755 3756 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3757 3758 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3759 job->job_result = FC_OFFLINE; 3760 mutex_exit(&port->fp_mutex); 3761 fp_jobdone(job); 3762 mutex_enter(&port->fp_mutex); 3763 return; 3764 } 3765 3766 if (port->fp_lilp_map.lilp_length == 0) { 3767 mutex_exit(&port->fp_mutex); 3768 job->job_result = FC_NO_MAP; 3769 fp_jobdone(job); 3770 mutex_enter(&port->fp_mutex); 3771 return; 3772 } 3773 mutex_exit(&port->fp_mutex); 3774 3775 lilp_map = &port->fp_lilp_map; 3776 job->job_counter = lilp_map->lilp_length; 3777 3778 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) { 3779 flag = FP_CMD_PLOGI_RETAIN; 3780 } else { 3781 flag = FP_CMD_PLOGI_DONT_CARE; 3782 } 3783 3784 for (count = 0; count < lilp_map->lilp_length; count++) { 3785 d_id = lilp_map->lilp_alpalist[count]; 3786 3787 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3788 fp_jobdone(job); 3789 continue; 3790 } 3791 3792 pd = fctl_get_remote_port_by_did(port, d_id); 3793 if (pd) { 3794 mutex_enter(&pd->pd_mutex); 3795 if (flag == FP_CMD_PLOGI_DONT_CARE || 3796 pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3797 mutex_exit(&pd->pd_mutex); 3798 fp_jobdone(job); 3799 continue; 3800 } 3801 mutex_exit(&pd->pd_mutex); 3802 } 3803 3804 rval = fp_port_login(port, d_id, job, flag, 3805 KM_SLEEP, pd, NULL); 3806 if (rval != FC_SUCCESS) { 3807 fp_jobdone(job); 3808 } 3809 } 3810 3811 mutex_enter(&port->fp_mutex); 3812 } 3813 3814 3815 /* 3816 * Perform loop ONLINE processing 3817 */ 3818 static void 3819 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan) 3820 { 3821 int count; 3822 int rval; 3823 uint32_t d_id; 3824 uint32_t listlen; 3825 fc_lilpmap_t *lilp_map; 3826 fc_remote_port_t *pd; 3827 fc_portmap_t *changelist; 3828 3829 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3830 3831 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p", 3832 port, job); 3833 3834 lilp_map = &port->fp_lilp_map; 3835 3836 if (lilp_map->lilp_length) { 3837 mutex_enter(&port->fp_mutex); 3838 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 3839 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 3840 mutex_exit(&port->fp_mutex); 3841 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000)); 3842 } else { 3843 mutex_exit(&port->fp_mutex); 3844 } 3845 3846 job->job_counter = lilp_map->lilp_length; 3847 3848 for (count = 0; count < lilp_map->lilp_length; count++) { 3849 d_id = lilp_map->lilp_alpalist[count]; 3850 3851 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3852 fp_jobdone(job); 3853 continue; 3854 } 3855 3856 pd = fctl_get_remote_port_by_did(port, d_id); 3857 if (pd != NULL) { 3858 #ifdef DEBUG 3859 mutex_enter(&pd->pd_mutex); 3860 if (pd->pd_recepient == PD_PLOGI_INITIATOR) { 3861 ASSERT(pd->pd_type != PORT_DEVICE_OLD); 3862 } 3863 mutex_exit(&pd->pd_mutex); 3864 #endif 3865 fp_jobdone(job); 3866 continue; 3867 } 3868 3869 rval = fp_port_login(port, d_id, job, 3870 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL); 3871 3872 if (rval != FC_SUCCESS) { 3873 fp_jobdone(job); 3874 } 3875 } 3876 fp_jobwait(job); 3877 } 3878 listlen = 0; 3879 changelist = NULL; 3880 3881 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3882 mutex_enter(&port->fp_mutex); 3883 ASSERT(port->fp_statec_busy > 0); 3884 if (port->fp_statec_busy == 1) { 3885 mutex_exit(&port->fp_mutex); 3886 fctl_fillout_map(port, &changelist, &listlen, 3887 1, 0, orphan); 3888 3889 mutex_enter(&port->fp_mutex); 3890 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 3891 ASSERT(port->fp_total_devices == 0); 3892 port->fp_total_devices = port->fp_dev_count; 3893 } 3894 } else { 3895 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3896 } 3897 mutex_exit(&port->fp_mutex); 3898 } 3899 3900 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3901 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 3902 listlen, listlen, KM_SLEEP); 3903 } else { 3904 mutex_enter(&port->fp_mutex); 3905 if (--port->fp_statec_busy == 0) { 3906 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 3907 } 3908 ASSERT(changelist == NULL && listlen == 0); 3909 mutex_exit(&port->fp_mutex); 3910 } 3911 3912 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p", 3913 port, job); 3914 } 3915 3916 3917 /* 3918 * Get an Arbitrated Loop map from the underlying FCA 3919 */ 3920 static int 3921 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map) 3922 { 3923 int rval; 3924 3925 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p", 3926 port, lilp_map); 3927 3928 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t)); 3929 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map); 3930 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */ 3931 3932 if (rval != FC_SUCCESS) { 3933 rval = FC_NO_MAP; 3934 } else if (lilp_map->lilp_length == 0 && 3935 (lilp_map->lilp_magic >= MAGIC_LISM && 3936 lilp_map->lilp_magic < MAGIC_LIRP)) { 3937 uchar_t lilp_length; 3938 3939 /* 3940 * Since the map length is zero, provide all 3941 * the valid AL_PAs for NL_ports discovery. 3942 */ 3943 lilp_length = sizeof (fp_valid_alpas) / 3944 sizeof (fp_valid_alpas[0]); 3945 lilp_map->lilp_length = lilp_length; 3946 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist, 3947 lilp_length); 3948 } else { 3949 rval = fp_validate_lilp_map(lilp_map); 3950 3951 if (rval == FC_SUCCESS) { 3952 mutex_enter(&port->fp_mutex); 3953 port->fp_total_devices = lilp_map->lilp_length - 1; 3954 mutex_exit(&port->fp_mutex); 3955 } 3956 } 3957 3958 mutex_enter(&port->fp_mutex); 3959 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) { 3960 port->fp_soft_state |= FP_SOFT_BAD_LINK; 3961 mutex_exit(&port->fp_mutex); 3962 3963 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle, 3964 FC_FCA_RESET_CORE) != FC_SUCCESS) { 3965 FP_TRACE(FP_NHEAD1(9, 0), 3966 "FCA reset failed after LILP map was found" 3967 " to be invalid"); 3968 } 3969 } else if (rval == FC_SUCCESS) { 3970 port->fp_soft_state &= ~FP_SOFT_BAD_LINK; 3971 mutex_exit(&port->fp_mutex); 3972 } else { 3973 mutex_exit(&port->fp_mutex); 3974 } 3975 3976 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port, 3977 lilp_map); 3978 3979 return (rval); 3980 } 3981 3982 3983 /* 3984 * Perform Fabric Login: 3985 * 3986 * Return Values: 3987 * FC_SUCCESS 3988 * FC_FAILURE 3989 * FC_NOMEM 3990 * FC_TRANSPORT_ERROR 3991 * and a lot others defined in fc_error.h 3992 */ 3993 static int 3994 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job, 3995 int flag, int sleep) 3996 { 3997 int rval; 3998 fp_cmd_t *cmd; 3999 uchar_t class; 4000 4001 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4002 4003 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p", 4004 port, job); 4005 4006 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4007 if (class == FC_TRAN_CLASS_INVALID) { 4008 return (FC_ELS_BAD); 4009 } 4010 4011 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4012 sizeof (la_els_logi_t), sleep, NULL); 4013 if (cmd == NULL) { 4014 return (FC_NOMEM); 4015 } 4016 4017 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4018 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4019 cmd->cmd_flags = flag; 4020 cmd->cmd_retry_count = fp_retry_count; 4021 cmd->cmd_ulp_pkt = NULL; 4022 4023 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr, 4024 job, LA_ELS_FLOGI); 4025 4026 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 4027 if (rval != FC_SUCCESS) { 4028 fp_free_pkt(cmd); 4029 } 4030 4031 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p", 4032 port, job); 4033 4034 return (rval); 4035 } 4036 4037 4038 /* 4039 * In some scenarios such as private loop device discovery period 4040 * the fc_remote_port_t data structure isn't allocated. The allocation 4041 * is done when the PLOGI is successful. In some other scenarios 4042 * such as Fabric topology, the fc_remote_port_t is already created 4043 * and initialized with appropriate values (as the NS provides 4044 * them) 4045 */ 4046 static int 4047 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job, 4048 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt) 4049 { 4050 uchar_t class; 4051 fp_cmd_t *cmd; 4052 uint32_t src_id; 4053 fc_remote_port_t *tmp_pd; 4054 int relogin; 4055 int found = 0; 4056 4057 #ifdef DEBUG 4058 if (pd == NULL) { 4059 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL); 4060 } 4061 #endif 4062 ASSERT(job->job_counter > 0); 4063 4064 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4065 if (class == FC_TRAN_CLASS_INVALID) { 4066 return (FC_ELS_BAD); 4067 } 4068 4069 mutex_enter(&port->fp_mutex); 4070 tmp_pd = fctl_lookup_pd_by_did(port, d_id); 4071 mutex_exit(&port->fp_mutex); 4072 4073 relogin = 1; 4074 if (tmp_pd) { 4075 mutex_enter(&tmp_pd->pd_mutex); 4076 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) && 4077 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) { 4078 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN; 4079 relogin = 0; 4080 } 4081 mutex_exit(&tmp_pd->pd_mutex); 4082 } 4083 4084 if (!relogin) { 4085 mutex_enter(&tmp_pd->pd_mutex); 4086 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4087 cmd_flag |= FP_CMD_PLOGI_RETAIN; 4088 } 4089 mutex_exit(&tmp_pd->pd_mutex); 4090 4091 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 4092 sizeof (la_els_adisc_t), sleep, tmp_pd); 4093 if (cmd == NULL) { 4094 return (FC_NOMEM); 4095 } 4096 4097 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4098 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4099 cmd->cmd_flags = cmd_flag; 4100 cmd->cmd_retry_count = fp_retry_count; 4101 cmd->cmd_ulp_pkt = ulp_pkt; 4102 4103 mutex_enter(&port->fp_mutex); 4104 mutex_enter(&tmp_pd->pd_mutex); 4105 fp_adisc_init(cmd, job); 4106 mutex_exit(&tmp_pd->pd_mutex); 4107 mutex_exit(&port->fp_mutex); 4108 4109 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t); 4110 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t); 4111 4112 } else { 4113 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4114 sizeof (la_els_logi_t), sleep, pd); 4115 if (cmd == NULL) { 4116 return (FC_NOMEM); 4117 } 4118 4119 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4120 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4121 cmd->cmd_flags = cmd_flag; 4122 cmd->cmd_retry_count = fp_retry_count; 4123 cmd->cmd_ulp_pkt = ulp_pkt; 4124 4125 mutex_enter(&port->fp_mutex); 4126 src_id = port->fp_port_id.port_id; 4127 mutex_exit(&port->fp_mutex); 4128 4129 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr, 4130 job, LA_ELS_PLOGI); 4131 } 4132 4133 if (pd) { 4134 mutex_enter(&pd->pd_mutex); 4135 pd->pd_flags = PD_ELS_IN_PROGRESS; 4136 mutex_exit(&pd->pd_mutex); 4137 } 4138 4139 /* npiv check to make sure we don't log into ourself */ 4140 if (relogin && 4141 ((port->fp_npiv_type == FC_NPIV_PORT) || 4142 (port->fp_npiv_flag == FC_NPIV_ENABLE))) { 4143 if ((d_id & 0xffff00) == 4144 (port->fp_port_id.port_id & 0xffff00)) { 4145 found = 1; 4146 } 4147 } 4148 4149 if (found || 4150 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) { 4151 if (found) { 4152 fc_packet_t *pkt = &cmd->cmd_pkt; 4153 pkt->pkt_state = FC_PKT_NPORT_RJT; 4154 } 4155 if (pd) { 4156 mutex_enter(&pd->pd_mutex); 4157 pd->pd_flags = PD_IDLE; 4158 mutex_exit(&pd->pd_mutex); 4159 } 4160 4161 if (ulp_pkt) { 4162 fc_packet_t *pkt = &cmd->cmd_pkt; 4163 4164 ulp_pkt->pkt_state = pkt->pkt_state; 4165 ulp_pkt->pkt_reason = pkt->pkt_reason; 4166 ulp_pkt->pkt_action = pkt->pkt_action; 4167 ulp_pkt->pkt_expln = pkt->pkt_expln; 4168 } 4169 4170 fp_iodone(cmd); 4171 } 4172 4173 return (FC_SUCCESS); 4174 } 4175 4176 4177 /* 4178 * Register the LOGIN parameters with a port device 4179 */ 4180 static void 4181 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 4182 la_els_logi_t *acc, uchar_t class) 4183 { 4184 fc_remote_node_t *node; 4185 4186 ASSERT(pd != NULL); 4187 4188 mutex_enter(&pd->pd_mutex); 4189 node = pd->pd_remote_nodep; 4190 if (pd->pd_login_count == 0) { 4191 pd->pd_login_count++; 4192 } 4193 4194 if (handle) { 4195 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp, 4196 (uint8_t *)&acc->common_service, 4197 sizeof (acc->common_service), DDI_DEV_AUTOINCR); 4198 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1, 4199 (uint8_t *)&acc->class_1, sizeof (acc->class_1), 4200 DDI_DEV_AUTOINCR); 4201 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2, 4202 (uint8_t *)&acc->class_2, sizeof (acc->class_2), 4203 DDI_DEV_AUTOINCR); 4204 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3, 4205 (uint8_t *)&acc->class_3, sizeof (acc->class_3), 4206 DDI_DEV_AUTOINCR); 4207 } else { 4208 pd->pd_csp = acc->common_service; 4209 pd->pd_clsp1 = acc->class_1; 4210 pd->pd_clsp2 = acc->class_2; 4211 pd->pd_clsp3 = acc->class_3; 4212 } 4213 4214 pd->pd_state = PORT_DEVICE_LOGGED_IN; 4215 pd->pd_login_class = class; 4216 mutex_exit(&pd->pd_mutex); 4217 4218 #ifndef __lock_lint 4219 ASSERT(fctl_get_remote_port_by_did(pd->pd_port, 4220 pd->pd_port_id.port_id) == pd); 4221 #endif 4222 4223 mutex_enter(&node->fd_mutex); 4224 if (handle) { 4225 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv, 4226 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv), 4227 DDI_DEV_AUTOINCR); 4228 } else { 4229 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv)); 4230 } 4231 mutex_exit(&node->fd_mutex); 4232 } 4233 4234 4235 /* 4236 * Mark the remote port as OFFLINE 4237 */ 4238 static void 4239 fp_remote_port_offline(fc_remote_port_t *pd) 4240 { 4241 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4242 if (pd->pd_login_count && 4243 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) { 4244 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4245 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4246 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4247 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4248 pd->pd_login_class = 0; 4249 } 4250 pd->pd_type = PORT_DEVICE_OLD; 4251 pd->pd_flags = PD_IDLE; 4252 fctl_tc_reset(&pd->pd_logo_tc); 4253 } 4254 4255 4256 /* 4257 * Deregistration of a port device 4258 */ 4259 static void 4260 fp_unregister_login(fc_remote_port_t *pd) 4261 { 4262 fc_remote_node_t *node; 4263 4264 ASSERT(pd != NULL); 4265 4266 mutex_enter(&pd->pd_mutex); 4267 pd->pd_login_count = 0; 4268 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4269 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4270 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4271 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4272 4273 pd->pd_state = PORT_DEVICE_VALID; 4274 pd->pd_login_class = 0; 4275 node = pd->pd_remote_nodep; 4276 mutex_exit(&pd->pd_mutex); 4277 4278 mutex_enter(&node->fd_mutex); 4279 bzero(node->fd_vv, sizeof (node->fd_vv)); 4280 mutex_exit(&node->fd_mutex); 4281 } 4282 4283 4284 /* 4285 * Handle OFFLINE state of an FCA port 4286 */ 4287 static void 4288 fp_port_offline(fc_local_port_t *port, int notify) 4289 { 4290 int index; 4291 int statec; 4292 timeout_id_t tid; 4293 struct pwwn_hash *head; 4294 fc_remote_port_t *pd; 4295 4296 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4297 4298 for (index = 0; index < pwwn_table_size; index++) { 4299 head = &port->fp_pwwn_table[index]; 4300 pd = head->pwwn_head; 4301 while (pd != NULL) { 4302 mutex_enter(&pd->pd_mutex); 4303 fp_remote_port_offline(pd); 4304 fctl_delist_did_table(port, pd); 4305 mutex_exit(&pd->pd_mutex); 4306 pd = pd->pd_wwn_hnext; 4307 } 4308 } 4309 port->fp_total_devices = 0; 4310 4311 statec = 0; 4312 if (notify) { 4313 /* 4314 * Decrement the statec busy counter as we 4315 * are almost done with handling the state 4316 * change 4317 */ 4318 ASSERT(port->fp_statec_busy > 0); 4319 if (--port->fp_statec_busy == 0) { 4320 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4321 } 4322 mutex_exit(&port->fp_mutex); 4323 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL, 4324 0, 0, KM_SLEEP); 4325 mutex_enter(&port->fp_mutex); 4326 4327 if (port->fp_statec_busy) { 4328 statec++; 4329 } 4330 } else if (port->fp_statec_busy > 1) { 4331 statec++; 4332 } 4333 4334 if ((tid = port->fp_offline_tid) != NULL) { 4335 mutex_exit(&port->fp_mutex); 4336 (void) untimeout(tid); 4337 mutex_enter(&port->fp_mutex); 4338 } 4339 4340 if (!statec) { 4341 port->fp_offline_tid = timeout(fp_offline_timeout, 4342 (caddr_t)port, fp_offline_ticks); 4343 } 4344 } 4345 4346 4347 /* 4348 * Offline devices and send up a state change notification to ULPs 4349 */ 4350 static void 4351 fp_offline_timeout(void *port_handle) 4352 { 4353 int ret; 4354 fc_local_port_t *port = port_handle; 4355 uint32_t listlen = 0; 4356 fc_portmap_t *changelist = NULL; 4357 4358 mutex_enter(&port->fp_mutex); 4359 4360 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) || 4361 (port->fp_soft_state & 4362 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 4363 port->fp_dev_count == 0 || port->fp_statec_busy) { 4364 port->fp_offline_tid = NULL; 4365 mutex_exit(&port->fp_mutex); 4366 return; 4367 } 4368 4369 mutex_exit(&port->fp_mutex); 4370 4371 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout"); 4372 4373 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) { 4374 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4375 FC_FCA_CORE)) != FC_SUCCESS) { 4376 FP_TRACE(FP_NHEAD1(9, ret), 4377 "Failed to force adapter dump"); 4378 } else { 4379 FP_TRACE(FP_NHEAD1(9, 0), 4380 "Forced adapter dump successfully"); 4381 } 4382 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) { 4383 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4384 FC_FCA_RESET_CORE)) != FC_SUCCESS) { 4385 FP_TRACE(FP_NHEAD1(9, ret), 4386 "Failed to force adapter dump and reset"); 4387 } else { 4388 FP_TRACE(FP_NHEAD1(9, 0), 4389 "Forced adapter dump and reset successfully"); 4390 } 4391 } 4392 4393 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 4394 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist, 4395 listlen, listlen, KM_SLEEP); 4396 4397 mutex_enter(&port->fp_mutex); 4398 port->fp_offline_tid = NULL; 4399 mutex_exit(&port->fp_mutex); 4400 } 4401 4402 4403 /* 4404 * Perform general purpose ELS request initialization 4405 */ 4406 static void 4407 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id, 4408 void (*comp) (), job_request_t *job) 4409 { 4410 fc_packet_t *pkt; 4411 4412 pkt = &cmd->cmd_pkt; 4413 cmd->cmd_job = job; 4414 4415 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; 4416 pkt->pkt_cmd_fhdr.d_id = d_id; 4417 pkt->pkt_cmd_fhdr.s_id = s_id; 4418 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 4419 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ; 4420 pkt->pkt_cmd_fhdr.seq_id = 0; 4421 pkt->pkt_cmd_fhdr.df_ctl = 0; 4422 pkt->pkt_cmd_fhdr.seq_cnt = 0; 4423 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 4424 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 4425 pkt->pkt_cmd_fhdr.ro = 0; 4426 pkt->pkt_cmd_fhdr.rsvd = 0; 4427 pkt->pkt_comp = comp; 4428 pkt->pkt_timeout = FP_ELS_TIMEOUT; 4429 } 4430 4431 4432 /* 4433 * Initialize PLOGI/FLOGI ELS request 4434 */ 4435 static void 4436 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id, 4437 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code) 4438 { 4439 ls_code_t payload; 4440 4441 fp_els_init(cmd, s_id, d_id, intr, job); 4442 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4443 4444 payload.ls_code = ls_code; 4445 payload.mbz = 0; 4446 4447 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, 4448 (uint8_t *)&port->fp_service_params, 4449 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params), 4450 DDI_DEV_AUTOINCR); 4451 4452 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload, 4453 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload), 4454 DDI_DEV_AUTOINCR); 4455 } 4456 4457 4458 /* 4459 * Initialize LOGO ELS request 4460 */ 4461 static void 4462 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job) 4463 { 4464 fc_local_port_t *port; 4465 fc_packet_t *pkt; 4466 la_els_logo_t payload; 4467 4468 port = pd->pd_port; 4469 pkt = &cmd->cmd_pkt; 4470 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4471 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4472 4473 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4474 fp_logo_intr, job); 4475 4476 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4477 4478 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4479 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4480 4481 payload.ls_code.ls_code = LA_ELS_LOGO; 4482 payload.ls_code.mbz = 0; 4483 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 4484 payload.nport_id = port->fp_port_id; 4485 4486 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4487 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4488 } 4489 4490 /* 4491 * Initialize RNID ELS request 4492 */ 4493 static void 4494 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job) 4495 { 4496 fc_local_port_t *port; 4497 fc_packet_t *pkt; 4498 la_els_rnid_t payload; 4499 fc_remote_port_t *pd; 4500 4501 pkt = &cmd->cmd_pkt; 4502 pd = pkt->pkt_pd; 4503 port = pd->pd_port; 4504 4505 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4506 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4507 4508 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4509 fp_rnid_intr, job); 4510 4511 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4512 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4513 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4514 4515 payload.ls_code.ls_code = LA_ELS_RNID; 4516 payload.ls_code.mbz = 0; 4517 payload.data_format = flag; 4518 4519 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4520 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4521 } 4522 4523 /* 4524 * Initialize RLS ELS request 4525 */ 4526 static void 4527 fp_rls_init(fp_cmd_t *cmd, job_request_t *job) 4528 { 4529 fc_local_port_t *port; 4530 fc_packet_t *pkt; 4531 la_els_rls_t payload; 4532 fc_remote_port_t *pd; 4533 4534 pkt = &cmd->cmd_pkt; 4535 pd = pkt->pkt_pd; 4536 port = pd->pd_port; 4537 4538 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4539 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4540 4541 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4542 fp_rls_intr, job); 4543 4544 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4545 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4546 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4547 4548 payload.ls_code.ls_code = LA_ELS_RLS; 4549 payload.ls_code.mbz = 0; 4550 payload.rls_portid = port->fp_port_id; 4551 4552 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4553 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4554 } 4555 4556 4557 /* 4558 * Initialize an ADISC ELS request 4559 */ 4560 static void 4561 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job) 4562 { 4563 fc_local_port_t *port; 4564 fc_packet_t *pkt; 4565 la_els_adisc_t payload; 4566 fc_remote_port_t *pd; 4567 4568 pkt = &cmd->cmd_pkt; 4569 pd = pkt->pkt_pd; 4570 port = pd->pd_port; 4571 4572 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4573 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex)); 4574 4575 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4576 fp_adisc_intr, job); 4577 4578 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4579 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4580 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4581 4582 payload.ls_code.ls_code = LA_ELS_ADISC; 4583 payload.ls_code.mbz = 0; 4584 payload.nport_id = port->fp_port_id; 4585 payload.port_wwn = port->fp_service_params.nport_ww_name; 4586 payload.node_wwn = port->fp_service_params.node_ww_name; 4587 payload.hard_addr = port->fp_hard_addr; 4588 4589 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4590 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4591 } 4592 4593 4594 /* 4595 * Send up a state change notification to ULPs. 4596 * Spawns a call to fctl_ulp_statec_cb in a taskq thread. 4597 */ 4598 static int 4599 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state, 4600 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep) 4601 { 4602 fc_port_clist_t *clist; 4603 fc_remote_port_t *pd; 4604 int count; 4605 4606 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4607 4608 clist = kmem_zalloc(sizeof (*clist), sleep); 4609 if (clist == NULL) { 4610 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4611 return (FC_NOMEM); 4612 } 4613 4614 clist->clist_state = state; 4615 4616 mutex_enter(&port->fp_mutex); 4617 clist->clist_flags = port->fp_topology; 4618 mutex_exit(&port->fp_mutex); 4619 4620 clist->clist_port = (opaque_t)port; 4621 clist->clist_len = listlen; 4622 clist->clist_size = alloc_len; 4623 clist->clist_map = changelist; 4624 4625 /* 4626 * Bump the reference count of each fc_remote_port_t in this changelist. 4627 * This is necessary since these devices will be sitting in a taskq 4628 * and referenced later. When the state change notification is 4629 * complete, the reference counts will be decremented. 4630 */ 4631 for (count = 0; count < clist->clist_len; count++) { 4632 pd = clist->clist_map[count].map_pd; 4633 4634 if (pd != NULL) { 4635 mutex_enter(&pd->pd_mutex); 4636 ASSERT((pd->pd_ref_count >= 0) || 4637 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4638 pd->pd_ref_count++; 4639 4640 if (clist->clist_map[count].map_state != 4641 PORT_DEVICE_INVALID) { 4642 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4643 } 4644 4645 mutex_exit(&pd->pd_mutex); 4646 } 4647 } 4648 4649 #ifdef DEBUG 4650 /* 4651 * Sanity check for presence of OLD devices in the hash lists 4652 */ 4653 if (clist->clist_size) { 4654 ASSERT(clist->clist_map != NULL); 4655 for (count = 0; count < clist->clist_len; count++) { 4656 if (clist->clist_map[count].map_state == 4657 PORT_DEVICE_INVALID) { 4658 la_wwn_t pwwn; 4659 fc_portid_t d_id; 4660 4661 pd = clist->clist_map[count].map_pd; 4662 ASSERT(pd != NULL); 4663 4664 mutex_enter(&pd->pd_mutex); 4665 pwwn = pd->pd_port_name; 4666 d_id = pd->pd_port_id; 4667 mutex_exit(&pd->pd_mutex); 4668 4669 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4670 ASSERT(pd != clist->clist_map[count].map_pd); 4671 4672 pd = fctl_get_remote_port_by_did(port, 4673 d_id.port_id); 4674 ASSERT(pd != clist->clist_map[count].map_pd); 4675 } 4676 } 4677 } 4678 #endif 4679 4680 mutex_enter(&port->fp_mutex); 4681 4682 if (state == FC_STATE_ONLINE) { 4683 if (--port->fp_statec_busy == 0) { 4684 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4685 } 4686 } 4687 mutex_exit(&port->fp_mutex); 4688 4689 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 4690 clist, KM_SLEEP); 4691 4692 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p," 4693 "state=%x, len=%d", port, state, listlen); 4694 4695 return (FC_SUCCESS); 4696 } 4697 4698 4699 /* 4700 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs 4701 */ 4702 static int 4703 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist, 4704 uint32_t listlen, uint32_t alloc_len, int sleep, int sync) 4705 { 4706 int ret; 4707 fc_port_clist_t *clist; 4708 4709 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4710 4711 clist = kmem_zalloc(sizeof (*clist), sleep); 4712 if (clist == NULL) { 4713 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4714 return (FC_NOMEM); 4715 } 4716 4717 clist->clist_state = FC_STATE_DEVICE_CHANGE; 4718 4719 mutex_enter(&port->fp_mutex); 4720 clist->clist_flags = port->fp_topology; 4721 mutex_exit(&port->fp_mutex); 4722 4723 clist->clist_port = (opaque_t)port; 4724 clist->clist_len = listlen; 4725 clist->clist_size = alloc_len; 4726 clist->clist_map = changelist; 4727 4728 /* Send sysevents for target state changes */ 4729 4730 if (clist->clist_size) { 4731 int count; 4732 fc_remote_port_t *pd; 4733 4734 ASSERT(clist->clist_map != NULL); 4735 for (count = 0; count < clist->clist_len; count++) { 4736 pd = clist->clist_map[count].map_pd; 4737 4738 /* 4739 * Bump reference counts on all fc_remote_port_t 4740 * structs in this list. We don't know when the task 4741 * will fire, and we don't need these fc_remote_port_t 4742 * structs going away behind our back. 4743 */ 4744 if (pd) { 4745 mutex_enter(&pd->pd_mutex); 4746 ASSERT((pd->pd_ref_count >= 0) || 4747 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4748 pd->pd_ref_count++; 4749 mutex_exit(&pd->pd_mutex); 4750 } 4751 4752 if (clist->clist_map[count].map_state == 4753 PORT_DEVICE_VALID) { 4754 if (clist->clist_map[count].map_type == 4755 PORT_DEVICE_NEW) { 4756 /* Update our state change counter */ 4757 mutex_enter(&port->fp_mutex); 4758 port->fp_last_change++; 4759 mutex_exit(&port->fp_mutex); 4760 4761 /* Additions */ 4762 fp_log_target_event(port, 4763 ESC_SUNFC_TARGET_ADD, 4764 clist->clist_map[count].map_pwwn, 4765 clist->clist_map[count].map_did. 4766 port_id); 4767 } 4768 4769 } else if ((clist->clist_map[count].map_type == 4770 PORT_DEVICE_OLD) && 4771 (clist->clist_map[count].map_state == 4772 PORT_DEVICE_INVALID)) { 4773 /* Update our state change counter */ 4774 mutex_enter(&port->fp_mutex); 4775 port->fp_last_change++; 4776 mutex_exit(&port->fp_mutex); 4777 4778 /* 4779 * For removals, we don't decrement 4780 * pd_ref_count until after the ULP's 4781 * state change callback function has 4782 * completed. 4783 */ 4784 4785 /* Removals */ 4786 fp_log_target_event(port, 4787 ESC_SUNFC_TARGET_REMOVE, 4788 clist->clist_map[count].map_pwwn, 4789 clist->clist_map[count].map_did.port_id); 4790 } 4791 4792 if (clist->clist_map[count].map_state != 4793 PORT_DEVICE_INVALID) { 4794 /* 4795 * Indicate that the ULPs are now aware of 4796 * this device. 4797 */ 4798 4799 mutex_enter(&pd->pd_mutex); 4800 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4801 mutex_exit(&pd->pd_mutex); 4802 } 4803 4804 #ifdef DEBUG 4805 /* 4806 * Sanity check for OLD devices in the hash lists 4807 */ 4808 if (pd && clist->clist_map[count].map_state == 4809 PORT_DEVICE_INVALID) { 4810 la_wwn_t pwwn; 4811 fc_portid_t d_id; 4812 4813 mutex_enter(&pd->pd_mutex); 4814 pwwn = pd->pd_port_name; 4815 d_id = pd->pd_port_id; 4816 mutex_exit(&pd->pd_mutex); 4817 4818 /* 4819 * This overwrites the 'pd' local variable. 4820 * Beware of this if 'pd' ever gets 4821 * referenced below this block. 4822 */ 4823 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4824 ASSERT(pd != clist->clist_map[count].map_pd); 4825 4826 pd = fctl_get_remote_port_by_did(port, 4827 d_id.port_id); 4828 ASSERT(pd != clist->clist_map[count].map_pd); 4829 } 4830 #endif 4831 } 4832 } 4833 4834 if (sync) { 4835 clist->clist_wait = 1; 4836 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL); 4837 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL); 4838 } 4839 4840 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep); 4841 if (sync && ret) { 4842 mutex_enter(&clist->clist_mutex); 4843 while (clist->clist_wait) { 4844 cv_wait(&clist->clist_cv, &clist->clist_mutex); 4845 } 4846 mutex_exit(&clist->clist_mutex); 4847 4848 mutex_destroy(&clist->clist_mutex); 4849 cv_destroy(&clist->clist_cv); 4850 kmem_free(clist, sizeof (*clist)); 4851 } 4852 4853 if (!ret) { 4854 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; " 4855 "port=%p", port); 4856 kmem_free(clist->clist_map, 4857 sizeof (*(clist->clist_map)) * clist->clist_size); 4858 kmem_free(clist, sizeof (*clist)); 4859 } else { 4860 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d", 4861 port, listlen); 4862 } 4863 4864 return (FC_SUCCESS); 4865 } 4866 4867 4868 /* 4869 * Perform PLOGI to the group of devices for ULPs 4870 */ 4871 static void 4872 fp_plogi_group(fc_local_port_t *port, job_request_t *job) 4873 { 4874 int offline; 4875 int count; 4876 int rval; 4877 uint32_t listlen; 4878 uint32_t done; 4879 uint32_t d_id; 4880 fc_remote_node_t *node; 4881 fc_remote_port_t *pd; 4882 fc_remote_port_t *tmp_pd; 4883 fc_packet_t *ulp_pkt; 4884 la_els_logi_t *els_data; 4885 ls_code_t ls_code; 4886 4887 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p", 4888 port, job); 4889 4890 done = 0; 4891 listlen = job->job_ulp_listlen; 4892 job->job_counter = job->job_ulp_listlen; 4893 4894 mutex_enter(&port->fp_mutex); 4895 offline = (port->fp_statec_busy || 4896 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0; 4897 mutex_exit(&port->fp_mutex); 4898 4899 for (count = 0; count < listlen; count++) { 4900 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >= 4901 sizeof (la_els_logi_t)); 4902 4903 ulp_pkt = job->job_ulp_pkts[count]; 4904 pd = ulp_pkt->pkt_pd; 4905 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 4906 4907 if (offline) { 4908 done++; 4909 4910 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 4911 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4912 ulp_pkt->pkt_pd = NULL; 4913 ulp_pkt->pkt_comp(ulp_pkt); 4914 4915 job->job_ulp_pkts[count] = NULL; 4916 4917 fp_jobdone(job); 4918 continue; 4919 } 4920 4921 if (pd == NULL) { 4922 pd = fctl_get_remote_port_by_did(port, d_id); 4923 if (pd == NULL) { 4924 /* reset later */ 4925 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4926 continue; 4927 } 4928 mutex_enter(&pd->pd_mutex); 4929 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 4930 mutex_exit(&pd->pd_mutex); 4931 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 4932 done++; 4933 ulp_pkt->pkt_comp(ulp_pkt); 4934 job->job_ulp_pkts[count] = NULL; 4935 fp_jobdone(job); 4936 } else { 4937 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4938 mutex_exit(&pd->pd_mutex); 4939 } 4940 continue; 4941 } 4942 4943 switch (ulp_pkt->pkt_state) { 4944 case FC_PKT_ELS_IN_PROGRESS: 4945 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4946 /* FALLTHRU */ 4947 case FC_PKT_LOCAL_RJT: 4948 done++; 4949 ulp_pkt->pkt_comp(ulp_pkt); 4950 job->job_ulp_pkts[count] = NULL; 4951 fp_jobdone(job); 4952 continue; 4953 default: 4954 break; 4955 } 4956 4957 /* 4958 * Validate the pd corresponding to the d_id passed 4959 * by the ULPs 4960 */ 4961 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 4962 if ((tmp_pd == NULL) || (pd != tmp_pd)) { 4963 done++; 4964 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4965 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION; 4966 ulp_pkt->pkt_pd = NULL; 4967 ulp_pkt->pkt_comp(ulp_pkt); 4968 job->job_ulp_pkts[count] = NULL; 4969 fp_jobdone(job); 4970 continue; 4971 } 4972 4973 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; " 4974 "port=%p, pd=%p", port, pd); 4975 4976 mutex_enter(&pd->pd_mutex); 4977 4978 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4979 done++; 4980 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp; 4981 4982 ls_code.ls_code = LA_ELS_ACC; 4983 ls_code.mbz = 0; 4984 4985 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4986 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code, 4987 sizeof (ls_code_t), DDI_DEV_AUTOINCR); 4988 4989 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4990 (uint8_t *)&pd->pd_csp, 4991 (uint8_t *)&els_data->common_service, 4992 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR); 4993 4994 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4995 (uint8_t *)&pd->pd_port_name, 4996 (uint8_t *)&els_data->nport_ww_name, 4997 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR); 4998 4999 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5000 (uint8_t *)&pd->pd_clsp1, 5001 (uint8_t *)&els_data->class_1, 5002 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR); 5003 5004 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5005 (uint8_t *)&pd->pd_clsp2, 5006 (uint8_t *)&els_data->class_2, 5007 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR); 5008 5009 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5010 (uint8_t *)&pd->pd_clsp3, 5011 (uint8_t *)&els_data->class_3, 5012 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR); 5013 5014 node = pd->pd_remote_nodep; 5015 pd->pd_login_count++; 5016 pd->pd_flags = PD_IDLE; 5017 ulp_pkt->pkt_pd = pd; 5018 mutex_exit(&pd->pd_mutex); 5019 5020 mutex_enter(&node->fd_mutex); 5021 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5022 (uint8_t *)&node->fd_node_name, 5023 (uint8_t *)(&els_data->node_ww_name), 5024 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR); 5025 5026 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5027 (uint8_t *)&node->fd_vv, 5028 (uint8_t *)(&els_data->vendor_version), 5029 sizeof (node->fd_vv), DDI_DEV_AUTOINCR); 5030 5031 mutex_exit(&node->fd_mutex); 5032 ulp_pkt->pkt_state = FC_PKT_SUCCESS; 5033 } else { 5034 5035 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */ 5036 mutex_exit(&pd->pd_mutex); 5037 } 5038 5039 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) { 5040 ulp_pkt->pkt_comp(ulp_pkt); 5041 job->job_ulp_pkts[count] = NULL; 5042 fp_jobdone(job); 5043 } 5044 } 5045 5046 if (done == listlen) { 5047 fp_jobwait(job); 5048 fctl_jobdone(job); 5049 return; 5050 } 5051 5052 job->job_counter = listlen - done; 5053 5054 for (count = 0; count < listlen; count++) { 5055 int cmd_flags; 5056 5057 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) { 5058 continue; 5059 } 5060 5061 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE); 5062 5063 cmd_flags = FP_CMD_PLOGI_RETAIN; 5064 5065 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5066 ASSERT(d_id != 0); 5067 5068 pd = fctl_get_remote_port_by_did(port, d_id); 5069 5070 /* 5071 * We need to properly adjust the port device 5072 * reference counter before we assign the pd 5073 * to the ULP packets port device pointer. 5074 */ 5075 if (pd != NULL && ulp_pkt->pkt_pd == NULL) { 5076 mutex_enter(&pd->pd_mutex); 5077 pd->pd_ref_count++; 5078 mutex_exit(&pd->pd_mutex); 5079 FP_TRACE(FP_NHEAD1(3, 0), 5080 "fp_plogi_group: DID = 0x%x using new pd %p \ 5081 old pd NULL\n", d_id, pd); 5082 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL && 5083 ulp_pkt->pkt_pd != pd) { 5084 mutex_enter(&pd->pd_mutex); 5085 pd->pd_ref_count++; 5086 mutex_exit(&pd->pd_mutex); 5087 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5088 ulp_pkt->pkt_pd->pd_ref_count--; 5089 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5090 FP_TRACE(FP_NHEAD1(3, 0), 5091 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n", 5092 d_id, ulp_pkt->pkt_pd, pd); 5093 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) { 5094 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5095 ulp_pkt->pkt_pd->pd_ref_count--; 5096 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5097 FP_TRACE(FP_NHEAD1(3, 0), 5098 "fp_plogi_group: DID = 0x%x pd is NULL and \ 5099 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd); 5100 } 5101 5102 ulp_pkt->pkt_pd = pd; 5103 5104 if (pd != NULL) { 5105 mutex_enter(&pd->pd_mutex); 5106 d_id = pd->pd_port_id.port_id; 5107 pd->pd_flags = PD_ELS_IN_PROGRESS; 5108 mutex_exit(&pd->pd_mutex); 5109 } else { 5110 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5111 #ifdef DEBUG 5112 pd = fctl_get_remote_port_by_did(port, d_id); 5113 ASSERT(pd == NULL); 5114 #endif 5115 /* 5116 * In the Fabric topology, use NS to create 5117 * port device, and if that fails still try 5118 * with PLOGI - which will make yet another 5119 * attempt to create after successful PLOGI 5120 */ 5121 mutex_enter(&port->fp_mutex); 5122 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 5123 mutex_exit(&port->fp_mutex); 5124 pd = fp_create_remote_port_by_ns(port, 5125 d_id, KM_SLEEP); 5126 if (pd) { 5127 cmd_flags |= FP_CMD_DELDEV_ON_ERROR; 5128 5129 mutex_enter(&pd->pd_mutex); 5130 pd->pd_flags = PD_ELS_IN_PROGRESS; 5131 mutex_exit(&pd->pd_mutex); 5132 5133 FP_TRACE(FP_NHEAD1(3, 0), 5134 "fp_plogi_group;" 5135 " NS created PD port=%p, job=%p," 5136 " pd=%p", port, job, pd); 5137 } 5138 } else { 5139 mutex_exit(&port->fp_mutex); 5140 } 5141 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) { 5142 FP_TRACE(FP_NHEAD1(3, 0), 5143 "fp_plogi_group;" 5144 "ulp_pkt's pd is NULL, get a pd %p", 5145 pd); 5146 mutex_enter(&pd->pd_mutex); 5147 pd->pd_ref_count++; 5148 mutex_exit(&pd->pd_mutex); 5149 } 5150 ulp_pkt->pkt_pd = pd; 5151 } 5152 5153 rval = fp_port_login(port, d_id, job, cmd_flags, 5154 KM_SLEEP, pd, ulp_pkt); 5155 5156 if (rval == FC_SUCCESS) { 5157 continue; 5158 } 5159 5160 if (rval == FC_STATEC_BUSY) { 5161 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5162 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5163 } else { 5164 ulp_pkt->pkt_state = FC_PKT_FAILURE; 5165 } 5166 5167 if (pd) { 5168 mutex_enter(&pd->pd_mutex); 5169 pd->pd_flags = PD_IDLE; 5170 mutex_exit(&pd->pd_mutex); 5171 } 5172 5173 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) { 5174 ASSERT(pd != NULL); 5175 5176 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created," 5177 " PD removed; port=%p, job=%p", port, job); 5178 5179 mutex_enter(&pd->pd_mutex); 5180 pd->pd_ref_count--; 5181 node = pd->pd_remote_nodep; 5182 mutex_exit(&pd->pd_mutex); 5183 5184 ASSERT(node != NULL); 5185 5186 if (fctl_destroy_remote_port(port, pd) == 0) { 5187 fctl_destroy_remote_node(node); 5188 } 5189 ulp_pkt->pkt_pd = NULL; 5190 } 5191 ulp_pkt->pkt_comp(ulp_pkt); 5192 fp_jobdone(job); 5193 } 5194 5195 fp_jobwait(job); 5196 fctl_jobdone(job); 5197 5198 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p", 5199 port, job); 5200 } 5201 5202 5203 /* 5204 * Name server request initialization 5205 */ 5206 static void 5207 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep) 5208 { 5209 int rval; 5210 int count; 5211 int size; 5212 5213 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5214 5215 job->job_counter = 1; 5216 job->job_result = FC_SUCCESS; 5217 5218 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN, 5219 KM_SLEEP, NULL, NULL); 5220 5221 if (rval != FC_SUCCESS) { 5222 mutex_enter(&port->fp_mutex); 5223 port->fp_topology = FC_TOP_NO_NS; 5224 mutex_exit(&port->fp_mutex); 5225 return; 5226 } 5227 5228 fp_jobwait(job); 5229 5230 if (job->job_result != FC_SUCCESS) { 5231 mutex_enter(&port->fp_mutex); 5232 port->fp_topology = FC_TOP_NO_NS; 5233 mutex_exit(&port->fp_mutex); 5234 return; 5235 } 5236 5237 /* 5238 * At this time, we'll do NS registration for objects in the 5239 * ns_reg_cmds (see top of this file) array. 5240 * 5241 * Each time a ULP module registers with the transport, the 5242 * appropriate fc4 bit is set fc4 types and registered with 5243 * the NS for this support. Also, ULPs and FC admin utilities 5244 * may do registration for objects like IP address, symbolic 5245 * port/node name, Initial process associator at run time. 5246 */ 5247 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]); 5248 job->job_counter = size; 5249 job->job_result = FC_SUCCESS; 5250 5251 for (count = 0; count < size; count++) { 5252 if (fp_ns_reg(port, NULL, ns_reg_cmds[count], 5253 job, 0, sleep) != FC_SUCCESS) { 5254 fp_jobdone(job); 5255 } 5256 } 5257 if (size) { 5258 fp_jobwait(job); 5259 } 5260 5261 job->job_result = FC_SUCCESS; 5262 5263 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 5264 5265 if (port->fp_dev_count < FP_MAX_DEVICES) { 5266 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP); 5267 } 5268 5269 job->job_counter = 1; 5270 5271 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION, 5272 sleep) == FC_SUCCESS) { 5273 fp_jobwait(job); 5274 } 5275 } 5276 5277 5278 /* 5279 * Name server finish: 5280 * Unregister for RSCNs 5281 * Unregister all the host port objects in the Name Server 5282 * Perform LOGO with the NS; 5283 */ 5284 static void 5285 fp_ns_fini(fc_local_port_t *port, job_request_t *job) 5286 { 5287 fp_cmd_t *cmd; 5288 uchar_t class; 5289 uint32_t s_id; 5290 fc_packet_t *pkt; 5291 la_els_logo_t payload; 5292 5293 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5294 5295 job->job_counter = 1; 5296 5297 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) != 5298 FC_SUCCESS) { 5299 fp_jobdone(job); 5300 } 5301 fp_jobwait(job); 5302 5303 job->job_counter = 1; 5304 5305 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) { 5306 fp_jobdone(job); 5307 } 5308 fp_jobwait(job); 5309 5310 job->job_counter = 1; 5311 5312 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 5313 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL); 5314 pkt = &cmd->cmd_pkt; 5315 5316 mutex_enter(&port->fp_mutex); 5317 class = port->fp_ns_login_class; 5318 s_id = port->fp_port_id.port_id; 5319 payload.nport_id = port->fp_port_id; 5320 mutex_exit(&port->fp_mutex); 5321 5322 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 5323 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 5324 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 5325 cmd->cmd_retry_count = 1; 5326 cmd->cmd_ulp_pkt = NULL; 5327 5328 if (port->fp_npiv_type == FC_NPIV_PORT) { 5329 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job); 5330 } else { 5331 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job); 5332 } 5333 5334 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 5335 5336 payload.ls_code.ls_code = LA_ELS_LOGO; 5337 payload.ls_code.mbz = 0; 5338 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 5339 5340 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 5341 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 5342 5343 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 5344 fp_iodone(cmd); 5345 } 5346 fp_jobwait(job); 5347 } 5348 5349 5350 /* 5351 * NS Registration function. 5352 * 5353 * It should be seriously noted that FC-GS-2 currently doesn't support 5354 * an Object Registration by a D_ID other than the owner of the object. 5355 * What we are aiming at currently is to at least allow Symbolic Node/Port 5356 * Name registration for any N_Port Identifier by the host software. 5357 * 5358 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this 5359 * function treats the request as Host NS Object. 5360 */ 5361 static int 5362 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code, 5363 job_request_t *job, int polled, int sleep) 5364 { 5365 int rval; 5366 fc_portid_t s_id; 5367 fc_packet_t *pkt; 5368 fp_cmd_t *cmd; 5369 5370 if (pd == NULL) { 5371 mutex_enter(&port->fp_mutex); 5372 s_id = port->fp_port_id; 5373 mutex_exit(&port->fp_mutex); 5374 } else { 5375 mutex_enter(&pd->pd_mutex); 5376 s_id = pd->pd_port_id; 5377 mutex_exit(&pd->pd_mutex); 5378 } 5379 5380 if (polled) { 5381 job->job_counter = 1; 5382 } 5383 5384 switch (cmd_code) { 5385 case NS_RPN_ID: 5386 case NS_RNN_ID: { 5387 ns_rxn_req_t rxn; 5388 5389 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5390 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL); 5391 if (cmd == NULL) { 5392 return (FC_NOMEM); 5393 } 5394 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5395 pkt = &cmd->cmd_pkt; 5396 5397 if (pd == NULL) { 5398 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ? 5399 (port->fp_service_params.nport_ww_name) : 5400 (port->fp_service_params.node_ww_name)); 5401 } else { 5402 if (cmd_code == NS_RPN_ID) { 5403 mutex_enter(&pd->pd_mutex); 5404 rxn.rxn_xname = pd->pd_port_name; 5405 mutex_exit(&pd->pd_mutex); 5406 } else { 5407 fc_remote_node_t *node; 5408 5409 mutex_enter(&pd->pd_mutex); 5410 node = pd->pd_remote_nodep; 5411 mutex_exit(&pd->pd_mutex); 5412 5413 mutex_enter(&node->fd_mutex); 5414 rxn.rxn_xname = node->fd_node_name; 5415 mutex_exit(&node->fd_mutex); 5416 } 5417 } 5418 rxn.rxn_port_id = s_id; 5419 5420 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn, 5421 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5422 sizeof (rxn), DDI_DEV_AUTOINCR); 5423 5424 break; 5425 } 5426 5427 case NS_RCS_ID: { 5428 ns_rcos_t rcos; 5429 5430 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5431 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL); 5432 if (cmd == NULL) { 5433 return (FC_NOMEM); 5434 } 5435 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5436 pkt = &cmd->cmd_pkt; 5437 5438 if (pd == NULL) { 5439 rcos.rcos_cos = port->fp_cos; 5440 } else { 5441 mutex_enter(&pd->pd_mutex); 5442 rcos.rcos_cos = pd->pd_cos; 5443 mutex_exit(&pd->pd_mutex); 5444 } 5445 rcos.rcos_port_id = s_id; 5446 5447 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos, 5448 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5449 sizeof (rcos), DDI_DEV_AUTOINCR); 5450 5451 break; 5452 } 5453 5454 case NS_RFT_ID: { 5455 ns_rfc_type_t rfc; 5456 5457 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5458 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep, 5459 NULL); 5460 if (cmd == NULL) { 5461 return (FC_NOMEM); 5462 } 5463 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5464 pkt = &cmd->cmd_pkt; 5465 5466 if (pd == NULL) { 5467 mutex_enter(&port->fp_mutex); 5468 bcopy(port->fp_fc4_types, rfc.rfc_types, 5469 sizeof (port->fp_fc4_types)); 5470 mutex_exit(&port->fp_mutex); 5471 } else { 5472 mutex_enter(&pd->pd_mutex); 5473 bcopy(pd->pd_fc4types, rfc.rfc_types, 5474 sizeof (pd->pd_fc4types)); 5475 mutex_exit(&pd->pd_mutex); 5476 } 5477 rfc.rfc_port_id = s_id; 5478 5479 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc, 5480 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5481 sizeof (rfc), DDI_DEV_AUTOINCR); 5482 5483 break; 5484 } 5485 5486 case NS_RSPN_ID: { 5487 uchar_t name_len; 5488 int pl_size; 5489 fc_portid_t spn; 5490 5491 if (pd == NULL) { 5492 mutex_enter(&port->fp_mutex); 5493 name_len = port->fp_sym_port_namelen; 5494 mutex_exit(&port->fp_mutex); 5495 } else { 5496 mutex_enter(&pd->pd_mutex); 5497 name_len = pd->pd_spn_len; 5498 mutex_exit(&pd->pd_mutex); 5499 } 5500 5501 pl_size = sizeof (fc_portid_t) + name_len + 1; 5502 5503 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size, 5504 sizeof (fc_reg_resp_t), sleep, NULL); 5505 if (cmd == NULL) { 5506 return (FC_NOMEM); 5507 } 5508 5509 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5510 5511 pkt = &cmd->cmd_pkt; 5512 5513 spn = s_id; 5514 5515 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *) 5516 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn), 5517 DDI_DEV_AUTOINCR); 5518 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5519 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) 5520 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR); 5521 5522 if (pd == NULL) { 5523 mutex_enter(&port->fp_mutex); 5524 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5525 (uint8_t *)port->fp_sym_port_name, (uint8_t *) 5526 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5527 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5528 mutex_exit(&port->fp_mutex); 5529 } else { 5530 mutex_enter(&pd->pd_mutex); 5531 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5532 (uint8_t *)pd->pd_spn, 5533 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5534 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5535 mutex_exit(&pd->pd_mutex); 5536 } 5537 break; 5538 } 5539 5540 case NS_RPT_ID: { 5541 ns_rpt_t rpt; 5542 5543 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5544 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL); 5545 if (cmd == NULL) { 5546 return (FC_NOMEM); 5547 } 5548 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5549 pkt = &cmd->cmd_pkt; 5550 5551 if (pd == NULL) { 5552 rpt.rpt_type = port->fp_port_type; 5553 } else { 5554 mutex_enter(&pd->pd_mutex); 5555 rpt.rpt_type = pd->pd_porttype; 5556 mutex_exit(&pd->pd_mutex); 5557 } 5558 rpt.rpt_port_id = s_id; 5559 5560 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt, 5561 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5562 sizeof (rpt), DDI_DEV_AUTOINCR); 5563 5564 break; 5565 } 5566 5567 case NS_RIP_NN: { 5568 ns_rip_t rip; 5569 5570 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5571 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL); 5572 if (cmd == NULL) { 5573 return (FC_NOMEM); 5574 } 5575 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5576 pkt = &cmd->cmd_pkt; 5577 5578 if (pd == NULL) { 5579 rip.rip_node_name = 5580 port->fp_service_params.node_ww_name; 5581 bcopy(port->fp_ip_addr, rip.rip_ip_addr, 5582 sizeof (port->fp_ip_addr)); 5583 } else { 5584 fc_remote_node_t *node; 5585 5586 /* 5587 * The most correct implementation should have the IP 5588 * address in the fc_remote_node_t structure; I believe 5589 * Node WWN and IP address should have one to one 5590 * correlation (but guess what this is changing in 5591 * FC-GS-2 latest draft) 5592 */ 5593 mutex_enter(&pd->pd_mutex); 5594 node = pd->pd_remote_nodep; 5595 bcopy(pd->pd_ip_addr, rip.rip_ip_addr, 5596 sizeof (pd->pd_ip_addr)); 5597 mutex_exit(&pd->pd_mutex); 5598 5599 mutex_enter(&node->fd_mutex); 5600 rip.rip_node_name = node->fd_node_name; 5601 mutex_exit(&node->fd_mutex); 5602 } 5603 5604 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip, 5605 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5606 sizeof (rip), DDI_DEV_AUTOINCR); 5607 5608 break; 5609 } 5610 5611 case NS_RIPA_NN: { 5612 ns_ipa_t ipa; 5613 5614 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5615 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL); 5616 if (cmd == NULL) { 5617 return (FC_NOMEM); 5618 } 5619 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5620 pkt = &cmd->cmd_pkt; 5621 5622 if (pd == NULL) { 5623 ipa.ipa_node_name = 5624 port->fp_service_params.node_ww_name; 5625 bcopy(port->fp_ipa, ipa.ipa_value, 5626 sizeof (port->fp_ipa)); 5627 } else { 5628 fc_remote_node_t *node; 5629 5630 mutex_enter(&pd->pd_mutex); 5631 node = pd->pd_remote_nodep; 5632 mutex_exit(&pd->pd_mutex); 5633 5634 mutex_enter(&node->fd_mutex); 5635 ipa.ipa_node_name = node->fd_node_name; 5636 bcopy(node->fd_ipa, ipa.ipa_value, 5637 sizeof (node->fd_ipa)); 5638 mutex_exit(&node->fd_mutex); 5639 } 5640 5641 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa, 5642 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5643 sizeof (ipa), DDI_DEV_AUTOINCR); 5644 5645 break; 5646 } 5647 5648 case NS_RSNN_NN: { 5649 uchar_t name_len; 5650 int pl_size; 5651 la_wwn_t snn; 5652 fc_remote_node_t *node = NULL; 5653 5654 if (pd == NULL) { 5655 mutex_enter(&port->fp_mutex); 5656 name_len = port->fp_sym_node_namelen; 5657 mutex_exit(&port->fp_mutex); 5658 } else { 5659 mutex_enter(&pd->pd_mutex); 5660 node = pd->pd_remote_nodep; 5661 mutex_exit(&pd->pd_mutex); 5662 5663 mutex_enter(&node->fd_mutex); 5664 name_len = node->fd_snn_len; 5665 mutex_exit(&node->fd_mutex); 5666 } 5667 5668 pl_size = sizeof (la_wwn_t) + name_len + 1; 5669 5670 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5671 pl_size, sizeof (fc_reg_resp_t), sleep, NULL); 5672 if (cmd == NULL) { 5673 return (FC_NOMEM); 5674 } 5675 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5676 5677 pkt = &cmd->cmd_pkt; 5678 5679 bcopy(&port->fp_service_params.node_ww_name, 5680 &snn, sizeof (la_wwn_t)); 5681 5682 if (pd == NULL) { 5683 mutex_enter(&port->fp_mutex); 5684 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5685 (uint8_t *)port->fp_sym_node_name, (uint8_t *) 5686 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5687 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5688 mutex_exit(&port->fp_mutex); 5689 } else { 5690 ASSERT(node != NULL); 5691 mutex_enter(&node->fd_mutex); 5692 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5693 (uint8_t *)node->fd_snn, 5694 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5695 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5696 mutex_exit(&node->fd_mutex); 5697 } 5698 5699 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn, 5700 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5701 sizeof (snn), DDI_DEV_AUTOINCR); 5702 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5703 (uint8_t *)(pkt->pkt_cmd 5704 + sizeof (fc_ct_header_t) + sizeof (snn)), 5705 1, DDI_DEV_AUTOINCR); 5706 5707 break; 5708 } 5709 5710 case NS_DA_ID: { 5711 ns_remall_t rall; 5712 char tmp[4] = {0}; 5713 char *ptr; 5714 5715 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5716 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL); 5717 5718 if (cmd == NULL) { 5719 return (FC_NOMEM); 5720 } 5721 5722 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5723 pkt = &cmd->cmd_pkt; 5724 5725 ptr = (char *)(&s_id); 5726 tmp[3] = *ptr++; 5727 tmp[2] = *ptr++; 5728 tmp[1] = *ptr++; 5729 tmp[0] = *ptr; 5730 #if defined(_BIT_FIELDS_LTOH) 5731 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4); 5732 #else 5733 rall.rem_port_id = s_id; 5734 #endif 5735 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall, 5736 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5737 sizeof (rall), DDI_DEV_AUTOINCR); 5738 5739 break; 5740 } 5741 5742 default: 5743 return (FC_FAILURE); 5744 } 5745 5746 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 5747 5748 if (rval != FC_SUCCESS) { 5749 job->job_result = rval; 5750 fp_iodone(cmd); 5751 } 5752 5753 if (polled) { 5754 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5755 fp_jobwait(job); 5756 } else { 5757 rval = FC_SUCCESS; 5758 } 5759 5760 return (rval); 5761 } 5762 5763 5764 /* 5765 * Common interrupt handler 5766 */ 5767 static int 5768 fp_common_intr(fc_packet_t *pkt, int iodone) 5769 { 5770 int rval = FC_FAILURE; 5771 fp_cmd_t *cmd; 5772 fc_local_port_t *port; 5773 5774 cmd = pkt->pkt_ulp_private; 5775 port = cmd->cmd_port; 5776 5777 /* 5778 * Fail fast the upper layer requests if 5779 * a state change has occurred amidst. 5780 */ 5781 mutex_enter(&port->fp_mutex); 5782 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) { 5783 mutex_exit(&port->fp_mutex); 5784 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5785 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5786 } else if (!(port->fp_soft_state & 5787 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) { 5788 mutex_exit(&port->fp_mutex); 5789 5790 switch (pkt->pkt_state) { 5791 case FC_PKT_LOCAL_BSY: 5792 case FC_PKT_FABRIC_BSY: 5793 case FC_PKT_NPORT_BSY: 5794 case FC_PKT_TIMEOUT: 5795 cmd->cmd_retry_interval = (pkt->pkt_state == 5796 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay; 5797 rval = fp_retry_cmd(pkt); 5798 break; 5799 5800 case FC_PKT_FABRIC_RJT: 5801 case FC_PKT_NPORT_RJT: 5802 case FC_PKT_LOCAL_RJT: 5803 case FC_PKT_LS_RJT: 5804 case FC_PKT_FS_RJT: 5805 case FC_PKT_BA_RJT: 5806 rval = fp_handle_reject(pkt); 5807 break; 5808 5809 default: 5810 if (pkt->pkt_resp_resid) { 5811 cmd->cmd_retry_interval = 0; 5812 rval = fp_retry_cmd(pkt); 5813 } 5814 break; 5815 } 5816 } else { 5817 mutex_exit(&port->fp_mutex); 5818 } 5819 5820 if (rval != FC_SUCCESS && iodone) { 5821 fp_iodone(cmd); 5822 rval = FC_SUCCESS; 5823 } 5824 5825 return (rval); 5826 } 5827 5828 5829 /* 5830 * Some not so long winding theory on point to point topology: 5831 * 5832 * In the ACC payload, if the D_ID is ZERO and the common service 5833 * parameters indicate N_Port, then the topology is POINT TO POINT. 5834 * 5835 * In a point to point topology with an N_Port, during Fabric Login, 5836 * the destination N_Port will check with our WWN and decide if it 5837 * needs to issue PLOGI or not. That means, FLOGI could potentially 5838 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited 5839 * PLOGI creates the device handles. 5840 * 5841 * Assuming that the host port WWN is greater than the other N_Port 5842 * WWN, then we become the master (be aware that this isn't the word 5843 * used in the FC standards) and initiate the PLOGI. 5844 * 5845 */ 5846 static void 5847 fp_flogi_intr(fc_packet_t *pkt) 5848 { 5849 int state; 5850 int f_port; 5851 uint32_t s_id; 5852 uint32_t d_id; 5853 fp_cmd_t *cmd; 5854 fc_local_port_t *port; 5855 la_wwn_t *swwn; 5856 la_wwn_t dwwn; 5857 la_wwn_t nwwn; 5858 fc_remote_port_t *pd; 5859 la_els_logi_t *acc; 5860 com_svc_t csp; 5861 ls_code_t resp; 5862 5863 cmd = pkt->pkt_ulp_private; 5864 port = cmd->cmd_port; 5865 5866 mutex_enter(&port->fp_mutex); 5867 port->fp_out_fpcmds--; 5868 mutex_exit(&port->fp_mutex); 5869 5870 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x", 5871 port, pkt, pkt->pkt_state); 5872 5873 if (FP_IS_PKT_ERROR(pkt)) { 5874 (void) fp_common_intr(pkt, 1); 5875 return; 5876 } 5877 5878 /* 5879 * Currently, we don't need to swap bytes here because qlc is faking the 5880 * response for us and so endianness is getting taken care of. But we 5881 * have to fix this and generalize this at some point 5882 */ 5883 acc = (la_els_logi_t *)pkt->pkt_resp; 5884 5885 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 5886 sizeof (resp), DDI_DEV_AUTOINCR); 5887 5888 ASSERT(resp.ls_code == LA_ELS_ACC); 5889 if (resp.ls_code != LA_ELS_ACC) { 5890 (void) fp_common_intr(pkt, 1); 5891 return; 5892 } 5893 5894 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp, 5895 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR); 5896 5897 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0; 5898 5899 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 5900 5901 mutex_enter(&port->fp_mutex); 5902 state = FC_PORT_STATE_MASK(port->fp_state); 5903 mutex_exit(&port->fp_mutex); 5904 5905 if (f_port == 0) { 5906 if (state != FC_STATE_LOOP) { 5907 swwn = &port->fp_service_params.nport_ww_name; 5908 5909 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn, 5910 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 5911 DDI_DEV_AUTOINCR); 5912 5913 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 5914 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 5915 DDI_DEV_AUTOINCR); 5916 5917 mutex_enter(&port->fp_mutex); 5918 5919 port->fp_topology = FC_TOP_PT_PT; 5920 port->fp_total_devices = 1; 5921 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) { 5922 port->fp_ptpt_master = 1; 5923 /* 5924 * Let us choose 'X' as S_ID and 'Y' 5925 * as D_ID and that'll work; hopefully 5926 * If not, it will get changed. 5927 */ 5928 s_id = port->fp_instance + FP_DEFAULT_SID; 5929 d_id = port->fp_instance + FP_DEFAULT_DID; 5930 port->fp_port_id.port_id = s_id; 5931 mutex_exit(&port->fp_mutex); 5932 5933 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x" 5934 "pd %x", port->fp_port_id.port_id, d_id); 5935 pd = fctl_create_remote_port(port, 5936 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR, 5937 KM_NOSLEEP); 5938 if (pd == NULL) { 5939 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 5940 0, NULL, "couldn't create device" 5941 " d_id=%X", d_id); 5942 fp_iodone(cmd); 5943 return; 5944 } 5945 5946 cmd->cmd_pkt.pkt_tran_flags = 5947 pkt->pkt_tran_flags; 5948 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type; 5949 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN; 5950 cmd->cmd_retry_count = fp_retry_count; 5951 5952 fp_xlogi_init(port, cmd, s_id, d_id, 5953 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI); 5954 5955 (&cmd->cmd_pkt)->pkt_pd = pd; 5956 5957 /* 5958 * We've just created this fc_remote_port_t, and 5959 * we're about to use it to send a PLOGI, so 5960 * bump the reference count right now. When 5961 * the packet is freed, the reference count will 5962 * be decremented. The ULP may also start using 5963 * it, so mark it as given away as well. 5964 */ 5965 pd->pd_ref_count++; 5966 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 5967 5968 if (fp_sendcmd(port, cmd, 5969 port->fp_fca_handle) == FC_SUCCESS) { 5970 return; 5971 } 5972 } else { 5973 /* 5974 * The device handles will be created when the 5975 * unsolicited PLOGI is completed successfully 5976 */ 5977 port->fp_ptpt_master = 0; 5978 mutex_exit(&port->fp_mutex); 5979 } 5980 } 5981 pkt->pkt_state = FC_PKT_FAILURE; 5982 } else { 5983 if (f_port) { 5984 mutex_enter(&port->fp_mutex); 5985 if (state == FC_STATE_LOOP) { 5986 port->fp_topology = FC_TOP_PUBLIC_LOOP; 5987 } else { 5988 port->fp_topology = FC_TOP_FABRIC; 5989 5990 FC_GET_RSP(port, pkt->pkt_resp_acc, 5991 (uint8_t *)&port->fp_fabric_name, 5992 (uint8_t *)&acc->node_ww_name, 5993 sizeof (la_wwn_t), 5994 DDI_DEV_AUTOINCR); 5995 } 5996 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id; 5997 mutex_exit(&port->fp_mutex); 5998 } else { 5999 pkt->pkt_state = FC_PKT_FAILURE; 6000 } 6001 } 6002 fp_iodone(cmd); 6003 } 6004 6005 6006 /* 6007 * Handle solicited PLOGI response 6008 */ 6009 static void 6010 fp_plogi_intr(fc_packet_t *pkt) 6011 { 6012 int nl_port; 6013 int bailout; 6014 uint32_t d_id; 6015 fp_cmd_t *cmd; 6016 la_els_logi_t *acc; 6017 fc_local_port_t *port; 6018 fc_remote_port_t *pd; 6019 la_wwn_t nwwn; 6020 la_wwn_t pwwn; 6021 ls_code_t resp; 6022 6023 nl_port = 0; 6024 cmd = pkt->pkt_ulp_private; 6025 port = cmd->cmd_port; 6026 d_id = pkt->pkt_cmd_fhdr.d_id; 6027 6028 #ifndef __lock_lint 6029 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6030 #endif 6031 6032 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x," 6033 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id, 6034 cmd->cmd_job->job_counter, pkt, pkt->pkt_state); 6035 6036 /* 6037 * Bail out early on ULP initiated requests if the 6038 * state change has occurred 6039 */ 6040 mutex_enter(&port->fp_mutex); 6041 port->fp_out_fpcmds--; 6042 bailout = ((port->fp_statec_busy || 6043 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6044 cmd->cmd_ulp_pkt) ? 1 : 0; 6045 mutex_exit(&port->fp_mutex); 6046 6047 if (FP_IS_PKT_ERROR(pkt) || bailout) { 6048 int skip_msg = 0; 6049 int giveup = 0; 6050 6051 if (cmd->cmd_ulp_pkt) { 6052 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6053 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason; 6054 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6055 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6056 } 6057 6058 /* 6059 * If an unsolicited cross login already created 6060 * a device speed up the discovery by not retrying 6061 * the command mindlessly. 6062 */ 6063 if (pkt->pkt_pd == NULL && 6064 fctl_get_remote_port_by_did(port, d_id) != NULL) { 6065 fp_iodone(cmd); 6066 return; 6067 } 6068 6069 if (pkt->pkt_pd != NULL) { 6070 giveup = (pkt->pkt_pd->pd_recepient == 6071 PD_PLOGI_RECEPIENT) ? 1 : 0; 6072 if (giveup) { 6073 /* 6074 * This pd is marked as plogi 6075 * recipient, stop retrying 6076 */ 6077 FP_TRACE(FP_NHEAD1(3, 0), 6078 "fp_plogi_intr: stop retry as" 6079 " a cross login was accepted" 6080 " from d_id=%x, port=%p.", 6081 d_id, port); 6082 fp_iodone(cmd); 6083 return; 6084 } 6085 } 6086 6087 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6088 return; 6089 } 6090 6091 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) { 6092 mutex_enter(&pd->pd_mutex); 6093 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 6094 skip_msg++; 6095 } 6096 mutex_exit(&pd->pd_mutex); 6097 } 6098 6099 mutex_enter(&port->fp_mutex); 6100 if (!bailout && !(skip_msg && port->fp_statec_busy) && 6101 port->fp_statec_busy <= 1 && 6102 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) { 6103 mutex_exit(&port->fp_mutex); 6104 /* 6105 * In case of Login Collisions, JNI HBAs returns the 6106 * FC pkt back to the Initiator with the state set to 6107 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR. 6108 * QLC HBAs handles such cases in the FW and doesnot 6109 * return the LS_RJT with Logical error when 6110 * login collision happens. 6111 */ 6112 if ((pkt->pkt_state != FC_PKT_LS_RJT) || 6113 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) { 6114 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6115 "PLOGI to %x failed", d_id); 6116 } 6117 FP_TRACE(FP_NHEAD2(9, 0), 6118 "PLOGI to %x failed. state=%x reason=%x.", 6119 d_id, pkt->pkt_state, pkt->pkt_reason); 6120 } else { 6121 mutex_exit(&port->fp_mutex); 6122 } 6123 6124 fp_iodone(cmd); 6125 return; 6126 } 6127 6128 acc = (la_els_logi_t *)pkt->pkt_resp; 6129 6130 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 6131 sizeof (resp), DDI_DEV_AUTOINCR); 6132 6133 ASSERT(resp.ls_code == LA_ELS_ACC); 6134 if (resp.ls_code != LA_ELS_ACC) { 6135 (void) fp_common_intr(pkt, 1); 6136 return; 6137 } 6138 6139 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) { 6140 mutex_enter(&port->fp_mutex); 6141 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags); 6142 mutex_exit(&port->fp_mutex); 6143 fp_iodone(cmd); 6144 return; 6145 } 6146 6147 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp); 6148 6149 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 6150 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 6151 DDI_DEV_AUTOINCR); 6152 6153 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 6154 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 6155 DDI_DEV_AUTOINCR); 6156 6157 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE); 6158 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE); 6159 6160 if ((pd = pkt->pkt_pd) == NULL) { 6161 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6162 if (pd == NULL) { 6163 FP_TRACE(FP_NHEAD2(1, 0), "fp_plogi_intr: fp %x pd %x", 6164 port->fp_port_id.port_id, d_id); 6165 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id, 6166 PD_PLOGI_INITIATOR, KM_NOSLEEP); 6167 if (pd == NULL) { 6168 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6169 "couldn't create port device handles" 6170 " d_id=%x", d_id); 6171 fp_iodone(cmd); 6172 return; 6173 } 6174 } else { 6175 fc_remote_port_t *tmp_pd; 6176 6177 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6178 if (tmp_pd != NULL) { 6179 fp_iodone(cmd); 6180 return; 6181 } 6182 6183 mutex_enter(&port->fp_mutex); 6184 mutex_enter(&pd->pd_mutex); 6185 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) || 6186 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6187 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN; 6188 } 6189 6190 if (pd->pd_type == PORT_DEVICE_OLD) { 6191 if (pd->pd_port_id.port_id != d_id) { 6192 fctl_delist_did_table(port, pd); 6193 pd->pd_type = PORT_DEVICE_CHANGED; 6194 pd->pd_port_id.port_id = d_id; 6195 } else { 6196 pd->pd_type = PORT_DEVICE_NOCHANGE; 6197 } 6198 } 6199 6200 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6201 char ww_name[17]; 6202 6203 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6204 6205 mutex_exit(&pd->pd_mutex); 6206 mutex_exit(&port->fp_mutex); 6207 FP_TRACE(FP_NHEAD2(9, 0), 6208 "Possible Duplicate name or address" 6209 " identifiers in the PLOGI response" 6210 " D_ID=%x, PWWN=%s: Please check the" 6211 " configuration", d_id, ww_name); 6212 fp_iodone(cmd); 6213 return; 6214 } 6215 fctl_enlist_did_table(port, pd); 6216 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6217 mutex_exit(&pd->pd_mutex); 6218 mutex_exit(&port->fp_mutex); 6219 } 6220 } else { 6221 fc_remote_port_t *tmp_pd, *new_wwn_pd; 6222 6223 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6224 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6225 6226 mutex_enter(&port->fp_mutex); 6227 mutex_enter(&pd->pd_mutex); 6228 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) { 6229 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x," 6230 " pd_state=%x pd_type=%x", d_id, pd->pd_state, 6231 pd->pd_type); 6232 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN && 6233 pd->pd_type == PORT_DEVICE_OLD) || 6234 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6235 pd->pd_type = PORT_DEVICE_NOCHANGE; 6236 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 6237 pd->pd_type = PORT_DEVICE_NEW; 6238 } 6239 } else { 6240 char old_name[17]; 6241 char new_name[17]; 6242 6243 fc_wwn_to_str(&pd->pd_port_name, old_name); 6244 fc_wwn_to_str(&pwwn, new_name); 6245 6246 FP_TRACE(FP_NHEAD1(9, 0), 6247 "fp_plogi_intr: PWWN of a device with D_ID=%x " 6248 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p " 6249 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x", 6250 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd, 6251 cmd->cmd_ulp_pkt, bailout); 6252 6253 FP_TRACE(FP_NHEAD2(9, 0), 6254 "PWWN of a device with D_ID=%x changed." 6255 " New PWWN = %s, OLD PWWN = %s", d_id, 6256 new_name, old_name); 6257 6258 if (cmd->cmd_ulp_pkt && !bailout) { 6259 fc_remote_node_t *rnodep; 6260 fc_portmap_t *changelist; 6261 fc_portmap_t *listptr; 6262 int len = 1; 6263 /* # entries in changelist */ 6264 6265 fctl_delist_pwwn_table(port, pd); 6266 6267 /* 6268 * Lets now check if there already is a pd with 6269 * this new WWN in the table. If so, we'll mark 6270 * it as invalid 6271 */ 6272 6273 if (new_wwn_pd) { 6274 /* 6275 * There is another pd with in the pwwn 6276 * table with the same WWN that we got 6277 * in the PLOGI payload. We have to get 6278 * it out of the pwwn table, update the 6279 * pd's state (fp_fillout_old_map does 6280 * this for us) and add it to the 6281 * changelist that goes up to ULPs. 6282 * 6283 * len is length of changelist and so 6284 * increment it. 6285 */ 6286 len++; 6287 6288 if (tmp_pd != pd) { 6289 /* 6290 * Odd case where pwwn and did 6291 * tables are out of sync but 6292 * we will handle that too. See 6293 * more comments below. 6294 * 6295 * One more device that ULPs 6296 * should know about and so len 6297 * gets incremented again. 6298 */ 6299 len++; 6300 } 6301 6302 listptr = changelist = kmem_zalloc(len * 6303 sizeof (*changelist), KM_SLEEP); 6304 6305 mutex_enter(&new_wwn_pd->pd_mutex); 6306 rnodep = new_wwn_pd->pd_remote_nodep; 6307 mutex_exit(&new_wwn_pd->pd_mutex); 6308 6309 /* 6310 * Hold the fd_mutex since 6311 * fctl_copy_portmap_held expects it. 6312 * Preserve lock hierarchy by grabbing 6313 * fd_mutex before pd_mutex 6314 */ 6315 if (rnodep) { 6316 mutex_enter(&rnodep->fd_mutex); 6317 } 6318 mutex_enter(&new_wwn_pd->pd_mutex); 6319 fp_fillout_old_map_held(listptr++, 6320 new_wwn_pd, 0); 6321 mutex_exit(&new_wwn_pd->pd_mutex); 6322 if (rnodep) { 6323 mutex_exit(&rnodep->fd_mutex); 6324 } 6325 6326 /* 6327 * Safety check : 6328 * Lets ensure that the pwwn and did 6329 * tables are in sync. Ideally, we 6330 * should not find that these two pd's 6331 * are different. 6332 */ 6333 if (tmp_pd != pd) { 6334 mutex_enter(&tmp_pd->pd_mutex); 6335 rnodep = 6336 tmp_pd->pd_remote_nodep; 6337 mutex_exit(&tmp_pd->pd_mutex); 6338 6339 /* As above grab fd_mutex */ 6340 if (rnodep) { 6341 mutex_enter(&rnodep-> 6342 fd_mutex); 6343 } 6344 mutex_enter(&tmp_pd->pd_mutex); 6345 6346 fp_fillout_old_map_held( 6347 listptr++, tmp_pd, 0); 6348 6349 mutex_exit(&tmp_pd->pd_mutex); 6350 if (rnodep) { 6351 mutex_exit(&rnodep-> 6352 fd_mutex); 6353 } 6354 6355 /* 6356 * Now add "pd" (not tmp_pd) 6357 * to fp_did_table to sync it up 6358 * with fp_pwwn_table 6359 * 6360 * pd->pd_mutex is already held 6361 * at this point 6362 */ 6363 fctl_enlist_did_table(port, pd); 6364 } 6365 } else { 6366 listptr = changelist = kmem_zalloc( 6367 sizeof (*changelist), KM_SLEEP); 6368 } 6369 6370 ASSERT(changelist != NULL); 6371 6372 fp_fillout_changed_map(listptr, pd, &d_id, 6373 &pwwn); 6374 fctl_enlist_pwwn_table(port, pd); 6375 6376 mutex_exit(&pd->pd_mutex); 6377 mutex_exit(&port->fp_mutex); 6378 6379 fp_iodone(cmd); 6380 6381 (void) fp_ulp_devc_cb(port, changelist, len, 6382 len, KM_NOSLEEP, 0); 6383 6384 return; 6385 } 6386 } 6387 6388 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) { 6389 nl_port = 1; 6390 } 6391 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6392 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6393 } 6394 6395 mutex_exit(&pd->pd_mutex); 6396 mutex_exit(&port->fp_mutex); 6397 6398 if (tmp_pd == NULL) { 6399 mutex_enter(&port->fp_mutex); 6400 mutex_enter(&pd->pd_mutex); 6401 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6402 char ww_name[17]; 6403 6404 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6405 mutex_exit(&pd->pd_mutex); 6406 mutex_exit(&port->fp_mutex); 6407 FP_TRACE(FP_NHEAD2(9, 0), 6408 "Possible Duplicate name or address" 6409 " identifiers in the PLOGI response" 6410 " D_ID=%x, PWWN=%s: Please check the" 6411 " configuration", d_id, ww_name); 6412 fp_iodone(cmd); 6413 return; 6414 } 6415 fctl_enlist_did_table(port, pd); 6416 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6417 mutex_exit(&pd->pd_mutex); 6418 mutex_exit(&port->fp_mutex); 6419 } 6420 } 6421 fp_register_login(&pkt->pkt_resp_acc, pd, acc, 6422 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 6423 6424 if (cmd->cmd_ulp_pkt) { 6425 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6426 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6427 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6428 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6429 if (pd != NULL) { 6430 FP_TRACE(FP_NHEAD1(9, 0), 6431 "fp_plogi_intr;" 6432 "ulp_pkt's pd is NULL, get a pd %p", 6433 pd); 6434 mutex_enter(&pd->pd_mutex); 6435 pd->pd_ref_count++; 6436 mutex_exit(&pd->pd_mutex); 6437 } 6438 cmd->cmd_ulp_pkt->pkt_pd = pd; 6439 } 6440 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6441 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6442 sizeof (fc_frame_hdr_t)); 6443 bcopy((caddr_t)pkt->pkt_resp, 6444 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6445 sizeof (la_els_logi_t)); 6446 } 6447 6448 mutex_enter(&port->fp_mutex); 6449 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) { 6450 mutex_enter(&pd->pd_mutex); 6451 6452 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6453 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6454 cmd->cmd_retry_count = fp_retry_count; 6455 6456 /* 6457 * If the fc_remote_port_t pointer is not set in the given 6458 * fc_packet_t, then this fc_remote_port_t must have just 6459 * been created. Save the pointer and also increment the 6460 * fc_remote_port_t reference count. 6461 */ 6462 if (pkt->pkt_pd == NULL) { 6463 pkt->pkt_pd = pd; 6464 pd->pd_ref_count++; /* It's in use! */ 6465 } 6466 6467 fp_adisc_init(cmd, cmd->cmd_job); 6468 6469 pkt->pkt_cmdlen = sizeof (la_els_adisc_t); 6470 pkt->pkt_rsplen = sizeof (la_els_adisc_t); 6471 6472 mutex_exit(&pd->pd_mutex); 6473 mutex_exit(&port->fp_mutex); 6474 6475 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6476 return; 6477 } 6478 } else { 6479 mutex_exit(&port->fp_mutex); 6480 } 6481 6482 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6483 mutex_enter(&port->fp_mutex); 6484 mutex_enter(&pd->pd_mutex); 6485 6486 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6487 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6488 cmd->cmd_retry_count = fp_retry_count; 6489 6490 fp_logo_init(pd, cmd, cmd->cmd_job); 6491 6492 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6493 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6494 6495 mutex_exit(&pd->pd_mutex); 6496 mutex_exit(&port->fp_mutex); 6497 6498 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6499 return; 6500 } 6501 6502 } 6503 fp_iodone(cmd); 6504 } 6505 6506 6507 /* 6508 * Handle solicited ADISC response 6509 */ 6510 static void 6511 fp_adisc_intr(fc_packet_t *pkt) 6512 { 6513 int rval; 6514 int bailout; 6515 fp_cmd_t *cmd, *logi_cmd; 6516 fc_local_port_t *port; 6517 fc_remote_port_t *pd; 6518 la_els_adisc_t *acc; 6519 ls_code_t resp; 6520 fc_hardaddr_t ha; 6521 fc_portmap_t *changelist; 6522 int initiator, adiscfail = 0; 6523 6524 pd = pkt->pkt_pd; 6525 cmd = pkt->pkt_ulp_private; 6526 port = cmd->cmd_port; 6527 6528 #ifndef __lock_lint 6529 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6530 #endif 6531 6532 ASSERT(pd != NULL && port != NULL && cmd != NULL); 6533 6534 mutex_enter(&port->fp_mutex); 6535 port->fp_out_fpcmds--; 6536 bailout = ((port->fp_statec_busy || 6537 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6538 cmd->cmd_ulp_pkt) ? 1 : 0; 6539 mutex_exit(&port->fp_mutex); 6540 6541 if (bailout) { 6542 fp_iodone(cmd); 6543 return; 6544 } 6545 6546 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) { 6547 acc = (la_els_adisc_t *)pkt->pkt_resp; 6548 6549 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6550 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR); 6551 6552 if (resp.ls_code == LA_ELS_ACC) { 6553 int is_private; 6554 6555 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha, 6556 (uint8_t *)&acc->hard_addr, sizeof (ha), 6557 DDI_DEV_AUTOINCR); 6558 6559 mutex_enter(&port->fp_mutex); 6560 6561 is_private = 6562 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0; 6563 6564 mutex_enter(&pd->pd_mutex); 6565 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) { 6566 fctl_enlist_did_table(port, pd); 6567 } 6568 mutex_exit(&pd->pd_mutex); 6569 6570 mutex_exit(&port->fp_mutex); 6571 6572 mutex_enter(&pd->pd_mutex); 6573 if (pd->pd_type != PORT_DEVICE_NEW) { 6574 if (is_private && (pd->pd_hard_addr.hard_addr != 6575 ha.hard_addr)) { 6576 pd->pd_type = PORT_DEVICE_CHANGED; 6577 } else { 6578 pd->pd_type = PORT_DEVICE_NOCHANGE; 6579 } 6580 } 6581 6582 if (is_private && (ha.hard_addr && 6583 pd->pd_port_id.port_id != ha.hard_addr)) { 6584 char ww_name[17]; 6585 6586 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6587 6588 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6589 "NL_Port Identifier %x doesn't match" 6590 " with Hard Address %x, Will use Port" 6591 " WWN %s", pd->pd_port_id.port_id, 6592 ha.hard_addr, ww_name); 6593 6594 pd->pd_hard_addr.hard_addr = 0; 6595 } else { 6596 pd->pd_hard_addr.hard_addr = ha.hard_addr; 6597 } 6598 mutex_exit(&pd->pd_mutex); 6599 } else { 6600 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6601 return; 6602 } 6603 } 6604 } else { 6605 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6606 return; 6607 } 6608 6609 mutex_enter(&port->fp_mutex); 6610 if (port->fp_statec_busy <= 1) { 6611 mutex_exit(&port->fp_mutex); 6612 if (pkt->pkt_state == FC_PKT_LS_RJT && 6613 pkt->pkt_reason == FC_REASON_CMD_UNABLE) { 6614 uchar_t class; 6615 int cmd_flag; 6616 uint32_t src_id; 6617 6618 class = fp_get_nextclass(port, 6619 FC_TRAN_CLASS_INVALID); 6620 if (class == FC_TRAN_CLASS_INVALID) { 6621 fp_iodone(cmd); 6622 return; 6623 } 6624 6625 FP_TRACE(FP_NHEAD1(1, 0), "ADISC re-login; " 6626 "fp_state=0x%x, pkt_state=0x%x, " 6627 "reason=0x%x, class=0x%x", 6628 port->fp_state, pkt->pkt_state, 6629 pkt->pkt_reason, class); 6630 cmd_flag = FP_CMD_PLOGI_RETAIN; 6631 6632 logi_cmd = fp_alloc_pkt(port, 6633 sizeof (la_els_logi_t), 6634 sizeof (la_els_logi_t), KM_SLEEP, pd); 6635 if (logi_cmd == NULL) { 6636 fp_iodone(cmd); 6637 return; 6638 } 6639 6640 logi_cmd->cmd_pkt.pkt_tran_flags = 6641 FC_TRAN_INTR | class; 6642 logi_cmd->cmd_pkt.pkt_tran_type = 6643 FC_PKT_EXCHANGE; 6644 logi_cmd->cmd_flags = cmd_flag; 6645 logi_cmd->cmd_retry_count = fp_retry_count; 6646 logi_cmd->cmd_ulp_pkt = NULL; 6647 6648 mutex_enter(&port->fp_mutex); 6649 src_id = port->fp_port_id.port_id; 6650 mutex_exit(&port->fp_mutex); 6651 6652 fp_xlogi_init(port, logi_cmd, src_id, 6653 pkt->pkt_cmd_fhdr.d_id, fp_plogi_intr, 6654 cmd->cmd_job, LA_ELS_PLOGI); 6655 if (pd) { 6656 mutex_enter(&pd->pd_mutex); 6657 pd->pd_flags = PD_ELS_IN_PROGRESS; 6658 mutex_exit(&pd->pd_mutex); 6659 } 6660 6661 if (fp_sendcmd(port, logi_cmd, 6662 port->fp_fca_handle) == FC_SUCCESS) { 6663 fp_free_pkt(cmd); 6664 return; 6665 } else { 6666 fp_free_pkt(logi_cmd); 6667 } 6668 } else { 6669 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6670 "ADISC to %x failed, cmd_flags=%x", 6671 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags); 6672 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN; 6673 adiscfail = 1; 6674 } 6675 } else { 6676 mutex_exit(&port->fp_mutex); 6677 } 6678 } 6679 6680 if (cmd->cmd_ulp_pkt) { 6681 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6682 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6683 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6684 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6685 cmd->cmd_ulp_pkt->pkt_pd = pd; 6686 FP_TRACE(FP_NHEAD1(9, 0), 6687 "fp_adisc__intr;" 6688 "ulp_pkt's pd is NULL, get a pd %p", 6689 pd); 6690 6691 } 6692 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6693 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6694 sizeof (fc_frame_hdr_t)); 6695 bcopy((caddr_t)pkt->pkt_resp, 6696 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6697 sizeof (la_els_adisc_t)); 6698 } 6699 6700 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6701 FP_TRACE(FP_NHEAD1(9, 0), 6702 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, " 6703 "fp_retry_count=%x, ulp_pkt=%p", 6704 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt); 6705 6706 mutex_enter(&port->fp_mutex); 6707 mutex_enter(&pd->pd_mutex); 6708 6709 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6710 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6711 cmd->cmd_retry_count = fp_retry_count; 6712 6713 fp_logo_init(pd, cmd, cmd->cmd_job); 6714 6715 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6716 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6717 6718 mutex_exit(&pd->pd_mutex); 6719 mutex_exit(&port->fp_mutex); 6720 6721 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 6722 if (adiscfail) { 6723 mutex_enter(&pd->pd_mutex); 6724 initiator = 6725 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0); 6726 pd->pd_state = PORT_DEVICE_VALID; 6727 pd->pd_aux_flags |= PD_LOGGED_OUT; 6728 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6729 pd->pd_type = PORT_DEVICE_NEW; 6730 } else { 6731 pd->pd_type = PORT_DEVICE_NOCHANGE; 6732 } 6733 mutex_exit(&pd->pd_mutex); 6734 6735 changelist = 6736 kmem_zalloc(sizeof (*changelist), KM_SLEEP); 6737 6738 if (initiator) { 6739 fp_unregister_login(pd); 6740 fctl_copy_portmap(changelist, pd); 6741 } else { 6742 fp_fillout_old_map(changelist, pd, 0); 6743 } 6744 6745 FP_TRACE(FP_NHEAD1(9, 0), 6746 "fp_adisc_intr: Dev change notification " 6747 "to ULP port=%p, pd=%p, map_type=%x map_state=%x " 6748 "map_flags=%x initiator=%d", port, pd, 6749 changelist->map_type, changelist->map_state, 6750 changelist->map_flags, initiator); 6751 6752 (void) fp_ulp_devc_cb(port, changelist, 6753 1, 1, KM_SLEEP, 0); 6754 } 6755 if (rval == FC_SUCCESS) { 6756 return; 6757 } 6758 } 6759 fp_iodone(cmd); 6760 } 6761 6762 6763 /* 6764 * Handle solicited LOGO response 6765 */ 6766 static void 6767 fp_logo_intr(fc_packet_t *pkt) 6768 { 6769 ls_code_t resp; 6770 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6771 6772 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6773 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6774 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6775 6776 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6777 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6778 6779 if (FP_IS_PKT_ERROR(pkt)) { 6780 (void) fp_common_intr(pkt, 1); 6781 return; 6782 } 6783 6784 ASSERT(resp.ls_code == LA_ELS_ACC); 6785 if (resp.ls_code != LA_ELS_ACC) { 6786 (void) fp_common_intr(pkt, 1); 6787 return; 6788 } 6789 6790 if (pkt->pkt_pd != NULL) { 6791 fp_unregister_login(pkt->pkt_pd); 6792 } 6793 6794 fp_iodone(pkt->pkt_ulp_private); 6795 } 6796 6797 6798 /* 6799 * Handle solicited RNID response 6800 */ 6801 static void 6802 fp_rnid_intr(fc_packet_t *pkt) 6803 { 6804 ls_code_t resp; 6805 job_request_t *job; 6806 fp_cmd_t *cmd; 6807 la_els_rnid_acc_t *acc; 6808 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6809 6810 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6811 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6812 cmd = pkt->pkt_ulp_private; 6813 6814 mutex_enter(&cmd->cmd_port->fp_mutex); 6815 cmd->cmd_port->fp_out_fpcmds--; 6816 mutex_exit(&cmd->cmd_port->fp_mutex); 6817 6818 job = cmd->cmd_job; 6819 ASSERT(job->job_private != NULL); 6820 6821 /* If failure or LS_RJT then retry the packet, if needed */ 6822 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) { 6823 (void) fp_common_intr(pkt, 1); 6824 return; 6825 } 6826 6827 /* Save node_id memory allocated in ioctl code */ 6828 acc = (la_els_rnid_acc_t *)pkt->pkt_resp; 6829 6830 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6831 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR); 6832 6833 /* wakeup the ioctl thread and free the pkt */ 6834 fp_iodone(cmd); 6835 } 6836 6837 6838 /* 6839 * Handle solicited RLS response 6840 */ 6841 static void 6842 fp_rls_intr(fc_packet_t *pkt) 6843 { 6844 ls_code_t resp; 6845 job_request_t *job; 6846 fp_cmd_t *cmd; 6847 la_els_rls_acc_t *acc; 6848 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6849 6850 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6851 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6852 cmd = pkt->pkt_ulp_private; 6853 6854 mutex_enter(&cmd->cmd_port->fp_mutex); 6855 cmd->cmd_port->fp_out_fpcmds--; 6856 mutex_exit(&cmd->cmd_port->fp_mutex); 6857 6858 job = cmd->cmd_job; 6859 ASSERT(job->job_private != NULL); 6860 6861 /* If failure or LS_RJT then retry the packet, if needed */ 6862 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) { 6863 (void) fp_common_intr(pkt, 1); 6864 return; 6865 } 6866 6867 /* Save link error status block in memory allocated in ioctl code */ 6868 acc = (la_els_rls_acc_t *)pkt->pkt_resp; 6869 6870 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6871 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t), 6872 DDI_DEV_AUTOINCR); 6873 6874 /* wakeup the ioctl thread and free the pkt */ 6875 fp_iodone(cmd); 6876 } 6877 6878 6879 /* 6880 * A solicited command completion interrupt (mostly for commands 6881 * that require almost no post processing such as SCR ELS) 6882 */ 6883 static void 6884 fp_intr(fc_packet_t *pkt) 6885 { 6886 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6887 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6888 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6889 6890 if (FP_IS_PKT_ERROR(pkt)) { 6891 (void) fp_common_intr(pkt, 1); 6892 return; 6893 } 6894 fp_iodone(pkt->pkt_ulp_private); 6895 } 6896 6897 6898 /* 6899 * Handle the underlying port's state change 6900 */ 6901 static void 6902 fp_statec_cb(opaque_t port_handle, uint32_t state) 6903 { 6904 fc_local_port_t *port = port_handle; 6905 job_request_t *job; 6906 6907 /* 6908 * If it is not possible to process the callbacks 6909 * just drop the callback on the floor; Don't bother 6910 * to do something that isn't safe at this time 6911 */ 6912 mutex_enter(&port->fp_mutex); 6913 if ((port->fp_soft_state & 6914 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 6915 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) { 6916 mutex_exit(&port->fp_mutex); 6917 return; 6918 } 6919 6920 if (port->fp_statec_busy == 0) { 6921 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 6922 #ifdef DEBUG 6923 } else { 6924 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB); 6925 #endif 6926 } 6927 6928 port->fp_statec_busy++; 6929 6930 /* 6931 * For now, force the trusted method of device authentication (by 6932 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition. 6933 */ 6934 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP || 6935 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) { 6936 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP; 6937 fp_port_offline(port, 0); 6938 } 6939 mutex_exit(&port->fp_mutex); 6940 6941 switch (FC_PORT_STATE_MASK(state)) { 6942 case FC_STATE_OFFLINE: 6943 job = fctl_alloc_job(JOB_PORT_OFFLINE, 6944 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6945 if (job == NULL) { 6946 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6947 " fp_statec_cb() couldn't submit a job " 6948 " to the thread: failing.."); 6949 mutex_enter(&port->fp_mutex); 6950 if (--port->fp_statec_busy == 0) { 6951 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6952 } 6953 mutex_exit(&port->fp_mutex); 6954 return; 6955 } 6956 mutex_enter(&port->fp_mutex); 6957 /* 6958 * Zero out this field so that we do not retain 6959 * the fabric name as its no longer valid 6960 */ 6961 bzero(&port->fp_fabric_name, sizeof (la_wwn_t)); 6962 port->fp_state = state; 6963 mutex_exit(&port->fp_mutex); 6964 6965 fctl_enque_job(port, job); 6966 break; 6967 6968 case FC_STATE_ONLINE: 6969 case FC_STATE_LOOP: 6970 mutex_enter(&port->fp_mutex); 6971 port->fp_state = state; 6972 6973 if (port->fp_offline_tid) { 6974 timeout_id_t tid; 6975 6976 tid = port->fp_offline_tid; 6977 port->fp_offline_tid = NULL; 6978 mutex_exit(&port->fp_mutex); 6979 (void) untimeout(tid); 6980 } else { 6981 mutex_exit(&port->fp_mutex); 6982 } 6983 6984 job = fctl_alloc_job(JOB_PORT_ONLINE, 6985 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6986 if (job == NULL) { 6987 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6988 "fp_statec_cb() couldn't submit a job " 6989 "to the thread: failing.."); 6990 6991 mutex_enter(&port->fp_mutex); 6992 if (--port->fp_statec_busy == 0) { 6993 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6994 } 6995 mutex_exit(&port->fp_mutex); 6996 return; 6997 } 6998 fctl_enque_job(port, job); 6999 break; 7000 7001 case FC_STATE_RESET_REQUESTED: 7002 mutex_enter(&port->fp_mutex); 7003 port->fp_state = FC_STATE_OFFLINE; 7004 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET; 7005 mutex_exit(&port->fp_mutex); 7006 /* FALLTHROUGH */ 7007 7008 case FC_STATE_RESET: 7009 job = fctl_alloc_job(JOB_ULP_NOTIFY, 7010 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 7011 if (job == NULL) { 7012 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 7013 "fp_statec_cb() couldn't submit a job" 7014 " to the thread: failing.."); 7015 7016 mutex_enter(&port->fp_mutex); 7017 if (--port->fp_statec_busy == 0) { 7018 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 7019 } 7020 mutex_exit(&port->fp_mutex); 7021 return; 7022 } 7023 7024 /* squeeze into some field in the job structure */ 7025 job->job_ulp_listlen = FC_PORT_STATE_MASK(state); 7026 fctl_enque_job(port, job); 7027 break; 7028 7029 case FC_STATE_TARGET_PORT_RESET: 7030 (void) fp_ulp_notify(port, state, KM_NOSLEEP); 7031 /* FALLTHROUGH */ 7032 7033 case FC_STATE_NAMESERVICE: 7034 /* FALLTHROUGH */ 7035 7036 default: 7037 mutex_enter(&port->fp_mutex); 7038 if (--port->fp_statec_busy == 0) { 7039 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 7040 } 7041 mutex_exit(&port->fp_mutex); 7042 break; 7043 } 7044 } 7045 7046 7047 /* 7048 * Register with the Name Server for RSCNs 7049 */ 7050 static int 7051 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func, 7052 int sleep) 7053 { 7054 uint32_t s_id; 7055 uchar_t class; 7056 fc_scr_req_t payload; 7057 fp_cmd_t *cmd; 7058 fc_packet_t *pkt; 7059 7060 mutex_enter(&port->fp_mutex); 7061 s_id = port->fp_port_id.port_id; 7062 class = port->fp_ns_login_class; 7063 mutex_exit(&port->fp_mutex); 7064 7065 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t), 7066 sizeof (fc_scr_resp_t), sleep, NULL); 7067 if (cmd == NULL) { 7068 return (FC_NOMEM); 7069 } 7070 7071 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 7072 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 7073 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 7074 cmd->cmd_retry_count = fp_retry_count; 7075 cmd->cmd_ulp_pkt = NULL; 7076 7077 pkt = &cmd->cmd_pkt; 7078 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 7079 7080 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job); 7081 7082 payload.ls_code.ls_code = LA_ELS_SCR; 7083 payload.ls_code.mbz = 0; 7084 payload.scr_rsvd = 0; 7085 payload.scr_func = scr_func; 7086 7087 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 7088 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 7089 7090 job->job_counter = 1; 7091 7092 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 7093 fp_iodone(cmd); 7094 } 7095 7096 return (FC_SUCCESS); 7097 } 7098 7099 7100 /* 7101 * There are basically two methods to determine the total number of 7102 * devices out in the NS database; Reading the details of the two 7103 * methods described below, it shouldn't be hard to identify which 7104 * of the two methods is better. 7105 * 7106 * Method 1. 7107 * Iteratively issue GANs until all ports identifiers are walked 7108 * 7109 * Method 2. 7110 * Issue GID_PT (get port Identifiers) with Maximum residual 7111 * field in the request CT HEADER set to accommodate only the 7112 * CT HEADER in the response frame. And if FC-GS2 has been 7113 * carefully read, the NS here has a chance to FS_ACC the 7114 * request and indicate the residual size in the FS_ACC. 7115 * 7116 * Method 2 is wonderful, although it's not mandatory for the NS 7117 * to update the Maximum/Residual Field as can be seen in 4.3.1.6 7118 * (note with particular care the use of the auxiliary verb 'may') 7119 * 7120 */ 7121 static int 7122 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create, 7123 int sleep) 7124 { 7125 int flags; 7126 int rval; 7127 uint32_t src_id; 7128 fctl_ns_req_t *ns_cmd; 7129 7130 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 7131 7132 mutex_enter(&port->fp_mutex); 7133 src_id = port->fp_port_id.port_id; 7134 mutex_exit(&port->fp_mutex); 7135 7136 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7137 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t), 7138 sizeof (ns_resp_gid_pt_t), 0, 7139 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep); 7140 7141 if (ns_cmd == NULL) { 7142 return (FC_NOMEM); 7143 } 7144 7145 ns_cmd->ns_cmd_code = NS_GID_PT; 7146 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type 7147 = FC_NS_PORT_NX; /* All port types */ 7148 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0; 7149 7150 } else { 7151 uint32_t ns_flags; 7152 7153 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF; 7154 if (create) { 7155 ns_flags |= FCTL_NS_CREATE_DEVICE; 7156 } 7157 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 7158 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep); 7159 7160 if (ns_cmd == NULL) { 7161 return (FC_NOMEM); 7162 } 7163 ns_cmd->ns_gan_index = 0; 7164 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 7165 ns_cmd->ns_cmd_code = NS_GA_NXT; 7166 ns_cmd->ns_gan_max = 0xFFFF; 7167 7168 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id; 7169 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 7170 } 7171 7172 flags = job->job_flags; 7173 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 7174 job->job_counter = 1; 7175 7176 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 7177 job->job_flags = flags; 7178 7179 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7180 uint16_t max_resid; 7181 7182 /* 7183 * Revert to scanning the NS if NS_GID_PT isn't 7184 * helping us figure out total number of devices. 7185 */ 7186 if (job->job_result != FC_SUCCESS || 7187 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) { 7188 mutex_enter(&port->fp_mutex); 7189 port->fp_options &= ~FP_NS_SMART_COUNT; 7190 mutex_exit(&port->fp_mutex); 7191 7192 fctl_free_ns_cmd(ns_cmd); 7193 return (fp_ns_get_devcount(port, job, create, sleep)); 7194 } 7195 7196 mutex_enter(&port->fp_mutex); 7197 port->fp_total_devices = 1; 7198 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize; 7199 if (max_resid) { 7200 /* 7201 * Since port identifier is 4 bytes and max_resid 7202 * is also in WORDS, max_resid simply indicates 7203 * the total number of port identifiers not 7204 * transferred 7205 */ 7206 port->fp_total_devices += max_resid; 7207 } 7208 mutex_exit(&port->fp_mutex); 7209 } 7210 mutex_enter(&port->fp_mutex); 7211 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf); 7212 mutex_exit(&port->fp_mutex); 7213 fctl_free_ns_cmd(ns_cmd); 7214 7215 return (rval); 7216 } 7217 7218 /* 7219 * One heck of a function to serve userland. 7220 */ 7221 static int 7222 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 7223 { 7224 int rval = 0; 7225 int jcode; 7226 uint32_t ret; 7227 uchar_t open_flag; 7228 fcio_t *kfcio; 7229 job_request_t *job; 7230 boolean_t use32 = B_FALSE; 7231 7232 #ifdef _MULTI_DATAMODEL 7233 switch (ddi_model_convert_from(mode & FMODELS)) { 7234 case DDI_MODEL_ILP32: 7235 use32 = B_TRUE; 7236 break; 7237 7238 case DDI_MODEL_NONE: 7239 default: 7240 break; 7241 } 7242 #endif 7243 7244 mutex_enter(&port->fp_mutex); 7245 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 7246 FP_SOFT_IN_UNSOL_CB)) { 7247 fcio->fcio_errno = FC_STATEC_BUSY; 7248 mutex_exit(&port->fp_mutex); 7249 rval = EAGAIN; 7250 if (fp_fcio_copyout(fcio, data, mode)) { 7251 rval = EFAULT; 7252 } 7253 return (rval); 7254 } 7255 open_flag = port->fp_flag; 7256 mutex_exit(&port->fp_mutex); 7257 7258 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) { 7259 fcio->fcio_errno = FC_FAILURE; 7260 rval = EACCES; 7261 if (fp_fcio_copyout(fcio, data, mode)) { 7262 rval = EFAULT; 7263 } 7264 return (rval); 7265 } 7266 7267 /* 7268 * If an exclusive open was demanded during open, don't let 7269 * either innocuous or devil threads to share the file 7270 * descriptor and fire down exclusive access commands 7271 */ 7272 mutex_enter(&port->fp_mutex); 7273 if (port->fp_flag & FP_EXCL) { 7274 if (port->fp_flag & FP_EXCL_BUSY) { 7275 mutex_exit(&port->fp_mutex); 7276 fcio->fcio_errno = FC_FAILURE; 7277 return (EBUSY); 7278 } 7279 port->fp_flag |= FP_EXCL_BUSY; 7280 } 7281 mutex_exit(&port->fp_mutex); 7282 7283 fcio->fcio_errno = FC_SUCCESS; 7284 7285 switch (fcio->fcio_cmd) { 7286 case FCIO_GET_HOST_PARAMS: { 7287 fc_port_dev_t *val; 7288 fc_port_dev32_t *val32; 7289 int index; 7290 int lilp_device_count; 7291 fc_lilpmap_t *lilp_map; 7292 uchar_t *alpa_list; 7293 7294 if (use32 == B_TRUE) { 7295 if (fcio->fcio_olen != sizeof (*val32) || 7296 fcio->fcio_xfer != FCIO_XFER_READ) { 7297 rval = EINVAL; 7298 break; 7299 } 7300 } else { 7301 if (fcio->fcio_olen != sizeof (*val) || 7302 fcio->fcio_xfer != FCIO_XFER_READ) { 7303 rval = EINVAL; 7304 break; 7305 } 7306 } 7307 7308 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7309 7310 mutex_enter(&port->fp_mutex); 7311 val->dev_did = port->fp_port_id; 7312 val->dev_hard_addr = port->fp_hard_addr; 7313 val->dev_pwwn = port->fp_service_params.nport_ww_name; 7314 val->dev_nwwn = port->fp_service_params.node_ww_name; 7315 val->dev_state = port->fp_state; 7316 7317 lilp_map = &port->fp_lilp_map; 7318 alpa_list = &lilp_map->lilp_alpalist[0]; 7319 lilp_device_count = lilp_map->lilp_length; 7320 for (index = 0; index < lilp_device_count; index++) { 7321 uint32_t d_id; 7322 7323 d_id = alpa_list[index]; 7324 if (d_id == port->fp_port_id.port_id) { 7325 break; 7326 } 7327 } 7328 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff); 7329 7330 bcopy(port->fp_fc4_types, val->dev_type, 7331 sizeof (port->fp_fc4_types)); 7332 mutex_exit(&port->fp_mutex); 7333 7334 if (use32 == B_TRUE) { 7335 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7336 7337 val32->dev_did = val->dev_did; 7338 val32->dev_hard_addr = val->dev_hard_addr; 7339 val32->dev_pwwn = val->dev_pwwn; 7340 val32->dev_nwwn = val->dev_nwwn; 7341 val32->dev_state = val->dev_state; 7342 val32->dev_did.priv_lilp_posit = 7343 val->dev_did.priv_lilp_posit; 7344 7345 bcopy(val->dev_type, val32->dev_type, 7346 sizeof (port->fp_fc4_types)); 7347 7348 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7349 fcio->fcio_olen, mode) == 0) { 7350 if (fp_fcio_copyout(fcio, data, mode)) { 7351 rval = EFAULT; 7352 } 7353 } else { 7354 rval = EFAULT; 7355 } 7356 7357 kmem_free(val32, sizeof (*val32)); 7358 } else { 7359 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7360 fcio->fcio_olen, mode) == 0) { 7361 if (fp_fcio_copyout(fcio, data, mode)) { 7362 rval = EFAULT; 7363 } 7364 } else { 7365 rval = EFAULT; 7366 } 7367 } 7368 7369 /* need to free "val" here */ 7370 kmem_free(val, sizeof (*val)); 7371 break; 7372 } 7373 7374 case FCIO_GET_OTHER_ADAPTER_PORTS: { 7375 uint32_t index; 7376 char *tmpPath; 7377 fc_local_port_t *tmpPort; 7378 7379 if (fcio->fcio_olen < MAXPATHLEN || 7380 fcio->fcio_ilen != sizeof (uint32_t)) { 7381 rval = EINVAL; 7382 break; 7383 } 7384 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7385 rval = EFAULT; 7386 break; 7387 } 7388 7389 tmpPort = fctl_get_adapter_port_by_index(port, index); 7390 if (tmpPort == NULL) { 7391 FP_TRACE(FP_NHEAD1(9, 0), 7392 "User supplied index out of range"); 7393 fcio->fcio_errno = FC_BADPORT; 7394 rval = EFAULT; 7395 if (fp_fcio_copyout(fcio, data, mode)) { 7396 rval = EFAULT; 7397 } 7398 break; 7399 } 7400 7401 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7402 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath); 7403 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf, 7404 MAXPATHLEN, mode) == 0) { 7405 if (fp_fcio_copyout(fcio, data, mode)) { 7406 rval = EFAULT; 7407 } 7408 } else { 7409 rval = EFAULT; 7410 } 7411 kmem_free(tmpPath, MAXPATHLEN); 7412 break; 7413 } 7414 7415 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES: 7416 case FCIO_GET_ADAPTER_ATTRIBUTES: { 7417 fc_hba_adapter_attributes_t *val; 7418 fc_hba_adapter_attributes32_t *val32; 7419 7420 if (use32 == B_TRUE) { 7421 if (fcio->fcio_olen < sizeof (*val32) || 7422 fcio->fcio_xfer != FCIO_XFER_READ) { 7423 rval = EINVAL; 7424 break; 7425 } 7426 } else { 7427 if (fcio->fcio_olen < sizeof (*val) || 7428 fcio->fcio_xfer != FCIO_XFER_READ) { 7429 rval = EINVAL; 7430 break; 7431 } 7432 } 7433 7434 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7435 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; 7436 mutex_enter(&port->fp_mutex); 7437 bcopy(port->fp_hba_port_attrs.manufacturer, 7438 val->Manufacturer, 7439 sizeof (val->Manufacturer)); 7440 bcopy(port->fp_hba_port_attrs.serial_number, 7441 val->SerialNumber, 7442 sizeof (val->SerialNumber)); 7443 bcopy(port->fp_hba_port_attrs.model, 7444 val->Model, 7445 sizeof (val->Model)); 7446 bcopy(port->fp_hba_port_attrs.model_description, 7447 val->ModelDescription, 7448 sizeof (val->ModelDescription)); 7449 bcopy(port->fp_sym_node_name, val->NodeSymbolicName, 7450 port->fp_sym_node_namelen); 7451 bcopy(port->fp_hba_port_attrs.hardware_version, 7452 val->HardwareVersion, 7453 sizeof (val->HardwareVersion)); 7454 bcopy(port->fp_hba_port_attrs.option_rom_version, 7455 val->OptionROMVersion, 7456 sizeof (val->OptionROMVersion)); 7457 bcopy(port->fp_hba_port_attrs.firmware_version, 7458 val->FirmwareVersion, 7459 sizeof (val->FirmwareVersion)); 7460 val->VendorSpecificID = 7461 port->fp_hba_port_attrs.vendor_specific_id; 7462 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7463 &val->NodeWWN.raw_wwn, 7464 sizeof (val->NodeWWN.raw_wwn)); 7465 7466 7467 bcopy(port->fp_hba_port_attrs.driver_name, 7468 val->DriverName, 7469 sizeof (val->DriverName)); 7470 bcopy(port->fp_hba_port_attrs.driver_version, 7471 val->DriverVersion, 7472 sizeof (val->DriverVersion)); 7473 mutex_exit(&port->fp_mutex); 7474 7475 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) { 7476 val->NumberOfPorts = fctl_count_fru_ports(port, 0); 7477 } else { 7478 val->NumberOfPorts = fctl_count_fru_ports(port, 1); 7479 } 7480 7481 if (use32 == B_TRUE) { 7482 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7483 val32->version = val->version; 7484 bcopy(val->Manufacturer, val32->Manufacturer, 7485 sizeof (val->Manufacturer)); 7486 bcopy(val->SerialNumber, val32->SerialNumber, 7487 sizeof (val->SerialNumber)); 7488 bcopy(val->Model, val32->Model, 7489 sizeof (val->Model)); 7490 bcopy(val->ModelDescription, val32->ModelDescription, 7491 sizeof (val->ModelDescription)); 7492 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName, 7493 sizeof (val->NodeSymbolicName)); 7494 bcopy(val->HardwareVersion, val32->HardwareVersion, 7495 sizeof (val->HardwareVersion)); 7496 bcopy(val->OptionROMVersion, val32->OptionROMVersion, 7497 sizeof (val->OptionROMVersion)); 7498 bcopy(val->FirmwareVersion, val32->FirmwareVersion, 7499 sizeof (val->FirmwareVersion)); 7500 val32->VendorSpecificID = val->VendorSpecificID; 7501 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7502 sizeof (val->NodeWWN.raw_wwn)); 7503 bcopy(val->DriverName, val32->DriverName, 7504 sizeof (val->DriverName)); 7505 bcopy(val->DriverVersion, val32->DriverVersion, 7506 sizeof (val->DriverVersion)); 7507 7508 val32->NumberOfPorts = val->NumberOfPorts; 7509 7510 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7511 fcio->fcio_olen, mode) == 0) { 7512 if (fp_fcio_copyout(fcio, data, mode)) { 7513 rval = EFAULT; 7514 } 7515 } else { 7516 rval = EFAULT; 7517 } 7518 7519 kmem_free(val32, sizeof (*val32)); 7520 } else { 7521 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7522 fcio->fcio_olen, mode) == 0) { 7523 if (fp_fcio_copyout(fcio, data, mode)) { 7524 rval = EFAULT; 7525 } 7526 } else { 7527 rval = EFAULT; 7528 } 7529 } 7530 7531 kmem_free(val, sizeof (*val)); 7532 break; 7533 } 7534 7535 case FCIO_GET_NPIV_ATTRIBUTES: { 7536 fc_hba_npiv_attributes_t *attrs; 7537 7538 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP); 7539 mutex_enter(&port->fp_mutex); 7540 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7541 &attrs->NodeWWN.raw_wwn, 7542 sizeof (attrs->NodeWWN.raw_wwn)); 7543 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7544 &attrs->PortWWN.raw_wwn, 7545 sizeof (attrs->PortWWN.raw_wwn)); 7546 mutex_exit(&port->fp_mutex); 7547 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf, 7548 fcio->fcio_olen, mode) == 0) { 7549 if (fp_fcio_copyout(fcio, data, mode)) { 7550 rval = EFAULT; 7551 } 7552 } else { 7553 rval = EFAULT; 7554 } 7555 kmem_free(attrs, sizeof (*attrs)); 7556 break; 7557 } 7558 7559 case FCIO_DELETE_NPIV_PORT: { 7560 fc_local_port_t *tmpport; 7561 char ww_pname[17]; 7562 la_wwn_t vwwn[1]; 7563 7564 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port"); 7565 if (ddi_copyin(fcio->fcio_ibuf, 7566 &vwwn, sizeof (la_wwn_t), mode)) { 7567 rval = EFAULT; 7568 break; 7569 } 7570 7571 fc_wwn_to_str(&vwwn[0], ww_pname); 7572 FP_TRACE(FP_NHEAD1(3, 0), 7573 "Delete NPIV Port %s", ww_pname); 7574 tmpport = fc_delete_npiv_port(port, &vwwn[0]); 7575 if (tmpport == NULL) { 7576 FP_TRACE(FP_NHEAD1(3, 0), 7577 "Delete NPIV Port : no found"); 7578 rval = EFAULT; 7579 } else { 7580 fc_local_port_t *nextport = tmpport->fp_port_next; 7581 fc_local_port_t *prevport = tmpport->fp_port_prev; 7582 int portlen, portindex, ret; 7583 7584 portlen = sizeof (portindex); 7585 ret = ddi_prop_op(DDI_DEV_T_ANY, 7586 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF, 7587 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 7588 (caddr_t)&portindex, &portlen); 7589 if (ret != DDI_SUCCESS) { 7590 rval = EFAULT; 7591 break; 7592 } 7593 if (ndi_devi_offline(tmpport->fp_port_dip, 7594 NDI_DEVI_REMOVE) != DDI_SUCCESS) { 7595 FP_TRACE(FP_NHEAD1(1, 0), 7596 "Delete NPIV Port failed"); 7597 mutex_enter(&port->fp_mutex); 7598 tmpport->fp_npiv_state = 0; 7599 mutex_exit(&port->fp_mutex); 7600 rval = EFAULT; 7601 } else { 7602 mutex_enter(&port->fp_mutex); 7603 nextport->fp_port_prev = prevport; 7604 prevport->fp_port_next = nextport; 7605 if (port == port->fp_port_next) { 7606 port->fp_port_next = 7607 port->fp_port_prev = NULL; 7608 } 7609 port->fp_npiv_portnum--; 7610 FP_TRACE(FP_NHEAD1(3, 0), 7611 "Delete NPIV Port %d", portindex); 7612 port->fp_npiv_portindex[portindex-1] = 0; 7613 mutex_exit(&port->fp_mutex); 7614 } 7615 } 7616 break; 7617 } 7618 7619 case FCIO_CREATE_NPIV_PORT: { 7620 char ww_nname[17], ww_pname[17]; 7621 la_npiv_create_entry_t entrybuf; 7622 uint32_t vportindex = 0; 7623 int npiv_ret = 0; 7624 char *portname, *fcaname; 7625 7626 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7627 (void) ddi_pathname(port->fp_port_dip, portname); 7628 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7629 (void) ddi_pathname(port->fp_fca_dip, fcaname); 7630 FP_TRACE(FP_NHEAD1(1, 0), 7631 "Create NPIV port %s %s %s", portname, fcaname, 7632 ddi_driver_name(port->fp_fca_dip)); 7633 kmem_free(portname, MAXPATHLEN); 7634 kmem_free(fcaname, MAXPATHLEN); 7635 if (ddi_copyin(fcio->fcio_ibuf, 7636 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) { 7637 rval = EFAULT; 7638 break; 7639 } 7640 7641 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname); 7642 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname); 7643 vportindex = entrybuf.vindex; 7644 FP_TRACE(FP_NHEAD1(3, 0), 7645 "Create NPIV Port %s %s %d", 7646 ww_nname, ww_pname, vportindex); 7647 7648 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) { 7649 rval = EFAULT; 7650 break; 7651 } 7652 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip, 7653 port->fp_port_dip, ww_nname, ww_pname, &vportindex); 7654 if (npiv_ret == NDI_SUCCESS) { 7655 mutex_enter(&port->fp_mutex); 7656 port->fp_npiv_portnum++; 7657 mutex_exit(&port->fp_mutex); 7658 if (fp_copyout((void *)&vportindex, 7659 (void *)fcio->fcio_obuf, 7660 fcio->fcio_olen, mode) == 0) { 7661 if (fp_fcio_copyout(fcio, data, mode)) { 7662 rval = EFAULT; 7663 } 7664 } else { 7665 rval = EFAULT; 7666 } 7667 } else { 7668 rval = EFAULT; 7669 } 7670 FP_TRACE(FP_NHEAD1(3, 0), 7671 "Create NPIV Port %d %d", npiv_ret, vportindex); 7672 break; 7673 } 7674 7675 case FCIO_GET_NPIV_PORT_LIST: { 7676 fc_hba_npiv_port_list_t *list; 7677 int count; 7678 7679 if ((fcio->fcio_xfer != FCIO_XFER_READ) || 7680 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { 7681 rval = EINVAL; 7682 break; 7683 } 7684 7685 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 7686 list->version = FC_HBA_LIST_VERSION; 7687 7688 count = (fcio->fcio_olen - 7689 (int)sizeof (fc_hba_npiv_port_list_t))/MAXPATHLEN + 1; 7690 if (port->fp_npiv_portnum > count) { 7691 list->numAdapters = port->fp_npiv_portnum; 7692 } else { 7693 /* build npiv port list */ 7694 count = fc_ulp_get_npiv_port_list(port, 7695 (char *)list->hbaPaths); 7696 if (count < 0) { 7697 rval = ENXIO; 7698 FP_TRACE(FP_NHEAD1(1, 0), 7699 "Build NPIV Port List error"); 7700 kmem_free(list, fcio->fcio_olen); 7701 break; 7702 } 7703 list->numAdapters = count; 7704 } 7705 7706 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf, 7707 fcio->fcio_olen, mode) == 0) { 7708 if (fp_fcio_copyout(fcio, data, mode)) { 7709 FP_TRACE(FP_NHEAD1(1, 0), 7710 "Copy NPIV Port data error"); 7711 rval = EFAULT; 7712 } 7713 } else { 7714 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error"); 7715 rval = EFAULT; 7716 } 7717 kmem_free(list, fcio->fcio_olen); 7718 break; 7719 } 7720 7721 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: { 7722 fc_hba_port_npiv_attributes_t *val; 7723 7724 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7725 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION; 7726 7727 mutex_enter(&port->fp_mutex); 7728 val->npivflag = port->fp_npiv_flag; 7729 val->lastChange = port->fp_last_change; 7730 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7731 &val->PortWWN.raw_wwn, 7732 sizeof (val->PortWWN.raw_wwn)); 7733 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7734 &val->NodeWWN.raw_wwn, 7735 sizeof (val->NodeWWN.raw_wwn)); 7736 mutex_exit(&port->fp_mutex); 7737 7738 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port); 7739 if (port->fp_npiv_type != FC_NPIV_PORT) { 7740 val->MaxNumberOfNPIVPorts = 7741 port->fp_fca_tran->fca_num_npivports; 7742 } else { 7743 val->MaxNumberOfNPIVPorts = 0; 7744 } 7745 7746 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7747 fcio->fcio_olen, mode) == 0) { 7748 if (fp_fcio_copyout(fcio, data, mode)) { 7749 rval = EFAULT; 7750 } 7751 } else { 7752 rval = EFAULT; 7753 } 7754 kmem_free(val, sizeof (*val)); 7755 break; 7756 } 7757 7758 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: { 7759 fc_hba_port_attributes_t *val; 7760 fc_hba_port_attributes32_t *val32; 7761 7762 if (use32 == B_TRUE) { 7763 if (fcio->fcio_olen < sizeof (*val32) || 7764 fcio->fcio_xfer != FCIO_XFER_READ) { 7765 rval = EINVAL; 7766 break; 7767 } 7768 } else { 7769 if (fcio->fcio_olen < sizeof (*val) || 7770 fcio->fcio_xfer != FCIO_XFER_READ) { 7771 rval = EINVAL; 7772 break; 7773 } 7774 } 7775 7776 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7777 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7778 mutex_enter(&port->fp_mutex); 7779 val->lastChange = port->fp_last_change; 7780 val->fp_minor = port->fp_instance; 7781 7782 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7783 &val->PortWWN.raw_wwn, 7784 sizeof (val->PortWWN.raw_wwn)); 7785 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7786 &val->NodeWWN.raw_wwn, 7787 sizeof (val->NodeWWN.raw_wwn)); 7788 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn, 7789 sizeof (val->FabricName.raw_wwn)); 7790 7791 val->PortFcId = port->fp_port_id.port_id; 7792 7793 switch (FC_PORT_STATE_MASK(port->fp_state)) { 7794 case FC_STATE_OFFLINE: 7795 val->PortState = FC_HBA_PORTSTATE_OFFLINE; 7796 break; 7797 case FC_STATE_ONLINE: 7798 case FC_STATE_LOOP: 7799 case FC_STATE_NAMESERVICE: 7800 val->PortState = FC_HBA_PORTSTATE_ONLINE; 7801 break; 7802 default: 7803 val->PortState = FC_HBA_PORTSTATE_UNKNOWN; 7804 break; 7805 } 7806 7807 /* Translate from LV to FC-HBA port type codes */ 7808 switch (port->fp_port_type.port_type) { 7809 case FC_NS_PORT_N: 7810 val->PortType = FC_HBA_PORTTYPE_NPORT; 7811 break; 7812 case FC_NS_PORT_NL: 7813 /* Actually means loop for us */ 7814 val->PortType = FC_HBA_PORTTYPE_LPORT; 7815 break; 7816 case FC_NS_PORT_F: 7817 val->PortType = FC_HBA_PORTTYPE_FPORT; 7818 break; 7819 case FC_NS_PORT_FL: 7820 val->PortType = FC_HBA_PORTTYPE_FLPORT; 7821 break; 7822 case FC_NS_PORT_E: 7823 val->PortType = FC_HBA_PORTTYPE_EPORT; 7824 break; 7825 default: 7826 val->PortType = FC_HBA_PORTTYPE_OTHER; 7827 break; 7828 } 7829 7830 7831 /* 7832 * If fp has decided that the topology is public loop, 7833 * we will indicate that using the appropriate 7834 * FC HBA API constant. 7835 */ 7836 switch (port->fp_topology) { 7837 case FC_TOP_PUBLIC_LOOP: 7838 val->PortType = FC_HBA_PORTTYPE_NLPORT; 7839 break; 7840 7841 case FC_TOP_PT_PT: 7842 val->PortType = FC_HBA_PORTTYPE_PTP; 7843 break; 7844 7845 case FC_TOP_UNKNOWN: 7846 /* 7847 * This should cover the case where nothing is connected 7848 * to the port. Crystal+ is p'bly an exception here. 7849 * For Crystal+, port 0 will come up as private loop 7850 * (i.e fp_bind_state will be FC_STATE_LOOP) even when 7851 * nothing is connected to it. 7852 * Current plan is to let userland handle this. 7853 */ 7854 if (port->fp_bind_state == FC_STATE_OFFLINE) { 7855 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7856 } 7857 break; 7858 7859 default: 7860 /* 7861 * Do Nothing. 7862 * Unused: 7863 * val->PortType = FC_HBA_PORTTYPE_GPORT; 7864 */ 7865 break; 7866 } 7867 7868 val->PortSupportedClassofService = 7869 port->fp_hba_port_attrs.supported_cos; 7870 val->PortSupportedFc4Types[0] = 0; 7871 bcopy(port->fp_fc4_types, val->PortActiveFc4Types, 7872 sizeof (val->PortActiveFc4Types)); 7873 bcopy(port->fp_sym_port_name, val->PortSymbolicName, 7874 port->fp_sym_port_namelen); 7875 val->PortSupportedSpeed = 7876 port->fp_hba_port_attrs.supported_speed; 7877 7878 switch (FC_PORT_SPEED_MASK(port->fp_state)) { 7879 case FC_STATE_1GBIT_SPEED: 7880 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT; 7881 break; 7882 case FC_STATE_2GBIT_SPEED: 7883 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT; 7884 break; 7885 case FC_STATE_4GBIT_SPEED: 7886 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT; 7887 break; 7888 case FC_STATE_8GBIT_SPEED: 7889 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT; 7890 break; 7891 case FC_STATE_10GBIT_SPEED: 7892 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT; 7893 break; 7894 case FC_STATE_16GBIT_SPEED: 7895 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT; 7896 break; 7897 default: 7898 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7899 break; 7900 } 7901 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size; 7902 val->NumberofDiscoveredPorts = port->fp_dev_count; 7903 mutex_exit(&port->fp_mutex); 7904 7905 if (use32 == B_TRUE) { 7906 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7907 val32->version = val->version; 7908 val32->lastChange = val->lastChange; 7909 val32->fp_minor = val->fp_minor; 7910 7911 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn, 7912 sizeof (val->PortWWN.raw_wwn)); 7913 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7914 sizeof (val->NodeWWN.raw_wwn)); 7915 val32->PortFcId = val->PortFcId; 7916 val32->PortState = val->PortState; 7917 val32->PortType = val->PortType; 7918 7919 val32->PortSupportedClassofService = 7920 val->PortSupportedClassofService; 7921 bcopy(val->PortActiveFc4Types, 7922 val32->PortActiveFc4Types, 7923 sizeof (val->PortActiveFc4Types)); 7924 bcopy(val->PortSymbolicName, val32->PortSymbolicName, 7925 sizeof (val->PortSymbolicName)); 7926 bcopy(&val->FabricName, &val32->FabricName, 7927 sizeof (val->FabricName.raw_wwn)); 7928 val32->PortSupportedSpeed = val->PortSupportedSpeed; 7929 val32->PortSpeed = val->PortSpeed; 7930 7931 val32->PortMaxFrameSize = val->PortMaxFrameSize; 7932 val32->NumberofDiscoveredPorts = 7933 val->NumberofDiscoveredPorts; 7934 7935 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7936 fcio->fcio_olen, mode) == 0) { 7937 if (fp_fcio_copyout(fcio, data, mode)) { 7938 rval = EFAULT; 7939 } 7940 } else { 7941 rval = EFAULT; 7942 } 7943 7944 kmem_free(val32, sizeof (*val32)); 7945 } else { 7946 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7947 fcio->fcio_olen, mode) == 0) { 7948 if (fp_fcio_copyout(fcio, data, mode)) { 7949 rval = EFAULT; 7950 } 7951 } else { 7952 rval = EFAULT; 7953 } 7954 } 7955 7956 kmem_free(val, sizeof (*val)); 7957 break; 7958 } 7959 7960 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: { 7961 fc_hba_port_attributes_t *val; 7962 fc_hba_port_attributes32_t *val32; 7963 uint32_t index = 0; 7964 fc_remote_port_t *tmp_pd; 7965 7966 if (use32 == B_TRUE) { 7967 if (fcio->fcio_olen < sizeof (*val32) || 7968 fcio->fcio_xfer != FCIO_XFER_READ) { 7969 rval = EINVAL; 7970 break; 7971 } 7972 } else { 7973 if (fcio->fcio_olen < sizeof (*val) || 7974 fcio->fcio_xfer != FCIO_XFER_READ) { 7975 rval = EINVAL; 7976 break; 7977 } 7978 } 7979 7980 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7981 rval = EFAULT; 7982 break; 7983 } 7984 7985 if (index >= port->fp_dev_count) { 7986 FP_TRACE(FP_NHEAD1(9, 0), 7987 "User supplied index out of range"); 7988 fcio->fcio_errno = FC_OUTOFBOUNDS; 7989 rval = EINVAL; 7990 if (fp_fcio_copyout(fcio, data, mode)) { 7991 rval = EFAULT; 7992 } 7993 break; 7994 } 7995 7996 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7997 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7998 7999 mutex_enter(&port->fp_mutex); 8000 tmp_pd = fctl_lookup_pd_by_index(port, index); 8001 8002 if (tmp_pd == NULL) { 8003 fcio->fcio_errno = FC_BADPORT; 8004 rval = EINVAL; 8005 } else { 8006 val->lastChange = port->fp_last_change; 8007 val->fp_minor = port->fp_instance; 8008 8009 mutex_enter(&tmp_pd->pd_mutex); 8010 bcopy(&tmp_pd->pd_port_name.raw_wwn, 8011 &val->PortWWN.raw_wwn, 8012 sizeof (val->PortWWN.raw_wwn)); 8013 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 8014 &val->NodeWWN.raw_wwn, 8015 sizeof (val->NodeWWN.raw_wwn)); 8016 val->PortFcId = tmp_pd->pd_port_id.port_id; 8017 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 8018 tmp_pd->pd_spn_len); 8019 val->PortSupportedClassofService = tmp_pd->pd_cos; 8020 /* 8021 * we will assume the sizeof these pd_fc4types and 8022 * portActiveFc4Types will remain the same. we could 8023 * add in a check for it, but we decided it was unneeded 8024 */ 8025 bcopy((caddr_t)tmp_pd->pd_fc4types, 8026 val->PortActiveFc4Types, 8027 sizeof (tmp_pd->pd_fc4types)); 8028 val->PortState = 8029 fp_map_remote_port_state(tmp_pd->pd_state); 8030 mutex_exit(&tmp_pd->pd_mutex); 8031 8032 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 8033 val->PortSupportedFc4Types[0] = 0; 8034 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8035 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8036 val->PortMaxFrameSize = 0; 8037 val->NumberofDiscoveredPorts = 0; 8038 8039 if (use32 == B_TRUE) { 8040 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 8041 val32->version = val->version; 8042 val32->lastChange = val->lastChange; 8043 val32->fp_minor = val->fp_minor; 8044 8045 bcopy(&val->PortWWN.raw_wwn, 8046 &val32->PortWWN.raw_wwn, 8047 sizeof (val->PortWWN.raw_wwn)); 8048 bcopy(&val->NodeWWN.raw_wwn, 8049 &val32->NodeWWN.raw_wwn, 8050 sizeof (val->NodeWWN.raw_wwn)); 8051 val32->PortFcId = val->PortFcId; 8052 bcopy(val->PortSymbolicName, 8053 val32->PortSymbolicName, 8054 sizeof (val->PortSymbolicName)); 8055 val32->PortSupportedClassofService = 8056 val->PortSupportedClassofService; 8057 bcopy(val->PortActiveFc4Types, 8058 val32->PortActiveFc4Types, 8059 sizeof (tmp_pd->pd_fc4types)); 8060 8061 val32->PortType = val->PortType; 8062 val32->PortState = val->PortState; 8063 val32->PortSupportedFc4Types[0] = 8064 val->PortSupportedFc4Types[0]; 8065 val32->PortSupportedSpeed = 8066 val->PortSupportedSpeed; 8067 val32->PortSpeed = val->PortSpeed; 8068 val32->PortMaxFrameSize = 8069 val->PortMaxFrameSize; 8070 val32->NumberofDiscoveredPorts = 8071 val->NumberofDiscoveredPorts; 8072 8073 if (fp_copyout((void *)val32, 8074 (void *)fcio->fcio_obuf, 8075 fcio->fcio_olen, mode) == 0) { 8076 if (fp_fcio_copyout(fcio, 8077 data, mode)) { 8078 rval = EFAULT; 8079 } 8080 } else { 8081 rval = EFAULT; 8082 } 8083 8084 kmem_free(val32, sizeof (*val32)); 8085 } else { 8086 if (fp_copyout((void *)val, 8087 (void *)fcio->fcio_obuf, 8088 fcio->fcio_olen, mode) == 0) { 8089 if (fp_fcio_copyout(fcio, data, mode)) { 8090 rval = EFAULT; 8091 } 8092 } else { 8093 rval = EFAULT; 8094 } 8095 } 8096 } 8097 8098 mutex_exit(&port->fp_mutex); 8099 kmem_free(val, sizeof (*val)); 8100 break; 8101 } 8102 8103 case FCIO_GET_PORT_ATTRIBUTES: { 8104 fc_hba_port_attributes_t *val; 8105 fc_hba_port_attributes32_t *val32; 8106 la_wwn_t wwn; 8107 fc_remote_port_t *tmp_pd; 8108 8109 if (use32 == B_TRUE) { 8110 if (fcio->fcio_olen < sizeof (*val32) || 8111 fcio->fcio_xfer != FCIO_XFER_READ) { 8112 rval = EINVAL; 8113 break; 8114 } 8115 } else { 8116 if (fcio->fcio_olen < sizeof (*val) || 8117 fcio->fcio_xfer != FCIO_XFER_READ) { 8118 rval = EINVAL; 8119 break; 8120 } 8121 } 8122 8123 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) { 8124 rval = EFAULT; 8125 break; 8126 } 8127 8128 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 8129 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 8130 8131 mutex_enter(&port->fp_mutex); 8132 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn); 8133 val->lastChange = port->fp_last_change; 8134 val->fp_minor = port->fp_instance; 8135 mutex_exit(&port->fp_mutex); 8136 8137 if (tmp_pd == NULL) { 8138 fcio->fcio_errno = FC_BADWWN; 8139 rval = EINVAL; 8140 } else { 8141 mutex_enter(&tmp_pd->pd_mutex); 8142 bcopy(&tmp_pd->pd_port_name.raw_wwn, 8143 &val->PortWWN.raw_wwn, 8144 sizeof (val->PortWWN.raw_wwn)); 8145 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 8146 &val->NodeWWN.raw_wwn, 8147 sizeof (val->NodeWWN.raw_wwn)); 8148 val->PortFcId = tmp_pd->pd_port_id.port_id; 8149 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 8150 tmp_pd->pd_spn_len); 8151 val->PortSupportedClassofService = tmp_pd->pd_cos; 8152 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 8153 val->PortState = 8154 fp_map_remote_port_state(tmp_pd->pd_state); 8155 val->PortSupportedFc4Types[0] = 0; 8156 /* 8157 * we will assume the sizeof these pd_fc4types and 8158 * portActiveFc4Types will remain the same. we could 8159 * add in a check for it, but we decided it was unneeded 8160 */ 8161 bcopy((caddr_t)tmp_pd->pd_fc4types, 8162 val->PortActiveFc4Types, 8163 sizeof (tmp_pd->pd_fc4types)); 8164 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8165 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8166 val->PortMaxFrameSize = 0; 8167 val->NumberofDiscoveredPorts = 0; 8168 mutex_exit(&tmp_pd->pd_mutex); 8169 8170 if (use32 == B_TRUE) { 8171 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 8172 val32->version = val->version; 8173 val32->lastChange = val->lastChange; 8174 val32->fp_minor = val->fp_minor; 8175 bcopy(&val->PortWWN.raw_wwn, 8176 &val32->PortWWN.raw_wwn, 8177 sizeof (val->PortWWN.raw_wwn)); 8178 bcopy(&val->NodeWWN.raw_wwn, 8179 &val32->NodeWWN.raw_wwn, 8180 sizeof (val->NodeWWN.raw_wwn)); 8181 val32->PortFcId = val->PortFcId; 8182 bcopy(val->PortSymbolicName, 8183 val32->PortSymbolicName, 8184 sizeof (val->PortSymbolicName)); 8185 val32->PortSupportedClassofService = 8186 val->PortSupportedClassofService; 8187 val32->PortType = val->PortType; 8188 val32->PortState = val->PortState; 8189 val32->PortSupportedFc4Types[0] = 8190 val->PortSupportedFc4Types[0]; 8191 bcopy(val->PortActiveFc4Types, 8192 val32->PortActiveFc4Types, 8193 sizeof (tmp_pd->pd_fc4types)); 8194 val32->PortSupportedSpeed = 8195 val->PortSupportedSpeed; 8196 val32->PortSpeed = val->PortSpeed; 8197 val32->PortMaxFrameSize = val->PortMaxFrameSize; 8198 val32->NumberofDiscoveredPorts = 8199 val->NumberofDiscoveredPorts; 8200 8201 if (fp_copyout((void *)val32, 8202 (void *)fcio->fcio_obuf, 8203 fcio->fcio_olen, mode) == 0) { 8204 if (fp_fcio_copyout(fcio, data, mode)) { 8205 rval = EFAULT; 8206 } 8207 } else { 8208 rval = EFAULT; 8209 } 8210 8211 kmem_free(val32, sizeof (*val32)); 8212 } else { 8213 if (fp_copyout((void *)val, 8214 (void *)fcio->fcio_obuf, 8215 fcio->fcio_olen, mode) == 0) { 8216 if (fp_fcio_copyout(fcio, data, mode)) { 8217 rval = EFAULT; 8218 } 8219 } else { 8220 rval = EFAULT; 8221 } 8222 } 8223 } 8224 kmem_free(val, sizeof (*val)); 8225 break; 8226 } 8227 8228 case FCIO_GET_NUM_DEVS: { 8229 int num_devices; 8230 8231 if (fcio->fcio_olen != sizeof (num_devices) || 8232 fcio->fcio_xfer != FCIO_XFER_READ) { 8233 rval = EINVAL; 8234 break; 8235 } 8236 8237 mutex_enter(&port->fp_mutex); 8238 switch (port->fp_topology) { 8239 case FC_TOP_PRIVATE_LOOP: 8240 case FC_TOP_PT_PT: 8241 num_devices = port->fp_total_devices; 8242 fcio->fcio_errno = FC_SUCCESS; 8243 break; 8244 8245 case FC_TOP_PUBLIC_LOOP: 8246 case FC_TOP_FABRIC: 8247 mutex_exit(&port->fp_mutex); 8248 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, 8249 NULL, KM_SLEEP); 8250 ASSERT(job != NULL); 8251 8252 /* 8253 * In FC-GS-2 the Name Server doesn't send out 8254 * RSCNs for any Name Server Database updates 8255 * When it is finally fixed there is no need 8256 * to probe as below and should be removed. 8257 */ 8258 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 8259 fctl_dealloc_job(job); 8260 8261 mutex_enter(&port->fp_mutex); 8262 num_devices = port->fp_total_devices; 8263 fcio->fcio_errno = FC_SUCCESS; 8264 break; 8265 8266 case FC_TOP_NO_NS: 8267 /* FALLTHROUGH */ 8268 case FC_TOP_UNKNOWN: 8269 /* FALLTHROUGH */ 8270 default: 8271 num_devices = 0; 8272 fcio->fcio_errno = FC_SUCCESS; 8273 break; 8274 } 8275 mutex_exit(&port->fp_mutex); 8276 8277 if (fp_copyout((void *)&num_devices, 8278 (void *)fcio->fcio_obuf, fcio->fcio_olen, 8279 mode) == 0) { 8280 if (fp_fcio_copyout(fcio, data, mode)) { 8281 rval = EFAULT; 8282 } 8283 } else { 8284 rval = EFAULT; 8285 } 8286 break; 8287 } 8288 8289 case FCIO_GET_DEV_LIST: { 8290 int num_devices; 8291 int new_count; 8292 int map_size; 8293 8294 if (fcio->fcio_xfer != FCIO_XFER_READ || 8295 fcio->fcio_alen != sizeof (new_count)) { 8296 rval = EINVAL; 8297 break; 8298 } 8299 8300 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 8301 8302 mutex_enter(&port->fp_mutex); 8303 if (num_devices < port->fp_total_devices) { 8304 fcio->fcio_errno = FC_TOOMANY; 8305 new_count = port->fp_total_devices; 8306 mutex_exit(&port->fp_mutex); 8307 8308 if (fp_copyout((void *)&new_count, 8309 (void *)fcio->fcio_abuf, 8310 sizeof (new_count), mode)) { 8311 rval = EFAULT; 8312 break; 8313 } 8314 8315 if (fp_fcio_copyout(fcio, data, mode)) { 8316 rval = EFAULT; 8317 break; 8318 } 8319 rval = EINVAL; 8320 break; 8321 } 8322 8323 if (port->fp_total_devices <= 0) { 8324 fcio->fcio_errno = FC_NO_MAP; 8325 new_count = port->fp_total_devices; 8326 mutex_exit(&port->fp_mutex); 8327 8328 if (fp_copyout((void *)&new_count, 8329 (void *)fcio->fcio_abuf, 8330 sizeof (new_count), mode)) { 8331 rval = EFAULT; 8332 break; 8333 } 8334 8335 if (fp_fcio_copyout(fcio, data, mode)) { 8336 rval = EFAULT; 8337 break; 8338 } 8339 rval = EINVAL; 8340 break; 8341 } 8342 8343 switch (port->fp_topology) { 8344 case FC_TOP_PRIVATE_LOOP: 8345 if (fp_fillout_loopmap(port, fcio, 8346 mode) != FC_SUCCESS) { 8347 rval = EFAULT; 8348 break; 8349 } 8350 if (fp_fcio_copyout(fcio, data, mode)) { 8351 rval = EFAULT; 8352 } 8353 break; 8354 8355 case FC_TOP_PT_PT: 8356 if (fp_fillout_p2pmap(port, fcio, 8357 mode) != FC_SUCCESS) { 8358 rval = EFAULT; 8359 break; 8360 } 8361 if (fp_fcio_copyout(fcio, data, mode)) { 8362 rval = EFAULT; 8363 } 8364 break; 8365 8366 case FC_TOP_PUBLIC_LOOP: 8367 case FC_TOP_FABRIC: { 8368 fctl_ns_req_t *ns_cmd; 8369 8370 map_size = 8371 sizeof (fc_port_dev_t) * port->fp_total_devices; 8372 8373 mutex_exit(&port->fp_mutex); 8374 8375 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 8376 sizeof (ns_resp_gan_t), map_size, 8377 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND), 8378 KM_SLEEP); 8379 ASSERT(ns_cmd != NULL); 8380 8381 ns_cmd->ns_gan_index = 0; 8382 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 8383 ns_cmd->ns_cmd_code = NS_GA_NXT; 8384 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t); 8385 8386 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, 8387 NULL, KM_SLEEP); 8388 ASSERT(job != NULL); 8389 8390 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 8391 8392 if (ret != FC_SUCCESS || 8393 job->job_result != FC_SUCCESS) { 8394 fctl_free_ns_cmd(ns_cmd); 8395 8396 fcio->fcio_errno = job->job_result; 8397 new_count = 0; 8398 if (fp_copyout((void *)&new_count, 8399 (void *)fcio->fcio_abuf, 8400 sizeof (new_count), mode)) { 8401 fctl_dealloc_job(job); 8402 mutex_enter(&port->fp_mutex); 8403 rval = EFAULT; 8404 break; 8405 } 8406 8407 if (fp_fcio_copyout(fcio, data, mode)) { 8408 fctl_dealloc_job(job); 8409 mutex_enter(&port->fp_mutex); 8410 rval = EFAULT; 8411 break; 8412 } 8413 rval = EIO; 8414 mutex_enter(&port->fp_mutex); 8415 break; 8416 } 8417 fctl_dealloc_job(job); 8418 8419 new_count = ns_cmd->ns_gan_index; 8420 if (fp_copyout((void *)&new_count, 8421 (void *)fcio->fcio_abuf, sizeof (new_count), 8422 mode)) { 8423 rval = EFAULT; 8424 fctl_free_ns_cmd(ns_cmd); 8425 mutex_enter(&port->fp_mutex); 8426 break; 8427 } 8428 8429 if (fp_copyout((void *)ns_cmd->ns_data_buf, 8430 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) * 8431 ns_cmd->ns_gan_index, mode)) { 8432 rval = EFAULT; 8433 fctl_free_ns_cmd(ns_cmd); 8434 mutex_enter(&port->fp_mutex); 8435 break; 8436 } 8437 fctl_free_ns_cmd(ns_cmd); 8438 8439 if (fp_fcio_copyout(fcio, data, mode)) { 8440 rval = EFAULT; 8441 } 8442 mutex_enter(&port->fp_mutex); 8443 break; 8444 } 8445 8446 case FC_TOP_NO_NS: 8447 /* FALLTHROUGH */ 8448 case FC_TOP_UNKNOWN: 8449 /* FALLTHROUGH */ 8450 default: 8451 fcio->fcio_errno = FC_NO_MAP; 8452 num_devices = port->fp_total_devices; 8453 8454 if (fp_copyout((void *)&new_count, 8455 (void *)fcio->fcio_abuf, 8456 sizeof (new_count), mode)) { 8457 rval = EFAULT; 8458 break; 8459 } 8460 8461 if (fp_fcio_copyout(fcio, data, mode)) { 8462 rval = EFAULT; 8463 break; 8464 } 8465 rval = EINVAL; 8466 break; 8467 } 8468 mutex_exit(&port->fp_mutex); 8469 break; 8470 } 8471 8472 case FCIO_GET_SYM_PNAME: { 8473 rval = ENOTSUP; 8474 break; 8475 } 8476 8477 case FCIO_GET_SYM_NNAME: { 8478 rval = ENOTSUP; 8479 break; 8480 } 8481 8482 case FCIO_SET_SYM_PNAME: { 8483 rval = ENOTSUP; 8484 break; 8485 } 8486 8487 case FCIO_SET_SYM_NNAME: { 8488 rval = ENOTSUP; 8489 break; 8490 } 8491 8492 case FCIO_GET_LOGI_PARAMS: { 8493 la_wwn_t pwwn; 8494 la_wwn_t *my_pwwn; 8495 la_els_logi_t *params; 8496 la_els_logi32_t *params32; 8497 fc_remote_node_t *node; 8498 fc_remote_port_t *pd; 8499 8500 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8501 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || 8502 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { 8503 rval = EINVAL; 8504 break; 8505 } 8506 8507 if (use32 == B_TRUE) { 8508 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) { 8509 rval = EINVAL; 8510 break; 8511 } 8512 } else { 8513 if (fcio->fcio_olen != sizeof (la_els_logi_t)) { 8514 rval = EINVAL; 8515 break; 8516 } 8517 } 8518 8519 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8520 rval = EFAULT; 8521 break; 8522 } 8523 8524 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8525 if (pd == NULL) { 8526 mutex_enter(&port->fp_mutex); 8527 my_pwwn = &port->fp_service_params.nport_ww_name; 8528 mutex_exit(&port->fp_mutex); 8529 8530 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) { 8531 rval = ENXIO; 8532 break; 8533 } 8534 8535 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8536 mutex_enter(&port->fp_mutex); 8537 *params = port->fp_service_params; 8538 mutex_exit(&port->fp_mutex); 8539 } else { 8540 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8541 8542 mutex_enter(&pd->pd_mutex); 8543 params->ls_code.mbz = params->ls_code.ls_code = 0; 8544 params->common_service = pd->pd_csp; 8545 params->nport_ww_name = pd->pd_port_name; 8546 params->class_1 = pd->pd_clsp1; 8547 params->class_2 = pd->pd_clsp2; 8548 params->class_3 = pd->pd_clsp3; 8549 node = pd->pd_remote_nodep; 8550 mutex_exit(&pd->pd_mutex); 8551 8552 bzero(params->reserved, sizeof (params->reserved)); 8553 8554 mutex_enter(&node->fd_mutex); 8555 bcopy(node->fd_vv, params->vendor_version, 8556 sizeof (node->fd_vv)); 8557 params->node_ww_name = node->fd_node_name; 8558 mutex_exit(&node->fd_mutex); 8559 8560 fctl_release_remote_port(pd); 8561 } 8562 8563 if (use32 == B_TRUE) { 8564 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP); 8565 8566 params32->ls_code.mbz = params->ls_code.mbz; 8567 params32->common_service = params->common_service; 8568 params32->nport_ww_name = params->nport_ww_name; 8569 params32->class_1 = params->class_1; 8570 params32->class_2 = params->class_2; 8571 params32->class_3 = params->class_3; 8572 bzero(params32->reserved, sizeof (params32->reserved)); 8573 bcopy(params->vendor_version, params32->vendor_version, 8574 sizeof (node->fd_vv)); 8575 params32->node_ww_name = params->node_ww_name; 8576 8577 if (ddi_copyout((void *)params32, 8578 (void *)fcio->fcio_obuf, 8579 sizeof (*params32), mode)) { 8580 rval = EFAULT; 8581 } 8582 8583 kmem_free(params32, sizeof (*params32)); 8584 } else { 8585 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf, 8586 sizeof (*params), mode)) { 8587 rval = EFAULT; 8588 } 8589 } 8590 8591 kmem_free(params, sizeof (*params)); 8592 if (fp_fcio_copyout(fcio, data, mode)) { 8593 rval = EFAULT; 8594 } 8595 break; 8596 } 8597 8598 case FCIO_DEV_LOGOUT: 8599 case FCIO_DEV_LOGIN: 8600 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8601 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8602 rval = EINVAL; 8603 8604 if (fp_fcio_copyout(fcio, data, mode)) { 8605 rval = EFAULT; 8606 } 8607 break; 8608 } 8609 8610 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) { 8611 jcode = JOB_FCIO_LOGIN; 8612 } else { 8613 jcode = JOB_FCIO_LOGOUT; 8614 } 8615 8616 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP); 8617 bcopy(fcio, kfcio, sizeof (*fcio)); 8618 8619 if (kfcio->fcio_ilen) { 8620 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen, 8621 KM_SLEEP); 8622 8623 if (ddi_copyin((void *)fcio->fcio_ibuf, 8624 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen, 8625 mode)) { 8626 rval = EFAULT; 8627 8628 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8629 kmem_free(kfcio, sizeof (*kfcio)); 8630 fcio->fcio_errno = job->job_result; 8631 if (fp_fcio_copyout(fcio, data, mode)) { 8632 rval = EFAULT; 8633 } 8634 break; 8635 } 8636 } 8637 8638 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP); 8639 job->job_private = kfcio; 8640 8641 fctl_enque_job(port, job); 8642 fctl_jobwait(job); 8643 8644 rval = job->job_result; 8645 8646 fcio->fcio_errno = kfcio->fcio_errno; 8647 if (fp_fcio_copyout(fcio, data, mode)) { 8648 rval = EFAULT; 8649 } 8650 8651 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8652 kmem_free(kfcio, sizeof (*kfcio)); 8653 fctl_dealloc_job(job); 8654 break; 8655 8656 case FCIO_GET_STATE: { 8657 la_wwn_t pwwn; 8658 uint32_t state; 8659 fc_remote_port_t *pd; 8660 fctl_ns_req_t *ns_cmd; 8661 8662 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8663 fcio->fcio_olen != sizeof (state) || 8664 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 || 8665 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { 8666 rval = EINVAL; 8667 break; 8668 } 8669 8670 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8671 rval = EFAULT; 8672 break; 8673 } 8674 fcio->fcio_errno = 0; 8675 8676 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8677 if (pd == NULL) { 8678 mutex_enter(&port->fp_mutex); 8679 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 8680 mutex_exit(&port->fp_mutex); 8681 job = fctl_alloc_job(JOB_PLOGI_ONE, 0, 8682 NULL, NULL, KM_SLEEP); 8683 8684 job->job_counter = 1; 8685 job->job_result = FC_SUCCESS; 8686 8687 ns_cmd = fctl_alloc_ns_cmd( 8688 sizeof (ns_req_gid_pn_t), 8689 sizeof (ns_resp_gid_pn_t), 8690 sizeof (ns_resp_gid_pn_t), 8691 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 8692 ASSERT(ns_cmd != NULL); 8693 8694 ns_cmd->ns_cmd_code = NS_GID_PN; 8695 ((ns_req_gid_pn_t *) 8696 (ns_cmd->ns_cmd_buf))->pwwn = pwwn; 8697 8698 ret = fp_ns_query(port, ns_cmd, job, 8699 1, KM_SLEEP); 8700 8701 if (ret != FC_SUCCESS || job->job_result != 8702 FC_SUCCESS) { 8703 if (ret != FC_SUCCESS) { 8704 fcio->fcio_errno = ret; 8705 } else { 8706 fcio->fcio_errno = 8707 job->job_result; 8708 } 8709 rval = EIO; 8710 } else { 8711 state = PORT_DEVICE_INVALID; 8712 } 8713 fctl_free_ns_cmd(ns_cmd); 8714 fctl_dealloc_job(job); 8715 } else { 8716 mutex_exit(&port->fp_mutex); 8717 fcio->fcio_errno = FC_BADWWN; 8718 rval = ENXIO; 8719 } 8720 } else { 8721 mutex_enter(&pd->pd_mutex); 8722 state = pd->pd_state; 8723 mutex_exit(&pd->pd_mutex); 8724 8725 fctl_release_remote_port(pd); 8726 } 8727 8728 if (!rval) { 8729 if (ddi_copyout((void *)&state, 8730 (void *)fcio->fcio_obuf, sizeof (state), 8731 mode)) { 8732 rval = EFAULT; 8733 } 8734 } 8735 if (fp_fcio_copyout(fcio, data, mode)) { 8736 rval = EFAULT; 8737 } 8738 break; 8739 } 8740 8741 case FCIO_DEV_REMOVE: { 8742 la_wwn_t pwwn; 8743 fc_portmap_t *changelist; 8744 fc_remote_port_t *pd; 8745 8746 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8747 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8748 rval = EINVAL; 8749 break; 8750 } 8751 8752 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8753 rval = EFAULT; 8754 break; 8755 } 8756 8757 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8758 if (pd == NULL) { 8759 rval = ENXIO; 8760 fcio->fcio_errno = FC_BADWWN; 8761 if (fp_fcio_copyout(fcio, data, mode)) { 8762 rval = EFAULT; 8763 } 8764 break; 8765 } 8766 8767 mutex_enter(&pd->pd_mutex); 8768 if (pd->pd_ref_count > 1) { 8769 mutex_exit(&pd->pd_mutex); 8770 8771 rval = EBUSY; 8772 fcio->fcio_errno = FC_FAILURE; 8773 fctl_release_remote_port(pd); 8774 8775 if (fp_fcio_copyout(fcio, data, mode)) { 8776 rval = EFAULT; 8777 } 8778 break; 8779 } 8780 mutex_exit(&pd->pd_mutex); 8781 8782 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 8783 8784 fctl_copy_portmap(changelist, pd); 8785 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 8786 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 8787 8788 fctl_release_remote_port(pd); 8789 break; 8790 } 8791 8792 case FCIO_GET_FCODE_REV: { 8793 caddr_t fcode_rev; 8794 fc_fca_pm_t pm; 8795 8796 if (fcio->fcio_olen < FC_FCODE_REV_SIZE || 8797 fcio->fcio_xfer != FCIO_XFER_READ) { 8798 rval = EINVAL; 8799 break; 8800 } 8801 bzero((caddr_t)&pm, sizeof (pm)); 8802 8803 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8804 8805 pm.pm_cmd_flags = FC_FCA_PM_READ; 8806 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV; 8807 pm.pm_data_len = fcio->fcio_olen; 8808 pm.pm_data_buf = fcode_rev; 8809 8810 ret = port->fp_fca_tran->fca_port_manage( 8811 port->fp_fca_handle, &pm); 8812 8813 if (ret == FC_SUCCESS) { 8814 if (ddi_copyout((void *)fcode_rev, 8815 (void *)fcio->fcio_obuf, 8816 fcio->fcio_olen, mode) == 0) { 8817 if (fp_fcio_copyout(fcio, data, mode)) { 8818 rval = EFAULT; 8819 } 8820 } else { 8821 rval = EFAULT; 8822 } 8823 } else { 8824 /* 8825 * check if buffer was not large enough to obtain 8826 * FCODE version. 8827 */ 8828 if (pm.pm_data_len > fcio->fcio_olen) { 8829 rval = ENOMEM; 8830 } else { 8831 rval = EIO; 8832 } 8833 fcio->fcio_errno = ret; 8834 if (fp_fcio_copyout(fcio, data, mode)) { 8835 rval = EFAULT; 8836 } 8837 } 8838 kmem_free(fcode_rev, fcio->fcio_olen); 8839 break; 8840 } 8841 8842 case FCIO_GET_FW_REV: { 8843 caddr_t fw_rev; 8844 fc_fca_pm_t pm; 8845 8846 if (fcio->fcio_olen < FC_FW_REV_SIZE || 8847 fcio->fcio_xfer != FCIO_XFER_READ) { 8848 rval = EINVAL; 8849 break; 8850 } 8851 bzero((caddr_t)&pm, sizeof (pm)); 8852 8853 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8854 8855 pm.pm_cmd_flags = FC_FCA_PM_READ; 8856 pm.pm_cmd_code = FC_PORT_GET_FW_REV; 8857 pm.pm_data_len = fcio->fcio_olen; 8858 pm.pm_data_buf = fw_rev; 8859 8860 ret = port->fp_fca_tran->fca_port_manage( 8861 port->fp_fca_handle, &pm); 8862 8863 if (ret == FC_SUCCESS) { 8864 if (ddi_copyout((void *)fw_rev, 8865 (void *)fcio->fcio_obuf, 8866 fcio->fcio_olen, mode) == 0) { 8867 if (fp_fcio_copyout(fcio, data, mode)) { 8868 rval = EFAULT; 8869 } 8870 } else { 8871 rval = EFAULT; 8872 } 8873 } else { 8874 if (fp_fcio_copyout(fcio, data, mode)) { 8875 rval = EFAULT; 8876 } 8877 rval = EIO; 8878 } 8879 kmem_free(fw_rev, fcio->fcio_olen); 8880 break; 8881 } 8882 8883 case FCIO_GET_DUMP_SIZE: { 8884 uint32_t dump_size; 8885 fc_fca_pm_t pm; 8886 8887 if (fcio->fcio_olen != sizeof (dump_size) || 8888 fcio->fcio_xfer != FCIO_XFER_READ) { 8889 rval = EINVAL; 8890 break; 8891 } 8892 bzero((caddr_t)&pm, sizeof (pm)); 8893 pm.pm_cmd_flags = FC_FCA_PM_READ; 8894 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8895 pm.pm_data_len = sizeof (dump_size); 8896 pm.pm_data_buf = (caddr_t)&dump_size; 8897 8898 ret = port->fp_fca_tran->fca_port_manage( 8899 port->fp_fca_handle, &pm); 8900 8901 if (ret == FC_SUCCESS) { 8902 if (ddi_copyout((void *)&dump_size, 8903 (void *)fcio->fcio_obuf, sizeof (dump_size), 8904 mode) == 0) { 8905 if (fp_fcio_copyout(fcio, data, mode)) { 8906 rval = EFAULT; 8907 } 8908 } else { 8909 rval = EFAULT; 8910 } 8911 } else { 8912 fcio->fcio_errno = ret; 8913 rval = EIO; 8914 if (fp_fcio_copyout(fcio, data, mode)) { 8915 rval = EFAULT; 8916 } 8917 } 8918 break; 8919 } 8920 8921 case FCIO_DOWNLOAD_FW: { 8922 caddr_t firmware; 8923 fc_fca_pm_t pm; 8924 8925 if (fcio->fcio_ilen <= 0 || 8926 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8927 rval = EINVAL; 8928 break; 8929 } 8930 8931 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8932 if (ddi_copyin(fcio->fcio_ibuf, firmware, 8933 fcio->fcio_ilen, mode)) { 8934 rval = EFAULT; 8935 kmem_free(firmware, fcio->fcio_ilen); 8936 break; 8937 } 8938 8939 bzero((caddr_t)&pm, sizeof (pm)); 8940 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8941 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW; 8942 pm.pm_data_len = fcio->fcio_ilen; 8943 pm.pm_data_buf = firmware; 8944 8945 ret = port->fp_fca_tran->fca_port_manage( 8946 port->fp_fca_handle, &pm); 8947 8948 kmem_free(firmware, fcio->fcio_ilen); 8949 8950 if (ret != FC_SUCCESS) { 8951 fcio->fcio_errno = ret; 8952 rval = EIO; 8953 if (fp_fcio_copyout(fcio, data, mode)) { 8954 rval = EFAULT; 8955 } 8956 } 8957 break; 8958 } 8959 8960 case FCIO_DOWNLOAD_FCODE: { 8961 caddr_t fcode; 8962 fc_fca_pm_t pm; 8963 8964 if (fcio->fcio_ilen <= 0 || 8965 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8966 rval = EINVAL; 8967 break; 8968 } 8969 8970 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8971 if (ddi_copyin(fcio->fcio_ibuf, fcode, 8972 fcio->fcio_ilen, mode)) { 8973 rval = EFAULT; 8974 kmem_free(fcode, fcio->fcio_ilen); 8975 break; 8976 } 8977 8978 bzero((caddr_t)&pm, sizeof (pm)); 8979 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8980 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE; 8981 pm.pm_data_len = fcio->fcio_ilen; 8982 pm.pm_data_buf = fcode; 8983 8984 ret = port->fp_fca_tran->fca_port_manage( 8985 port->fp_fca_handle, &pm); 8986 8987 kmem_free(fcode, fcio->fcio_ilen); 8988 8989 if (ret != FC_SUCCESS) { 8990 fcio->fcio_errno = ret; 8991 rval = EIO; 8992 if (fp_fcio_copyout(fcio, data, mode)) { 8993 rval = EFAULT; 8994 } 8995 } 8996 break; 8997 } 8998 8999 case FCIO_FORCE_DUMP: 9000 ret = port->fp_fca_tran->fca_reset( 9001 port->fp_fca_handle, FC_FCA_CORE); 9002 9003 if (ret != FC_SUCCESS) { 9004 fcio->fcio_errno = ret; 9005 rval = EIO; 9006 if (fp_fcio_copyout(fcio, data, mode)) { 9007 rval = EFAULT; 9008 } 9009 } 9010 break; 9011 9012 case FCIO_GET_DUMP: { 9013 caddr_t dump; 9014 uint32_t dump_size; 9015 fc_fca_pm_t pm; 9016 9017 if (fcio->fcio_xfer != FCIO_XFER_READ) { 9018 rval = EINVAL; 9019 break; 9020 } 9021 bzero((caddr_t)&pm, sizeof (pm)); 9022 9023 pm.pm_cmd_flags = FC_FCA_PM_READ; 9024 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 9025 pm.pm_data_len = sizeof (dump_size); 9026 pm.pm_data_buf = (caddr_t)&dump_size; 9027 9028 ret = port->fp_fca_tran->fca_port_manage( 9029 port->fp_fca_handle, &pm); 9030 9031 if (ret != FC_SUCCESS) { 9032 fcio->fcio_errno = ret; 9033 rval = EIO; 9034 if (fp_fcio_copyout(fcio, data, mode)) { 9035 rval = EFAULT; 9036 } 9037 break; 9038 } 9039 if (fcio->fcio_olen != dump_size) { 9040 fcio->fcio_errno = FC_NOMEM; 9041 rval = EINVAL; 9042 if (fp_fcio_copyout(fcio, data, mode)) { 9043 rval = EFAULT; 9044 } 9045 break; 9046 } 9047 9048 dump = kmem_zalloc(dump_size, KM_SLEEP); 9049 9050 bzero((caddr_t)&pm, sizeof (pm)); 9051 pm.pm_cmd_flags = FC_FCA_PM_READ; 9052 pm.pm_cmd_code = FC_PORT_GET_DUMP; 9053 pm.pm_data_len = dump_size; 9054 pm.pm_data_buf = dump; 9055 9056 ret = port->fp_fca_tran->fca_port_manage( 9057 port->fp_fca_handle, &pm); 9058 9059 if (ret == FC_SUCCESS) { 9060 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf, 9061 dump_size, mode) == 0) { 9062 if (fp_fcio_copyout(fcio, data, mode)) { 9063 rval = EFAULT; 9064 } 9065 } else { 9066 rval = EFAULT; 9067 } 9068 } else { 9069 fcio->fcio_errno = ret; 9070 rval = EIO; 9071 if (fp_fcio_copyout(fcio, data, mode)) { 9072 rval = EFAULT; 9073 } 9074 } 9075 kmem_free(dump, dump_size); 9076 break; 9077 } 9078 9079 case FCIO_GET_TOPOLOGY: { 9080 uint32_t user_topology; 9081 9082 if (fcio->fcio_xfer != FCIO_XFER_READ || 9083 fcio->fcio_olen != sizeof (user_topology)) { 9084 rval = EINVAL; 9085 break; 9086 } 9087 9088 mutex_enter(&port->fp_mutex); 9089 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 9090 user_topology = FC_TOP_UNKNOWN; 9091 } else { 9092 user_topology = port->fp_topology; 9093 } 9094 mutex_exit(&port->fp_mutex); 9095 9096 if (ddi_copyout((void *)&user_topology, 9097 (void *)fcio->fcio_obuf, sizeof (user_topology), 9098 mode)) { 9099 rval = EFAULT; 9100 } 9101 break; 9102 } 9103 9104 case FCIO_RESET_LINK: { 9105 la_wwn_t pwwn; 9106 9107 /* 9108 * Look at the output buffer field; if this field has zero 9109 * bytes then attempt to reset the local link/loop. If the 9110 * fcio_ibuf field points to a WWN, see if it's an NL_Port, 9111 * and if yes, determine the LFA and reset the remote LIP 9112 * by LINIT ELS. 9113 */ 9114 9115 if (fcio->fcio_xfer != FCIO_XFER_WRITE || 9116 fcio->fcio_ilen != sizeof (pwwn)) { 9117 rval = EINVAL; 9118 break; 9119 } 9120 9121 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9122 sizeof (pwwn), mode)) { 9123 rval = EFAULT; 9124 break; 9125 } 9126 9127 mutex_enter(&port->fp_mutex); 9128 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 9129 mutex_exit(&port->fp_mutex); 9130 break; 9131 } 9132 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 9133 mutex_exit(&port->fp_mutex); 9134 9135 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP); 9136 if (job == NULL) { 9137 rval = ENOMEM; 9138 break; 9139 } 9140 job->job_counter = 1; 9141 job->job_private = (void *)&pwwn; 9142 9143 fctl_enque_job(port, job); 9144 fctl_jobwait(job); 9145 9146 mutex_enter(&port->fp_mutex); 9147 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 9148 mutex_exit(&port->fp_mutex); 9149 9150 if (job->job_result != FC_SUCCESS) { 9151 fcio->fcio_errno = job->job_result; 9152 rval = EIO; 9153 if (fp_fcio_copyout(fcio, data, mode)) { 9154 rval = EFAULT; 9155 } 9156 } 9157 fctl_dealloc_job(job); 9158 break; 9159 } 9160 9161 case FCIO_RESET_HARD: 9162 ret = port->fp_fca_tran->fca_reset( 9163 port->fp_fca_handle, FC_FCA_RESET); 9164 if (ret != FC_SUCCESS) { 9165 fcio->fcio_errno = ret; 9166 rval = EIO; 9167 if (fp_fcio_copyout(fcio, data, mode)) { 9168 rval = EFAULT; 9169 } 9170 } 9171 break; 9172 9173 case FCIO_RESET_HARD_CORE: 9174 ret = port->fp_fca_tran->fca_reset( 9175 port->fp_fca_handle, FC_FCA_RESET_CORE); 9176 if (ret != FC_SUCCESS) { 9177 rval = EIO; 9178 fcio->fcio_errno = ret; 9179 if (fp_fcio_copyout(fcio, data, mode)) { 9180 rval = EFAULT; 9181 } 9182 } 9183 break; 9184 9185 case FCIO_DIAG: { 9186 fc_fca_pm_t pm; 9187 9188 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); 9189 9190 /* Validate user buffer from ioctl call. */ 9191 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) || 9192 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) || 9193 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) || 9194 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) || 9195 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) || 9196 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) { 9197 rval = EFAULT; 9198 break; 9199 } 9200 9201 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) { 9202 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 9203 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf, 9204 fcio->fcio_ilen, mode)) { 9205 rval = EFAULT; 9206 goto fp_fcio_diag_cleanup; 9207 } 9208 } 9209 9210 if ((pm.pm_data_len = fcio->fcio_alen) > 0) { 9211 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP); 9212 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf, 9213 fcio->fcio_alen, mode)) { 9214 rval = EFAULT; 9215 goto fp_fcio_diag_cleanup; 9216 } 9217 } 9218 9219 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) { 9220 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 9221 } 9222 9223 pm.pm_cmd_code = FC_PORT_DIAG; 9224 pm.pm_cmd_flags = fcio->fcio_cmd_flags; 9225 9226 ret = port->fp_fca_tran->fca_port_manage( 9227 port->fp_fca_handle, &pm); 9228 9229 if (ret != FC_SUCCESS) { 9230 if (ret == FC_INVALID_REQUEST) { 9231 rval = ENOTTY; 9232 } else { 9233 rval = EIO; 9234 } 9235 9236 fcio->fcio_errno = ret; 9237 if (fp_fcio_copyout(fcio, data, mode)) { 9238 rval = EFAULT; 9239 } 9240 goto fp_fcio_diag_cleanup; 9241 } 9242 9243 /* 9244 * pm_stat_len will contain the number of status bytes 9245 * an FCA driver requires to return the complete status 9246 * of the requested diag operation. If the user buffer 9247 * is not large enough to hold the entire status, We 9248 * copy only the portion of data the fits in the buffer and 9249 * return a ENOMEM to the user application. 9250 */ 9251 if (pm.pm_stat_len > fcio->fcio_olen) { 9252 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 9253 "fp:FCIO_DIAG:status buffer too small\n"); 9254 9255 rval = ENOMEM; 9256 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9257 fcio->fcio_olen, mode)) { 9258 rval = EFAULT; 9259 goto fp_fcio_diag_cleanup; 9260 } 9261 } else { 9262 /* 9263 * Copy only data pm_stat_len bytes of data 9264 */ 9265 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9266 pm.pm_stat_len, mode)) { 9267 rval = EFAULT; 9268 goto fp_fcio_diag_cleanup; 9269 } 9270 } 9271 9272 if (fp_fcio_copyout(fcio, data, mode)) { 9273 rval = EFAULT; 9274 } 9275 9276 fp_fcio_diag_cleanup: 9277 if (pm.pm_cmd_buf != NULL) { 9278 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen); 9279 } 9280 if (pm.pm_data_buf != NULL) { 9281 kmem_free(pm.pm_data_buf, fcio->fcio_alen); 9282 } 9283 if (pm.pm_stat_buf != NULL) { 9284 kmem_free(pm.pm_stat_buf, fcio->fcio_olen); 9285 } 9286 9287 break; 9288 } 9289 9290 case FCIO_GET_NODE_ID: { 9291 /* validate parameters */ 9292 if (fcio->fcio_xfer != FCIO_XFER_READ || 9293 fcio->fcio_olen < sizeof (fc_rnid_t)) { 9294 rval = EINVAL; 9295 break; 9296 } 9297 9298 rval = fp_get_rnid(port, data, mode, fcio); 9299 9300 /* ioctl handling is over */ 9301 break; 9302 } 9303 9304 case FCIO_SEND_NODE_ID: { 9305 la_wwn_t pwwn; 9306 9307 /* validate parameters */ 9308 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 9309 fcio->fcio_xfer != FCIO_XFER_READ) { 9310 rval = EINVAL; 9311 break; 9312 } 9313 9314 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9315 sizeof (la_wwn_t), mode)) { 9316 rval = EFAULT; 9317 break; 9318 } 9319 9320 rval = fp_send_rnid(port, data, mode, fcio, &pwwn); 9321 9322 /* ioctl handling is over */ 9323 break; 9324 } 9325 9326 case FCIO_SET_NODE_ID: { 9327 if (fcio->fcio_ilen != sizeof (fc_rnid_t) || 9328 (fcio->fcio_xfer != FCIO_XFER_WRITE)) { 9329 rval = EINVAL; 9330 break; 9331 } 9332 9333 rval = fp_set_rnid(port, data, mode, fcio); 9334 break; 9335 } 9336 9337 case FCIO_LINK_STATUS: { 9338 fc_portid_t rls_req; 9339 fc_rls_acc_t *rls_acc; 9340 fc_fca_pm_t pm; 9341 uint32_t dest, src_id; 9342 fp_cmd_t *cmd; 9343 fc_remote_port_t *pd; 9344 uchar_t pd_flags; 9345 9346 /* validate parameters */ 9347 if (fcio->fcio_ilen != sizeof (fc_portid_t) || 9348 fcio->fcio_olen != sizeof (fc_rls_acc_t) || 9349 fcio->fcio_xfer != FCIO_XFER_RW) { 9350 rval = EINVAL; 9351 break; 9352 } 9353 9354 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && 9355 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { 9356 rval = EINVAL; 9357 break; 9358 } 9359 9360 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req, 9361 sizeof (fc_portid_t), mode)) { 9362 rval = EFAULT; 9363 break; 9364 } 9365 9366 9367 /* Determine the destination of the RLS frame */ 9368 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) { 9369 dest = FS_FABRIC_F_PORT; 9370 } else { 9371 dest = rls_req.port_id; 9372 } 9373 9374 mutex_enter(&port->fp_mutex); 9375 src_id = port->fp_port_id.port_id; 9376 mutex_exit(&port->fp_mutex); 9377 9378 /* If dest is zero OR same as FCA ID, then use port_manage() */ 9379 if (dest == 0 || dest == src_id) { 9380 9381 /* Allocate memory for link error status block */ 9382 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9383 ASSERT(rls_acc != NULL); 9384 9385 /* Prepare the port management structure */ 9386 bzero((caddr_t)&pm, sizeof (pm)); 9387 9388 pm.pm_cmd_flags = FC_FCA_PM_READ; 9389 pm.pm_cmd_code = FC_PORT_RLS; 9390 pm.pm_data_len = sizeof (*rls_acc); 9391 pm.pm_data_buf = (caddr_t)rls_acc; 9392 9393 /* Get the adapter's link error status block */ 9394 ret = port->fp_fca_tran->fca_port_manage( 9395 port->fp_fca_handle, &pm); 9396 9397 if (ret == FC_SUCCESS) { 9398 /* xfer link status block to userland */ 9399 if (ddi_copyout((void *)rls_acc, 9400 (void *)fcio->fcio_obuf, 9401 sizeof (*rls_acc), mode) == 0) { 9402 if (fp_fcio_copyout(fcio, data, 9403 mode)) { 9404 rval = EFAULT; 9405 } 9406 } else { 9407 rval = EFAULT; 9408 } 9409 } else { 9410 rval = EIO; 9411 fcio->fcio_errno = ret; 9412 if (fp_fcio_copyout(fcio, data, mode)) { 9413 rval = EFAULT; 9414 } 9415 } 9416 9417 kmem_free(rls_acc, sizeof (*rls_acc)); 9418 9419 /* ioctl handling is over */ 9420 break; 9421 } 9422 9423 /* 9424 * Send RLS to the destination port. 9425 * Having RLS frame destination is as FPORT is not yet 9426 * supported and will be implemented in future, if needed. 9427 * Following call to get "pd" will fail if dest is FPORT 9428 */ 9429 pd = fctl_hold_remote_port_by_did(port, dest); 9430 if (pd == NULL) { 9431 fcio->fcio_errno = FC_BADOBJECT; 9432 rval = ENXIO; 9433 if (fp_fcio_copyout(fcio, data, mode)) { 9434 rval = EFAULT; 9435 } 9436 break; 9437 } 9438 9439 mutex_enter(&pd->pd_mutex); 9440 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 9441 mutex_exit(&pd->pd_mutex); 9442 fctl_release_remote_port(pd); 9443 9444 fcio->fcio_errno = FC_LOGINREQ; 9445 rval = EINVAL; 9446 if (fp_fcio_copyout(fcio, data, mode)) { 9447 rval = EFAULT; 9448 } 9449 break; 9450 } 9451 ASSERT(pd->pd_login_count >= 1); 9452 mutex_exit(&pd->pd_mutex); 9453 9454 /* 9455 * Allocate job structure and set job_code as DUMMY, 9456 * because we will not go through the job thread. 9457 * Instead fp_sendcmd() is called directly here. 9458 */ 9459 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9460 NULL, NULL, KM_SLEEP); 9461 ASSERT(job != NULL); 9462 9463 job->job_counter = 1; 9464 9465 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t), 9466 sizeof (la_els_rls_acc_t), KM_SLEEP, pd); 9467 if (cmd == NULL) { 9468 fcio->fcio_errno = FC_NOMEM; 9469 rval = ENOMEM; 9470 9471 fctl_release_remote_port(pd); 9472 9473 fctl_dealloc_job(job); 9474 if (fp_fcio_copyout(fcio, data, mode)) { 9475 rval = EFAULT; 9476 } 9477 break; 9478 } 9479 9480 /* Allocate memory for link error status block */ 9481 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9482 9483 mutex_enter(&port->fp_mutex); 9484 mutex_enter(&pd->pd_mutex); 9485 9486 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9487 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9488 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9489 cmd->cmd_retry_count = 1; 9490 cmd->cmd_ulp_pkt = NULL; 9491 9492 fp_rls_init(cmd, job); 9493 9494 job->job_private = (void *)rls_acc; 9495 9496 pd_flags = pd->pd_flags; 9497 pd->pd_flags = PD_ELS_IN_PROGRESS; 9498 9499 mutex_exit(&pd->pd_mutex); 9500 mutex_exit(&port->fp_mutex); 9501 9502 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9503 fctl_jobwait(job); 9504 9505 fcio->fcio_errno = job->job_result; 9506 if (job->job_result == FC_SUCCESS) { 9507 ASSERT(pd != NULL); 9508 /* 9509 * link error status block is now available. 9510 * Copy it to userland 9511 */ 9512 ASSERT(job->job_private == (void *)rls_acc); 9513 if (ddi_copyout((void *)rls_acc, 9514 (void *)fcio->fcio_obuf, 9515 sizeof (*rls_acc), mode) == 0) { 9516 if (fp_fcio_copyout(fcio, data, 9517 mode)) { 9518 rval = EFAULT; 9519 } 9520 } else { 9521 rval = EFAULT; 9522 } 9523 } else { 9524 rval = EIO; 9525 } 9526 } else { 9527 rval = EIO; 9528 fp_free_pkt(cmd); 9529 } 9530 9531 if (rval) { 9532 mutex_enter(&port->fp_mutex); 9533 mutex_enter(&pd->pd_mutex); 9534 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 9535 pd->pd_flags = pd_flags; 9536 } 9537 mutex_exit(&pd->pd_mutex); 9538 mutex_exit(&port->fp_mutex); 9539 } 9540 9541 fctl_release_remote_port(pd); 9542 fctl_dealloc_job(job); 9543 kmem_free(rls_acc, sizeof (*rls_acc)); 9544 9545 if (fp_fcio_copyout(fcio, data, mode)) { 9546 rval = EFAULT; 9547 } 9548 break; 9549 } 9550 9551 case FCIO_NS: { 9552 fc_ns_cmd_t *ns_req; 9553 fc_ns_cmd32_t *ns_req32; 9554 fctl_ns_req_t *ns_cmd; 9555 9556 if (use32 == B_TRUE) { 9557 if (fcio->fcio_ilen != sizeof (*ns_req32)) { 9558 rval = EINVAL; 9559 break; 9560 } 9561 9562 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9563 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP); 9564 9565 if (ddi_copyin(fcio->fcio_ibuf, ns_req32, 9566 sizeof (*ns_req32), mode)) { 9567 rval = EFAULT; 9568 kmem_free(ns_req, sizeof (*ns_req)); 9569 kmem_free(ns_req32, sizeof (*ns_req32)); 9570 break; 9571 } 9572 9573 ns_req->ns_flags = ns_req32->ns_flags; 9574 ns_req->ns_cmd = ns_req32->ns_cmd; 9575 ns_req->ns_req_len = ns_req32->ns_req_len; 9576 ns_req->ns_req_payload = ns_req32->ns_req_payload; 9577 ns_req->ns_resp_len = ns_req32->ns_resp_len; 9578 ns_req->ns_resp_payload = ns_req32->ns_resp_payload; 9579 ns_req->ns_fctl_private = ns_req32->ns_fctl_private; 9580 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr; 9581 9582 kmem_free(ns_req32, sizeof (*ns_req32)); 9583 } else { 9584 if (fcio->fcio_ilen != sizeof (*ns_req)) { 9585 rval = EINVAL; 9586 break; 9587 } 9588 9589 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9590 9591 if (ddi_copyin(fcio->fcio_ibuf, ns_req, 9592 sizeof (fc_ns_cmd_t), mode)) { 9593 rval = EFAULT; 9594 kmem_free(ns_req, sizeof (*ns_req)); 9595 break; 9596 } 9597 } 9598 9599 if (ns_req->ns_req_len <= 0) { 9600 rval = EINVAL; 9601 kmem_free(ns_req, sizeof (*ns_req)); 9602 break; 9603 } 9604 9605 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 9606 ASSERT(job != NULL); 9607 9608 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 9609 ns_req->ns_resp_len, ns_req->ns_resp_len, 9610 FCTL_NS_FILL_NS_MAP, KM_SLEEP); 9611 ASSERT(ns_cmd != NULL); 9612 ns_cmd->ns_cmd_code = ns_req->ns_cmd; 9613 9614 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 9615 ns_cmd->ns_gan_max = 1; 9616 ns_cmd->ns_gan_index = 0; 9617 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 9618 } 9619 9620 if (ddi_copyin(ns_req->ns_req_payload, 9621 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) { 9622 rval = EFAULT; 9623 fctl_free_ns_cmd(ns_cmd); 9624 fctl_dealloc_job(job); 9625 kmem_free(ns_req, sizeof (*ns_req)); 9626 break; 9627 } 9628 9629 job->job_private = (void *)ns_cmd; 9630 fctl_enque_job(port, job); 9631 fctl_jobwait(job); 9632 rval = job->job_result; 9633 9634 if (rval == FC_SUCCESS) { 9635 if (ns_req->ns_resp_len) { 9636 if (ddi_copyout(ns_cmd->ns_data_buf, 9637 ns_req->ns_resp_payload, 9638 ns_cmd->ns_data_len, mode)) { 9639 rval = EFAULT; 9640 fctl_free_ns_cmd(ns_cmd); 9641 fctl_dealloc_job(job); 9642 kmem_free(ns_req, sizeof (*ns_req)); 9643 break; 9644 } 9645 } 9646 } else { 9647 rval = EIO; 9648 } 9649 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr; 9650 fctl_free_ns_cmd(ns_cmd); 9651 fctl_dealloc_job(job); 9652 kmem_free(ns_req, sizeof (*ns_req)); 9653 9654 if (fp_fcio_copyout(fcio, data, mode)) { 9655 rval = EFAULT; 9656 } 9657 break; 9658 } 9659 9660 default: 9661 rval = ENOTTY; 9662 break; 9663 } 9664 9665 /* 9666 * If set, reset the EXCL busy bit to 9667 * receive other exclusive access commands 9668 */ 9669 mutex_enter(&port->fp_mutex); 9670 if (port->fp_flag & FP_EXCL_BUSY) { 9671 port->fp_flag &= ~FP_EXCL_BUSY; 9672 } 9673 mutex_exit(&port->fp_mutex); 9674 9675 return (rval); 9676 } 9677 9678 9679 /* 9680 * This function assumes that the response length 9681 * is same regardless of data model (LP32 or LP64) 9682 * which is true for all the ioctls currently 9683 * supported. 9684 */ 9685 static int 9686 fp_copyout(void *from, void *to, size_t len, int mode) 9687 { 9688 return (ddi_copyout(from, to, len, mode)); 9689 } 9690 9691 /* 9692 * This function does the set rnid 9693 */ 9694 static int 9695 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9696 { 9697 int rval = 0; 9698 fc_rnid_t *rnid; 9699 fc_fca_pm_t pm; 9700 9701 /* Allocate memory for node id block */ 9702 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9703 9704 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) { 9705 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT); 9706 kmem_free(rnid, sizeof (fc_rnid_t)); 9707 return (EFAULT); 9708 } 9709 9710 /* Prepare the port management structure */ 9711 bzero((caddr_t)&pm, sizeof (pm)); 9712 9713 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 9714 pm.pm_cmd_code = FC_PORT_SET_NODE_ID; 9715 pm.pm_data_len = sizeof (*rnid); 9716 pm.pm_data_buf = (caddr_t)rnid; 9717 9718 /* Get the adapter's node data */ 9719 rval = port->fp_fca_tran->fca_port_manage( 9720 port->fp_fca_handle, &pm); 9721 9722 if (rval != FC_SUCCESS) { 9723 fcio->fcio_errno = rval; 9724 rval = EIO; 9725 if (fp_fcio_copyout(fcio, data, mode)) { 9726 rval = EFAULT; 9727 } 9728 } else { 9729 mutex_enter(&port->fp_mutex); 9730 /* copy to the port structure */ 9731 bcopy(rnid, &port->fp_rnid_params, 9732 sizeof (port->fp_rnid_params)); 9733 mutex_exit(&port->fp_mutex); 9734 } 9735 9736 kmem_free(rnid, sizeof (fc_rnid_t)); 9737 9738 if (rval != FC_SUCCESS) { 9739 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval); 9740 } 9741 9742 return (rval); 9743 } 9744 9745 /* 9746 * This function does the local pwwn get rnid 9747 */ 9748 static int 9749 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9750 { 9751 fc_rnid_t *rnid; 9752 fc_fca_pm_t pm; 9753 int rval = 0; 9754 uint32_t ret; 9755 9756 /* Allocate memory for rnid data block */ 9757 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9758 9759 mutex_enter(&port->fp_mutex); 9760 if (port->fp_rnid_init == 1) { 9761 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t)); 9762 mutex_exit(&port->fp_mutex); 9763 /* xfer node info to userland */ 9764 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf, 9765 sizeof (*rnid), mode) == 0) { 9766 if (fp_fcio_copyout(fcio, data, mode)) { 9767 rval = EFAULT; 9768 } 9769 } else { 9770 rval = EFAULT; 9771 } 9772 9773 kmem_free(rnid, sizeof (fc_rnid_t)); 9774 9775 if (rval != FC_SUCCESS) { 9776 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", 9777 rval); 9778 } 9779 9780 return (rval); 9781 } 9782 mutex_exit(&port->fp_mutex); 9783 9784 /* Prepare the port management structure */ 9785 bzero((caddr_t)&pm, sizeof (pm)); 9786 9787 pm.pm_cmd_flags = FC_FCA_PM_READ; 9788 pm.pm_cmd_code = FC_PORT_GET_NODE_ID; 9789 pm.pm_data_len = sizeof (fc_rnid_t); 9790 pm.pm_data_buf = (caddr_t)rnid; 9791 9792 /* Get the adapter's node data */ 9793 ret = port->fp_fca_tran->fca_port_manage( 9794 port->fp_fca_handle, 9795 &pm); 9796 9797 if (ret == FC_SUCCESS) { 9798 /* initialize in the port_info */ 9799 mutex_enter(&port->fp_mutex); 9800 port->fp_rnid_init = 1; 9801 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid)); 9802 mutex_exit(&port->fp_mutex); 9803 9804 /* xfer node info to userland */ 9805 if (ddi_copyout((void *)rnid, 9806 (void *)fcio->fcio_obuf, 9807 sizeof (*rnid), mode) == 0) { 9808 if (fp_fcio_copyout(fcio, data, 9809 mode)) { 9810 rval = EFAULT; 9811 } 9812 } else { 9813 rval = EFAULT; 9814 } 9815 } else { 9816 rval = EIO; 9817 fcio->fcio_errno = ret; 9818 if (fp_fcio_copyout(fcio, data, mode)) { 9819 rval = EFAULT; 9820 } 9821 } 9822 9823 kmem_free(rnid, sizeof (fc_rnid_t)); 9824 9825 if (rval != FC_SUCCESS) { 9826 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval); 9827 } 9828 9829 return (rval); 9830 } 9831 9832 static int 9833 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio, 9834 la_wwn_t *pwwn) 9835 { 9836 int rval = 0; 9837 fc_remote_port_t *pd; 9838 fp_cmd_t *cmd; 9839 job_request_t *job; 9840 la_els_rnid_acc_t *rnid_acc; 9841 9842 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 9843 if (pd == NULL) { 9844 /* 9845 * We can safely assume that the destination port 9846 * is logged in. Either the user land will explicitly 9847 * login before issuing RNID ioctl or the device would 9848 * have been configured, meaning already logged in. 9849 */ 9850 9851 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO); 9852 9853 return (ENXIO); 9854 } 9855 /* 9856 * Allocate job structure and set job_code as DUMMY, 9857 * because we will not go thorugh the job thread. 9858 * Instead fp_sendcmd() is called directly here. 9859 */ 9860 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9861 NULL, NULL, KM_SLEEP); 9862 9863 ASSERT(job != NULL); 9864 9865 job->job_counter = 1; 9866 9867 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t), 9868 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd); 9869 if (cmd == NULL) { 9870 fcio->fcio_errno = FC_NOMEM; 9871 rval = ENOMEM; 9872 9873 fctl_dealloc_job(job); 9874 if (fp_fcio_copyout(fcio, data, mode)) { 9875 rval = EFAULT; 9876 } 9877 9878 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9879 9880 return (rval); 9881 } 9882 9883 /* Allocate memory for node id accept block */ 9884 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP); 9885 9886 mutex_enter(&port->fp_mutex); 9887 mutex_enter(&pd->pd_mutex); 9888 9889 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9890 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9891 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9892 cmd->cmd_retry_count = 1; 9893 cmd->cmd_ulp_pkt = NULL; 9894 9895 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job); 9896 9897 job->job_private = (void *)rnid_acc; 9898 9899 pd->pd_flags = PD_ELS_IN_PROGRESS; 9900 9901 mutex_exit(&pd->pd_mutex); 9902 mutex_exit(&port->fp_mutex); 9903 9904 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9905 fctl_jobwait(job); 9906 fcio->fcio_errno = job->job_result; 9907 if (job->job_result == FC_SUCCESS) { 9908 int rnid_cnt; 9909 ASSERT(pd != NULL); 9910 /* 9911 * node id block is now available. 9912 * Copy it to userland 9913 */ 9914 ASSERT(job->job_private == (void *)rnid_acc); 9915 9916 /* get the response length */ 9917 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) + 9918 rnid_acc->hdr.cmn_len + 9919 rnid_acc->hdr.specific_len; 9920 9921 if (fcio->fcio_olen < rnid_cnt) { 9922 rval = EINVAL; 9923 } else if (ddi_copyout((void *)rnid_acc, 9924 (void *)fcio->fcio_obuf, 9925 rnid_cnt, mode) == 0) { 9926 if (fp_fcio_copyout(fcio, data, 9927 mode)) { 9928 rval = EFAULT; 9929 } 9930 } else { 9931 rval = EFAULT; 9932 } 9933 } else { 9934 rval = EIO; 9935 } 9936 } else { 9937 rval = EIO; 9938 if (pd) { 9939 mutex_enter(&pd->pd_mutex); 9940 pd->pd_flags = PD_IDLE; 9941 mutex_exit(&pd->pd_mutex); 9942 } 9943 fp_free_pkt(cmd); 9944 } 9945 9946 fctl_dealloc_job(job); 9947 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t)); 9948 9949 if (fp_fcio_copyout(fcio, data, mode)) { 9950 rval = EFAULT; 9951 } 9952 9953 if (rval != FC_SUCCESS) { 9954 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9955 } 9956 9957 return (rval); 9958 } 9959 9960 /* 9961 * Copy out to userland 9962 */ 9963 static int 9964 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode) 9965 { 9966 int rval; 9967 9968 #ifdef _MULTI_DATAMODEL 9969 switch (ddi_model_convert_from(mode & FMODELS)) { 9970 case DDI_MODEL_ILP32: { 9971 struct fcio32 fcio32; 9972 9973 fcio32.fcio_xfer = fcio->fcio_xfer; 9974 fcio32.fcio_cmd = fcio->fcio_cmd; 9975 fcio32.fcio_flags = fcio->fcio_flags; 9976 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags; 9977 fcio32.fcio_ilen = fcio->fcio_ilen; 9978 fcio32.fcio_ibuf = 9979 (caddr32_t)(uintptr_t)fcio->fcio_ibuf; 9980 fcio32.fcio_olen = fcio->fcio_olen; 9981 fcio32.fcio_obuf = 9982 (caddr32_t)(uintptr_t)fcio->fcio_obuf; 9983 fcio32.fcio_alen = fcio->fcio_alen; 9984 fcio32.fcio_abuf = 9985 (caddr32_t)(uintptr_t)fcio->fcio_abuf; 9986 fcio32.fcio_errno = fcio->fcio_errno; 9987 9988 rval = ddi_copyout((void *)&fcio32, (void *)data, 9989 sizeof (struct fcio32), mode); 9990 break; 9991 } 9992 case DDI_MODEL_NONE: 9993 rval = ddi_copyout((void *)fcio, (void *)data, 9994 sizeof (fcio_t), mode); 9995 break; 9996 } 9997 #else 9998 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode); 9999 #endif 10000 10001 return (rval); 10002 } 10003 10004 10005 static void 10006 fp_p2p_online(fc_local_port_t *port, job_request_t *job) 10007 { 10008 uint32_t listlen; 10009 fc_portmap_t *changelist; 10010 10011 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10012 ASSERT(port->fp_topology == FC_TOP_PT_PT); 10013 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 10014 10015 listlen = 0; 10016 changelist = NULL; 10017 10018 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10019 if (port->fp_statec_busy > 1) { 10020 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10021 } 10022 } 10023 mutex_exit(&port->fp_mutex); 10024 10025 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10026 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10027 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10028 listlen, listlen, KM_SLEEP); 10029 10030 mutex_enter(&port->fp_mutex); 10031 } else { 10032 ASSERT(changelist == NULL && listlen == 0); 10033 mutex_enter(&port->fp_mutex); 10034 if (--port->fp_statec_busy == 0) { 10035 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10036 } 10037 } 10038 } 10039 10040 static int 10041 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10042 { 10043 int rval; 10044 int count; 10045 int index; 10046 int num_devices; 10047 fc_remote_node_t *node; 10048 fc_port_dev_t *devlist; 10049 struct pwwn_hash *head; 10050 fc_remote_port_t *pd; 10051 10052 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10053 10054 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10055 10056 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP); 10057 10058 for (count = index = 0; index < pwwn_table_size; index++) { 10059 head = &port->fp_pwwn_table[index]; 10060 pd = head->pwwn_head; 10061 while (pd != NULL) { 10062 mutex_enter(&pd->pd_mutex); 10063 if (pd->pd_state == PORT_DEVICE_INVALID) { 10064 mutex_exit(&pd->pd_mutex); 10065 pd = pd->pd_wwn_hnext; 10066 continue; 10067 } 10068 10069 devlist[count].dev_state = pd->pd_state; 10070 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10071 devlist[count].dev_did = pd->pd_port_id; 10072 devlist[count].dev_did.priv_lilp_posit = 10073 (uint8_t)(index & 0xff); 10074 bcopy((caddr_t)pd->pd_fc4types, 10075 (caddr_t)devlist[count].dev_type, 10076 sizeof (pd->pd_fc4types)); 10077 10078 bcopy((caddr_t)&pd->pd_port_name, 10079 (caddr_t)&devlist[count].dev_pwwn, 10080 sizeof (la_wwn_t)); 10081 10082 node = pd->pd_remote_nodep; 10083 mutex_exit(&pd->pd_mutex); 10084 10085 if (node) { 10086 mutex_enter(&node->fd_mutex); 10087 bcopy((caddr_t)&node->fd_node_name, 10088 (caddr_t)&devlist[count].dev_nwwn, 10089 sizeof (la_wwn_t)); 10090 mutex_exit(&node->fd_mutex); 10091 } 10092 count++; 10093 if (count >= num_devices) { 10094 goto found; 10095 } 10096 } 10097 } 10098 found: 10099 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10100 sizeof (count), mode)) { 10101 rval = FC_FAILURE; 10102 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10103 sizeof (fc_port_dev_t) * num_devices, mode)) { 10104 rval = FC_FAILURE; 10105 } else { 10106 rval = FC_SUCCESS; 10107 } 10108 10109 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices); 10110 10111 return (rval); 10112 } 10113 10114 10115 /* 10116 * Handle Fabric ONLINE 10117 */ 10118 static void 10119 fp_fabric_online(fc_local_port_t *port, job_request_t *job) 10120 { 10121 int index; 10122 int rval; 10123 int dbg_count; 10124 int count = 0; 10125 char ww_name[17]; 10126 uint32_t d_id; 10127 uint32_t listlen; 10128 fctl_ns_req_t *ns_cmd; 10129 struct pwwn_hash *head; 10130 fc_remote_port_t *pd; 10131 fc_remote_port_t *npd; 10132 fc_portmap_t *changelist; 10133 10134 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10135 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 10136 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 10137 10138 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 10139 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 10140 0, KM_SLEEP); 10141 10142 ASSERT(ns_cmd != NULL); 10143 10144 ns_cmd->ns_cmd_code = NS_GID_PN; 10145 10146 /* 10147 * Check if orphans are showing up now 10148 */ 10149 if (port->fp_orphan_count) { 10150 fc_orphan_t *orp; 10151 fc_orphan_t *norp = NULL; 10152 fc_orphan_t *prev = NULL; 10153 10154 for (orp = port->fp_orphan_list; orp; orp = norp) { 10155 norp = orp->orp_next; 10156 mutex_exit(&port->fp_mutex); 10157 orp->orp_nscan++; 10158 10159 job->job_counter = 1; 10160 job->job_result = FC_SUCCESS; 10161 10162 ((ns_req_gid_pn_t *) 10163 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn; 10164 ((ns_resp_gid_pn_t *) 10165 ns_cmd->ns_data_buf)->pid.port_id = 0; 10166 ((ns_resp_gid_pn_t *) 10167 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 10168 10169 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10170 if (rval == FC_SUCCESS) { 10171 d_id = 10172 BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10173 pd = fp_create_remote_port_by_ns(port, 10174 d_id, KM_SLEEP); 10175 10176 if (pd != NULL) { 10177 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10178 10179 fp_printf(port, CE_WARN, FP_LOG_ONLY, 10180 0, NULL, "N_x Port with D_ID=%x," 10181 " PWWN=%s reappeared in fabric", 10182 d_id, ww_name); 10183 10184 mutex_enter(&port->fp_mutex); 10185 if (prev) { 10186 prev->orp_next = orp->orp_next; 10187 } else { 10188 ASSERT(orp == 10189 port->fp_orphan_list); 10190 port->fp_orphan_list = 10191 orp->orp_next; 10192 } 10193 port->fp_orphan_count--; 10194 mutex_exit(&port->fp_mutex); 10195 kmem_free(orp, sizeof (*orp)); 10196 count++; 10197 10198 mutex_enter(&pd->pd_mutex); 10199 pd->pd_flags = PD_ELS_MARK; 10200 10201 mutex_exit(&pd->pd_mutex); 10202 } else { 10203 prev = orp; 10204 } 10205 } else { 10206 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) { 10207 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10208 10209 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, 10210 NULL, 10211 " Port WWN %s removed from orphan" 10212 " list after %d scans", ww_name, 10213 orp->orp_nscan); 10214 10215 mutex_enter(&port->fp_mutex); 10216 if (prev) { 10217 prev->orp_next = orp->orp_next; 10218 } else { 10219 ASSERT(orp == 10220 port->fp_orphan_list); 10221 port->fp_orphan_list = 10222 orp->orp_next; 10223 } 10224 port->fp_orphan_count--; 10225 mutex_exit(&port->fp_mutex); 10226 10227 kmem_free(orp, sizeof (*orp)); 10228 } else { 10229 prev = orp; 10230 } 10231 } 10232 mutex_enter(&port->fp_mutex); 10233 } 10234 } 10235 10236 /* 10237 * Walk the Port WWN hash table, reestablish LOGIN 10238 * if a LOGIN is already performed on a particular 10239 * device; Any failure to LOGIN should mark the 10240 * port device OLD. 10241 */ 10242 for (index = 0; index < pwwn_table_size; index++) { 10243 head = &port->fp_pwwn_table[index]; 10244 npd = head->pwwn_head; 10245 10246 while ((pd = npd) != NULL) { 10247 la_wwn_t *pwwn; 10248 10249 npd = pd->pd_wwn_hnext; 10250 10251 /* 10252 * Don't count in the port devices that are new 10253 * unless the total number of devices visible 10254 * through this port is less than FP_MAX_DEVICES 10255 */ 10256 mutex_enter(&pd->pd_mutex); 10257 if (port->fp_dev_count >= FP_MAX_DEVICES || 10258 (port->fp_options & FP_TARGET_MODE)) { 10259 if (pd->pd_type == PORT_DEVICE_NEW || 10260 pd->pd_flags == PD_ELS_MARK || 10261 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10262 mutex_exit(&pd->pd_mutex); 10263 continue; 10264 } 10265 } else { 10266 if (pd->pd_flags == PD_ELS_MARK || 10267 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10268 mutex_exit(&pd->pd_mutex); 10269 continue; 10270 } 10271 pd->pd_type = PORT_DEVICE_OLD; 10272 } 10273 count++; 10274 10275 /* 10276 * Consult with the name server about D_ID changes 10277 */ 10278 job->job_counter = 1; 10279 job->job_result = FC_SUCCESS; 10280 10281 ((ns_req_gid_pn_t *) 10282 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name; 10283 ((ns_resp_gid_pn_t *) 10284 ns_cmd->ns_data_buf)->pid.port_id = 0; 10285 10286 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)-> 10287 pid.priv_lilp_posit = 0; 10288 10289 pwwn = &pd->pd_port_name; 10290 pd->pd_flags = PD_ELS_MARK; 10291 10292 mutex_exit(&pd->pd_mutex); 10293 mutex_exit(&port->fp_mutex); 10294 10295 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10296 if (rval != FC_SUCCESS) { 10297 fc_wwn_to_str(pwwn, ww_name); 10298 10299 mutex_enter(&pd->pd_mutex); 10300 d_id = pd->pd_port_id.port_id; 10301 pd->pd_type = PORT_DEVICE_DELETE; 10302 mutex_exit(&pd->pd_mutex); 10303 10304 FP_TRACE(FP_NHEAD1(3, 0), 10305 "fp_fabric_online: PD " 10306 "disappeared; d_id=%x, PWWN=%s", 10307 d_id, ww_name); 10308 10309 FP_TRACE(FP_NHEAD2(9, 0), 10310 "N_x Port with D_ID=%x, PWWN=%s" 10311 " disappeared from fabric", d_id, 10312 ww_name); 10313 10314 mutex_enter(&port->fp_mutex); 10315 continue; 10316 } 10317 10318 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10319 10320 mutex_enter(&port->fp_mutex); 10321 mutex_enter(&pd->pd_mutex); 10322 if (d_id != pd->pd_port_id.port_id) { 10323 fctl_delist_did_table(port, pd); 10324 fc_wwn_to_str(pwwn, ww_name); 10325 10326 FP_TRACE(FP_NHEAD2(9, 0), 10327 "D_ID of a device with PWWN %s changed." 10328 " New D_ID = %x, OLD D_ID = %x", ww_name, 10329 d_id, pd->pd_port_id.port_id); 10330 10331 pd->pd_port_id.port_id = BE_32(d_id); 10332 pd->pd_type = PORT_DEVICE_CHANGED; 10333 fctl_enlist_did_table(port, pd); 10334 } 10335 mutex_exit(&pd->pd_mutex); 10336 10337 } 10338 } 10339 10340 if (ns_cmd) { 10341 fctl_free_ns_cmd(ns_cmd); 10342 } 10343 10344 listlen = 0; 10345 changelist = NULL; 10346 if (count) { 10347 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 10348 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 10349 mutex_exit(&port->fp_mutex); 10350 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000)); 10351 mutex_enter(&port->fp_mutex); 10352 } 10353 10354 dbg_count = 0; 10355 10356 job->job_counter = count; 10357 10358 for (index = 0; index < pwwn_table_size; index++) { 10359 head = &port->fp_pwwn_table[index]; 10360 npd = head->pwwn_head; 10361 10362 while ((pd = npd) != NULL) { 10363 npd = pd->pd_wwn_hnext; 10364 10365 mutex_enter(&pd->pd_mutex); 10366 if (pd->pd_flags != PD_ELS_MARK) { 10367 mutex_exit(&pd->pd_mutex); 10368 continue; 10369 } 10370 10371 dbg_count++; 10372 10373 /* 10374 * If it is already marked deletion, nothing 10375 * else to do. 10376 */ 10377 if (pd->pd_type == PORT_DEVICE_DELETE) { 10378 pd->pd_type = PORT_DEVICE_OLD; 10379 10380 mutex_exit(&pd->pd_mutex); 10381 mutex_exit(&port->fp_mutex); 10382 fp_jobdone(job); 10383 mutex_enter(&port->fp_mutex); 10384 10385 continue; 10386 } 10387 10388 /* 10389 * If it is freshly discovered out of 10390 * the orphan list, nothing else to do 10391 */ 10392 if (pd->pd_type == PORT_DEVICE_NEW) { 10393 pd->pd_flags = PD_IDLE; 10394 10395 mutex_exit(&pd->pd_mutex); 10396 mutex_exit(&port->fp_mutex); 10397 fp_jobdone(job); 10398 mutex_enter(&port->fp_mutex); 10399 10400 continue; 10401 } 10402 10403 pd->pd_flags = PD_IDLE; 10404 d_id = pd->pd_port_id.port_id; 10405 10406 /* 10407 * Explicitly mark all devices OLD; successful 10408 * PLOGI should reset this to either NO_CHANGE 10409 * or CHANGED. 10410 */ 10411 if (pd->pd_type != PORT_DEVICE_CHANGED) { 10412 pd->pd_type = PORT_DEVICE_OLD; 10413 } 10414 10415 mutex_exit(&pd->pd_mutex); 10416 mutex_exit(&port->fp_mutex); 10417 10418 rval = fp_port_login(port, d_id, job, 10419 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 10420 10421 if (rval != FC_SUCCESS) { 10422 fp_jobdone(job); 10423 } 10424 mutex_enter(&port->fp_mutex); 10425 } 10426 } 10427 mutex_exit(&port->fp_mutex); 10428 10429 ASSERT(dbg_count == count); 10430 fp_jobwait(job); 10431 10432 mutex_enter(&port->fp_mutex); 10433 10434 ASSERT(port->fp_statec_busy > 0); 10435 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10436 if (port->fp_statec_busy > 1) { 10437 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10438 } 10439 } 10440 mutex_exit(&port->fp_mutex); 10441 } else { 10442 ASSERT(port->fp_statec_busy > 0); 10443 if (port->fp_statec_busy > 1) { 10444 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10445 } 10446 mutex_exit(&port->fp_mutex); 10447 } 10448 10449 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10450 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10451 10452 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10453 listlen, listlen, KM_SLEEP); 10454 10455 mutex_enter(&port->fp_mutex); 10456 } else { 10457 ASSERT(changelist == NULL && listlen == 0); 10458 mutex_enter(&port->fp_mutex); 10459 if (--port->fp_statec_busy == 0) { 10460 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10461 } 10462 } 10463 } 10464 10465 10466 /* 10467 * Fill out device list for userland ioctl in private loop 10468 */ 10469 static int 10470 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10471 { 10472 int rval; 10473 int count; 10474 int index; 10475 int num_devices; 10476 fc_remote_node_t *node; 10477 fc_port_dev_t *devlist; 10478 int lilp_device_count; 10479 fc_lilpmap_t *lilp_map; 10480 uchar_t *alpa_list; 10481 10482 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10483 10484 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10485 if (port->fp_total_devices > port->fp_dev_count && 10486 num_devices >= port->fp_total_devices) { 10487 job_request_t *job; 10488 10489 mutex_exit(&port->fp_mutex); 10490 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP); 10491 job->job_counter = 1; 10492 10493 mutex_enter(&port->fp_mutex); 10494 fp_get_loopmap(port, job); 10495 mutex_exit(&port->fp_mutex); 10496 10497 fp_jobwait(job); 10498 fctl_dealloc_job(job); 10499 } else { 10500 mutex_exit(&port->fp_mutex); 10501 } 10502 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP); 10503 10504 mutex_enter(&port->fp_mutex); 10505 10506 /* 10507 * Applications are accustomed to getting the device list in 10508 * LILP map order. The HBA firmware usually returns the device 10509 * map in the LILP map order and diagnostic applications would 10510 * prefer to receive in the device list in that order too 10511 */ 10512 lilp_map = &port->fp_lilp_map; 10513 alpa_list = &lilp_map->lilp_alpalist[0]; 10514 10515 /* 10516 * the length field corresponds to the offset in the LILP frame 10517 * which begins with 1. The thing to note here is that the 10518 * lilp_device_count is 1 more than fp->fp_total_devices since 10519 * the host adapter's alpa also shows up in the lilp map. We 10520 * don't however return details of the host adapter since 10521 * fctl_get_remote_port_by_did fails for the host adapter's ALPA 10522 * and applications are required to issue the FCIO_GET_HOST_PARAMS 10523 * ioctl to obtain details about the host adapter port. 10524 */ 10525 lilp_device_count = lilp_map->lilp_length; 10526 10527 for (count = index = 0; index < lilp_device_count && 10528 count < num_devices; index++) { 10529 uint32_t d_id; 10530 fc_remote_port_t *pd; 10531 10532 d_id = alpa_list[index]; 10533 10534 mutex_exit(&port->fp_mutex); 10535 pd = fctl_get_remote_port_by_did(port, d_id); 10536 mutex_enter(&port->fp_mutex); 10537 10538 if (pd != NULL) { 10539 mutex_enter(&pd->pd_mutex); 10540 10541 if (pd->pd_state == PORT_DEVICE_INVALID) { 10542 mutex_exit(&pd->pd_mutex); 10543 continue; 10544 } 10545 10546 devlist[count].dev_state = pd->pd_state; 10547 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10548 devlist[count].dev_did = pd->pd_port_id; 10549 devlist[count].dev_did.priv_lilp_posit = 10550 (uint8_t)(index & 0xff); 10551 bcopy((caddr_t)pd->pd_fc4types, 10552 (caddr_t)devlist[count].dev_type, 10553 sizeof (pd->pd_fc4types)); 10554 10555 bcopy((caddr_t)&pd->pd_port_name, 10556 (caddr_t)&devlist[count].dev_pwwn, 10557 sizeof (la_wwn_t)); 10558 10559 node = pd->pd_remote_nodep; 10560 mutex_exit(&pd->pd_mutex); 10561 10562 if (node) { 10563 mutex_enter(&node->fd_mutex); 10564 bcopy((caddr_t)&node->fd_node_name, 10565 (caddr_t)&devlist[count].dev_nwwn, 10566 sizeof (la_wwn_t)); 10567 mutex_exit(&node->fd_mutex); 10568 } 10569 count++; 10570 } 10571 } 10572 10573 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10574 sizeof (count), mode)) { 10575 rval = FC_FAILURE; 10576 } 10577 10578 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10579 sizeof (fc_port_dev_t) * num_devices, mode)) { 10580 rval = FC_FAILURE; 10581 } else { 10582 rval = FC_SUCCESS; 10583 } 10584 10585 kmem_free(devlist, sizeof (*devlist) * num_devices); 10586 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10587 10588 return (rval); 10589 } 10590 10591 10592 /* 10593 * Completion function for responses to unsolicited commands 10594 */ 10595 static void 10596 fp_unsol_intr(fc_packet_t *pkt) 10597 { 10598 fp_cmd_t *cmd; 10599 fc_local_port_t *port; 10600 10601 cmd = pkt->pkt_ulp_private; 10602 port = cmd->cmd_port; 10603 10604 mutex_enter(&port->fp_mutex); 10605 port->fp_out_fpcmds--; 10606 mutex_exit(&port->fp_mutex); 10607 10608 if (pkt->pkt_state != FC_PKT_SUCCESS) { 10609 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt, 10610 "couldn't post response to unsolicited request;" 10611 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id, 10612 pkt->pkt_resp_fhdr.rx_id); 10613 } 10614 10615 if (cmd == port->fp_els_resp_pkt) { 10616 mutex_enter(&port->fp_mutex); 10617 port->fp_els_resp_pkt_busy = 0; 10618 mutex_exit(&port->fp_mutex); 10619 return; 10620 } 10621 10622 fp_free_pkt(cmd); 10623 } 10624 10625 10626 /* 10627 * solicited LINIT ELS completion function 10628 */ 10629 static void 10630 fp_linit_intr(fc_packet_t *pkt) 10631 { 10632 fp_cmd_t *cmd; 10633 job_request_t *job; 10634 fc_linit_resp_t acc; 10635 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 10636 10637 cmd = (fp_cmd_t *)pkt->pkt_ulp_private; 10638 10639 mutex_enter(&cmd->cmd_port->fp_mutex); 10640 cmd->cmd_port->fp_out_fpcmds--; 10641 mutex_exit(&cmd->cmd_port->fp_mutex); 10642 10643 if (FP_IS_PKT_ERROR(pkt)) { 10644 (void) fp_common_intr(pkt, 1); 10645 return; 10646 } 10647 10648 job = cmd->cmd_job; 10649 10650 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc, 10651 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR); 10652 if (acc.status != FC_LINIT_SUCCESS) { 10653 job->job_result = FC_FAILURE; 10654 } else { 10655 job->job_result = FC_SUCCESS; 10656 } 10657 10658 fp_iodone(cmd); 10659 } 10660 10661 10662 /* 10663 * Decode the unsolicited request; For FC-4 Device and Link data frames 10664 * notify the registered ULP of this FC-4 type right here. For Unsolicited 10665 * ELS requests, submit a request to the job_handler thread to work on it. 10666 * The intent is to act quickly on the FC-4 unsolicited link and data frames 10667 * and save much of the interrupt time processing of unsolicited ELS requests 10668 * and hand it off to the job_handler thread. 10669 */ 10670 static void 10671 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type) 10672 { 10673 uchar_t r_ctl; 10674 uchar_t ls_code; 10675 uint32_t s_id; 10676 uint32_t rscn_count = FC_INVALID_RSCN_COUNT; 10677 uint32_t cb_arg; 10678 fp_cmd_t *cmd; 10679 fc_local_port_t *port; 10680 job_request_t *job; 10681 fc_remote_port_t *pd; 10682 10683 port = port_handle; 10684 10685 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x," 10686 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x" 10687 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x" 10688 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10689 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl, 10690 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt, 10691 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro, 10692 buf->ub_buffer[0]); 10693 10694 if (type & 0x80000000) { 10695 /* 10696 * Huh ? Nothing much can be done without 10697 * a valid buffer. So just exit. 10698 */ 10699 return; 10700 } 10701 /* 10702 * If the unsolicited interrupts arrive while it isn't 10703 * safe to handle unsolicited callbacks; Drop them, yes, 10704 * drop them on the floor 10705 */ 10706 mutex_enter(&port->fp_mutex); 10707 port->fp_active_ubs++; 10708 if ((port->fp_soft_state & 10709 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 10710 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 10711 10712 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is " 10713 "not ONLINE. s_id=%x, d_id=%x, type=%x, " 10714 "seq_id=%x, ox_id=%x, rx_id=%x" 10715 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10716 buf->ub_frame.type, buf->ub_frame.seq_id, 10717 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 10718 10719 ASSERT(port->fp_active_ubs > 0); 10720 if (--(port->fp_active_ubs) == 0) { 10721 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10722 } 10723 10724 mutex_exit(&port->fp_mutex); 10725 10726 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10727 1, &buf->ub_token); 10728 10729 return; 10730 } 10731 10732 r_ctl = buf->ub_frame.r_ctl; 10733 s_id = buf->ub_frame.s_id; 10734 if (port->fp_active_ubs == 1) { 10735 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB; 10736 } 10737 10738 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO && 10739 port->fp_statec_busy) { 10740 mutex_exit(&port->fp_mutex); 10741 pd = fctl_get_remote_port_by_did(port, s_id); 10742 if (pd) { 10743 mutex_enter(&pd->pd_mutex); 10744 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10745 FP_TRACE(FP_NHEAD1(3, 0), 10746 "LOGO for LOGGED IN D_ID %x", 10747 buf->ub_frame.s_id); 10748 pd->pd_state = PORT_DEVICE_VALID; 10749 } 10750 mutex_exit(&pd->pd_mutex); 10751 } 10752 10753 mutex_enter(&port->fp_mutex); 10754 ASSERT(port->fp_active_ubs > 0); 10755 if (--(port->fp_active_ubs) == 0) { 10756 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10757 } 10758 mutex_exit(&port->fp_mutex); 10759 10760 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10761 1, &buf->ub_token); 10762 10763 FP_TRACE(FP_NHEAD1(3, 0), 10764 "fp_unsol_cb() bailing out LOGO for D_ID %x", 10765 buf->ub_frame.s_id); 10766 return; 10767 } 10768 10769 if (port->fp_els_resp_pkt_busy == 0) { 10770 if (r_ctl == R_CTL_ELS_REQ) { 10771 ls_code = buf->ub_buffer[0]; 10772 10773 switch (ls_code) { 10774 case LA_ELS_PLOGI: 10775 case LA_ELS_FLOGI: 10776 port->fp_els_resp_pkt_busy = 1; 10777 mutex_exit(&port->fp_mutex); 10778 fp_i_handle_unsol_els(port, buf); 10779 10780 mutex_enter(&port->fp_mutex); 10781 ASSERT(port->fp_active_ubs > 0); 10782 if (--(port->fp_active_ubs) == 0) { 10783 port->fp_soft_state &= 10784 ~FP_SOFT_IN_UNSOL_CB; 10785 } 10786 mutex_exit(&port->fp_mutex); 10787 port->fp_fca_tran->fca_ub_release( 10788 port->fp_fca_handle, 1, &buf->ub_token); 10789 10790 return; 10791 case LA_ELS_RSCN: 10792 if (++(port)->fp_rscn_count == 10793 FC_INVALID_RSCN_COUNT) { 10794 ++(port)->fp_rscn_count; 10795 } 10796 rscn_count = port->fp_rscn_count; 10797 break; 10798 10799 default: 10800 break; 10801 } 10802 } 10803 } else if ((r_ctl == R_CTL_ELS_REQ) && 10804 (buf->ub_buffer[0] == LA_ELS_RSCN)) { 10805 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10806 ++port->fp_rscn_count; 10807 } 10808 rscn_count = port->fp_rscn_count; 10809 } 10810 10811 mutex_exit(&port->fp_mutex); 10812 10813 switch (r_ctl & R_CTL_ROUTING) { 10814 case R_CTL_DEVICE_DATA: 10815 /* 10816 * If the unsolicited buffer is a CT IU, 10817 * have the job_handler thread work on it. 10818 */ 10819 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 10820 break; 10821 } 10822 /* FALLTHROUGH */ 10823 10824 case R_CTL_FC4_SVC: { 10825 int sendup = 0; 10826 10827 /* 10828 * If a LOGIN isn't performed before this request 10829 * shut the door on this port with a reply that a 10830 * LOGIN is required. We make an exception however 10831 * for IP broadcast packets and pass them through 10832 * to the IP ULP(s) to handle broadcast requests. 10833 * This is not a problem for private loop devices 10834 * but for fabric topologies we don't log into the 10835 * remote ports during port initialization and 10836 * the ULPs need to log into requesting ports on 10837 * demand. 10838 */ 10839 pd = fctl_get_remote_port_by_did(port, s_id); 10840 if (pd) { 10841 mutex_enter(&pd->pd_mutex); 10842 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10843 sendup++; 10844 } 10845 mutex_exit(&pd->pd_mutex); 10846 } else if ((pd == NULL) && 10847 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) && 10848 (buf->ub_frame.d_id == 0xffffff || 10849 buf->ub_frame.d_id == 0x00)) { 10850 /* brodacst IP frame - so sendup via job thread */ 10851 break; 10852 } 10853 10854 /* 10855 * Send all FC4 services via job thread too 10856 */ 10857 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) { 10858 break; 10859 } 10860 10861 if (sendup || !FC_IS_REAL_DEVICE(s_id)) { 10862 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type); 10863 return; 10864 } 10865 10866 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10867 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10868 0, KM_NOSLEEP, pd); 10869 if (cmd != NULL) { 10870 fp_els_rjt_init(port, cmd, buf, 10871 FC_ACTION_NON_RETRYABLE, 10872 FC_REASON_LOGIN_REQUIRED, NULL); 10873 10874 if (fp_sendcmd(port, cmd, 10875 port->fp_fca_handle) != FC_SUCCESS) { 10876 fp_free_pkt(cmd); 10877 } 10878 } 10879 } 10880 10881 mutex_enter(&port->fp_mutex); 10882 ASSERT(port->fp_active_ubs > 0); 10883 if (--(port->fp_active_ubs) == 0) { 10884 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10885 } 10886 mutex_exit(&port->fp_mutex); 10887 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10888 1, &buf->ub_token); 10889 10890 return; 10891 } 10892 10893 default: 10894 break; 10895 } 10896 10897 /* 10898 * Submit a Request to the job_handler thread to work 10899 * on the unsolicited request. The potential side effect 10900 * of this is that the unsolicited buffer takes a little 10901 * longer to get released but we save interrupt time in 10902 * the bargain. 10903 */ 10904 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count; 10905 10906 /* 10907 * One way that the rscn_count will get used is described below : 10908 * 10909 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count. 10910 * 2. Before mutex is released, a copy of it is stored in rscn_count. 10911 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below) 10912 * by overloading the job_cb_arg to pass the rscn_count 10913 * 4. When one of the routines processing the RSCN picks it up (ex: 10914 * fp_validate_rscn_page()), it passes this count in the map 10915 * structure (as part of the map_rscn_info structure member) to the 10916 * ULPs. 10917 * 5. When ULPs make calls back to the transport (example interfaces for 10918 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they 10919 * can now pass back this count as part of the fc_packet's 10920 * pkt_ulp_rscn_count member. fcp does this currently. 10921 * 6. When transport gets a call to transport a command on the wire, it 10922 * will check to see if there is a valid pkt_ulp_rsvd1 field in the 10923 * fc_packet. If there is, it will match that info with the current 10924 * rscn_count on that instance of the port. If they don't match up 10925 * then there was a newer RSCN. The ULP gets back an error code which 10926 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN. 10927 * 7. At this point the ULP is free to make up its own mind as to how to 10928 * handle this. Currently, fcp will reset its retry counters and keep 10929 * retrying the operation it was doing in anticipation of getting a 10930 * new state change call back for the new RSCN. 10931 */ 10932 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL, 10933 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP); 10934 if (job == NULL) { 10935 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() " 10936 "couldn't submit a job to the thread, failing.."); 10937 10938 mutex_enter(&port->fp_mutex); 10939 10940 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10941 --port->fp_rscn_count; 10942 } 10943 10944 ASSERT(port->fp_active_ubs > 0); 10945 if (--(port->fp_active_ubs) == 0) { 10946 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10947 } 10948 10949 mutex_exit(&port->fp_mutex); 10950 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10951 1, &buf->ub_token); 10952 10953 return; 10954 } 10955 job->job_private = (void *)buf; 10956 fctl_enque_job(port, job); 10957 } 10958 10959 10960 /* 10961 * Handle unsolicited requests 10962 */ 10963 static void 10964 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf, 10965 job_request_t *job) 10966 { 10967 uchar_t r_ctl; 10968 uchar_t ls_code; 10969 uint32_t s_id; 10970 fp_cmd_t *cmd; 10971 fc_remote_port_t *pd; 10972 fp_unsol_spec_t *ub_spec; 10973 10974 r_ctl = buf->ub_frame.r_ctl; 10975 s_id = buf->ub_frame.s_id; 10976 10977 switch (r_ctl & R_CTL_ROUTING) { 10978 case R_CTL_EXTENDED_SVC: 10979 if (r_ctl != R_CTL_ELS_REQ) { 10980 break; 10981 } 10982 10983 ls_code = buf->ub_buffer[0]; 10984 switch (ls_code) { 10985 case LA_ELS_LOGO: 10986 case LA_ELS_ADISC: 10987 case LA_ELS_PRLO: 10988 pd = fctl_get_remote_port_by_did(port, s_id); 10989 if (pd == NULL) { 10990 if (!FC_IS_REAL_DEVICE(s_id)) { 10991 break; 10992 } 10993 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10994 break; 10995 } 10996 if ((cmd = fp_alloc_pkt(port, 10997 sizeof (la_els_rjt_t), 0, KM_SLEEP, 10998 NULL)) == NULL) { 10999 /* 11000 * Can this actually fail when 11001 * given KM_SLEEP? (Could be used 11002 * this way in a number of places.) 11003 */ 11004 break; 11005 } 11006 11007 fp_els_rjt_init(port, cmd, buf, 11008 FC_ACTION_NON_RETRYABLE, 11009 FC_REASON_INVALID_LINK_CTRL, job); 11010 11011 if (fp_sendcmd(port, cmd, 11012 port->fp_fca_handle) != FC_SUCCESS) { 11013 fp_free_pkt(cmd); 11014 } 11015 11016 break; 11017 } 11018 if (ls_code == LA_ELS_LOGO) { 11019 fp_handle_unsol_logo(port, buf, pd, job); 11020 } else if (ls_code == LA_ELS_ADISC) { 11021 fp_handle_unsol_adisc(port, buf, pd, job); 11022 } else { 11023 fp_handle_unsol_prlo(port, buf, pd, job); 11024 } 11025 break; 11026 11027 case LA_ELS_PLOGI: 11028 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP); 11029 break; 11030 11031 case LA_ELS_FLOGI: 11032 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP); 11033 break; 11034 11035 case LA_ELS_RSCN: 11036 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP); 11037 break; 11038 11039 default: 11040 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 11041 ub_spec->port = port; 11042 ub_spec->buf = buf; 11043 11044 (void) taskq_dispatch(port->fp_taskq, 11045 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 11046 return; 11047 } 11048 break; 11049 11050 case R_CTL_BASIC_SVC: 11051 /* 11052 * The unsolicited basic link services could be ABTS 11053 * and RMC (Or even a NOP). Just BA_RJT them until 11054 * such time there arises a need to handle them more 11055 * carefully. 11056 */ 11057 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11058 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t), 11059 0, KM_SLEEP, NULL); 11060 if (cmd != NULL) { 11061 fp_ba_rjt_init(port, cmd, buf, job); 11062 if (fp_sendcmd(port, cmd, 11063 port->fp_fca_handle) != FC_SUCCESS) { 11064 fp_free_pkt(cmd); 11065 } 11066 } 11067 } 11068 break; 11069 11070 case R_CTL_DEVICE_DATA: 11071 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 11072 /* 11073 * Mostly this is of type FC_TYPE_FC_SERVICES. 11074 * As we don't like any Unsolicited FC services 11075 * requests, we would do well to RJT them as 11076 * well. 11077 */ 11078 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11079 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11080 0, KM_SLEEP, NULL); 11081 if (cmd != NULL) { 11082 fp_els_rjt_init(port, cmd, buf, 11083 FC_ACTION_NON_RETRYABLE, 11084 FC_REASON_INVALID_LINK_CTRL, job); 11085 11086 if (fp_sendcmd(port, cmd, 11087 port->fp_fca_handle) != 11088 FC_SUCCESS) { 11089 fp_free_pkt(cmd); 11090 } 11091 } 11092 } 11093 break; 11094 } 11095 /* FALLTHROUGH */ 11096 11097 case R_CTL_FC4_SVC: 11098 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 11099 ub_spec->port = port; 11100 ub_spec->buf = buf; 11101 11102 (void) taskq_dispatch(port->fp_taskq, 11103 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 11104 return; 11105 11106 case R_CTL_LINK_CTL: 11107 /* 11108 * Turn deaf ear on unsolicited link control frames. 11109 * Typical unsolicited link control Frame is an LCR 11110 * (to reset End to End credit to the default login 11111 * value and abort current sequences for all classes) 11112 * An intelligent microcode/firmware should handle 11113 * this transparently at its level and not pass all 11114 * the way up here. 11115 * 11116 * Possible responses to LCR are R_RDY, F_RJT, P_RJT 11117 * or F_BSY. P_RJT is chosen to be the most appropriate 11118 * at this time. 11119 */ 11120 /* FALLTHROUGH */ 11121 11122 default: 11123 /* 11124 * Just reject everything else as an invalid request. 11125 */ 11126 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11127 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11128 0, KM_SLEEP, NULL); 11129 if (cmd != NULL) { 11130 fp_els_rjt_init(port, cmd, buf, 11131 FC_ACTION_NON_RETRYABLE, 11132 FC_REASON_INVALID_LINK_CTRL, job); 11133 11134 if (fp_sendcmd(port, cmd, 11135 port->fp_fca_handle) != FC_SUCCESS) { 11136 fp_free_pkt(cmd); 11137 } 11138 } 11139 } 11140 break; 11141 } 11142 11143 mutex_enter(&port->fp_mutex); 11144 ASSERT(port->fp_active_ubs > 0); 11145 if (--(port->fp_active_ubs) == 0) { 11146 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 11147 } 11148 mutex_exit(&port->fp_mutex); 11149 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 11150 1, &buf->ub_token); 11151 } 11152 11153 11154 /* 11155 * Prepare a BA_RJT and send it over. 11156 */ 11157 static void 11158 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11159 job_request_t *job) 11160 { 11161 fc_packet_t *pkt; 11162 la_ba_rjt_t payload; 11163 11164 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11165 11166 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11167 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11168 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11169 cmd->cmd_retry_count = 1; 11170 cmd->cmd_ulp_pkt = NULL; 11171 11172 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11173 cmd->cmd_job = job; 11174 11175 pkt = &cmd->cmd_pkt; 11176 11177 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS); 11178 11179 payload.reserved = 0; 11180 payload.reason_code = FC_REASON_CMD_UNSUPPORTED; 11181 payload.explanation = FC_EXPLN_NONE; 11182 payload.vendor = 0; 11183 11184 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11185 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11186 } 11187 11188 11189 /* 11190 * Prepare an LS_RJT and send it over 11191 */ 11192 static void 11193 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11194 uchar_t action, uchar_t reason, job_request_t *job) 11195 { 11196 fc_packet_t *pkt; 11197 la_els_rjt_t payload; 11198 11199 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11200 11201 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11202 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11203 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11204 cmd->cmd_retry_count = 1; 11205 cmd->cmd_ulp_pkt = NULL; 11206 11207 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11208 cmd->cmd_job = job; 11209 11210 pkt = &cmd->cmd_pkt; 11211 11212 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11213 11214 payload.ls_code.ls_code = LA_ELS_RJT; 11215 payload.ls_code.mbz = 0; 11216 payload.action = action; 11217 payload.reason = reason; 11218 payload.reserved = 0; 11219 payload.vu = 0; 11220 11221 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11222 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11223 } 11224 11225 /* 11226 * Function: fp_prlo_acc_init 11227 * 11228 * Description: Initializes an Link Service Accept for a PRLO. 11229 * 11230 * Arguments: *port Local port through which the PRLO was 11231 * received. 11232 * cmd Command that will carry the accept. 11233 * *buf Unsolicited buffer containing the PRLO 11234 * request. 11235 * job Job request. 11236 * sleep Allocation mode. 11237 * 11238 * Return Value: *cmd Command containing the response. 11239 * 11240 * Context: Depends on the parameter sleep. 11241 */ 11242 fp_cmd_t * 11243 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd, 11244 fc_unsol_buf_t *buf, job_request_t *job, int sleep) 11245 { 11246 fp_cmd_t *cmd; 11247 fc_packet_t *pkt; 11248 la_els_prlo_t *req; 11249 size_t len; 11250 uint16_t flags; 11251 11252 req = (la_els_prlo_t *)buf->ub_buffer; 11253 len = (size_t)ntohs(req->payload_length); 11254 11255 /* 11256 * The payload of the accept to a PRLO has to be the exact match of 11257 * the payload of the request (at the exception of the code). 11258 */ 11259 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd); 11260 11261 if (cmd) { 11262 /* 11263 * The fp command was successfully allocated. 11264 */ 11265 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11266 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11267 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11268 cmd->cmd_retry_count = 1; 11269 cmd->cmd_ulp_pkt = NULL; 11270 11271 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11272 cmd->cmd_job = job; 11273 11274 pkt = &cmd->cmd_pkt; 11275 11276 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, 11277 FC_TYPE_EXTENDED_LS); 11278 11279 /* The code is overwritten for the copy. */ 11280 req->ls_code = LA_ELS_ACC; 11281 /* Response code is set. */ 11282 flags = ntohs(req->flags); 11283 flags &= ~SP_RESP_CODE_MASK; 11284 flags |= SP_RESP_CODE_REQ_EXECUTED; 11285 req->flags = htons(flags); 11286 11287 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req, 11288 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR); 11289 } 11290 return (cmd); 11291 } 11292 11293 /* 11294 * Prepare an ACC response to an ELS request 11295 */ 11296 static void 11297 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11298 job_request_t *job) 11299 { 11300 fc_packet_t *pkt; 11301 ls_code_t payload; 11302 11303 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11304 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11305 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11306 cmd->cmd_retry_count = 1; 11307 cmd->cmd_ulp_pkt = NULL; 11308 11309 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11310 cmd->cmd_job = job; 11311 11312 pkt = &cmd->cmd_pkt; 11313 11314 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11315 11316 payload.ls_code = LA_ELS_ACC; 11317 payload.mbz = 0; 11318 11319 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11320 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11321 } 11322 11323 /* 11324 * Unsolicited PRLO handler 11325 * 11326 * A Process Logout should be handled by the ULP that established it. However, 11327 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens 11328 * when a device implicitly logs out an initiator (for whatever reason) and 11329 * tries to get that initiator to restablish the connection (PLOGI and PRLI). 11330 * The logical thing to do for the device would be to send a LOGO in response 11331 * to any FC4 frame sent by the initiator. Some devices choose, however, to send 11332 * a PRLO instead. 11333 * 11334 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to 11335 * think that the Port Login has been lost. If we follow the Fibre Channel 11336 * protocol to the letter a PRLI should be sent after accepting the PRLO. If 11337 * the Port Login has also been lost, the remote port will reject the PRLI 11338 * indicating that we must PLOGI first. The initiator will then turn around and 11339 * send a PLOGI. The way Leadville is layered and the way the ULP interface 11340 * is defined doesn't allow this scenario to be followed easily. If FCP were to 11341 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is 11342 * needed would be received by FCP. FCP would have, then, to tell the transport 11343 * (fp) to PLOGI. The problem is, the transport would still think the Port 11344 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even 11345 * if you think it's not necessary". To work around that difficulty, the PRLO 11346 * is treated by the transport as a LOGO. The downside to it is a Port Login 11347 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that 11348 * has nothing to do with the PRLO) may be impacted. However, this is a 11349 * scenario very unlikely to happen. As of today the only ULP in Leadville 11350 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be 11351 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very 11352 * unlikely). 11353 */ 11354 static void 11355 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11356 fc_remote_port_t *pd, job_request_t *job) 11357 { 11358 int busy; 11359 int rval; 11360 int retain; 11361 fp_cmd_t *cmd; 11362 fc_portmap_t *listptr; 11363 boolean_t tolerance; 11364 la_els_prlo_t *req; 11365 11366 req = (la_els_prlo_t *)buf->ub_buffer; 11367 11368 if ((ntohs(req->payload_length) != 11369 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) || 11370 (req->page_length != sizeof (service_parameter_page_t))) { 11371 /* 11372 * We are being very restrictive. Only on page per 11373 * payload. If it is not the case we reject the ELS although 11374 * we should reply indicating we handle only single page 11375 * per PRLO. 11376 */ 11377 goto fp_reject_prlo; 11378 } 11379 11380 if (ntohs(req->payload_length) > buf->ub_bufsize) { 11381 /* 11382 * This is in case the payload advertizes a size bigger than 11383 * what it really is. 11384 */ 11385 goto fp_reject_prlo; 11386 } 11387 11388 mutex_enter(&port->fp_mutex); 11389 busy = port->fp_statec_busy; 11390 mutex_exit(&port->fp_mutex); 11391 11392 mutex_enter(&pd->pd_mutex); 11393 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11394 if (!busy) { 11395 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11396 pd->pd_state == PORT_DEVICE_INVALID || 11397 pd->pd_flags == PD_ELS_IN_PROGRESS || 11398 pd->pd_type == PORT_DEVICE_OLD) { 11399 busy++; 11400 } 11401 } 11402 11403 if (busy) { 11404 mutex_exit(&pd->pd_mutex); 11405 11406 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11407 "pd=%p - busy", 11408 pd->pd_port_id.port_id, pd); 11409 11410 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11411 goto fp_reject_prlo; 11412 } 11413 } else { 11414 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11415 11416 if (tolerance) { 11417 fctl_tc_reset(&pd->pd_logo_tc); 11418 retain = 0; 11419 pd->pd_state = PORT_DEVICE_INVALID; 11420 } 11421 11422 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11423 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11424 tolerance, retain); 11425 11426 pd->pd_aux_flags |= PD_LOGGED_OUT; 11427 mutex_exit(&pd->pd_mutex); 11428 11429 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP); 11430 if (cmd == NULL) { 11431 return; 11432 } 11433 11434 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11435 if (rval != FC_SUCCESS) { 11436 fp_free_pkt(cmd); 11437 return; 11438 } 11439 11440 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11441 11442 if (retain) { 11443 fp_unregister_login(pd); 11444 fctl_copy_portmap(listptr, pd); 11445 } else { 11446 uint32_t d_id; 11447 char ww_name[17]; 11448 11449 mutex_enter(&pd->pd_mutex); 11450 d_id = pd->pd_port_id.port_id; 11451 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11452 mutex_exit(&pd->pd_mutex); 11453 11454 FP_TRACE(FP_NHEAD2(9, 0), 11455 "N_x Port with D_ID=%x, PWWN=%s logged out" 11456 " %d times in %d us; Giving up", d_id, ww_name, 11457 FC_LOGO_TOLERANCE_LIMIT, 11458 FC_LOGO_TOLERANCE_TIME_LIMIT); 11459 11460 fp_fillout_old_map(listptr, pd, 0); 11461 listptr->map_type = PORT_DEVICE_OLD; 11462 } 11463 11464 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11465 return; 11466 } 11467 11468 fp_reject_prlo: 11469 11470 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd); 11471 if (cmd != NULL) { 11472 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE, 11473 FC_REASON_INVALID_LINK_CTRL, job); 11474 11475 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11476 fp_free_pkt(cmd); 11477 } 11478 } 11479 } 11480 11481 /* 11482 * Unsolicited LOGO handler 11483 */ 11484 static void 11485 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11486 fc_remote_port_t *pd, job_request_t *job) 11487 { 11488 int busy; 11489 int rval; 11490 int retain; 11491 fp_cmd_t *cmd; 11492 fc_portmap_t *listptr; 11493 boolean_t tolerance; 11494 11495 mutex_enter(&port->fp_mutex); 11496 busy = port->fp_statec_busy; 11497 mutex_exit(&port->fp_mutex); 11498 11499 mutex_enter(&pd->pd_mutex); 11500 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11501 if (!busy) { 11502 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11503 pd->pd_state == PORT_DEVICE_INVALID || 11504 pd->pd_flags == PD_ELS_IN_PROGRESS || 11505 pd->pd_type == PORT_DEVICE_OLD) { 11506 busy++; 11507 } 11508 } 11509 11510 if (busy) { 11511 mutex_exit(&pd->pd_mutex); 11512 11513 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11514 "pd=%p - busy", 11515 pd->pd_port_id.port_id, pd); 11516 11517 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11518 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11519 0, KM_SLEEP, pd); 11520 if (cmd != NULL) { 11521 fp_els_rjt_init(port, cmd, buf, 11522 FC_ACTION_NON_RETRYABLE, 11523 FC_REASON_INVALID_LINK_CTRL, job); 11524 11525 if (fp_sendcmd(port, cmd, 11526 port->fp_fca_handle) != FC_SUCCESS) { 11527 fp_free_pkt(cmd); 11528 } 11529 } 11530 } 11531 } else { 11532 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11533 11534 if (tolerance) { 11535 fctl_tc_reset(&pd->pd_logo_tc); 11536 retain = 0; 11537 pd->pd_state = PORT_DEVICE_INVALID; 11538 } 11539 11540 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11541 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11542 tolerance, retain); 11543 11544 pd->pd_aux_flags |= PD_LOGGED_OUT; 11545 mutex_exit(&pd->pd_mutex); 11546 11547 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, 11548 KM_SLEEP, pd); 11549 if (cmd == NULL) { 11550 return; 11551 } 11552 11553 fp_els_acc_init(port, cmd, buf, job); 11554 11555 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11556 if (rval != FC_SUCCESS) { 11557 fp_free_pkt(cmd); 11558 return; 11559 } 11560 11561 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11562 11563 if (retain) { 11564 job_request_t *job; 11565 fctl_ns_req_t *ns_cmd; 11566 11567 /* 11568 * when get LOGO, first try to get PID from nameserver 11569 * if failed, then we do not need 11570 * send PLOGI to that remote port 11571 */ 11572 job = fctl_alloc_job( 11573 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP); 11574 11575 if (job != NULL) { 11576 ns_cmd = fctl_alloc_ns_cmd( 11577 sizeof (ns_req_gid_pn_t), 11578 sizeof (ns_resp_gid_pn_t), 11579 sizeof (ns_resp_gid_pn_t), 11580 0, KM_SLEEP); 11581 if (ns_cmd != NULL) { 11582 int ret; 11583 job->job_result = FC_SUCCESS; 11584 ns_cmd->ns_cmd_code = NS_GID_PN; 11585 ((ns_req_gid_pn_t *) 11586 (ns_cmd->ns_cmd_buf))->pwwn = 11587 pd->pd_port_name; 11588 ret = fp_ns_query( 11589 port, ns_cmd, job, 1, KM_SLEEP); 11590 if ((ret != FC_SUCCESS) || 11591 (job->job_result != FC_SUCCESS)) { 11592 fctl_free_ns_cmd(ns_cmd); 11593 fctl_dealloc_job(job); 11594 FP_TRACE(FP_NHEAD2(9, 0), 11595 "NS query failed,", 11596 " delete pd"); 11597 goto delete_pd; 11598 } 11599 fctl_free_ns_cmd(ns_cmd); 11600 } 11601 fctl_dealloc_job(job); 11602 } 11603 fp_unregister_login(pd); 11604 fctl_copy_portmap(listptr, pd); 11605 } else { 11606 uint32_t d_id; 11607 char ww_name[17]; 11608 11609 delete_pd: 11610 mutex_enter(&pd->pd_mutex); 11611 d_id = pd->pd_port_id.port_id; 11612 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11613 mutex_exit(&pd->pd_mutex); 11614 11615 FP_TRACE(FP_NHEAD2(9, 0), 11616 "N_x Port with D_ID=%x, PWWN=%s logged out" 11617 " %d times in %d us; Giving up", d_id, ww_name, 11618 FC_LOGO_TOLERANCE_LIMIT, 11619 FC_LOGO_TOLERANCE_TIME_LIMIT); 11620 11621 fp_fillout_old_map(listptr, pd, 0); 11622 listptr->map_type = PORT_DEVICE_OLD; 11623 } 11624 11625 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11626 } 11627 } 11628 11629 11630 /* 11631 * Perform general purpose preparation of a response to an unsolicited request 11632 */ 11633 static void 11634 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf, 11635 uchar_t r_ctl, uchar_t type) 11636 { 11637 pkt->pkt_cmd_fhdr.r_ctl = r_ctl; 11638 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id; 11639 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id; 11640 pkt->pkt_cmd_fhdr.type = type; 11641 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT; 11642 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id; 11643 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl; 11644 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt; 11645 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id; 11646 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id; 11647 pkt->pkt_cmd_fhdr.ro = 0; 11648 pkt->pkt_cmd_fhdr.rsvd = 0; 11649 pkt->pkt_comp = fp_unsol_intr; 11650 pkt->pkt_timeout = FP_ELS_TIMEOUT; 11651 pkt->pkt_ub_resp_token = (opaque_t)buf; 11652 } 11653 11654 /* 11655 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the 11656 * early development days of public loop soc+ firmware, numerous problems 11657 * were encountered (the details are undocumented and history now) which 11658 * led to the birth of this function. 11659 * 11660 * If a pre-allocated unsolicited response packet is free, send out an 11661 * immediate response, otherwise submit the request to the port thread 11662 * to do the deferred processing. 11663 */ 11664 static void 11665 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf) 11666 { 11667 int sent; 11668 int f_port; 11669 int do_acc; 11670 fp_cmd_t *cmd; 11671 la_els_logi_t *payload; 11672 fc_remote_port_t *pd; 11673 char dww_name[17]; 11674 11675 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11676 11677 cmd = port->fp_els_resp_pkt; 11678 11679 mutex_enter(&port->fp_mutex); 11680 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11681 mutex_exit(&port->fp_mutex); 11682 11683 switch (buf->ub_buffer[0]) { 11684 case LA_ELS_PLOGI: { 11685 int small; 11686 11687 payload = (la_els_logi_t *)buf->ub_buffer; 11688 11689 f_port = FP_IS_F_PORT(payload-> 11690 common_service.cmn_features) ? 1 : 0; 11691 11692 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 11693 &payload->nport_ww_name); 11694 pd = fctl_get_remote_port_by_pwwn(port, 11695 &payload->nport_ww_name); 11696 if (pd) { 11697 mutex_enter(&pd->pd_mutex); 11698 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11699 /* 11700 * Most likely this means a cross login is in 11701 * progress or a device about to be yanked out. 11702 * Only accept the plogi if my wwn is smaller. 11703 */ 11704 if (pd->pd_type == PORT_DEVICE_OLD) { 11705 sent = 1; 11706 } 11707 /* 11708 * Stop plogi request (if any) 11709 * attempt from local side to speedup 11710 * the discovery progress. 11711 * Mark the pd as PD_PLOGI_RECEPIENT. 11712 */ 11713 if (f_port == 0 && small < 0) { 11714 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11715 } 11716 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11717 11718 mutex_exit(&pd->pd_mutex); 11719 11720 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: " 11721 "Unsol PLOGI received. PD still exists in the " 11722 "PWWN list. pd=%p PWWN=%s, sent=%x", 11723 pd, dww_name, sent); 11724 11725 if (f_port == 0 && small < 0) { 11726 FP_TRACE(FP_NHEAD1(3, 0), 11727 "fp_i_handle_unsol_els: Mark the pd" 11728 " as plogi recipient, pd=%p, PWWN=%s" 11729 ", sent=%x", 11730 pd, dww_name, sent); 11731 } 11732 } else { 11733 sent = 0; 11734 } 11735 11736 /* 11737 * To avoid Login collisions, accept only if my WWN 11738 * is smaller than the requester (A curious side note 11739 * would be that this rule may not satisfy the PLOGIs 11740 * initiated by the switch from not-so-well known 11741 * ports such as 0xFFFC41) 11742 */ 11743 if ((f_port == 0 && small < 0) || 11744 (((small > 0 && do_acc) || 11745 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11746 if (fp_is_class_supported(port->fp_cos, 11747 buf->ub_class) == FC_FAILURE) { 11748 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11749 cmd->cmd_pkt.pkt_cmdlen = 11750 sizeof (la_els_rjt_t); 11751 cmd->cmd_pkt.pkt_rsplen = 0; 11752 fp_els_rjt_init(port, cmd, buf, 11753 FC_ACTION_NON_RETRYABLE, 11754 FC_REASON_CLASS_NOT_SUPP, NULL); 11755 FP_TRACE(FP_NHEAD1(3, 0), 11756 "fp_i_handle_unsol_els: " 11757 "Unsupported class. " 11758 "Rejecting PLOGI"); 11759 11760 } else { 11761 mutex_enter(&port->fp_mutex); 11762 port->fp_els_resp_pkt_busy = 0; 11763 mutex_exit(&port->fp_mutex); 11764 return; 11765 } 11766 } else { 11767 cmd->cmd_pkt.pkt_cmdlen = 11768 sizeof (la_els_logi_t); 11769 cmd->cmd_pkt.pkt_rsplen = 0; 11770 11771 /* 11772 * If fp_port_id is zero and topology is 11773 * Point-to-Point, get the local port id from 11774 * the d_id in the PLOGI request. 11775 * If the outgoing FLOGI hasn't been accepted, 11776 * the topology will be unknown here. But it's 11777 * still safe to save the d_id to fp_port_id, 11778 * just because it will be overwritten later 11779 * if the topology is not Point-to-Point. 11780 */ 11781 mutex_enter(&port->fp_mutex); 11782 if ((port->fp_port_id.port_id == 0) && 11783 (port->fp_topology == FC_TOP_PT_PT || 11784 port->fp_topology == FC_TOP_UNKNOWN)) { 11785 port->fp_port_id.port_id = 11786 buf->ub_frame.d_id; 11787 } 11788 mutex_exit(&port->fp_mutex); 11789 11790 /* 11791 * Sometime later, we should validate 11792 * the service parameters instead of 11793 * just accepting it. 11794 */ 11795 fp_login_acc_init(port, cmd, buf, NULL, 11796 KM_NOSLEEP); 11797 FP_TRACE(FP_NHEAD1(3, 0), 11798 "fp_i_handle_unsol_els: Accepting PLOGI," 11799 " f_port=%d, small=%d, do_acc=%d," 11800 " sent=%d.", f_port, small, do_acc, 11801 sent); 11802 } 11803 } else { 11804 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 11805 port->fp_options & FP_SEND_RJT) { 11806 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11807 cmd->cmd_pkt.pkt_rsplen = 0; 11808 fp_els_rjt_init(port, cmd, buf, 11809 FC_ACTION_NON_RETRYABLE, 11810 FC_REASON_LOGICAL_BSY, NULL); 11811 FP_TRACE(FP_NHEAD1(3, 0), 11812 "fp_i_handle_unsol_els: " 11813 "Rejecting PLOGI with Logical Busy." 11814 "Possible Login collision."); 11815 } else { 11816 mutex_enter(&port->fp_mutex); 11817 port->fp_els_resp_pkt_busy = 0; 11818 mutex_exit(&port->fp_mutex); 11819 return; 11820 } 11821 } 11822 break; 11823 } 11824 11825 case LA_ELS_FLOGI: 11826 if (fp_is_class_supported(port->fp_cos, 11827 buf->ub_class) == FC_FAILURE) { 11828 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11829 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11830 cmd->cmd_pkt.pkt_rsplen = 0; 11831 fp_els_rjt_init(port, cmd, buf, 11832 FC_ACTION_NON_RETRYABLE, 11833 FC_REASON_CLASS_NOT_SUPP, NULL); 11834 FP_TRACE(FP_NHEAD1(3, 0), 11835 "fp_i_handle_unsol_els: " 11836 "Unsupported Class. Rejecting FLOGI."); 11837 } else { 11838 mutex_enter(&port->fp_mutex); 11839 port->fp_els_resp_pkt_busy = 0; 11840 mutex_exit(&port->fp_mutex); 11841 return; 11842 } 11843 } else { 11844 mutex_enter(&port->fp_mutex); 11845 if (FC_PORT_STATE_MASK(port->fp_state) != 11846 FC_STATE_ONLINE || (port->fp_port_id.port_id && 11847 buf->ub_frame.s_id == port->fp_port_id.port_id)) { 11848 mutex_exit(&port->fp_mutex); 11849 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11850 cmd->cmd_pkt.pkt_cmdlen = 11851 sizeof (la_els_rjt_t); 11852 cmd->cmd_pkt.pkt_rsplen = 0; 11853 fp_els_rjt_init(port, cmd, buf, 11854 FC_ACTION_NON_RETRYABLE, 11855 FC_REASON_INVALID_LINK_CTRL, 11856 NULL); 11857 FP_TRACE(FP_NHEAD1(3, 0), 11858 "fp_i_handle_unsol_els: " 11859 "Invalid Link Ctrl. " 11860 "Rejecting FLOGI."); 11861 } else { 11862 mutex_enter(&port->fp_mutex); 11863 port->fp_els_resp_pkt_busy = 0; 11864 mutex_exit(&port->fp_mutex); 11865 return; 11866 } 11867 } else { 11868 mutex_exit(&port->fp_mutex); 11869 cmd->cmd_pkt.pkt_cmdlen = 11870 sizeof (la_els_logi_t); 11871 cmd->cmd_pkt.pkt_rsplen = 0; 11872 /* 11873 * Let's not aggressively validate the N_Port's 11874 * service parameters until PLOGI. Suffice it 11875 * to give a hint that we are an N_Port and we 11876 * are game to some serious stuff here. 11877 */ 11878 fp_login_acc_init(port, cmd, buf, 11879 NULL, KM_NOSLEEP); 11880 FP_TRACE(FP_NHEAD1(3, 0), 11881 "fp_i_handle_unsol_els: " 11882 "Accepting FLOGI."); 11883 } 11884 } 11885 break; 11886 11887 default: 11888 return; 11889 } 11890 11891 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) { 11892 mutex_enter(&port->fp_mutex); 11893 port->fp_els_resp_pkt_busy = 0; 11894 mutex_exit(&port->fp_mutex); 11895 } 11896 } 11897 11898 11899 /* 11900 * Handle unsolicited PLOGI request 11901 */ 11902 static void 11903 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 11904 job_request_t *job, int sleep) 11905 { 11906 int sent; 11907 int small; 11908 int f_port; 11909 int do_acc; 11910 fp_cmd_t *cmd; 11911 la_wwn_t *swwn; 11912 la_wwn_t *dwwn; 11913 la_els_logi_t *payload; 11914 fc_remote_port_t *pd; 11915 char dww_name[17]; 11916 11917 payload = (la_els_logi_t *)buf->ub_buffer; 11918 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0; 11919 11920 mutex_enter(&port->fp_mutex); 11921 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11922 mutex_exit(&port->fp_mutex); 11923 11924 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x," 11925 "type=%x, f_ctl=%x" 11926 " seq_id=%x, ox_id=%x, rx_id=%x" 11927 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 11928 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 11929 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 11930 11931 swwn = &port->fp_service_params.nport_ww_name; 11932 dwwn = &payload->nport_ww_name; 11933 small = fctl_wwn_cmp(swwn, dwwn); 11934 pd = fctl_get_remote_port_by_pwwn(port, dwwn); 11935 if (pd) { 11936 mutex_enter(&pd->pd_mutex); 11937 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11938 /* 11939 * Most likely this means a cross login is in 11940 * progress or a device about to be yanked out. 11941 * Only accept the plogi if my wwn is smaller. 11942 */ 11943 11944 if (pd->pd_type == PORT_DEVICE_OLD) { 11945 sent = 1; 11946 } 11947 /* 11948 * Stop plogi request (if any) 11949 * attempt from local side to speedup 11950 * the discovery progress. 11951 * Mark the pd as PD_PLOGI_RECEPIENT. 11952 */ 11953 if (f_port == 0 && small < 0) { 11954 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11955 } 11956 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11957 11958 mutex_exit(&pd->pd_mutex); 11959 11960 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI" 11961 " received. PD still exists in the PWWN list. pd=%p " 11962 "PWWN=%s, sent=%x", pd, dww_name, sent); 11963 11964 if (f_port == 0 && small < 0) { 11965 FP_TRACE(FP_NHEAD1(3, 0), 11966 "fp_handle_unsol_plogi: Mark the pd" 11967 " as plogi recipient, pd=%p, PWWN=%s" 11968 ", sent=%x", 11969 pd, dww_name, sent); 11970 } 11971 } else { 11972 sent = 0; 11973 } 11974 11975 /* 11976 * Avoid Login collisions by accepting only if my WWN is smaller. 11977 * 11978 * A side note: There is no need to start a PLOGI from this end in 11979 * this context if login isn't going to be accepted for the 11980 * above reason as either a LIP (in private loop), RSCN (in 11981 * fabric topology), or an FLOGI (in point to point - Huh ? 11982 * check FC-PH) would normally drive the PLOGI from this end. 11983 * At this point of time there is no need for an inbound PLOGI 11984 * to kick an outbound PLOGI when it is going to be rejected 11985 * for the reason of WWN being smaller. However it isn't hard 11986 * to do that either (when such a need arises, start a timer 11987 * for a duration that extends beyond a normal device discovery 11988 * time and check if an outbound PLOGI did go before that, if 11989 * none fire one) 11990 * 11991 * Unfortunately, as it turned out, during booting, it is possible 11992 * to miss another initiator in the same loop as port driver 11993 * instances are serially attached. While preserving the above 11994 * comments for belly laughs, please kick an outbound PLOGI in 11995 * a non-switch environment (which is a pt pt between N_Ports or 11996 * a private loop) 11997 * 11998 * While preserving the above comments for amusement, send an 11999 * ACC if the PLOGI is going to be rejected for WWN being smaller 12000 * when no discovery is in progress at this end. Turn around 12001 * and make the port device as the PLOGI initiator, so that 12002 * during subsequent link/loop initialization, this end drives 12003 * the PLOGI (In fact both ends do in this particular case, but 12004 * only one wins) 12005 * 12006 * Make sure the PLOGIs initiated by the switch from not-so-well-known 12007 * ports (such as 0xFFFC41) are accepted too. 12008 */ 12009 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) || 12010 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 12011 if (fp_is_class_supported(port->fp_cos, 12012 buf->ub_class) == FC_FAILURE) { 12013 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12014 cmd = fp_alloc_pkt(port, 12015 sizeof (la_els_logi_t), 0, sleep, pd); 12016 if (cmd == NULL) { 12017 return; 12018 } 12019 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 12020 cmd->cmd_pkt.pkt_rsplen = 0; 12021 fp_els_rjt_init(port, cmd, buf, 12022 FC_ACTION_NON_RETRYABLE, 12023 FC_REASON_CLASS_NOT_SUPP, job); 12024 FP_TRACE(FP_NHEAD1(3, 0), 12025 "fp_handle_unsol_plogi: " 12026 "Unsupported class. rejecting PLOGI"); 12027 } 12028 } else { 12029 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12030 0, sleep, pd); 12031 if (cmd == NULL) { 12032 return; 12033 } 12034 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t); 12035 cmd->cmd_pkt.pkt_rsplen = 0; 12036 12037 /* 12038 * Sometime later, we should validate the service 12039 * parameters instead of just accepting it. 12040 */ 12041 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 12042 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 12043 "Accepting PLOGI, f_port=%d, small=%d, " 12044 "do_acc=%d, sent=%d.", f_port, small, do_acc, 12045 sent); 12046 12047 /* 12048 * If fp_port_id is zero and topology is 12049 * Point-to-Point, get the local port id from 12050 * the d_id in the PLOGI request. 12051 * If the outgoing FLOGI hasn't been accepted, 12052 * the topology will be unknown here. But it's 12053 * still safe to save the d_id to fp_port_id, 12054 * just because it will be overwritten later 12055 * if the topology is not Point-to-Point. 12056 */ 12057 mutex_enter(&port->fp_mutex); 12058 if ((port->fp_port_id.port_id == 0) && 12059 (port->fp_topology == FC_TOP_PT_PT || 12060 port->fp_topology == FC_TOP_UNKNOWN)) { 12061 port->fp_port_id.port_id = 12062 buf->ub_frame.d_id; 12063 } 12064 mutex_exit(&port->fp_mutex); 12065 } 12066 } else { 12067 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 12068 port->fp_options & FP_SEND_RJT) { 12069 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12070 0, sleep, pd); 12071 if (cmd == NULL) { 12072 return; 12073 } 12074 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 12075 cmd->cmd_pkt.pkt_rsplen = 0; 12076 /* 12077 * Send out Logical busy to indicate 12078 * the detection of PLOGI collision 12079 */ 12080 fp_els_rjt_init(port, cmd, buf, 12081 FC_ACTION_NON_RETRYABLE, 12082 FC_REASON_LOGICAL_BSY, job); 12083 12084 fc_wwn_to_str(dwwn, dww_name); 12085 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 12086 "Rejecting Unsol PLOGI with Logical Busy." 12087 "possible PLOGI collision. PWWN=%s, sent=%x", 12088 dww_name, sent); 12089 } else { 12090 return; 12091 } 12092 } 12093 12094 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12095 fp_free_pkt(cmd); 12096 } 12097 } 12098 12099 12100 /* 12101 * Handle mischievous turning over of our own FLOGI requests back to 12102 * us by the SOC+ microcode. In other words, look at the class of such 12103 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them 12104 * on the floor 12105 */ 12106 static void 12107 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 12108 job_request_t *job, int sleep) 12109 { 12110 uint32_t state; 12111 uint32_t s_id; 12112 fp_cmd_t *cmd; 12113 12114 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) { 12115 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12116 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12117 0, sleep, NULL); 12118 if (cmd == NULL) { 12119 return; 12120 } 12121 fp_els_rjt_init(port, cmd, buf, 12122 FC_ACTION_NON_RETRYABLE, 12123 FC_REASON_CLASS_NOT_SUPP, job); 12124 } else { 12125 return; 12126 } 12127 } else { 12128 12129 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:" 12130 " s_id=%x, d_id=%x, type=%x, f_ctl=%x" 12131 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x", 12132 buf->ub_frame.s_id, buf->ub_frame.d_id, 12133 buf->ub_frame.type, buf->ub_frame.f_ctl, 12134 buf->ub_frame.seq_id, buf->ub_frame.ox_id, 12135 buf->ub_frame.rx_id, buf->ub_frame.ro); 12136 12137 mutex_enter(&port->fp_mutex); 12138 state = FC_PORT_STATE_MASK(port->fp_state); 12139 s_id = port->fp_port_id.port_id; 12140 mutex_exit(&port->fp_mutex); 12141 12142 if (state != FC_STATE_ONLINE || 12143 (s_id && buf->ub_frame.s_id == s_id)) { 12144 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12145 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12146 0, sleep, NULL); 12147 if (cmd == NULL) { 12148 return; 12149 } 12150 fp_els_rjt_init(port, cmd, buf, 12151 FC_ACTION_NON_RETRYABLE, 12152 FC_REASON_INVALID_LINK_CTRL, job); 12153 FP_TRACE(FP_NHEAD1(3, 0), 12154 "fp_handle_unsol_flogi: " 12155 "Rejecting PLOGI. Invalid Link CTRL"); 12156 } else { 12157 return; 12158 } 12159 } else { 12160 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12161 0, sleep, NULL); 12162 if (cmd == NULL) { 12163 return; 12164 } 12165 /* 12166 * Let's not aggressively validate the N_Port's 12167 * service parameters until PLOGI. Suffice it 12168 * to give a hint that we are an N_Port and we 12169 * are game to some serious stuff here. 12170 */ 12171 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 12172 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: " 12173 "Accepting PLOGI"); 12174 } 12175 } 12176 12177 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12178 fp_free_pkt(cmd); 12179 } 12180 } 12181 12182 12183 /* 12184 * Perform PLOGI accept 12185 */ 12186 static void 12187 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 12188 job_request_t *job, int sleep) 12189 { 12190 fc_packet_t *pkt; 12191 fc_portmap_t *listptr; 12192 la_els_logi_t payload; 12193 12194 ASSERT(buf != NULL); 12195 12196 /* 12197 * If we are sending ACC to PLOGI and we haven't already 12198 * create port and node device handles, let's create them 12199 * here. 12200 */ 12201 if (buf->ub_buffer[0] == LA_ELS_PLOGI && 12202 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) { 12203 int small; 12204 int do_acc; 12205 fc_remote_port_t *pd; 12206 la_els_logi_t *req; 12207 12208 req = (la_els_logi_t *)buf->ub_buffer; 12209 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 12210 &req->nport_ww_name); 12211 12212 mutex_enter(&port->fp_mutex); 12213 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 12214 mutex_exit(&port->fp_mutex); 12215 12216 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x", 12217 port->fp_port_id.port_id, buf->ub_frame.s_id); 12218 pd = fctl_create_remote_port(port, &req->node_ww_name, 12219 &req->nport_ww_name, buf->ub_frame.s_id, 12220 PD_PLOGI_RECEPIENT, sleep); 12221 if (pd == NULL) { 12222 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: " 12223 "Couldn't create port device for d_id:0x%x", 12224 buf->ub_frame.s_id); 12225 12226 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 12227 "couldn't create port device d_id=%x", 12228 buf->ub_frame.s_id); 12229 } else { 12230 /* 12231 * usoc currently returns PLOGIs inline and 12232 * the maximum buffer size is 60 bytes or so. 12233 * So attempt not to look beyond what is in 12234 * the unsolicited buffer 12235 * 12236 * JNI also traverses this path sometimes 12237 */ 12238 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) { 12239 fp_register_login(NULL, pd, req, buf->ub_class); 12240 } else { 12241 mutex_enter(&pd->pd_mutex); 12242 if (pd->pd_login_count == 0) { 12243 pd->pd_login_count++; 12244 } 12245 pd->pd_state = PORT_DEVICE_LOGGED_IN; 12246 pd->pd_login_class = buf->ub_class; 12247 mutex_exit(&pd->pd_mutex); 12248 } 12249 12250 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep); 12251 if (listptr != NULL) { 12252 fctl_copy_portmap(listptr, pd); 12253 (void) fp_ulp_devc_cb(port, listptr, 12254 1, 1, sleep, 0); 12255 } 12256 12257 if (small > 0 && do_acc) { 12258 mutex_enter(&pd->pd_mutex); 12259 pd->pd_recepient = PD_PLOGI_INITIATOR; 12260 mutex_exit(&pd->pd_mutex); 12261 } 12262 } 12263 } 12264 12265 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 12266 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 12267 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12268 cmd->cmd_retry_count = 1; 12269 cmd->cmd_ulp_pkt = NULL; 12270 12271 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12272 cmd->cmd_job = job; 12273 12274 pkt = &cmd->cmd_pkt; 12275 12276 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 12277 12278 payload = port->fp_service_params; 12279 payload.ls_code.ls_code = LA_ELS_ACC; 12280 12281 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12282 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12283 12284 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x " 12285 "bufsize:0x%x sizeof (la_els_logi):0x%x " 12286 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x " 12287 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id, 12288 buf->ub_bufsize, sizeof (la_els_logi_t), 12289 port->fp_service_params.nport_ww_name.w.naa_id, 12290 port->fp_service_params.nport_ww_name.w.nport_id, 12291 port->fp_service_params.nport_ww_name.w.wwn_hi, 12292 port->fp_service_params.nport_ww_name.w.wwn_lo, 12293 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id, 12294 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id, 12295 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi, 12296 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo, 12297 port->fp_statec_busy); 12298 } 12299 12300 12301 #define RSCN_EVENT_NAME_LEN 256 12302 12303 /* 12304 * Handle RSCNs 12305 */ 12306 static void 12307 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf, 12308 job_request_t *job, int sleep) 12309 { 12310 uint32_t mask; 12311 fp_cmd_t *cmd; 12312 uint32_t count; 12313 int listindex; 12314 int16_t len; 12315 fc_rscn_t *payload; 12316 fc_portmap_t *listptr; 12317 fctl_ns_req_t *ns_cmd; 12318 fc_affected_id_t *page; 12319 caddr_t nvname; 12320 nvlist_t *attr_list = NULL; 12321 12322 mutex_enter(&port->fp_mutex); 12323 if (!FC_IS_TOP_SWITCH(port->fp_topology)) { 12324 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12325 --port->fp_rscn_count; 12326 } 12327 mutex_exit(&port->fp_mutex); 12328 return; 12329 } 12330 mutex_exit(&port->fp_mutex); 12331 12332 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL); 12333 if (cmd != NULL) { 12334 fp_els_acc_init(port, cmd, buf, job); 12335 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12336 fp_free_pkt(cmd); 12337 } 12338 } 12339 12340 payload = (fc_rscn_t *)buf->ub_buffer; 12341 ASSERT(payload->rscn_code == LA_ELS_RSCN); 12342 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN); 12343 12344 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN; 12345 12346 if (len <= 0) { 12347 mutex_enter(&port->fp_mutex); 12348 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12349 --port->fp_rscn_count; 12350 } 12351 mutex_exit(&port->fp_mutex); 12352 12353 return; 12354 } 12355 12356 ASSERT((len & 0x3) == 0); /* Must be power of 4 */ 12357 count = (len >> 2) << 1; /* number of pages multiplied by 2 */ 12358 12359 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 12360 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t)); 12361 12362 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12363 12364 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t), 12365 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t), 12366 0, sleep); 12367 if (ns_cmd == NULL) { 12368 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12369 12370 mutex_enter(&port->fp_mutex); 12371 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12372 --port->fp_rscn_count; 12373 } 12374 mutex_exit(&port->fp_mutex); 12375 12376 return; 12377 } 12378 12379 ns_cmd->ns_cmd_code = NS_GPN_ID; 12380 12381 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x," 12382 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x" 12383 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 12384 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 12385 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 12386 12387 /* Only proceed if we can allocate nvname and the nvlist */ 12388 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL && 12389 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 12390 KM_NOSLEEP) == DDI_SUCCESS) { 12391 if (!(attr_list && nvlist_add_uint32(attr_list, "instance", 12392 port->fp_instance) == DDI_SUCCESS && 12393 nvlist_add_byte_array(attr_list, "port-wwn", 12394 port->fp_service_params.nport_ww_name.raw_wwn, 12395 sizeof (la_wwn_t)) == DDI_SUCCESS)) { 12396 nvlist_free(attr_list); 12397 attr_list = NULL; 12398 } 12399 } 12400 12401 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) { 12402 /* Add affected page to the event payload */ 12403 if (attr_list != NULL) { 12404 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN, 12405 "affected_page_%d", listindex); 12406 if (attr_list && nvlist_add_uint32(attr_list, nvname, 12407 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) { 12408 /* We don't send a partial event, so dump it */ 12409 nvlist_free(attr_list); 12410 attr_list = NULL; 12411 } 12412 } 12413 /* 12414 * Query the NS to get the Port WWN for this 12415 * affected D_ID. 12416 */ 12417 mask = 0; 12418 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) { 12419 case FC_RSCN_PORT_ADDRESS: 12420 fp_validate_rscn_page(port, page, job, ns_cmd, 12421 listptr, &listindex, sleep); 12422 12423 if (listindex == 0) { 12424 /* 12425 * We essentially did not process this RSCN. So, 12426 * ULPs are not going to be called and so we 12427 * decrement the rscn_count 12428 */ 12429 mutex_enter(&port->fp_mutex); 12430 if (--port->fp_rscn_count == 12431 FC_INVALID_RSCN_COUNT) { 12432 --port->fp_rscn_count; 12433 } 12434 mutex_exit(&port->fp_mutex); 12435 } 12436 break; 12437 12438 case FC_RSCN_AREA_ADDRESS: 12439 mask = 0xFFFF00; 12440 /* FALLTHROUGH */ 12441 12442 case FC_RSCN_DOMAIN_ADDRESS: 12443 if (!mask) { 12444 mask = 0xFF0000; 12445 } 12446 fp_validate_area_domain(port, page->aff_d_id, mask, 12447 job, sleep); 12448 break; 12449 12450 case FC_RSCN_FABRIC_ADDRESS: 12451 /* 12452 * We need to discover all the devices on this 12453 * port. 12454 */ 12455 fp_validate_area_domain(port, 0, 0, job, sleep); 12456 break; 12457 12458 default: 12459 break; 12460 } 12461 } 12462 if (attr_list != NULL) { 12463 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, 12464 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list, 12465 NULL, DDI_SLEEP); 12466 nvlist_free(attr_list); 12467 } else { 12468 FP_TRACE(FP_NHEAD1(9, 0), 12469 "RSCN handled, but event not sent to userland"); 12470 } 12471 if (nvname != NULL) { 12472 kmem_free(nvname, RSCN_EVENT_NAME_LEN); 12473 } 12474 12475 if (ns_cmd) { 12476 fctl_free_ns_cmd(ns_cmd); 12477 } 12478 12479 if (listindex) { 12480 #ifdef DEBUG 12481 page = (fc_affected_id_t *)(buf->ub_buffer + 12482 sizeof (fc_rscn_t)); 12483 12484 if (listptr->map_did.port_id != page->aff_d_id) { 12485 FP_TRACE(FP_NHEAD1(9, 0), 12486 "PORT RSCN: processed=%x, reporting=%x", 12487 listptr->map_did.port_id, page->aff_d_id); 12488 } 12489 #endif 12490 12491 (void) fp_ulp_devc_cb(port, listptr, listindex, count, 12492 sleep, 0); 12493 } else { 12494 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12495 } 12496 } 12497 12498 12499 /* 12500 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held 12501 */ 12502 static void 12503 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12504 { 12505 int is_switch; 12506 int initiator; 12507 fc_local_port_t *port; 12508 12509 port = pd->pd_port; 12510 12511 /* This function has the following bunch of assumptions */ 12512 ASSERT(port != NULL); 12513 ASSERT(MUTEX_HELD(&port->fp_mutex)); 12514 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex)); 12515 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12516 12517 pd->pd_state = PORT_DEVICE_INVALID; 12518 pd->pd_type = PORT_DEVICE_OLD; 12519 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12520 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12521 12522 fctl_delist_did_table(port, pd); 12523 fctl_delist_pwwn_table(port, pd); 12524 12525 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x" 12526 " removed the PD=%p from DID and PWWN tables", 12527 port, pd->pd_port_id.port_id, pd); 12528 12529 if ((!flag) && port && initiator && is_switch) { 12530 (void) fctl_add_orphan_held(port, pd); 12531 } 12532 fctl_copy_portmap_held(map, pd); 12533 map->map_pd = pd; 12534 } 12535 12536 /* 12537 * Fill out old map for ULPs 12538 */ 12539 static void 12540 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12541 { 12542 int is_switch; 12543 int initiator; 12544 fc_local_port_t *port; 12545 12546 mutex_enter(&pd->pd_mutex); 12547 port = pd->pd_port; 12548 mutex_exit(&pd->pd_mutex); 12549 12550 mutex_enter(&port->fp_mutex); 12551 mutex_enter(&pd->pd_mutex); 12552 12553 pd->pd_state = PORT_DEVICE_INVALID; 12554 pd->pd_type = PORT_DEVICE_OLD; 12555 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12556 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12557 12558 fctl_delist_did_table(port, pd); 12559 fctl_delist_pwwn_table(port, pd); 12560 12561 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x" 12562 " removed the PD=%p from DID and PWWN tables", 12563 port, pd->pd_port_id.port_id, pd); 12564 12565 mutex_exit(&pd->pd_mutex); 12566 mutex_exit(&port->fp_mutex); 12567 12568 ASSERT(port != NULL); 12569 if ((!flag) && port && initiator && is_switch) { 12570 (void) fctl_add_orphan(port, pd, KM_NOSLEEP); 12571 } 12572 fctl_copy_portmap(map, pd); 12573 map->map_pd = pd; 12574 } 12575 12576 12577 /* 12578 * Fillout Changed Map for ULPs 12579 */ 12580 static void 12581 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd, 12582 uint32_t *new_did, la_wwn_t *new_pwwn) 12583 { 12584 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12585 12586 pd->pd_type = PORT_DEVICE_CHANGED; 12587 if (new_did) { 12588 pd->pd_port_id.port_id = *new_did; 12589 } 12590 if (new_pwwn) { 12591 pd->pd_port_name = *new_pwwn; 12592 } 12593 mutex_exit(&pd->pd_mutex); 12594 12595 fctl_copy_portmap(map, pd); 12596 12597 mutex_enter(&pd->pd_mutex); 12598 pd->pd_type = PORT_DEVICE_NOCHANGE; 12599 } 12600 12601 12602 /* 12603 * Fillout New Name Server map 12604 */ 12605 static void 12606 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle, 12607 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id) 12608 { 12609 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12610 12611 if (handle) { 12612 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn, 12613 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn), 12614 DDI_DEV_AUTOINCR); 12615 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn, 12616 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn), 12617 DDI_DEV_AUTOINCR); 12618 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types, 12619 (uint8_t *)gan_resp->gan_fc4types, 12620 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR); 12621 } else { 12622 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn, 12623 sizeof (gan_resp->gan_pwwn)); 12624 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn, 12625 sizeof (gan_resp->gan_nwwn)); 12626 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types, 12627 sizeof (gan_resp->gan_fc4types)); 12628 } 12629 port_map->map_did.port_id = d_id; 12630 port_map->map_did.priv_lilp_posit = 0; 12631 port_map->map_hard_addr.hard_addr = 0; 12632 port_map->map_hard_addr.rsvd = 0; 12633 port_map->map_state = PORT_DEVICE_INVALID; 12634 port_map->map_type = PORT_DEVICE_NEW; 12635 port_map->map_flags = 0; 12636 port_map->map_pd = NULL; 12637 12638 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn); 12639 12640 ASSERT(port != NULL); 12641 } 12642 12643 12644 /* 12645 * Perform LINIT ELS 12646 */ 12647 static int 12648 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep, 12649 job_request_t *job) 12650 { 12651 int rval; 12652 uint32_t d_id; 12653 uint32_t s_id; 12654 uint32_t lfa; 12655 uchar_t class; 12656 uint32_t ret; 12657 fp_cmd_t *cmd; 12658 fc_porttype_t ptype; 12659 fc_packet_t *pkt; 12660 fc_linit_req_t payload; 12661 fc_remote_port_t *pd; 12662 12663 rval = 0; 12664 12665 ASSERT(job != NULL); 12666 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12667 12668 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 12669 if (pd == NULL) { 12670 fctl_ns_req_t *ns_cmd; 12671 12672 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 12673 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 12674 0, sleep); 12675 12676 if (ns_cmd == NULL) { 12677 return (FC_NOMEM); 12678 } 12679 job->job_result = FC_SUCCESS; 12680 ns_cmd->ns_cmd_code = NS_GID_PN; 12681 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 12682 12683 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12684 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12685 fctl_free_ns_cmd(ns_cmd); 12686 return (FC_FAILURE); 12687 } 12688 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id)); 12689 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 12690 12691 fctl_free_ns_cmd(ns_cmd); 12692 lfa = d_id & 0xFFFF00; 12693 12694 /* 12695 * Given this D_ID, get the port type to see if 12696 * we can do LINIT on the LFA 12697 */ 12698 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t), 12699 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t), 12700 0, sleep); 12701 12702 if (ns_cmd == NULL) { 12703 return (FC_NOMEM); 12704 } 12705 12706 job->job_result = FC_SUCCESS; 12707 ns_cmd->ns_cmd_code = NS_GPT_ID; 12708 12709 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id; 12710 ((ns_req_gpt_id_t *) 12711 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 12712 12713 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12714 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12715 fctl_free_ns_cmd(ns_cmd); 12716 return (FC_FAILURE); 12717 } 12718 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype)); 12719 12720 fctl_free_ns_cmd(ns_cmd); 12721 12722 switch (ptype.port_type) { 12723 case FC_NS_PORT_NL: 12724 case FC_NS_PORT_F_NL: 12725 case FC_NS_PORT_FL: 12726 break; 12727 12728 default: 12729 return (FC_FAILURE); 12730 } 12731 } else { 12732 mutex_enter(&pd->pd_mutex); 12733 ptype = pd->pd_porttype; 12734 12735 switch (pd->pd_porttype.port_type) { 12736 case FC_NS_PORT_NL: 12737 case FC_NS_PORT_F_NL: 12738 case FC_NS_PORT_FL: 12739 lfa = pd->pd_port_id.port_id & 0xFFFF00; 12740 break; 12741 12742 default: 12743 mutex_exit(&pd->pd_mutex); 12744 return (FC_FAILURE); 12745 } 12746 mutex_exit(&pd->pd_mutex); 12747 } 12748 12749 mutex_enter(&port->fp_mutex); 12750 s_id = port->fp_port_id.port_id; 12751 class = port->fp_ns_login_class; 12752 mutex_exit(&port->fp_mutex); 12753 12754 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t), 12755 sizeof (fc_linit_resp_t), sleep, pd); 12756 if (cmd == NULL) { 12757 return (FC_NOMEM); 12758 } 12759 12760 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12761 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12762 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12763 cmd->cmd_retry_count = fp_retry_count; 12764 cmd->cmd_ulp_pkt = NULL; 12765 12766 pkt = &cmd->cmd_pkt; 12767 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12768 12769 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job); 12770 12771 /* 12772 * How does LIP work by the way ? 12773 * If the L_Port receives three consecutive identical ordered 12774 * sets whose first two characters (fully decoded) are equal to 12775 * the values shown in Table 3 of FC-AL-2 then the L_Port shall 12776 * recognize a Loop Initialization Primitive sequence. The 12777 * character 3 determines the type of lip: 12778 * LIP(F7) Normal LIP 12779 * LIP(F8) Loop Failure LIP 12780 * 12781 * The possible combination for the 3rd and 4th bytes are: 12782 * F7, F7 Normal Lip - No valid AL_PA 12783 * F8, F8 Loop Failure - No valid AL_PA 12784 * F7, AL_PS Normal Lip - Valid source AL_PA 12785 * F8, AL_PS Loop Failure - Valid source AL_PA 12786 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS 12787 * And Normal Lip for all other loop members 12788 * 0xFF AL_PS Vendor specific reset of all loop members 12789 * 12790 * Now, it may not always be that we, at the source, may have an 12791 * AL_PS (AL_PA of source) for 4th character slot, so we decide 12792 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT 12793 * payload we are going to set: 12794 * lip_b3 = 0xF7; Normal LIP 12795 * lip_b4 = 0xF7; No valid source AL_PA 12796 */ 12797 payload.ls_code.ls_code = LA_ELS_LINIT; 12798 payload.ls_code.mbz = 0; 12799 payload.rsvd = 0; 12800 payload.func = 0; /* Let Fabric determine the best way */ 12801 payload.lip_b3 = 0xF7; /* Normal LIP */ 12802 payload.lip_b4 = 0xF7; /* No valid source AL_PA */ 12803 12804 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12805 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12806 12807 job->job_counter = 1; 12808 12809 ret = fp_sendcmd(port, cmd, port->fp_fca_handle); 12810 if (ret == FC_SUCCESS) { 12811 fp_jobwait(job); 12812 rval = job->job_result; 12813 } else { 12814 rval = FC_FAILURE; 12815 fp_free_pkt(cmd); 12816 } 12817 12818 return (rval); 12819 } 12820 12821 12822 /* 12823 * Fill out the device handles with GAN response 12824 */ 12825 static void 12826 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 12827 ns_resp_gan_t *gan_resp) 12828 { 12829 fc_remote_node_t *node; 12830 fc_porttype_t type; 12831 fc_local_port_t *port; 12832 12833 ASSERT(pd != NULL); 12834 ASSERT(handle != NULL); 12835 12836 port = pd->pd_port; 12837 12838 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p," 12839 " port_id=%x, sym_len=%d fc4-type=%x", 12840 pd, gan_resp->gan_type_id.rsvd, 12841 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]); 12842 12843 mutex_enter(&pd->pd_mutex); 12844 12845 FC_GET_RSP(port, *handle, (uint8_t *)&type, 12846 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR); 12847 12848 pd->pd_porttype.port_type = type.port_type; 12849 pd->pd_porttype.rsvd = 0; 12850 12851 pd->pd_spn_len = gan_resp->gan_spnlen; 12852 if (pd->pd_spn_len) { 12853 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn, 12854 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len, 12855 DDI_DEV_AUTOINCR); 12856 } 12857 12858 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr, 12859 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr), 12860 DDI_DEV_AUTOINCR); 12861 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos, 12862 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos), 12863 DDI_DEV_AUTOINCR); 12864 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types, 12865 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types), 12866 DDI_DEV_AUTOINCR); 12867 12868 node = pd->pd_remote_nodep; 12869 mutex_exit(&pd->pd_mutex); 12870 12871 mutex_enter(&node->fd_mutex); 12872 12873 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa, 12874 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa), 12875 DDI_DEV_AUTOINCR); 12876 12877 node->fd_snn_len = gan_resp->gan_snnlen; 12878 if (node->fd_snn_len) { 12879 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn, 12880 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len, 12881 DDI_DEV_AUTOINCR); 12882 } 12883 12884 mutex_exit(&node->fd_mutex); 12885 } 12886 12887 12888 /* 12889 * Handles all NS Queries (also means that this function 12890 * doesn't handle NS object registration) 12891 */ 12892 static int 12893 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job, 12894 int polled, int sleep) 12895 { 12896 int rval; 12897 fp_cmd_t *cmd; 12898 12899 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12900 12901 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 12902 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x", 12903 port->fp_port_id.port_id, ns_cmd->ns_gan_sid); 12904 } 12905 12906 if (ns_cmd->ns_cmd_size == 0) { 12907 return (FC_FAILURE); 12908 } 12909 12910 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 12911 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) + 12912 ns_cmd->ns_resp_size, sleep, NULL); 12913 if (cmd == NULL) { 12914 return (FC_NOMEM); 12915 } 12916 12917 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf, 12918 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job); 12919 12920 if (polled) { 12921 job->job_counter = 1; 12922 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12923 } 12924 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 12925 if (rval != FC_SUCCESS) { 12926 job->job_result = rval; 12927 fp_iodone(cmd); 12928 if (polled == 0) { 12929 /* 12930 * Return FC_SUCCESS to indicate that 12931 * fp_iodone is performed already. 12932 */ 12933 rval = FC_SUCCESS; 12934 } 12935 } 12936 12937 if (polled) { 12938 fp_jobwait(job); 12939 rval = job->job_result; 12940 } 12941 12942 return (rval); 12943 } 12944 12945 12946 /* 12947 * Initialize Common Transport request 12948 */ 12949 static void 12950 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd, 12951 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len, 12952 uint16_t resp_len, job_request_t *job) 12953 { 12954 uint32_t s_id; 12955 uchar_t class; 12956 fc_packet_t *pkt; 12957 fc_ct_header_t ct; 12958 12959 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12960 12961 mutex_enter(&port->fp_mutex); 12962 s_id = port->fp_port_id.port_id; 12963 class = port->fp_ns_login_class; 12964 mutex_exit(&port->fp_mutex); 12965 12966 cmd->cmd_job = job; 12967 cmd->cmd_private = ns_cmd; 12968 pkt = &cmd->cmd_pkt; 12969 12970 ct.ct_rev = CT_REV; 12971 ct.ct_inid = 0; 12972 ct.ct_fcstype = FCSTYPE_DIRECTORY; 12973 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER; 12974 ct.ct_options = 0; 12975 ct.ct_reserved1 = 0; 12976 ct.ct_cmdrsp = cmd_code; 12977 ct.ct_aiusize = resp_len >> 2; 12978 ct.ct_reserved2 = 0; 12979 ct.ct_reason = 0; 12980 ct.ct_expln = 0; 12981 ct.ct_vendor = 0; 12982 12983 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct, 12984 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR); 12985 12986 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 12987 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC; 12988 pkt->pkt_cmd_fhdr.s_id = s_id; 12989 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 12990 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | 12991 F_CTL_FIRST_SEQ | F_CTL_END_SEQ; 12992 pkt->pkt_cmd_fhdr.seq_id = 0; 12993 pkt->pkt_cmd_fhdr.df_ctl = 0; 12994 pkt->pkt_cmd_fhdr.seq_cnt = 0; 12995 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 12996 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 12997 pkt->pkt_cmd_fhdr.ro = 0; 12998 pkt->pkt_cmd_fhdr.rsvd = 0; 12999 13000 pkt->pkt_comp = fp_ns_intr; 13001 pkt->pkt_ulp_private = (opaque_t)cmd; 13002 pkt->pkt_timeout = FP_NS_TIMEOUT; 13003 13004 if (cmd_buf) { 13005 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf, 13006 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13007 cmd_len, DDI_DEV_AUTOINCR); 13008 } 13009 13010 cmd->cmd_transport = port->fp_fca_tran->fca_transport; 13011 13012 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 13013 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13014 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 13015 cmd->cmd_retry_count = fp_retry_count; 13016 cmd->cmd_ulp_pkt = NULL; 13017 } 13018 13019 13020 /* 13021 * Name Server request interrupt routine 13022 */ 13023 static void 13024 fp_ns_intr(fc_packet_t *pkt) 13025 { 13026 fp_cmd_t *cmd; 13027 fc_local_port_t *port; 13028 fc_ct_header_t resp_hdr; 13029 fc_ct_header_t cmd_hdr; 13030 fctl_ns_req_t *ns_cmd; 13031 13032 cmd = pkt->pkt_ulp_private; 13033 port = cmd->cmd_port; 13034 13035 mutex_enter(&port->fp_mutex); 13036 port->fp_out_fpcmds--; 13037 mutex_exit(&port->fp_mutex); 13038 13039 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr, 13040 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR); 13041 ns_cmd = (fctl_ns_req_t *) 13042 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private); 13043 if (!FP_IS_PKT_ERROR(pkt)) { 13044 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr, 13045 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr), 13046 DDI_DEV_AUTOINCR); 13047 13048 /* 13049 * On x86 architectures, make sure the resp_hdr is big endian. 13050 * This macro is a NOP on sparc architectures mainly because 13051 * we don't want to end up wasting time since the end result 13052 * is going to be the same. 13053 */ 13054 MAKE_BE_32(&resp_hdr); 13055 13056 if (ns_cmd) { 13057 /* 13058 * Always copy out the response CT_HDR 13059 */ 13060 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr, 13061 sizeof (resp_hdr)); 13062 } 13063 13064 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) { 13065 pkt->pkt_state = FC_PKT_FS_RJT; 13066 pkt->pkt_reason = resp_hdr.ct_reason; 13067 pkt->pkt_expln = resp_hdr.ct_expln; 13068 } 13069 } 13070 13071 if (FP_IS_PKT_ERROR(pkt)) { 13072 if (ns_cmd) { 13073 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13074 ASSERT(ns_cmd->ns_pd != NULL); 13075 13076 /* Mark it OLD if not already done */ 13077 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13078 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD; 13079 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13080 } 13081 13082 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13083 fctl_free_ns_cmd(ns_cmd); 13084 ((fp_cmd_t *) 13085 (pkt->pkt_ulp_private))->cmd_private = NULL; 13086 } 13087 13088 } 13089 13090 FP_TRACE(FP_NHEAD2(1, 0), "%x NS failure pkt state=%x " 13091 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X", 13092 port->fp_port_id.port_id, pkt->pkt_state, 13093 pkt->pkt_reason, pkt->pkt_expln, 13094 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp); 13095 13096 (void) fp_common_intr(pkt, 1); 13097 13098 return; 13099 } 13100 13101 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) { 13102 uint32_t d_id; 13103 fc_local_port_t *port; 13104 fp_cmd_t *cmd; 13105 13106 d_id = pkt->pkt_cmd_fhdr.d_id; 13107 cmd = pkt->pkt_ulp_private; 13108 port = cmd->cmd_port; 13109 FP_TRACE(FP_NHEAD2(9, 0), 13110 "Bogus NS response received for D_ID=%x", d_id); 13111 } 13112 13113 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) { 13114 fp_gan_handler(pkt, ns_cmd); 13115 return; 13116 } 13117 13118 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID && 13119 cmd_hdr.ct_cmdrsp <= NS_GID_PT) { 13120 if (ns_cmd) { 13121 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) { 13122 fp_ns_query_handler(pkt, ns_cmd); 13123 return; 13124 } 13125 } 13126 } 13127 13128 fp_iodone(pkt->pkt_ulp_private); 13129 } 13130 13131 13132 /* 13133 * Process NS_GAN response 13134 */ 13135 static void 13136 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13137 { 13138 int my_did; 13139 fc_portid_t d_id; 13140 fp_cmd_t *cmd; 13141 fc_local_port_t *port; 13142 fc_remote_port_t *pd; 13143 ns_req_gan_t gan_req; 13144 ns_resp_gan_t *gan_resp; 13145 13146 ASSERT(ns_cmd != NULL); 13147 13148 cmd = pkt->pkt_ulp_private; 13149 port = cmd->cmd_port; 13150 13151 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t)); 13152 13153 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id, 13154 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR); 13155 13156 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id); 13157 13158 /* 13159 * In this case the priv_lilp_posit field in reality 13160 * is actually represents the relative position on a private loop. 13161 * So zero it while dealing with Port Identifiers. 13162 */ 13163 d_id.priv_lilp_posit = 0; 13164 pd = fctl_get_remote_port_by_did(port, d_id.port_id); 13165 if (ns_cmd->ns_gan_sid == d_id.port_id) { 13166 /* 13167 * We've come a full circle; time to get out. 13168 */ 13169 fp_iodone(cmd); 13170 return; 13171 } 13172 13173 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) { 13174 ns_cmd->ns_gan_sid = d_id.port_id; 13175 } 13176 13177 mutex_enter(&port->fp_mutex); 13178 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0; 13179 mutex_exit(&port->fp_mutex); 13180 13181 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port, 13182 port->fp_port_id.port_id, d_id.port_id); 13183 if (my_did == 0) { 13184 la_wwn_t pwwn; 13185 la_wwn_t nwwn; 13186 13187 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; " 13188 "port=%p, d_id=%x, type_id=%x, " 13189 "pwwn=%x %x %x %x %x %x %x %x, " 13190 "nwwn=%x %x %x %x %x %x %x %x", 13191 port, d_id.port_id, gan_resp->gan_type_id, 13192 13193 gan_resp->gan_pwwn.raw_wwn[0], 13194 gan_resp->gan_pwwn.raw_wwn[1], 13195 gan_resp->gan_pwwn.raw_wwn[2], 13196 gan_resp->gan_pwwn.raw_wwn[3], 13197 gan_resp->gan_pwwn.raw_wwn[4], 13198 gan_resp->gan_pwwn.raw_wwn[5], 13199 gan_resp->gan_pwwn.raw_wwn[6], 13200 gan_resp->gan_pwwn.raw_wwn[7], 13201 13202 gan_resp->gan_nwwn.raw_wwn[0], 13203 gan_resp->gan_nwwn.raw_wwn[1], 13204 gan_resp->gan_nwwn.raw_wwn[2], 13205 gan_resp->gan_nwwn.raw_wwn[3], 13206 gan_resp->gan_nwwn.raw_wwn[4], 13207 gan_resp->gan_nwwn.raw_wwn[5], 13208 gan_resp->gan_nwwn.raw_wwn[6], 13209 gan_resp->gan_nwwn.raw_wwn[7]); 13210 13211 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 13212 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn), 13213 DDI_DEV_AUTOINCR); 13214 13215 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 13216 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn), 13217 DDI_DEV_AUTOINCR); 13218 13219 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) { 13220 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create" 13221 "pd %x", port->fp_port_id.port_id, d_id.port_id); 13222 pd = fctl_create_remote_port(port, &nwwn, &pwwn, 13223 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); 13224 } 13225 if (pd != NULL) { 13226 fp_stuff_device_with_gan(&pkt->pkt_resp_acc, 13227 pd, gan_resp); 13228 } 13229 13230 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) { 13231 *((int *)ns_cmd->ns_data_buf) += 1; 13232 } 13233 13234 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) { 13235 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0); 13236 13237 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) { 13238 fc_port_dev_t *userbuf; 13239 13240 userbuf = ((fc_port_dev_t *) 13241 ns_cmd->ns_data_buf) + 13242 ns_cmd->ns_gan_index++; 13243 13244 userbuf->dev_did = d_id; 13245 13246 FC_GET_RSP(port, pkt->pkt_resp_acc, 13247 (uint8_t *)userbuf->dev_type, 13248 (uint8_t *)gan_resp->gan_fc4types, 13249 sizeof (userbuf->dev_type), 13250 DDI_DEV_AUTOINCR); 13251 13252 userbuf->dev_nwwn = nwwn; 13253 userbuf->dev_pwwn = pwwn; 13254 13255 if (pd != NULL) { 13256 mutex_enter(&pd->pd_mutex); 13257 userbuf->dev_state = pd->pd_state; 13258 userbuf->dev_hard_addr = 13259 pd->pd_hard_addr; 13260 mutex_exit(&pd->pd_mutex); 13261 } else { 13262 userbuf->dev_state = 13263 PORT_DEVICE_INVALID; 13264 } 13265 } else if (ns_cmd->ns_flags & 13266 FCTL_NS_BUF_IS_FC_PORTMAP) { 13267 fc_portmap_t *map; 13268 13269 map = ((fc_portmap_t *) 13270 ns_cmd->ns_data_buf) + 13271 ns_cmd->ns_gan_index++; 13272 13273 /* 13274 * First fill it like any new map 13275 * and update the port device info 13276 * below. 13277 */ 13278 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc, 13279 map, gan_resp, d_id.port_id); 13280 if (pd != NULL) { 13281 fctl_copy_portmap(map, pd); 13282 } else { 13283 map->map_state = PORT_DEVICE_INVALID; 13284 map->map_type = PORT_DEVICE_NOCHANGE; 13285 } 13286 } else { 13287 caddr_t dst_ptr; 13288 13289 dst_ptr = ns_cmd->ns_data_buf + 13290 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++; 13291 13292 FC_GET_RSP(port, pkt->pkt_resp_acc, 13293 (uint8_t *)dst_ptr, (uint8_t *)gan_resp, 13294 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR); 13295 } 13296 } else { 13297 ns_cmd->ns_gan_index++; 13298 } 13299 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) { 13300 fp_iodone(cmd); 13301 return; 13302 } 13303 } 13304 13305 gan_req.pid = d_id; 13306 13307 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req, 13308 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13309 sizeof (gan_req), DDI_DEV_AUTOINCR); 13310 13311 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) { 13312 pkt->pkt_state = FC_PKT_TRAN_ERROR; 13313 fp_iodone(cmd); 13314 } else { 13315 mutex_enter(&port->fp_mutex); 13316 port->fp_out_fpcmds++; 13317 mutex_exit(&port->fp_mutex); 13318 } 13319 } 13320 13321 13322 /* 13323 * Handle NS Query interrupt 13324 */ 13325 static void 13326 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13327 { 13328 fp_cmd_t *cmd; 13329 fc_local_port_t *port; 13330 caddr_t src_ptr; 13331 uint32_t xfer_len; 13332 13333 cmd = pkt->pkt_ulp_private; 13334 port = cmd->cmd_port; 13335 13336 xfer_len = ns_cmd->ns_resp_size; 13337 13338 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x", 13339 ns_cmd->ns_cmd_code, xfer_len); 13340 13341 if (ns_cmd->ns_cmd_code == NS_GPN_ID) { 13342 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13343 13344 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x", 13345 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]); 13346 } 13347 13348 if (xfer_len <= ns_cmd->ns_data_len) { 13349 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13350 FC_GET_RSP(port, pkt->pkt_resp_acc, 13351 (uint8_t *)ns_cmd->ns_data_buf, 13352 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR); 13353 } 13354 13355 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13356 ASSERT(ns_cmd->ns_pd != NULL); 13357 13358 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13359 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) { 13360 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE; 13361 } 13362 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13363 } 13364 13365 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13366 fctl_free_ns_cmd(ns_cmd); 13367 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL; 13368 } 13369 fp_iodone(cmd); 13370 } 13371 13372 13373 /* 13374 * Handle unsolicited ADISC ELS request 13375 */ 13376 static void 13377 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf, 13378 fc_remote_port_t *pd, job_request_t *job) 13379 { 13380 int rval; 13381 fp_cmd_t *cmd; 13382 13383 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p", 13384 port, pd->pd_port_id.port_id, pd->pd_state, pd); 13385 mutex_enter(&pd->pd_mutex); 13386 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 13387 mutex_exit(&pd->pd_mutex); 13388 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 13389 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 13390 0, KM_SLEEP, pd); 13391 if (cmd != NULL) { 13392 fp_els_rjt_init(port, cmd, buf, 13393 FC_ACTION_NON_RETRYABLE, 13394 FC_REASON_INVALID_LINK_CTRL, job); 13395 13396 if (fp_sendcmd(port, cmd, 13397 port->fp_fca_handle) != FC_SUCCESS) { 13398 fp_free_pkt(cmd); 13399 } 13400 } 13401 } 13402 } else { 13403 mutex_exit(&pd->pd_mutex); 13404 /* 13405 * Yes, yes, we don't have a hard address. But we 13406 * we should still respond. Huh ? Visit 21.19.2 13407 * of FC-PH-2 which essentially says that if an 13408 * NL_Port doesn't have a hard address, or if a port 13409 * does not have FC-AL capability, it shall report 13410 * zeroes in this field. 13411 */ 13412 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 13413 0, KM_SLEEP, pd); 13414 if (cmd == NULL) { 13415 return; 13416 } 13417 fp_adisc_acc_init(port, cmd, buf, job); 13418 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13419 if (rval != FC_SUCCESS) { 13420 fp_free_pkt(cmd); 13421 } 13422 } 13423 } 13424 13425 13426 /* 13427 * Initialize ADISC response. 13428 */ 13429 static void 13430 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 13431 job_request_t *job) 13432 { 13433 fc_packet_t *pkt; 13434 la_els_adisc_t payload; 13435 13436 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 13437 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 13438 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 13439 cmd->cmd_retry_count = 1; 13440 cmd->cmd_ulp_pkt = NULL; 13441 13442 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 13443 cmd->cmd_job = job; 13444 13445 pkt = &cmd->cmd_pkt; 13446 13447 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 13448 13449 payload.ls_code.ls_code = LA_ELS_ACC; 13450 payload.ls_code.mbz = 0; 13451 13452 mutex_enter(&port->fp_mutex); 13453 payload.nport_id = port->fp_port_id; 13454 payload.hard_addr = port->fp_hard_addr; 13455 mutex_exit(&port->fp_mutex); 13456 13457 payload.port_wwn = port->fp_service_params.nport_ww_name; 13458 payload.node_wwn = port->fp_service_params.node_ww_name; 13459 13460 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 13461 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 13462 } 13463 13464 13465 /* 13466 * Hold and Install the requested ULP drivers 13467 */ 13468 static void 13469 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port) 13470 { 13471 int len; 13472 int count; 13473 int data_len; 13474 major_t ulp_major; 13475 caddr_t ulp_name; 13476 caddr_t data_ptr; 13477 caddr_t data_buf; 13478 13479 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13480 13481 data_buf = NULL; 13482 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 13483 DDI_PROP_DONTPASS, "load-ulp-list", 13484 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) { 13485 return; 13486 } 13487 13488 len = strlen(data_buf); 13489 port->fp_ulp_nload = fctl_atoi(data_buf, 10); 13490 13491 data_ptr = data_buf + len + 1; 13492 for (count = 0; count < port->fp_ulp_nload; count++) { 13493 len = strlen(data_ptr) + 1; 13494 ulp_name = kmem_zalloc(len, KM_SLEEP); 13495 bcopy(data_ptr, ulp_name, len); 13496 13497 ulp_major = ddi_name_to_major(ulp_name); 13498 13499 if (ulp_major != (major_t)-1) { 13500 if (modload("drv", ulp_name) < 0) { 13501 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 13502 0, NULL, "failed to load %s", 13503 ulp_name); 13504 } 13505 } else { 13506 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 13507 "%s isn't a valid driver", ulp_name); 13508 } 13509 13510 kmem_free(ulp_name, len); 13511 data_ptr += len; /* Skip to next field */ 13512 } 13513 13514 /* 13515 * Free the memory allocated by DDI 13516 */ 13517 if (data_buf != NULL) { 13518 kmem_free(data_buf, data_len); 13519 } 13520 } 13521 13522 13523 /* 13524 * Perform LOGO operation 13525 */ 13526 static int 13527 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job) 13528 { 13529 int rval; 13530 fp_cmd_t *cmd; 13531 13532 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13533 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 13534 13535 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 13536 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 13537 13538 mutex_enter(&port->fp_mutex); 13539 mutex_enter(&pd->pd_mutex); 13540 13541 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN); 13542 ASSERT(pd->pd_login_count == 1); 13543 13544 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 13545 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13546 cmd->cmd_flags = 0; 13547 cmd->cmd_retry_count = 1; 13548 cmd->cmd_ulp_pkt = NULL; 13549 13550 fp_logo_init(pd, cmd, job); 13551 13552 mutex_exit(&pd->pd_mutex); 13553 mutex_exit(&port->fp_mutex); 13554 13555 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13556 if (rval != FC_SUCCESS) { 13557 fp_iodone(cmd); 13558 } 13559 13560 return (rval); 13561 } 13562 13563 13564 /* 13565 * Perform Port attach callbacks to registered ULPs 13566 */ 13567 static void 13568 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd) 13569 { 13570 fp_soft_attach_t *att; 13571 13572 att = kmem_zalloc(sizeof (*att), KM_SLEEP); 13573 att->att_cmd = cmd; 13574 att->att_port = port; 13575 13576 /* 13577 * We need to remember whether or not fctl_busy_port 13578 * succeeded so we know whether or not to call 13579 * fctl_idle_port when the task is complete. 13580 */ 13581 13582 if (fctl_busy_port(port) == 0) { 13583 att->att_need_pm_idle = B_TRUE; 13584 } else { 13585 att->att_need_pm_idle = B_FALSE; 13586 } 13587 13588 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach, 13589 att, KM_SLEEP); 13590 } 13591 13592 13593 /* 13594 * Forward state change notifications on to interested ULPs. 13595 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the 13596 * real work. 13597 */ 13598 static int 13599 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep) 13600 { 13601 fc_port_clist_t *clist; 13602 13603 clist = kmem_zalloc(sizeof (*clist), sleep); 13604 if (clist == NULL) { 13605 return (FC_NOMEM); 13606 } 13607 13608 clist->clist_state = statec; 13609 13610 mutex_enter(&port->fp_mutex); 13611 clist->clist_flags = port->fp_topology; 13612 mutex_exit(&port->fp_mutex); 13613 13614 clist->clist_port = (opaque_t)port; 13615 clist->clist_len = 0; 13616 clist->clist_size = 0; 13617 clist->clist_map = NULL; 13618 13619 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 13620 clist, KM_SLEEP); 13621 13622 return (FC_SUCCESS); 13623 } 13624 13625 13626 /* 13627 * Get name server map 13628 */ 13629 static int 13630 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map, 13631 uint32_t *len, uint32_t sid) 13632 { 13633 int ret; 13634 fctl_ns_req_t *ns_cmd; 13635 13636 /* 13637 * Don't let the allocator do anything for response; 13638 * we have have buffer ready to fillout. 13639 */ 13640 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13641 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP | 13642 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP); 13643 13644 ns_cmd->ns_data_len = sizeof (**map) * (*len); 13645 ns_cmd->ns_data_buf = (caddr_t)*map; 13646 13647 ASSERT(ns_cmd != NULL); 13648 13649 ns_cmd->ns_gan_index = 0; 13650 ns_cmd->ns_gan_sid = sid; 13651 ns_cmd->ns_cmd_code = NS_GA_NXT; 13652 ns_cmd->ns_gan_max = *len; 13653 13654 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13655 13656 if (ns_cmd->ns_gan_index != *len) { 13657 *len = ns_cmd->ns_gan_index; 13658 } 13659 ns_cmd->ns_data_len = 0; 13660 ns_cmd->ns_data_buf = NULL; 13661 fctl_free_ns_cmd(ns_cmd); 13662 13663 return (ret); 13664 } 13665 13666 13667 /* 13668 * Create a remote port in Fabric topology by using NS services 13669 */ 13670 static fc_remote_port_t * 13671 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep) 13672 { 13673 int rval; 13674 job_request_t *job; 13675 fctl_ns_req_t *ns_cmd; 13676 fc_remote_port_t *pd; 13677 13678 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13679 13680 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x", 13681 port, d_id); 13682 13683 #ifdef DEBUG 13684 mutex_enter(&port->fp_mutex); 13685 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 13686 mutex_exit(&port->fp_mutex); 13687 #endif 13688 13689 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep); 13690 if (job == NULL) { 13691 return (NULL); 13692 } 13693 13694 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13695 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE | 13696 FCTL_NS_NO_DATA_BUF), sleep); 13697 if (ns_cmd == NULL) { 13698 return (NULL); 13699 } 13700 13701 job->job_result = FC_SUCCESS; 13702 ns_cmd->ns_gan_max = 1; 13703 ns_cmd->ns_cmd_code = NS_GA_NXT; 13704 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 13705 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 13706 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 13707 13708 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 13709 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13710 fctl_free_ns_cmd(ns_cmd); 13711 13712 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) { 13713 fctl_dealloc_job(job); 13714 return (NULL); 13715 } 13716 fctl_dealloc_job(job); 13717 13718 pd = fctl_get_remote_port_by_did(port, d_id); 13719 13720 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p", 13721 port, d_id, pd); 13722 13723 return (pd); 13724 } 13725 13726 13727 /* 13728 * Check for the permissions on an ioctl command. If it is required to have an 13729 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If 13730 * the ioctl command isn't in one of the list built, shut the door on that too. 13731 * 13732 * Certain ioctls perform hardware accesses in FCA drivers, and it needs 13733 * to be made sure that users open the port for an exclusive access while 13734 * performing those operations. 13735 * 13736 * This can prevent a casual user from inflicting damage on the port by 13737 * sending these ioctls from multiple processes/threads (there is no good 13738 * reason why one would need to do that) without actually realizing how 13739 * expensive such commands could turn out to be. 13740 * 13741 * It is also important to note that, even with an exclusive access, 13742 * multiple threads can share the same file descriptor and fire down 13743 * commands in parallel. To prevent that the driver needs to make sure 13744 * that such commands aren't in progress already. This is taken care of 13745 * in the FP_EXCL_BUSY bit of fp_flag. 13746 */ 13747 static int 13748 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd) 13749 { 13750 int ret = FC_FAILURE; 13751 int count; 13752 13753 for (count = 0; 13754 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]); 13755 count++) { 13756 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) { 13757 if (fp_perm_list[count].fp_open_flag & open_flag) { 13758 ret = FC_SUCCESS; 13759 } 13760 break; 13761 } 13762 } 13763 13764 return (ret); 13765 } 13766 13767 13768 /* 13769 * Bind Port driver's unsolicited, state change callbacks 13770 */ 13771 static int 13772 fp_bind_callbacks(fc_local_port_t *port) 13773 { 13774 fc_fca_bind_info_t bind_info = {0}; 13775 fc_fca_port_info_t *port_info; 13776 int rval = DDI_SUCCESS; 13777 uint16_t class; 13778 int node_namelen, port_namelen; 13779 char *nname = NULL, *pname = NULL; 13780 13781 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13782 13783 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13784 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13785 "node-name", &nname) != DDI_PROP_SUCCESS) { 13786 FP_TRACE(FP_NHEAD1(1, 0), 13787 "fp_bind_callback fail to get node-name"); 13788 } 13789 if (nname) { 13790 fc_str_to_wwn(nname, &(bind_info.port_nwwn)); 13791 } 13792 13793 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13794 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13795 "port-name", &pname) != DDI_PROP_SUCCESS) { 13796 FP_TRACE(FP_NHEAD1(1, 0), 13797 "fp_bind_callback fail to get port-name"); 13798 } 13799 if (pname) { 13800 fc_str_to_wwn(pname, &(bind_info.port_pwwn)); 13801 } 13802 13803 if (port->fp_npiv_type == FC_NPIV_PORT) { 13804 bind_info.port_npiv = 1; 13805 } 13806 13807 /* 13808 * fca_bind_port returns the FCA driver's handle for the local 13809 * port instance. If the port number isn't supported it returns NULL. 13810 * It also sets up callback in the FCA for various 13811 * things like state change, ELS etc.. 13812 */ 13813 bind_info.port_statec_cb = fp_statec_cb; 13814 bind_info.port_unsol_cb = fp_unsol_cb; 13815 bind_info.port_num = port->fp_port_num; 13816 bind_info.port_handle = (opaque_t)port; 13817 13818 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP); 13819 13820 /* 13821 * Hold the port driver mutex as the callbacks are bound until the 13822 * service parameters are properly filled in (in order to be able to 13823 * properly respond to unsolicited ELS requests) 13824 */ 13825 mutex_enter(&port->fp_mutex); 13826 13827 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port( 13828 port->fp_fca_dip, port_info, &bind_info); 13829 13830 if (port->fp_fca_handle == NULL) { 13831 rval = DDI_FAILURE; 13832 goto exit; 13833 } 13834 13835 /* 13836 * Only fcoei will set this bit 13837 */ 13838 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) { 13839 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA; 13840 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA); 13841 } 13842 13843 port->fp_bind_state = port->fp_state = port_info->pi_port_state; 13844 port->fp_service_params = port_info->pi_login_params; 13845 port->fp_hard_addr = port_info->pi_hard_addr; 13846 13847 /* Copy from the FCA structure to the FP structure */ 13848 port->fp_hba_port_attrs = port_info->pi_attrs; 13849 13850 if (port_info->pi_rnid_params.status == FC_SUCCESS) { 13851 port->fp_rnid_init = 1; 13852 bcopy(&port_info->pi_rnid_params.params, 13853 &port->fp_rnid_params, 13854 sizeof (port->fp_rnid_params)); 13855 } else { 13856 port->fp_rnid_init = 0; 13857 } 13858 13859 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name); 13860 if (node_namelen) { 13861 bcopy(&port_info->pi_attrs.sym_node_name, 13862 &port->fp_sym_node_name, 13863 node_namelen); 13864 port->fp_sym_node_namelen = node_namelen; 13865 } 13866 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name); 13867 if (port_namelen) { 13868 bcopy(&port_info->pi_attrs.sym_port_name, 13869 &port->fp_sym_port_name, 13870 port_namelen); 13871 port->fp_sym_port_namelen = port_namelen; 13872 } 13873 13874 /* zero out the normally unused fields right away */ 13875 port->fp_service_params.ls_code.mbz = 0; 13876 port->fp_service_params.ls_code.ls_code = 0; 13877 bzero(&port->fp_service_params.reserved, 13878 sizeof (port->fp_service_params.reserved)); 13879 13880 class = port_info->pi_login_params.class_1.class_opt; 13881 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0; 13882 13883 class = port_info->pi_login_params.class_2.class_opt; 13884 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0; 13885 13886 class = port_info->pi_login_params.class_3.class_opt; 13887 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0; 13888 13889 exit: 13890 if (nname) { 13891 ddi_prop_free(nname); 13892 } 13893 if (pname) { 13894 ddi_prop_free(pname); 13895 } 13896 mutex_exit(&port->fp_mutex); 13897 kmem_free(port_info, sizeof (*port_info)); 13898 13899 return (rval); 13900 } 13901 13902 13903 /* 13904 * Retrieve FCA capabilities 13905 */ 13906 static void 13907 fp_retrieve_caps(fc_local_port_t *port) 13908 { 13909 int rval; 13910 int ub_count; 13911 fc_fcp_dma_t fcp_dma; 13912 fc_reset_action_t action; 13913 fc_dma_behavior_t dma_behavior; 13914 13915 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13916 13917 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13918 FC_CAP_UNSOL_BUF, &ub_count); 13919 13920 switch (rval) { 13921 case FC_CAP_FOUND: 13922 case FC_CAP_SETTABLE: 13923 switch (ub_count) { 13924 case 0: 13925 break; 13926 13927 case -1: 13928 ub_count = fp_unsol_buf_count; 13929 break; 13930 13931 default: 13932 /* 1/4th of total buffers is my share */ 13933 ub_count = 13934 (ub_count / port->fp_fca_tran->fca_numports) >> 2; 13935 break; 13936 } 13937 break; 13938 13939 default: 13940 ub_count = 0; 13941 break; 13942 } 13943 13944 mutex_enter(&port->fp_mutex); 13945 port->fp_ub_count = ub_count; 13946 mutex_exit(&port->fp_mutex); 13947 13948 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13949 FC_CAP_POST_RESET_BEHAVIOR, &action); 13950 13951 switch (rval) { 13952 case FC_CAP_FOUND: 13953 case FC_CAP_SETTABLE: 13954 switch (action) { 13955 case FC_RESET_RETURN_NONE: 13956 case FC_RESET_RETURN_ALL: 13957 case FC_RESET_RETURN_OUTSTANDING: 13958 break; 13959 13960 default: 13961 action = FC_RESET_RETURN_NONE; 13962 break; 13963 } 13964 break; 13965 13966 default: 13967 action = FC_RESET_RETURN_NONE; 13968 break; 13969 } 13970 mutex_enter(&port->fp_mutex); 13971 port->fp_reset_action = action; 13972 mutex_exit(&port->fp_mutex); 13973 13974 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13975 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior); 13976 13977 switch (rval) { 13978 case FC_CAP_FOUND: 13979 switch (dma_behavior) { 13980 case FC_ALLOW_STREAMING: 13981 /* FALLTHROUGH */ 13982 case FC_NO_STREAMING: 13983 break; 13984 13985 default: 13986 /* 13987 * If capability was found and the value 13988 * was incorrect assume the worst 13989 */ 13990 dma_behavior = FC_NO_STREAMING; 13991 break; 13992 } 13993 break; 13994 13995 default: 13996 /* 13997 * If capability was not defined - allow streaming; existing 13998 * FCAs should not be affected. 13999 */ 14000 dma_behavior = FC_ALLOW_STREAMING; 14001 break; 14002 } 14003 mutex_enter(&port->fp_mutex); 14004 port->fp_dma_behavior = dma_behavior; 14005 mutex_exit(&port->fp_mutex); 14006 14007 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 14008 FC_CAP_FCP_DMA, &fcp_dma); 14009 14010 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE && 14011 fcp_dma != FC_DVMA_SPACE)) { 14012 fcp_dma = FC_DVMA_SPACE; 14013 } 14014 14015 mutex_enter(&port->fp_mutex); 14016 port->fp_fcp_dma = fcp_dma; 14017 mutex_exit(&port->fp_mutex); 14018 } 14019 14020 14021 /* 14022 * Handle Domain, Area changes in the Fabric. 14023 */ 14024 static void 14025 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask, 14026 job_request_t *job, int sleep) 14027 { 14028 #ifdef DEBUG 14029 uint32_t dcnt; 14030 #endif 14031 int rval; 14032 int send; 14033 int index; 14034 int listindex; 14035 int login; 14036 int job_flags; 14037 char ww_name[17]; 14038 uint32_t d_id; 14039 uint32_t count; 14040 fctl_ns_req_t *ns_cmd; 14041 fc_portmap_t *list; 14042 fc_orphan_t *orp; 14043 fc_orphan_t *norp; 14044 fc_orphan_t *prev; 14045 fc_remote_port_t *pd; 14046 fc_remote_port_t *npd; 14047 struct pwwn_hash *head; 14048 14049 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14050 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14051 0, sleep); 14052 if (ns_cmd == NULL) { 14053 mutex_enter(&port->fp_mutex); 14054 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14055 --port->fp_rscn_count; 14056 } 14057 mutex_exit(&port->fp_mutex); 14058 14059 return; 14060 } 14061 ns_cmd->ns_cmd_code = NS_GID_PN; 14062 14063 /* 14064 * We need to get a new count of devices from the 14065 * name server, which will also create any new devices 14066 * as needed. 14067 */ 14068 14069 (void) fp_ns_get_devcount(port, job, 1, sleep); 14070 14071 FP_TRACE(FP_NHEAD1(3, 0), 14072 "fp_validate_area_domain: get_devcount found %d devices", 14073 port->fp_total_devices); 14074 14075 mutex_enter(&port->fp_mutex); 14076 14077 for (count = index = 0; index < pwwn_table_size; index++) { 14078 head = &port->fp_pwwn_table[index]; 14079 pd = head->pwwn_head; 14080 while (pd != NULL) { 14081 mutex_enter(&pd->pd_mutex); 14082 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14083 if ((pd->pd_port_id.port_id & mask) == id && 14084 pd->pd_recepient == PD_PLOGI_INITIATOR) { 14085 count++; 14086 pd->pd_type = PORT_DEVICE_OLD; 14087 pd->pd_flags = PD_ELS_MARK; 14088 } 14089 } 14090 mutex_exit(&pd->pd_mutex); 14091 pd = pd->pd_wwn_hnext; 14092 } 14093 } 14094 14095 #ifdef DEBUG 14096 dcnt = count; 14097 #endif /* DEBUG */ 14098 14099 /* 14100 * Since port->fp_orphan_count is declared an 'int' it is 14101 * theoretically possible that the count could go negative. 14102 * 14103 * This would be bad and if that happens we really do want 14104 * to know. 14105 */ 14106 14107 ASSERT(port->fp_orphan_count >= 0); 14108 14109 count += port->fp_orphan_count; 14110 14111 /* 14112 * We add the port->fp_total_devices value to the count 14113 * in the case where our port is newly attached. This is 14114 * because we haven't done any discovery and we don't have 14115 * any orphans in the port's orphan list. If we do not do 14116 * this addition to count then we won't alloc enough kmem 14117 * to do discovery with. 14118 */ 14119 14120 if (count == 0) { 14121 count += port->fp_total_devices; 14122 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: " 14123 "0x%x orphans found, using 0x%x", 14124 port->fp_orphan_count, count); 14125 } 14126 14127 mutex_exit(&port->fp_mutex); 14128 14129 /* 14130 * Allocate the change list 14131 */ 14132 14133 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 14134 if (list == NULL) { 14135 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 14136 " Not enough memory to service RSCNs" 14137 " for %d ports, continuing...", count); 14138 14139 fctl_free_ns_cmd(ns_cmd); 14140 14141 mutex_enter(&port->fp_mutex); 14142 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14143 --port->fp_rscn_count; 14144 } 14145 mutex_exit(&port->fp_mutex); 14146 14147 return; 14148 } 14149 14150 /* 14151 * Attempt to validate or invalidate the devices that were 14152 * already in the pwwn hash table. 14153 */ 14154 14155 mutex_enter(&port->fp_mutex); 14156 for (listindex = 0, index = 0; index < pwwn_table_size; index++) { 14157 head = &port->fp_pwwn_table[index]; 14158 npd = head->pwwn_head; 14159 14160 while ((pd = npd) != NULL) { 14161 npd = pd->pd_wwn_hnext; 14162 14163 mutex_enter(&pd->pd_mutex); 14164 if ((pd->pd_port_id.port_id & mask) == id && 14165 pd->pd_flags == PD_ELS_MARK) { 14166 la_wwn_t *pwwn; 14167 14168 job->job_result = FC_SUCCESS; 14169 14170 ((ns_req_gid_pn_t *) 14171 (ns_cmd->ns_cmd_buf))->pwwn = 14172 pd->pd_port_name; 14173 14174 pwwn = &pd->pd_port_name; 14175 d_id = pd->pd_port_id.port_id; 14176 14177 mutex_exit(&pd->pd_mutex); 14178 mutex_exit(&port->fp_mutex); 14179 14180 rval = fp_ns_query(port, ns_cmd, job, 1, 14181 sleep); 14182 if (rval != FC_SUCCESS) { 14183 fc_wwn_to_str(pwwn, ww_name); 14184 14185 FP_TRACE(FP_NHEAD1(3, 0), 14186 "AREA RSCN: PD disappeared; " 14187 "d_id=%x, PWWN=%s", d_id, ww_name); 14188 14189 FP_TRACE(FP_NHEAD2(9, 0), 14190 "N_x Port with D_ID=%x," 14191 " PWWN=%s disappeared from fabric", 14192 d_id, ww_name); 14193 14194 fp_fillout_old_map(list + listindex++, 14195 pd, 1); 14196 } else { 14197 fctl_copy_portmap(list + listindex++, 14198 pd); 14199 14200 mutex_enter(&pd->pd_mutex); 14201 pd->pd_flags = PD_ELS_IN_PROGRESS; 14202 mutex_exit(&pd->pd_mutex); 14203 } 14204 14205 mutex_enter(&port->fp_mutex); 14206 } else { 14207 mutex_exit(&pd->pd_mutex); 14208 } 14209 } 14210 } 14211 14212 mutex_exit(&port->fp_mutex); 14213 14214 ASSERT(listindex == dcnt); 14215 14216 job->job_counter = listindex; 14217 job_flags = job->job_flags; 14218 job->job_flags |= JOB_TYPE_FP_ASYNC; 14219 14220 /* 14221 * Login (if we were the initiator) or validate devices in the 14222 * port map. 14223 */ 14224 14225 for (index = 0; index < listindex; index++) { 14226 pd = list[index].map_pd; 14227 14228 mutex_enter(&pd->pd_mutex); 14229 ASSERT((pd->pd_port_id.port_id & mask) == id); 14230 14231 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14232 ASSERT(pd->pd_type == PORT_DEVICE_OLD); 14233 mutex_exit(&pd->pd_mutex); 14234 fp_jobdone(job); 14235 continue; 14236 } 14237 14238 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0; 14239 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 14240 d_id = pd->pd_port_id.port_id; 14241 mutex_exit(&pd->pd_mutex); 14242 14243 if ((d_id & mask) == id && send) { 14244 if (login) { 14245 FP_TRACE(FP_NHEAD1(6, 0), 14246 "RSCN and PLOGI request;" 14247 " pd=%p, job=%p d_id=%x, index=%d", pd, 14248 job, d_id, index); 14249 14250 rval = fp_port_login(port, d_id, job, 14251 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL); 14252 if (rval != FC_SUCCESS) { 14253 mutex_enter(&pd->pd_mutex); 14254 pd->pd_flags = PD_IDLE; 14255 mutex_exit(&pd->pd_mutex); 14256 14257 job->job_result = rval; 14258 fp_jobdone(job); 14259 } 14260 FP_TRACE(FP_NHEAD1(1, 0), 14261 "PLOGI succeeded:no skip(1) for " 14262 "D_ID %x", d_id); 14263 list[index].map_flags |= 14264 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14265 } else { 14266 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;" 14267 " pd=%p, job=%p d_id=%x, index=%d", pd, 14268 job, d_id, index); 14269 14270 rval = fp_ns_validate_device(port, pd, job, 14271 0, sleep); 14272 if (rval != FC_SUCCESS) { 14273 fp_jobdone(job); 14274 } 14275 mutex_enter(&pd->pd_mutex); 14276 pd->pd_flags = PD_IDLE; 14277 mutex_exit(&pd->pd_mutex); 14278 } 14279 } else { 14280 FP_TRACE(FP_NHEAD1(6, 0), 14281 "RSCN and NO request sent; pd=%p," 14282 " d_id=%x, index=%d", pd, d_id, index); 14283 14284 mutex_enter(&pd->pd_mutex); 14285 pd->pd_flags = PD_IDLE; 14286 mutex_exit(&pd->pd_mutex); 14287 14288 fp_jobdone(job); 14289 } 14290 } 14291 14292 if (listindex) { 14293 fctl_jobwait(job); 14294 } 14295 job->job_flags = job_flags; 14296 14297 /* 14298 * Orphan list validation. 14299 */ 14300 mutex_enter(&port->fp_mutex); 14301 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count && 14302 orp != NULL; orp = norp) { 14303 norp = orp->orp_next; 14304 mutex_exit(&port->fp_mutex); 14305 14306 job->job_counter = 1; 14307 job->job_result = FC_SUCCESS; 14308 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 14309 14310 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn; 14311 14312 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14313 ((ns_resp_gid_pn_t *) 14314 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14315 14316 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 14317 if (rval == FC_SUCCESS) { 14318 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 14319 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 14320 if (pd != NULL) { 14321 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 14322 14323 FP_TRACE(FP_NHEAD1(6, 0), 14324 "RSCN and ORPHAN list " 14325 "success; d_id=%x, PWWN=%s", d_id, ww_name); 14326 14327 FP_TRACE(FP_NHEAD2(6, 0), 14328 "N_x Port with D_ID=%x, PWWN=%s reappeared" 14329 " in fabric", d_id, ww_name); 14330 14331 mutex_enter(&port->fp_mutex); 14332 if (prev) { 14333 prev->orp_next = orp->orp_next; 14334 } else { 14335 ASSERT(orp == port->fp_orphan_list); 14336 port->fp_orphan_list = orp->orp_next; 14337 } 14338 port->fp_orphan_count--; 14339 mutex_exit(&port->fp_mutex); 14340 14341 kmem_free(orp, sizeof (*orp)); 14342 fctl_copy_portmap(list + listindex++, pd); 14343 } else { 14344 prev = orp; 14345 } 14346 } else { 14347 prev = orp; 14348 } 14349 mutex_enter(&port->fp_mutex); 14350 } 14351 mutex_exit(&port->fp_mutex); 14352 14353 /* 14354 * One more pass through the list to delist old devices from 14355 * the d_id and pwwn tables and possibly add to the orphan list. 14356 */ 14357 14358 for (index = 0; index < listindex; index++) { 14359 pd = list[index].map_pd; 14360 ASSERT(pd != NULL); 14361 14362 /* 14363 * Update PLOGI results; For NS validation 14364 * of orphan list, it is redundant 14365 * 14366 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if 14367 * appropriate as fctl_copy_portmap() will clear map_flags. 14368 */ 14369 if (list[index].map_flags & 14370 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) { 14371 fctl_copy_portmap(list + index, pd); 14372 list[index].map_flags |= 14373 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14374 } else { 14375 fctl_copy_portmap(list + index, pd); 14376 } 14377 14378 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14379 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x", 14380 pd, pd->pd_port_id.port_id, 14381 pd->pd_port_name.raw_wwn[0], 14382 pd->pd_port_name.raw_wwn[1], 14383 pd->pd_port_name.raw_wwn[2], 14384 pd->pd_port_name.raw_wwn[3], 14385 pd->pd_port_name.raw_wwn[4], 14386 pd->pd_port_name.raw_wwn[5], 14387 pd->pd_port_name.raw_wwn[6], 14388 pd->pd_port_name.raw_wwn[7]); 14389 14390 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14391 "results continued, pd=%p type=%x, flags=%x, state=%x", 14392 pd, pd->pd_type, pd->pd_flags, pd->pd_state); 14393 14394 mutex_enter(&pd->pd_mutex); 14395 if (pd->pd_type == PORT_DEVICE_OLD) { 14396 int initiator; 14397 14398 pd->pd_flags = PD_IDLE; 14399 initiator = (pd->pd_recepient == 14400 PD_PLOGI_INITIATOR) ? 1 : 0; 14401 14402 mutex_exit(&pd->pd_mutex); 14403 14404 mutex_enter(&port->fp_mutex); 14405 mutex_enter(&pd->pd_mutex); 14406 14407 pd->pd_state = PORT_DEVICE_INVALID; 14408 fctl_delist_did_table(port, pd); 14409 fctl_delist_pwwn_table(port, pd); 14410 14411 mutex_exit(&pd->pd_mutex); 14412 mutex_exit(&port->fp_mutex); 14413 14414 if (initiator) { 14415 (void) fctl_add_orphan(port, pd, sleep); 14416 } 14417 list[index].map_pd = pd; 14418 } else { 14419 ASSERT(pd->pd_flags == PD_IDLE); 14420 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 14421 /* 14422 * Reset LOGO tolerance to zero 14423 */ 14424 fctl_tc_reset(&pd->pd_logo_tc); 14425 } 14426 mutex_exit(&pd->pd_mutex); 14427 } 14428 } 14429 14430 if (ns_cmd) { 14431 fctl_free_ns_cmd(ns_cmd); 14432 } 14433 if (listindex) { 14434 (void) fp_ulp_devc_cb(port, list, listindex, count, 14435 sleep, 0); 14436 } else { 14437 kmem_free(list, sizeof (*list) * count); 14438 14439 mutex_enter(&port->fp_mutex); 14440 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14441 --port->fp_rscn_count; 14442 } 14443 mutex_exit(&port->fp_mutex); 14444 } 14445 } 14446 14447 14448 /* 14449 * Work hard to make sense out of an RSCN page. 14450 */ 14451 static void 14452 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page, 14453 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr, 14454 int *listindex, int sleep) 14455 { 14456 int rval; 14457 char ww_name[17]; 14458 la_wwn_t *pwwn; 14459 fc_remote_port_t *pwwn_pd; 14460 fc_remote_port_t *did_pd; 14461 14462 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id); 14463 14464 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; " 14465 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id, 14466 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg); 14467 14468 if (did_pd != NULL) { 14469 mutex_enter(&did_pd->pd_mutex); 14470 if (did_pd->pd_flags != PD_IDLE) { 14471 mutex_exit(&did_pd->pd_mutex); 14472 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: " 14473 "PD is BUSY; port=%p, d_id=%x, pd=%p", 14474 port, page->aff_d_id, did_pd); 14475 return; 14476 } 14477 did_pd->pd_flags = PD_ELS_IN_PROGRESS; 14478 mutex_exit(&did_pd->pd_mutex); 14479 } 14480 14481 job->job_counter = 1; 14482 14483 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn; 14484 14485 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id; 14486 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0; 14487 14488 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t)); 14489 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 14490 14491 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x," 14492 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x", 14493 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid, 14494 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason, 14495 ns_cmd->ns_resp_hdr.ct_expln); 14496 14497 job->job_counter = 1; 14498 14499 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) { 14500 /* 14501 * What this means is that the D_ID 14502 * disappeared from the Fabric. 14503 */ 14504 if (did_pd == NULL) { 14505 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;" 14506 " NULL PD disappeared, rval=%x", rval); 14507 return; 14508 } 14509 14510 fc_wwn_to_str(&did_pd->pd_port_name, ww_name); 14511 14512 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14513 (uint32_t)(uintptr_t)job->job_cb_arg; 14514 14515 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14516 14517 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; " 14518 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name); 14519 14520 FP_TRACE(FP_NHEAD2(9, 0), 14521 "GPN_ID for D_ID=%x failed", page->aff_d_id); 14522 14523 FP_TRACE(FP_NHEAD2(9, 0), 14524 "N_x Port with D_ID=%x, PWWN=%s disappeared from" 14525 " fabric", page->aff_d_id, ww_name); 14526 14527 mutex_enter(&did_pd->pd_mutex); 14528 did_pd->pd_flags = PD_IDLE; 14529 mutex_exit(&did_pd->pd_mutex); 14530 14531 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; " 14532 "PD disappeared, pd=%p", page->aff_d_id, did_pd); 14533 14534 return; 14535 } 14536 14537 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn); 14538 14539 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) { 14540 /* 14541 * There is no change. Do PLOGI again and add it to 14542 * ULP portmap baggage and return. Note: When RSCNs 14543 * arrive with per page states, the need for PLOGI 14544 * can be determined correctly. 14545 */ 14546 mutex_enter(&pwwn_pd->pd_mutex); 14547 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE; 14548 mutex_exit(&pwwn_pd->pd_mutex); 14549 14550 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14551 (uint32_t)(uintptr_t)job->job_cb_arg; 14552 14553 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14554 14555 mutex_enter(&pwwn_pd->pd_mutex); 14556 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14557 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14558 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14559 mutex_exit(&pwwn_pd->pd_mutex); 14560 14561 rval = fp_port_login(port, page->aff_d_id, job, 14562 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14563 if (rval == FC_SUCCESS) { 14564 fp_jobwait(job); 14565 rval = job->job_result; 14566 14567 /* 14568 * Reset LOGO tolerance to zero 14569 * Also we are the PLOGI initiator now. 14570 */ 14571 mutex_enter(&pwwn_pd->pd_mutex); 14572 fctl_tc_reset(&pwwn_pd->pd_logo_tc); 14573 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR; 14574 mutex_exit(&pwwn_pd->pd_mutex); 14575 } 14576 14577 if (rval == FC_SUCCESS) { 14578 struct fc_portmap *map = 14579 listptr + *listindex - 1; 14580 14581 FP_TRACE(FP_NHEAD1(1, 0), 14582 "PLOGI succeeded: no skip(2)" 14583 " for D_ID %x", page->aff_d_id); 14584 map->map_flags |= 14585 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14586 } else { 14587 FP_TRACE(FP_NHEAD2(9, rval), 14588 "PLOGI to D_ID=%x failed", page->aff_d_id); 14589 14590 FP_TRACE(FP_NHEAD2(9, 0), 14591 "N_x Port with D_ID=%x, PWWN=%s" 14592 " disappeared from fabric", 14593 page->aff_d_id, ww_name); 14594 14595 fp_fillout_old_map(listptr + 14596 *listindex - 1, pwwn_pd, 0); 14597 } 14598 } else { 14599 mutex_exit(&pwwn_pd->pd_mutex); 14600 } 14601 14602 mutex_enter(&did_pd->pd_mutex); 14603 did_pd->pd_flags = PD_IDLE; 14604 mutex_exit(&did_pd->pd_mutex); 14605 14606 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14607 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval, 14608 job->job_result, pwwn_pd); 14609 14610 return; 14611 } 14612 14613 if (did_pd == NULL && pwwn_pd == NULL) { 14614 14615 fc_orphan_t *orp = NULL; 14616 fc_orphan_t *norp = NULL; 14617 fc_orphan_t *prev = NULL; 14618 14619 /* 14620 * Hunt down the orphan list before giving up. 14621 */ 14622 14623 mutex_enter(&port->fp_mutex); 14624 if (port->fp_orphan_count) { 14625 14626 for (orp = port->fp_orphan_list; orp; orp = norp) { 14627 norp = orp->orp_next; 14628 14629 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) { 14630 prev = orp; 14631 continue; 14632 } 14633 14634 if (prev) { 14635 prev->orp_next = orp->orp_next; 14636 } else { 14637 ASSERT(orp == 14638 port->fp_orphan_list); 14639 port->fp_orphan_list = 14640 orp->orp_next; 14641 } 14642 port->fp_orphan_count--; 14643 break; 14644 } 14645 } 14646 14647 mutex_exit(&port->fp_mutex); 14648 pwwn_pd = fp_create_remote_port_by_ns(port, 14649 page->aff_d_id, sleep); 14650 14651 if (pwwn_pd != NULL) { 14652 14653 if (orp) { 14654 fc_wwn_to_str(&orp->orp_pwwn, 14655 ww_name); 14656 14657 FP_TRACE(FP_NHEAD2(9, 0), 14658 "N_x Port with D_ID=%x," 14659 " PWWN=%s reappeared in fabric", 14660 page->aff_d_id, ww_name); 14661 14662 kmem_free(orp, sizeof (*orp)); 14663 } 14664 14665 (listptr + *listindex)-> 14666 map_rscn_info.ulp_rscn_count = 14667 (uint32_t)(uintptr_t)job->job_cb_arg; 14668 14669 fctl_copy_portmap(listptr + 14670 (*listindex)++, pwwn_pd); 14671 } 14672 14673 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14674 "Case TWO", page->aff_d_id); 14675 14676 return; 14677 } 14678 14679 if (pwwn_pd != NULL && did_pd == NULL) { 14680 uint32_t old_d_id; 14681 uint32_t d_id = page->aff_d_id; 14682 14683 /* 14684 * What this means is there is a new D_ID for this 14685 * Port WWN. Take out the port device off D_ID 14686 * list and put it back with a new D_ID. Perform 14687 * PLOGI if already logged in. 14688 */ 14689 mutex_enter(&port->fp_mutex); 14690 mutex_enter(&pwwn_pd->pd_mutex); 14691 14692 old_d_id = pwwn_pd->pd_port_id.port_id; 14693 14694 fctl_delist_did_table(port, pwwn_pd); 14695 14696 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14697 (uint32_t)(uintptr_t)job->job_cb_arg; 14698 14699 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd, 14700 &d_id, NULL); 14701 fctl_enlist_did_table(port, pwwn_pd); 14702 14703 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;" 14704 " Case THREE, pd=%p," 14705 " state=%x", pwwn_pd, pwwn_pd->pd_state); 14706 14707 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14708 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14709 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14710 14711 mutex_exit(&pwwn_pd->pd_mutex); 14712 mutex_exit(&port->fp_mutex); 14713 14714 FP_TRACE(FP_NHEAD2(9, 0), 14715 "N_x Port with D_ID=%x, PWWN=%s has a new" 14716 " D_ID=%x now", old_d_id, ww_name, d_id); 14717 14718 rval = fp_port_login(port, page->aff_d_id, job, 14719 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14720 if (rval == FC_SUCCESS) { 14721 fp_jobwait(job); 14722 rval = job->job_result; 14723 } 14724 14725 if (rval != FC_SUCCESS) { 14726 fp_fillout_old_map(listptr + 14727 *listindex - 1, pwwn_pd, 0); 14728 } 14729 } else { 14730 mutex_exit(&pwwn_pd->pd_mutex); 14731 mutex_exit(&port->fp_mutex); 14732 } 14733 14734 return; 14735 } 14736 14737 if (pwwn_pd == NULL && did_pd != NULL) { 14738 fc_portmap_t *ptr; 14739 uint32_t len = 1; 14740 char old_ww_name[17]; 14741 14742 mutex_enter(&did_pd->pd_mutex); 14743 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name); 14744 mutex_exit(&did_pd->pd_mutex); 14745 14746 fc_wwn_to_str(pwwn, ww_name); 14747 14748 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14749 (uint32_t)(uintptr_t)job->job_cb_arg; 14750 14751 /* 14752 * What this means is that there is a new Port WWN for 14753 * this D_ID; Mark the Port device as old and provide 14754 * the new PWWN and D_ID combination as new. 14755 */ 14756 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14757 14758 FP_TRACE(FP_NHEAD2(9, 0), 14759 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now", 14760 page->aff_d_id, old_ww_name, ww_name); 14761 14762 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14763 (uint32_t)(uintptr_t)job->job_cb_arg; 14764 14765 ptr = listptr + (*listindex)++; 14766 14767 job->job_counter = 1; 14768 14769 if (fp_ns_getmap(port, job, &ptr, &len, 14770 page->aff_d_id - 1) != FC_SUCCESS) { 14771 (*listindex)--; 14772 } 14773 14774 mutex_enter(&did_pd->pd_mutex); 14775 did_pd->pd_flags = PD_IDLE; 14776 mutex_exit(&did_pd->pd_mutex); 14777 14778 return; 14779 } 14780 14781 /* 14782 * A weird case of Port WWN and D_ID existence but not matching up 14783 * between them. Trust your instincts - Take the port device handle 14784 * off Port WWN list, fix it with new Port WWN and put it back, In 14785 * the mean time mark the port device corresponding to the old port 14786 * WWN as OLD. 14787 */ 14788 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p," 14789 " did_pd=%p", pwwn_pd, did_pd); 14790 14791 mutex_enter(&port->fp_mutex); 14792 mutex_enter(&pwwn_pd->pd_mutex); 14793 14794 pwwn_pd->pd_type = PORT_DEVICE_OLD; 14795 pwwn_pd->pd_state = PORT_DEVICE_INVALID; 14796 fctl_delist_did_table(port, pwwn_pd); 14797 fctl_delist_pwwn_table(port, pwwn_pd); 14798 14799 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14800 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x", 14801 pwwn_pd->pd_port_id.port_id, 14802 14803 pwwn_pd->pd_port_name.raw_wwn[0], 14804 pwwn_pd->pd_port_name.raw_wwn[1], 14805 pwwn_pd->pd_port_name.raw_wwn[2], 14806 pwwn_pd->pd_port_name.raw_wwn[3], 14807 pwwn_pd->pd_port_name.raw_wwn[4], 14808 pwwn_pd->pd_port_name.raw_wwn[5], 14809 pwwn_pd->pd_port_name.raw_wwn[6], 14810 pwwn_pd->pd_port_name.raw_wwn[7]); 14811 14812 mutex_exit(&pwwn_pd->pd_mutex); 14813 mutex_exit(&port->fp_mutex); 14814 14815 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14816 (uint32_t)(uintptr_t)job->job_cb_arg; 14817 14818 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14819 14820 mutex_enter(&port->fp_mutex); 14821 mutex_enter(&did_pd->pd_mutex); 14822 14823 fctl_delist_pwwn_table(port, did_pd); 14824 14825 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14826 (uint32_t)(uintptr_t)job->job_cb_arg; 14827 14828 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn); 14829 fctl_enlist_pwwn_table(port, did_pd); 14830 14831 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14832 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x", 14833 did_pd->pd_port_id.port_id, did_pd->pd_state, 14834 14835 did_pd->pd_port_name.raw_wwn[0], 14836 did_pd->pd_port_name.raw_wwn[1], 14837 did_pd->pd_port_name.raw_wwn[2], 14838 did_pd->pd_port_name.raw_wwn[3], 14839 did_pd->pd_port_name.raw_wwn[4], 14840 did_pd->pd_port_name.raw_wwn[5], 14841 did_pd->pd_port_name.raw_wwn[6], 14842 did_pd->pd_port_name.raw_wwn[7]); 14843 14844 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14845 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14846 mutex_exit(&did_pd->pd_mutex); 14847 mutex_exit(&port->fp_mutex); 14848 14849 rval = fp_port_login(port, page->aff_d_id, job, 14850 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL); 14851 if (rval == FC_SUCCESS) { 14852 fp_jobwait(job); 14853 if (job->job_result != FC_SUCCESS) { 14854 fp_fillout_old_map(listptr + 14855 *listindex - 1, did_pd, 0); 14856 } 14857 } else { 14858 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0); 14859 } 14860 } else { 14861 mutex_exit(&did_pd->pd_mutex); 14862 mutex_exit(&port->fp_mutex); 14863 } 14864 14865 mutex_enter(&did_pd->pd_mutex); 14866 did_pd->pd_flags = PD_IDLE; 14867 mutex_exit(&did_pd->pd_mutex); 14868 } 14869 14870 14871 /* 14872 * Check with NS for the presence of this port WWN 14873 */ 14874 static int 14875 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd, 14876 job_request_t *job, int polled, int sleep) 14877 { 14878 la_wwn_t pwwn; 14879 uint32_t flags; 14880 fctl_ns_req_t *ns_cmd; 14881 14882 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST); 14883 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14884 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14885 flags, sleep); 14886 if (ns_cmd == NULL) { 14887 return (FC_NOMEM); 14888 } 14889 14890 mutex_enter(&pd->pd_mutex); 14891 pwwn = pd->pd_port_name; 14892 mutex_exit(&pd->pd_mutex); 14893 14894 ns_cmd->ns_cmd_code = NS_GID_PN; 14895 ns_cmd->ns_pd = pd; 14896 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn; 14897 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14898 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14899 14900 return (fp_ns_query(port, ns_cmd, job, polled, sleep)); 14901 } 14902 14903 14904 /* 14905 * Sanity check the LILP map returned by FCA 14906 */ 14907 static int 14908 fp_validate_lilp_map(fc_lilpmap_t *lilp_map) 14909 { 14910 int count; 14911 14912 if (lilp_map->lilp_length == 0) { 14913 return (FC_FAILURE); 14914 } 14915 14916 for (count = 0; count < lilp_map->lilp_length; count++) { 14917 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) != 14918 FC_SUCCESS) { 14919 return (FC_FAILURE); 14920 } 14921 } 14922 14923 return (FC_SUCCESS); 14924 } 14925 14926 14927 /* 14928 * Sanity check if the AL_PA is a valid address 14929 */ 14930 static int 14931 fp_is_valid_alpa(uchar_t al_pa) 14932 { 14933 int count; 14934 14935 for (count = 0; count < sizeof (fp_valid_alpas); count++) { 14936 if (al_pa == fp_valid_alpas[count] || al_pa == 0) { 14937 return (FC_SUCCESS); 14938 } 14939 } 14940 14941 return (FC_FAILURE); 14942 } 14943 14944 14945 /* 14946 * Post unsolicited callbacks to ULPs 14947 */ 14948 static void 14949 fp_ulp_unsol_cb(void *arg) 14950 { 14951 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg; 14952 14953 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf, 14954 ub_spec->buf->ub_frame.type); 14955 kmem_free(ub_spec, sizeof (*ub_spec)); 14956 } 14957 14958 14959 /* 14960 * Perform message reporting in a consistent manner. Unless there is 14961 * a strong reason NOT to use this function (which is very very rare) 14962 * all message reporting should go through this. 14963 */ 14964 static void 14965 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno, 14966 fc_packet_t *pkt, const char *fmt, ...) 14967 { 14968 caddr_t buf; 14969 va_list ap; 14970 14971 switch (level) { 14972 case CE_NOTE: 14973 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) { 14974 return; 14975 } 14976 break; 14977 14978 case CE_WARN: 14979 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) { 14980 return; 14981 } 14982 break; 14983 } 14984 14985 buf = kmem_zalloc(256, KM_NOSLEEP); 14986 if (buf == NULL) { 14987 return; 14988 } 14989 14990 (void) sprintf(buf, "fp(%d): ", port->fp_instance); 14991 14992 va_start(ap, fmt); 14993 (void) vsprintf(buf + strlen(buf), fmt, ap); 14994 va_end(ap); 14995 14996 if (fc_errno) { 14997 char *errmsg; 14998 14999 (void) fc_ulp_error(fc_errno, &errmsg); 15000 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg); 15001 } else { 15002 if (pkt) { 15003 caddr_t state, reason, action, expln; 15004 15005 (void) fc_ulp_pkt_error(pkt, &state, &reason, 15006 &action, &expln); 15007 15008 (void) sprintf(buf + strlen(buf), 15009 " state=%s, reason=%s", state, reason); 15010 15011 if (pkt->pkt_resp_resid) { 15012 (void) sprintf(buf + strlen(buf), 15013 " resp resid=%x\n", pkt->pkt_resp_resid); 15014 } 15015 } 15016 } 15017 15018 switch (dest) { 15019 case FP_CONSOLE_ONLY: 15020 cmn_err(level, "^%s", buf); 15021 break; 15022 15023 case FP_LOG_ONLY: 15024 cmn_err(level, "!%s", buf); 15025 break; 15026 15027 default: 15028 cmn_err(level, "%s", buf); 15029 break; 15030 } 15031 15032 kmem_free(buf, 256); 15033 } 15034 15035 static int 15036 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 15037 { 15038 int ret; 15039 uint32_t d_id; 15040 la_wwn_t pwwn; 15041 fc_remote_port_t *pd = NULL; 15042 fc_remote_port_t *held_pd = NULL; 15043 fctl_ns_req_t *ns_cmd; 15044 fc_portmap_t *changelist; 15045 15046 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 15047 15048 mutex_enter(&port->fp_mutex); 15049 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 15050 mutex_exit(&port->fp_mutex); 15051 job->job_counter = 1; 15052 15053 job->job_result = FC_SUCCESS; 15054 15055 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 15056 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 15057 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 15058 15059 ASSERT(ns_cmd != NULL); 15060 15061 ns_cmd->ns_cmd_code = NS_GID_PN; 15062 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn; 15063 15064 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 15065 15066 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 15067 if (ret != FC_SUCCESS) { 15068 fcio->fcio_errno = ret; 15069 } else { 15070 fcio->fcio_errno = job->job_result; 15071 } 15072 fctl_free_ns_cmd(ns_cmd); 15073 return (EIO); 15074 } 15075 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 15076 fctl_free_ns_cmd(ns_cmd); 15077 } else { 15078 mutex_exit(&port->fp_mutex); 15079 15080 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15081 if (held_pd == NULL) { 15082 fcio->fcio_errno = FC_BADWWN; 15083 return (EIO); 15084 } 15085 pd = held_pd; 15086 15087 mutex_enter(&pd->pd_mutex); 15088 d_id = pd->pd_port_id.port_id; 15089 mutex_exit(&pd->pd_mutex); 15090 } 15091 15092 job->job_counter = 1; 15093 15094 pd = fctl_get_remote_port_by_did(port, d_id); 15095 15096 if (pd) { 15097 mutex_enter(&pd->pd_mutex); 15098 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 15099 pd->pd_login_count++; 15100 mutex_exit(&pd->pd_mutex); 15101 15102 fcio->fcio_errno = FC_SUCCESS; 15103 if (held_pd) { 15104 fctl_release_remote_port(held_pd); 15105 } 15106 15107 return (0); 15108 } 15109 mutex_exit(&pd->pd_mutex); 15110 } else { 15111 mutex_enter(&port->fp_mutex); 15112 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 15113 mutex_exit(&port->fp_mutex); 15114 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 15115 if (pd == NULL) { 15116 fcio->fcio_errno = FC_FAILURE; 15117 if (held_pd) { 15118 fctl_release_remote_port(held_pd); 15119 } 15120 return (EIO); 15121 } 15122 } else { 15123 mutex_exit(&port->fp_mutex); 15124 } 15125 } 15126 15127 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 15128 job->job_counter = 1; 15129 15130 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN, 15131 KM_SLEEP, pd, NULL); 15132 15133 if (ret != FC_SUCCESS) { 15134 fcio->fcio_errno = ret; 15135 if (held_pd) { 15136 fctl_release_remote_port(held_pd); 15137 } 15138 return (EIO); 15139 } 15140 fp_jobwait(job); 15141 15142 fcio->fcio_errno = job->job_result; 15143 15144 if (held_pd) { 15145 fctl_release_remote_port(held_pd); 15146 } 15147 15148 if (job->job_result != FC_SUCCESS) { 15149 return (EIO); 15150 } 15151 15152 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15153 if (pd == NULL) { 15154 fcio->fcio_errno = FC_BADDEV; 15155 return (ENODEV); 15156 } 15157 15158 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15159 15160 fctl_copy_portmap(changelist, pd); 15161 changelist->map_type = PORT_DEVICE_USER_LOGIN; 15162 15163 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15164 15165 mutex_enter(&pd->pd_mutex); 15166 pd->pd_type = PORT_DEVICE_NOCHANGE; 15167 mutex_exit(&pd->pd_mutex); 15168 15169 fctl_release_remote_port(pd); 15170 15171 return (0); 15172 } 15173 15174 15175 static int 15176 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 15177 { 15178 la_wwn_t pwwn; 15179 fp_cmd_t *cmd; 15180 fc_portmap_t *changelist; 15181 fc_remote_port_t *pd; 15182 15183 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 15184 15185 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15186 if (pd == NULL) { 15187 fcio->fcio_errno = FC_BADWWN; 15188 return (ENXIO); 15189 } 15190 15191 mutex_enter(&pd->pd_mutex); 15192 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 15193 fcio->fcio_errno = FC_LOGINREQ; 15194 mutex_exit(&pd->pd_mutex); 15195 15196 fctl_release_remote_port(pd); 15197 15198 return (EINVAL); 15199 } 15200 15201 ASSERT(pd->pd_login_count >= 1); 15202 15203 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 15204 fcio->fcio_errno = FC_FAILURE; 15205 mutex_exit(&pd->pd_mutex); 15206 15207 fctl_release_remote_port(pd); 15208 15209 return (EBUSY); 15210 } 15211 15212 if (pd->pd_login_count > 1) { 15213 pd->pd_login_count--; 15214 fcio->fcio_errno = FC_SUCCESS; 15215 mutex_exit(&pd->pd_mutex); 15216 15217 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15218 15219 fctl_copy_portmap(changelist, pd); 15220 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15221 15222 fctl_release_remote_port(pd); 15223 15224 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15225 15226 return (0); 15227 } 15228 15229 pd->pd_flags = PD_ELS_IN_PROGRESS; 15230 mutex_exit(&pd->pd_mutex); 15231 15232 job->job_counter = 1; 15233 15234 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 15235 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 15236 if (cmd == NULL) { 15237 fcio->fcio_errno = FC_NOMEM; 15238 fctl_release_remote_port(pd); 15239 15240 mutex_enter(&pd->pd_mutex); 15241 pd->pd_flags = PD_IDLE; 15242 mutex_exit(&pd->pd_mutex); 15243 15244 return (ENOMEM); 15245 } 15246 15247 mutex_enter(&port->fp_mutex); 15248 mutex_enter(&pd->pd_mutex); 15249 15250 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 15251 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 15252 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 15253 cmd->cmd_retry_count = 1; 15254 cmd->cmd_ulp_pkt = NULL; 15255 15256 fp_logo_init(pd, cmd, job); 15257 15258 mutex_exit(&pd->pd_mutex); 15259 mutex_exit(&port->fp_mutex); 15260 15261 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 15262 mutex_enter(&pd->pd_mutex); 15263 pd->pd_flags = PD_IDLE; 15264 mutex_exit(&pd->pd_mutex); 15265 15266 fp_free_pkt(cmd); 15267 fctl_release_remote_port(pd); 15268 15269 return (EIO); 15270 } 15271 15272 fp_jobwait(job); 15273 15274 fcio->fcio_errno = job->job_result; 15275 if (job->job_result != FC_SUCCESS) { 15276 mutex_enter(&pd->pd_mutex); 15277 pd->pd_flags = PD_IDLE; 15278 mutex_exit(&pd->pd_mutex); 15279 15280 fctl_release_remote_port(pd); 15281 15282 return (EIO); 15283 } 15284 15285 ASSERT(pd != NULL); 15286 15287 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15288 15289 fctl_copy_portmap(changelist, pd); 15290 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15291 changelist->map_state = PORT_DEVICE_INVALID; 15292 15293 mutex_enter(&port->fp_mutex); 15294 mutex_enter(&pd->pd_mutex); 15295 15296 fctl_delist_did_table(port, pd); 15297 fctl_delist_pwwn_table(port, pd); 15298 pd->pd_flags = PD_IDLE; 15299 15300 mutex_exit(&pd->pd_mutex); 15301 mutex_exit(&port->fp_mutex); 15302 15303 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15304 15305 fctl_release_remote_port(pd); 15306 15307 return (0); 15308 } 15309 15310 15311 15312 /* 15313 * Send a syslog event for adapter port level events. 15314 */ 15315 static void 15316 fp_log_port_event(fc_local_port_t *port, char *subclass) 15317 { 15318 nvlist_t *attr_list; 15319 15320 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15321 KM_SLEEP) != DDI_SUCCESS) { 15322 goto alloc_failed; 15323 } 15324 15325 if (nvlist_add_uint32(attr_list, "instance", 15326 port->fp_instance) != DDI_SUCCESS) { 15327 goto error; 15328 } 15329 15330 if (nvlist_add_byte_array(attr_list, "port-wwn", 15331 port->fp_service_params.nport_ww_name.raw_wwn, 15332 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15333 goto error; 15334 } 15335 15336 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15337 subclass, attr_list, NULL, DDI_SLEEP); 15338 15339 nvlist_free(attr_list); 15340 return; 15341 15342 error: 15343 nvlist_free(attr_list); 15344 alloc_failed: 15345 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15346 } 15347 15348 15349 static void 15350 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn, 15351 uint32_t port_id) 15352 { 15353 nvlist_t *attr_list; 15354 15355 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15356 KM_SLEEP) != DDI_SUCCESS) { 15357 goto alloc_failed; 15358 } 15359 15360 if (nvlist_add_uint32(attr_list, "instance", 15361 port->fp_instance) != DDI_SUCCESS) { 15362 goto error; 15363 } 15364 15365 if (nvlist_add_byte_array(attr_list, "port-wwn", 15366 port->fp_service_params.nport_ww_name.raw_wwn, 15367 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15368 goto error; 15369 } 15370 15371 if (nvlist_add_byte_array(attr_list, "target-port-wwn", 15372 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) { 15373 goto error; 15374 } 15375 15376 if (nvlist_add_uint32(attr_list, "target-port-id", 15377 port_id) != DDI_SUCCESS) { 15378 goto error; 15379 } 15380 15381 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15382 subclass, attr_list, NULL, DDI_SLEEP); 15383 15384 nvlist_free(attr_list); 15385 return; 15386 15387 error: 15388 nvlist_free(attr_list); 15389 alloc_failed: 15390 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15391 } 15392 15393 static uint32_t 15394 fp_map_remote_port_state(uint32_t rm_state) 15395 { 15396 switch (rm_state) { 15397 case PORT_DEVICE_LOGGED_IN: 15398 return (FC_HBA_PORTSTATE_ONLINE); 15399 case PORT_DEVICE_VALID: 15400 case PORT_DEVICE_INVALID: 15401 default: 15402 return (FC_HBA_PORTSTATE_UNKNOWN); 15403 } 15404 }