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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * NOT a DDI compliant Sun Fibre Channel port driver(fp) 26 * 27 */ 28 29 #include <sys/types.h> 30 #include <sys/varargs.h> 31 #include <sys/param.h> 32 #include <sys/errno.h> 33 #include <sys/uio.h> 34 #include <sys/buf.h> 35 #include <sys/modctl.h> 36 #include <sys/open.h> 37 #include <sys/file.h> 38 #include <sys/kmem.h> 39 #include <sys/poll.h> 40 #include <sys/conf.h> 41 #include <sys/thread.h> 42 #include <sys/var.h> 43 #include <sys/cmn_err.h> 44 #include <sys/stat.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/promif.h> 48 #include <sys/nvpair.h> 49 #include <sys/byteorder.h> 50 #include <sys/scsi/scsi.h> 51 #include <sys/fibre-channel/fc.h> 52 #include <sys/fibre-channel/impl/fc_ulpif.h> 53 #include <sys/fibre-channel/impl/fc_fcaif.h> 54 #include <sys/fibre-channel/impl/fctl_private.h> 55 #include <sys/fibre-channel/impl/fc_portif.h> 56 #include <sys/fibre-channel/impl/fp.h> 57 58 /* These are defined in fctl.c! */ 59 extern int did_table_size; 60 extern int pwwn_table_size; 61 62 static struct cb_ops fp_cb_ops = { 63 fp_open, /* open */ 64 fp_close, /* close */ 65 nodev, /* strategy */ 66 nodev, /* print */ 67 nodev, /* dump */ 68 nodev, /* read */ 69 nodev, /* write */ 70 fp_ioctl, /* ioctl */ 71 nodev, /* devmap */ 72 nodev, /* mmap */ 73 nodev, /* segmap */ 74 nochpoll, /* chpoll */ 75 ddi_prop_op, /* cb_prop_op */ 76 0, /* streamtab */ 77 D_NEW | D_MP | D_HOTPLUG, /* cb_flag */ 78 CB_REV, /* rev */ 79 nodev, /* aread */ 80 nodev /* awrite */ 81 }; 82 83 static struct dev_ops fp_ops = { 84 DEVO_REV, /* build revision */ 85 0, /* reference count */ 86 fp_getinfo, /* getinfo */ 87 nulldev, /* identify - Obsoleted */ 88 nulldev, /* probe */ 89 fp_attach, /* attach */ 90 fp_detach, /* detach */ 91 nodev, /* reset */ 92 &fp_cb_ops, /* cb_ops */ 93 NULL, /* bus_ops */ 94 fp_power /* power */ 95 }; 96 97 #define FP_VERSION "1.96" 98 #define FP_NAME_VERSION "SunFC Port v" FP_VERSION 99 100 char *fp_version = FP_NAME_VERSION; 101 102 static struct modldrv modldrv = { 103 &mod_driverops, /* Type of Module */ 104 FP_NAME_VERSION, /* Name/Version of fp */ 105 &fp_ops /* driver ops */ 106 }; 107 108 static struct modlinkage modlinkage = { 109 MODREV_1, /* Rev of the loadable modules system */ 110 &modldrv, /* NULL terminated list of */ 111 NULL /* Linkage structures */ 112 }; 113 114 115 116 static uint16_t ns_reg_cmds[] = { 117 NS_RPN_ID, 118 NS_RNN_ID, 119 NS_RCS_ID, 120 NS_RFT_ID, 121 NS_RPT_ID, 122 NS_RSPN_ID, 123 NS_RSNN_NN 124 }; 125 126 struct fp_xlat { 127 uchar_t xlat_state; 128 int xlat_rval; 129 } fp_xlat [] = { 130 { FC_PKT_SUCCESS, FC_SUCCESS }, 131 { FC_PKT_REMOTE_STOP, FC_FAILURE }, 132 { FC_PKT_LOCAL_RJT, FC_FAILURE }, 133 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT }, 134 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT }, 135 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY }, 136 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY }, 137 { FC_PKT_NPORT_BSY, FC_PBUSY }, 138 { FC_PKT_FABRIC_BSY, FC_FBUSY }, 139 { FC_PKT_LS_RJT, FC_FAILURE }, 140 { FC_PKT_BA_RJT, FC_FAILURE }, 141 { FC_PKT_TIMEOUT, FC_FAILURE }, 142 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR }, 143 { FC_PKT_FAILURE, FC_FAILURE }, 144 { FC_PKT_PORT_OFFLINE, FC_OFFLINE } 145 }; 146 147 static uchar_t fp_valid_alpas[] = { 148 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 149 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 150 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 151 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 152 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 153 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 154 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, 155 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82, 156 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E, 157 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC, 158 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 159 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 160 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 161 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF 162 }; 163 164 static struct fp_perms { 165 uint16_t fp_ioctl_cmd; 166 uchar_t fp_open_flag; 167 } fp_perm_list [] = { 168 { FCIO_GET_NUM_DEVS, FP_OPEN }, 169 { FCIO_GET_DEV_LIST, FP_OPEN }, 170 { FCIO_GET_SYM_PNAME, FP_OPEN }, 171 { FCIO_GET_SYM_NNAME, FP_OPEN }, 172 { FCIO_SET_SYM_PNAME, FP_EXCL }, 173 { FCIO_SET_SYM_NNAME, FP_EXCL }, 174 { FCIO_GET_LOGI_PARAMS, FP_OPEN }, 175 { FCIO_DEV_LOGIN, FP_EXCL }, 176 { FCIO_DEV_LOGOUT, FP_EXCL }, 177 { FCIO_GET_STATE, FP_OPEN }, 178 { FCIO_DEV_REMOVE, FP_EXCL }, 179 { FCIO_GET_FCODE_REV, FP_OPEN }, 180 { FCIO_GET_FW_REV, FP_OPEN }, 181 { FCIO_GET_DUMP_SIZE, FP_OPEN }, 182 { FCIO_FORCE_DUMP, FP_EXCL }, 183 { FCIO_GET_DUMP, FP_OPEN }, 184 { FCIO_GET_TOPOLOGY, FP_OPEN }, 185 { FCIO_RESET_LINK, FP_EXCL }, 186 { FCIO_RESET_HARD, FP_EXCL }, 187 { FCIO_RESET_HARD_CORE, FP_EXCL }, 188 { FCIO_DIAG, FP_OPEN }, 189 { FCIO_NS, FP_EXCL }, 190 { FCIO_DOWNLOAD_FW, FP_EXCL }, 191 { FCIO_DOWNLOAD_FCODE, FP_EXCL }, 192 { FCIO_LINK_STATUS, FP_OPEN }, 193 { FCIO_GET_HOST_PARAMS, FP_OPEN }, 194 { FCIO_GET_NODE_ID, FP_OPEN }, 195 { FCIO_SET_NODE_ID, FP_EXCL }, 196 { FCIO_SEND_NODE_ID, FP_OPEN }, 197 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN }, 198 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN }, 199 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN }, 200 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN }, 201 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN }, 202 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN }, 203 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN }, 204 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN }, 205 { FCIO_DELETE_NPIV_PORT, FP_OPEN }, 206 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN }, 207 { FCIO_CREATE_NPIV_PORT, FP_OPEN }, 208 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN } 209 }; 210 211 static char *fp_pm_comps[] = { 212 "NAME=FC Port", 213 "0=Port Down", 214 "1=Port Up" 215 }; 216 217 218 #ifdef _LITTLE_ENDIAN 219 #define MAKE_BE_32(x) { \ 220 uint32_t *ptr1, i; \ 221 ptr1 = (uint32_t *)(x); \ 222 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \ 223 *ptr1 = BE_32(*ptr1); \ 224 ptr1++; \ 225 } \ 226 } 227 #else 228 #define MAKE_BE_32(x) 229 #endif 230 231 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES); 232 static uint32_t fp_options = 0; 233 234 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY; 235 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */ 236 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */ 237 unsigned int fp_offline_ticker; /* seconds */ 238 239 /* 240 * Driver global variable to anchor the list of soft state structs for 241 * all fp driver instances. Used with the Solaris DDI soft state functions. 242 */ 243 static void *fp_driver_softstate; 244 245 static clock_t fp_retry_ticks; 246 static clock_t fp_offline_ticks; 247 248 static int fp_retry_ticker; 249 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT; 250 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE; 251 252 static int fp_log_size = FP_LOG_SIZE; 253 static int fp_trace = FP_TRACE_DEFAULT; 254 static fc_trace_logq_t *fp_logq = NULL; 255 256 int fp_get_adapter_paths(char *pathList, int count); 257 static void fp_log_port_event(fc_local_port_t *port, char *subclass); 258 static void fp_log_target_event(fc_local_port_t *port, char *subclass, 259 la_wwn_t tgt_pwwn, uint32_t port_id); 260 static uint32_t fp_map_remote_port_state(uint32_t rm_state); 261 static void fp_init_symbolic_names(fc_local_port_t *port); 262 263 264 /* 265 * Perform global initialization 266 */ 267 int 268 _init(void) 269 { 270 int ret; 271 272 if ((ret = ddi_soft_state_init(&fp_driver_softstate, 273 sizeof (struct fc_local_port), 8)) != 0) { 274 return (ret); 275 } 276 277 if ((ret = scsi_hba_init(&modlinkage)) != 0) { 278 ddi_soft_state_fini(&fp_driver_softstate); 279 return (ret); 280 } 281 282 fp_logq = fc_trace_alloc_logq(fp_log_size); 283 284 if ((ret = mod_install(&modlinkage)) != 0) { 285 fc_trace_free_logq(fp_logq); 286 ddi_soft_state_fini(&fp_driver_softstate); 287 scsi_hba_fini(&modlinkage); 288 } 289 290 return (ret); 291 } 292 293 294 /* 295 * Prepare for driver unload 296 */ 297 int 298 _fini(void) 299 { 300 int ret; 301 302 if ((ret = mod_remove(&modlinkage)) == 0) { 303 fc_trace_free_logq(fp_logq); 304 ddi_soft_state_fini(&fp_driver_softstate); 305 scsi_hba_fini(&modlinkage); 306 } 307 308 return (ret); 309 } 310 311 312 /* 313 * Request mod_info() to handle all cases 314 */ 315 int 316 _info(struct modinfo *modinfo) 317 { 318 return (mod_info(&modlinkage, modinfo)); 319 } 320 321 322 /* 323 * fp_attach: 324 * 325 * The respective cmd handlers take care of performing 326 * ULP related invocations 327 */ 328 static int 329 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 330 { 331 int rval; 332 333 /* 334 * We check the value of fp_offline_ticker at this 335 * point. The variable is global for the driver and 336 * not specific to an instance. 337 * 338 * If there is no user-defined value found in /etc/system 339 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER). 340 * The minimum setting for this offline timeout according 341 * to the FC-FS2 standard (Fibre Channel Framing and 342 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec. 343 * 344 * We do not recommend setting the value to less than 10 345 * seconds (RA_TOV) or more than 90 seconds. If this 346 * variable is greater than 90 seconds then drivers above 347 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain. 348 */ 349 350 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY, 351 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker", 352 FP_OFFLINE_TICKER); 353 354 if ((fp_offline_ticker < 10) || 355 (fp_offline_ticker > 90)) { 356 cmn_err(CE_WARN, "Setting fp_offline_ticker to " 357 "%d second(s). This is outside the " 358 "recommended range of 10..90 seconds", 359 fp_offline_ticker); 360 } 361 362 /* 363 * Tick every second when there are commands to retry. 364 * It should tick at the least granular value of pkt_timeout 365 * (which is one second) 366 */ 367 fp_retry_ticker = 1; 368 369 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000); 370 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000); 371 372 switch (cmd) { 373 case DDI_ATTACH: 374 rval = fp_attach_handler(dip); 375 break; 376 377 case DDI_RESUME: 378 rval = fp_resume_handler(dip); 379 break; 380 381 default: 382 rval = DDI_FAILURE; 383 break; 384 } 385 return (rval); 386 } 387 388 389 /* 390 * fp_detach: 391 * 392 * If a ULP fails to handle cmd request converse of 393 * cmd is invoked for ULPs that previously succeeded 394 * cmd request. 395 */ 396 static int 397 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 398 { 399 int rval = DDI_FAILURE; 400 fc_local_port_t *port; 401 fc_attach_cmd_t converse; 402 uint8_t cnt; 403 404 if ((port = ddi_get_soft_state(fp_driver_softstate, 405 ddi_get_instance(dip))) == NULL) { 406 return (DDI_FAILURE); 407 } 408 409 mutex_enter(&port->fp_mutex); 410 411 if (port->fp_ulp_attach) { 412 mutex_exit(&port->fp_mutex); 413 return (DDI_FAILURE); 414 } 415 416 switch (cmd) { 417 case DDI_DETACH: 418 if (port->fp_task != FP_TASK_IDLE) { 419 mutex_exit(&port->fp_mutex); 420 return (DDI_FAILURE); 421 } 422 423 /* Let's attempt to quit the job handler gracefully */ 424 port->fp_soft_state |= FP_DETACH_INPROGRESS; 425 426 mutex_exit(&port->fp_mutex); 427 converse = FC_CMD_ATTACH; 428 if (fctl_detach_ulps(port, FC_CMD_DETACH, 429 &modlinkage) != FC_SUCCESS) { 430 mutex_enter(&port->fp_mutex); 431 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 432 mutex_exit(&port->fp_mutex); 433 rval = DDI_FAILURE; 434 break; 435 } 436 437 mutex_enter(&port->fp_mutex); 438 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt); 439 cnt++) { 440 mutex_exit(&port->fp_mutex); 441 delay(drv_usectohz(1000000)); 442 mutex_enter(&port->fp_mutex); 443 } 444 445 if (port->fp_job_head) { 446 mutex_exit(&port->fp_mutex); 447 rval = DDI_FAILURE; 448 break; 449 } 450 mutex_exit(&port->fp_mutex); 451 452 rval = fp_detach_handler(port); 453 break; 454 455 case DDI_SUSPEND: 456 mutex_exit(&port->fp_mutex); 457 converse = FC_CMD_RESUME; 458 if (fctl_detach_ulps(port, FC_CMD_SUSPEND, 459 &modlinkage) != FC_SUCCESS) { 460 rval = DDI_FAILURE; 461 break; 462 } 463 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) { 464 (void) callb_generic_cpr(&port->fp_cpr_info, 465 CB_CODE_CPR_RESUME); 466 } 467 break; 468 469 default: 470 mutex_exit(&port->fp_mutex); 471 break; 472 } 473 474 /* 475 * Use softint to perform reattach. Mark fp_ulp_attach so we 476 * don't attempt to do this repeatedly on behalf of some persistent 477 * caller. 478 */ 479 if (rval != DDI_SUCCESS) { 480 mutex_enter(&port->fp_mutex); 481 port->fp_ulp_attach = 1; 482 483 /* 484 * If the port is in the low power mode then there is 485 * possibility that fca too could be in low power mode. 486 * Try to raise the power before calling attach ulps. 487 */ 488 489 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 490 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 491 mutex_exit(&port->fp_mutex); 492 (void) pm_raise_power(port->fp_port_dip, 493 FP_PM_COMPONENT, FP_PM_PORT_UP); 494 } else { 495 mutex_exit(&port->fp_mutex); 496 } 497 498 499 fp_attach_ulps(port, converse); 500 501 mutex_enter(&port->fp_mutex); 502 while (port->fp_ulp_attach) { 503 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 504 } 505 506 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 507 508 /* 509 * Mark state as detach failed so asynchronous ULP attach 510 * events (downstream, not the ones we're initiating with 511 * the call to fp_attach_ulps) are not honored. We're 512 * really still in pending detach. 513 */ 514 port->fp_soft_state |= FP_DETACH_FAILED; 515 516 mutex_exit(&port->fp_mutex); 517 } 518 519 return (rval); 520 } 521 522 523 /* 524 * fp_getinfo: 525 * Given the device number, return either the 526 * dev_info_t pointer or the instance number. 527 */ 528 529 /* ARGSUSED */ 530 static int 531 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 532 { 533 int rval; 534 minor_t instance; 535 fc_local_port_t *port; 536 537 rval = DDI_SUCCESS; 538 instance = getminor((dev_t)arg); 539 540 switch (cmd) { 541 case DDI_INFO_DEVT2DEVINFO: 542 if ((port = ddi_get_soft_state(fp_driver_softstate, 543 instance)) == NULL) { 544 rval = DDI_FAILURE; 545 break; 546 } 547 *result = (void *)port->fp_port_dip; 548 break; 549 550 case DDI_INFO_DEVT2INSTANCE: 551 *result = (void *)(uintptr_t)instance; 552 break; 553 554 default: 555 rval = DDI_FAILURE; 556 break; 557 } 558 559 return (rval); 560 } 561 562 563 /* 564 * Entry point for power up and power down request from kernel 565 */ 566 static int 567 fp_power(dev_info_t *dip, int comp, int level) 568 { 569 int rval = DDI_FAILURE; 570 fc_local_port_t *port; 571 572 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 573 if (port == NULL || comp != FP_PM_COMPONENT) { 574 return (rval); 575 } 576 577 switch (level) { 578 case FP_PM_PORT_UP: 579 rval = DDI_SUCCESS; 580 581 /* 582 * If the port is DDI_SUSPENDed, let the DDI_RESUME 583 * code complete the rediscovery. 584 */ 585 mutex_enter(&port->fp_mutex); 586 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 587 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 588 port->fp_pm_level = FP_PM_PORT_UP; 589 mutex_exit(&port->fp_mutex); 590 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage); 591 break; 592 } 593 594 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 595 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 596 597 port->fp_pm_level = FP_PM_PORT_UP; 598 rval = fp_power_up(port); 599 if (rval != DDI_SUCCESS) { 600 port->fp_pm_level = FP_PM_PORT_DOWN; 601 } 602 } else { 603 port->fp_pm_level = FP_PM_PORT_UP; 604 } 605 mutex_exit(&port->fp_mutex); 606 break; 607 608 case FP_PM_PORT_DOWN: 609 mutex_enter(&port->fp_mutex); 610 611 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP)); 612 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 613 /* 614 * PM framework goofed up. We have don't 615 * have any PM components. Let's never go down. 616 */ 617 mutex_exit(&port->fp_mutex); 618 break; 619 620 } 621 622 if (port->fp_ulp_attach) { 623 /* We shouldn't let the power go down */ 624 mutex_exit(&port->fp_mutex); 625 break; 626 } 627 628 /* 629 * Not a whole lot to do if we are detaching 630 */ 631 if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 632 port->fp_pm_level = FP_PM_PORT_DOWN; 633 mutex_exit(&port->fp_mutex); 634 rval = DDI_SUCCESS; 635 break; 636 } 637 638 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) { 639 port->fp_pm_level = FP_PM_PORT_DOWN; 640 641 rval = fp_power_down(port); 642 if (rval != DDI_SUCCESS) { 643 port->fp_pm_level = FP_PM_PORT_UP; 644 ASSERT(!(port->fp_soft_state & 645 FP_SOFT_POWER_DOWN)); 646 } else { 647 ASSERT(port->fp_soft_state & 648 FP_SOFT_POWER_DOWN); 649 } 650 } 651 mutex_exit(&port->fp_mutex); 652 break; 653 654 default: 655 break; 656 } 657 658 return (rval); 659 } 660 661 662 /* 663 * Open FC port devctl node 664 */ 665 static int 666 fp_open(dev_t *devp, int flag, int otype, cred_t *credp) 667 { 668 int instance; 669 fc_local_port_t *port; 670 671 if (otype != OTYP_CHR) { 672 return (EINVAL); 673 } 674 675 /* 676 * This is not a toy to play with. Allow only powerful 677 * users (hopefully knowledgeable) to access the port 678 * (A hacker potentially could download a sick binary 679 * file into FCA) 680 */ 681 if (drv_priv(credp)) { 682 return (EPERM); 683 } 684 685 instance = (int)getminor(*devp); 686 687 port = ddi_get_soft_state(fp_driver_softstate, instance); 688 if (port == NULL) { 689 return (ENXIO); 690 } 691 692 mutex_enter(&port->fp_mutex); 693 if (port->fp_flag & FP_EXCL) { 694 /* 695 * It is already open for exclusive access. 696 * So shut the door on this caller. 697 */ 698 mutex_exit(&port->fp_mutex); 699 return (EBUSY); 700 } 701 702 if (flag & FEXCL) { 703 if (port->fp_flag & FP_OPEN) { 704 /* 705 * Exclusive operation not possible 706 * as it is already opened 707 */ 708 mutex_exit(&port->fp_mutex); 709 return (EBUSY); 710 } 711 port->fp_flag |= FP_EXCL; 712 } 713 port->fp_flag |= FP_OPEN; 714 mutex_exit(&port->fp_mutex); 715 716 return (0); 717 } 718 719 720 /* 721 * The driver close entry point is called on the last close() 722 * of a device. So it is perfectly alright to just clobber the 723 * open flag and reset it to idle (instead of having to reset 724 * each flag bits). For any confusion, check out close(9E). 725 */ 726 727 /* ARGSUSED */ 728 static int 729 fp_close(dev_t dev, int flag, int otype, cred_t *credp) 730 { 731 int instance; 732 fc_local_port_t *port; 733 734 if (otype != OTYP_CHR) { 735 return (EINVAL); 736 } 737 738 instance = (int)getminor(dev); 739 740 port = ddi_get_soft_state(fp_driver_softstate, instance); 741 if (port == NULL) { 742 return (ENXIO); 743 } 744 745 mutex_enter(&port->fp_mutex); 746 if ((port->fp_flag & FP_OPEN) == 0) { 747 mutex_exit(&port->fp_mutex); 748 return (ENODEV); 749 } 750 port->fp_flag = FP_IDLE; 751 mutex_exit(&port->fp_mutex); 752 753 return (0); 754 } 755 756 /* 757 * Handle IOCTL requests 758 */ 759 760 /* ARGSUSED */ 761 static int 762 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval) 763 { 764 int instance; 765 int ret = 0; 766 fcio_t fcio; 767 fc_local_port_t *port; 768 769 instance = (int)getminor(dev); 770 771 port = ddi_get_soft_state(fp_driver_softstate, instance); 772 if (port == NULL) { 773 return (ENXIO); 774 } 775 776 mutex_enter(&port->fp_mutex); 777 if ((port->fp_flag & FP_OPEN) == 0) { 778 mutex_exit(&port->fp_mutex); 779 return (ENXIO); 780 } 781 782 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 783 mutex_exit(&port->fp_mutex); 784 return (ENXIO); 785 } 786 787 mutex_exit(&port->fp_mutex); 788 789 /* this will raise power if necessary */ 790 ret = fctl_busy_port(port); 791 if (ret != 0) { 792 return (ret); 793 } 794 795 ASSERT(port->fp_pm_level == FP_PM_PORT_UP); 796 797 798 switch (cmd) { 799 case FCIO_CMD: { 800 #ifdef _MULTI_DATAMODEL 801 switch (ddi_model_convert_from(mode & FMODELS)) { 802 case DDI_MODEL_ILP32: { 803 struct fcio32 fcio32; 804 805 if (ddi_copyin((void *)data, (void *)&fcio32, 806 sizeof (struct fcio32), mode)) { 807 ret = EFAULT; 808 break; 809 } 810 fcio.fcio_xfer = fcio32.fcio_xfer; 811 fcio.fcio_cmd = fcio32.fcio_cmd; 812 fcio.fcio_flags = fcio32.fcio_flags; 813 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags; 814 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen; 815 fcio.fcio_ibuf = 816 (caddr_t)(uintptr_t)fcio32.fcio_ibuf; 817 fcio.fcio_olen = (size_t)fcio32.fcio_olen; 818 fcio.fcio_obuf = 819 (caddr_t)(uintptr_t)fcio32.fcio_obuf; 820 fcio.fcio_alen = (size_t)fcio32.fcio_alen; 821 fcio.fcio_abuf = 822 (caddr_t)(uintptr_t)fcio32.fcio_abuf; 823 fcio.fcio_errno = fcio32.fcio_errno; 824 break; 825 } 826 827 case DDI_MODEL_NONE: 828 if (ddi_copyin((void *)data, (void *)&fcio, 829 sizeof (fcio_t), mode)) { 830 ret = EFAULT; 831 } 832 break; 833 } 834 #else /* _MULTI_DATAMODEL */ 835 if (ddi_copyin((void *)data, (void *)&fcio, 836 sizeof (fcio_t), mode)) { 837 ret = EFAULT; 838 break; 839 } 840 #endif /* _MULTI_DATAMODEL */ 841 if (!ret) { 842 ret = fp_fciocmd(port, data, mode, &fcio); 843 } 844 break; 845 } 846 847 default: 848 ret = fctl_ulp_port_ioctl(port, dev, cmd, data, 849 mode, credp, rval); 850 } 851 852 fctl_idle_port(port); 853 854 return (ret); 855 } 856 857 858 /* 859 * Init Symbolic Port Name and Node Name 860 * LV will try to get symbolic names from FCA driver 861 * and register these to name server, 862 * if LV fails to get these, 863 * LV will register its default symbolic names to name server. 864 * The Default symbolic node name format is : 865 * <hostname>:<hba driver name>(instance) 866 * The Default symbolic port name format is : 867 * <fp path name> 868 */ 869 static void 870 fp_init_symbolic_names(fc_local_port_t *port) 871 { 872 const char *vendorname = ddi_driver_name(port->fp_fca_dip); 873 char *sym_name; 874 char fcaname[50] = {0}; 875 int hostnlen, fcanlen; 876 877 if (port->fp_sym_node_namelen == 0) { 878 hostnlen = strlen(utsname.nodename); 879 (void) snprintf(fcaname, sizeof (fcaname), 880 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip)); 881 fcanlen = strlen(fcaname); 882 883 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP); 884 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname); 885 port->fp_sym_node_namelen = strlen(sym_name); 886 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) { 887 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN; 888 } 889 (void) strncpy(port->fp_sym_node_name, sym_name, 890 port->fp_sym_node_namelen); 891 kmem_free(sym_name, hostnlen + fcanlen + 2); 892 } 893 894 if (port->fp_sym_port_namelen == 0) { 895 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 896 897 (void) ddi_pathname(port->fp_port_dip, pathname); 898 port->fp_sym_port_namelen = strlen(pathname); 899 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) { 900 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN; 901 } 902 (void) strncpy(port->fp_sym_port_name, pathname, 903 port->fp_sym_port_namelen); 904 kmem_free(pathname, MAXPATHLEN); 905 } 906 } 907 908 909 /* 910 * Perform port attach 911 */ 912 static int 913 fp_attach_handler(dev_info_t *dip) 914 { 915 int rval; 916 int instance; 917 int port_num; 918 int port_len; 919 char name[30]; 920 char i_pwwn[17]; 921 fp_cmd_t *pkt; 922 uint32_t ub_count; 923 fc_local_port_t *port; 924 job_request_t *job; 925 fc_local_port_t *phyport = NULL; 926 int portpro1; 927 char pwwn[17], nwwn[17]; 928 929 instance = ddi_get_instance(dip); 930 931 port_len = sizeof (port_num); 932 933 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 934 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 935 (caddr_t)&port_num, &port_len); 936 937 if (rval != DDI_SUCCESS) { 938 cmn_err(CE_WARN, "fp(%d): No port property in devinfo", 939 instance); 940 return (DDI_FAILURE); 941 } 942 943 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 944 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 945 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node", 946 instance); 947 return (DDI_FAILURE); 948 } 949 950 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance, 951 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 952 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment" 953 " point minor node", instance); 954 ddi_remove_minor_node(dip, NULL); 955 return (DDI_FAILURE); 956 } 957 958 if (ddi_soft_state_zalloc(fp_driver_softstate, instance) 959 != DDI_SUCCESS) { 960 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state", 961 instance); 962 ddi_remove_minor_node(dip, NULL); 963 return (DDI_FAILURE); 964 } 965 port = ddi_get_soft_state(fp_driver_softstate, instance); 966 967 (void) sprintf(port->fp_ibuf, "fp(%d)", instance); 968 969 port->fp_instance = instance; 970 port->fp_ulp_attach = 1; 971 port->fp_port_num = port_num; 972 port->fp_verbose = fp_verbosity; 973 port->fp_options = fp_options; 974 975 port->fp_fca_dip = ddi_get_parent(dip); 976 port->fp_port_dip = dip; 977 port->fp_fca_tran = (fc_fca_tran_t *) 978 ddi_get_driver_private(port->fp_fca_dip); 979 980 port->fp_task = port->fp_last_task = FP_TASK_IDLE; 981 982 /* 983 * Init the starting value of fp_rscn_count. Note that if 984 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the 985 * actual # of RSCNs will be (fp_rscn_count - 1) 986 */ 987 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1; 988 989 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL); 990 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL); 991 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL); 992 993 (void) sprintf(name, "fp%d_cache", instance); 994 995 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY, 996 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 997 "phyport-instance", -1)) != -1) { 998 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1); 999 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn); 1000 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn); 1001 port->fp_npiv_type = FC_NPIV_PORT; 1002 } 1003 1004 /* 1005 * Allocate the pool of fc_packet_t structs to be used with 1006 * this fp instance. 1007 */ 1008 port->fp_pkt_cache = kmem_cache_create(name, 1009 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8, 1010 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port, 1011 NULL, 0); 1012 1013 if (port->fp_pkt_cache == NULL) { 1014 goto cache_alloc_failed; 1015 } 1016 1017 1018 /* 1019 * Allocate the d_id and pwwn hash tables for all remote ports 1020 * connected to this local port. 1021 */ 1022 port->fp_did_table = kmem_zalloc(did_table_size * 1023 sizeof (struct d_id_hash), KM_SLEEP); 1024 1025 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size * 1026 sizeof (struct pwwn_hash), KM_SLEEP); 1027 1028 port->fp_taskq = taskq_create("fp_ulp_callback", 1, 1029 MINCLSYSPRI, 1, 16, 0); 1030 1031 /* Indicate that don't have the pm components yet */ 1032 port->fp_soft_state |= FP_SOFT_NO_PMCOMP; 1033 1034 /* 1035 * Bind the callbacks with the FCA driver. This will open the gate 1036 * for asynchronous callbacks, so after this call the fp_mutex 1037 * must be held when updating the fc_local_port_t struct. 1038 * 1039 * This is done _before_ setting up the job thread so we can avoid 1040 * cleaning up after the thread_create() in the error path. This 1041 * also means fp will be operating with fp_els_resp_pkt set to NULL. 1042 */ 1043 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1044 goto bind_callbacks_failed; 1045 } 1046 1047 if (phyport) { 1048 mutex_enter(&phyport->fp_mutex); 1049 if (phyport->fp_port_next) { 1050 phyport->fp_port_next->fp_port_prev = port; 1051 port->fp_port_next = phyport->fp_port_next; 1052 phyport->fp_port_next = port; 1053 port->fp_port_prev = phyport; 1054 } else { 1055 phyport->fp_port_next = port; 1056 phyport->fp_port_prev = port; 1057 port->fp_port_next = phyport; 1058 port->fp_port_prev = phyport; 1059 } 1060 mutex_exit(&phyport->fp_mutex); 1061 } 1062 1063 /* 1064 * Init Symbolic Names 1065 */ 1066 fp_init_symbolic_names(port); 1067 1068 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t), 1069 KM_SLEEP, NULL); 1070 1071 if (pkt == NULL) { 1072 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet", 1073 instance); 1074 goto alloc_els_packet_failed; 1075 } 1076 1077 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN, 1078 v.v_maxsyspri - 2); 1079 1080 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn); 1081 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port", 1082 i_pwwn) != DDI_PROP_SUCCESS) { 1083 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1084 "fp(%d): Updating 'initiator-port' property" 1085 " on fp dev_info node failed", instance); 1086 } 1087 1088 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn); 1089 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node", 1090 i_pwwn) != DDI_PROP_SUCCESS) { 1091 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1092 "fp(%d): Updating 'initiator-node' property" 1093 " on fp dev_info node failed", instance); 1094 } 1095 1096 mutex_enter(&port->fp_mutex); 1097 port->fp_els_resp_pkt = pkt; 1098 mutex_exit(&port->fp_mutex); 1099 1100 /* 1101 * Determine the count of unsolicited buffers this FCA can support 1102 */ 1103 fp_retrieve_caps(port); 1104 1105 /* 1106 * Allocate unsolicited buffer tokens 1107 */ 1108 if (port->fp_ub_count) { 1109 ub_count = port->fp_ub_count; 1110 port->fp_ub_tokens = kmem_zalloc(ub_count * 1111 sizeof (*port->fp_ub_tokens), KM_SLEEP); 1112 /* 1113 * Do not fail the attach if unsolicited buffer allocation 1114 * fails; Just try to get along with whatever the FCA can do. 1115 */ 1116 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size, 1117 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) != 1118 FC_SUCCESS || ub_count != port->fp_ub_count) { 1119 cmn_err(CE_WARN, "fp(%d): failed to allocate " 1120 " Unsolicited buffers. proceeding with attach...", 1121 instance); 1122 kmem_free(port->fp_ub_tokens, 1123 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1124 port->fp_ub_tokens = NULL; 1125 } 1126 } 1127 1128 fp_load_ulp_modules(dip, port); 1129 1130 /* 1131 * Enable DDI_SUSPEND and DDI_RESUME for this instance. 1132 */ 1133 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 1134 "pm-hardware-state", "needs-suspend-resume", 1135 strlen("needs-suspend-resume") + 1); 1136 1137 /* 1138 * fctl maintains a list of all port handles, so 1139 * help fctl add this one to its list now. 1140 */ 1141 mutex_enter(&port->fp_mutex); 1142 fctl_add_port(port); 1143 1144 /* 1145 * If a state change is already in progress, set the bind state t 1146 * OFFLINE as well, so further state change callbacks into ULPs 1147 * will pass the appropriate states 1148 */ 1149 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE || 1150 port->fp_statec_busy) { 1151 port->fp_bind_state = FC_STATE_OFFLINE; 1152 mutex_exit(&port->fp_mutex); 1153 1154 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 1155 } else { 1156 /* 1157 * Without dropping the mutex, ensure that the port 1158 * startup happens ahead of state change callback 1159 * processing 1160 */ 1161 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL); 1162 1163 port->fp_last_task = port->fp_task; 1164 port->fp_task = FP_TASK_PORT_STARTUP; 1165 1166 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC, 1167 fp_startup_done, (opaque_t)port, KM_SLEEP); 1168 1169 port->fp_job_head = port->fp_job_tail = job; 1170 1171 cv_signal(&port->fp_cv); 1172 1173 mutex_exit(&port->fp_mutex); 1174 } 1175 1176 mutex_enter(&port->fp_mutex); 1177 while (port->fp_ulp_attach) { 1178 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 1179 } 1180 mutex_exit(&port->fp_mutex); 1181 1182 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1183 "pm-components", fp_pm_comps, 1184 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) != 1185 DDI_PROP_SUCCESS) { 1186 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM" 1187 " components property, PM disabled on this port."); 1188 mutex_enter(&port->fp_mutex); 1189 port->fp_pm_level = FP_PM_PORT_UP; 1190 mutex_exit(&port->fp_mutex); 1191 } else { 1192 if (pm_raise_power(dip, FP_PM_COMPONENT, 1193 FP_PM_PORT_UP) != DDI_SUCCESS) { 1194 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise" 1195 " power level"); 1196 mutex_enter(&port->fp_mutex); 1197 port->fp_pm_level = FP_PM_PORT_UP; 1198 mutex_exit(&port->fp_mutex); 1199 } 1200 1201 /* 1202 * Don't unset the FP_SOFT_NO_PMCOMP flag until after 1203 * the call to pm_raise_power. The PM framework can't 1204 * handle multiple threads calling into it during attach. 1205 */ 1206 1207 mutex_enter(&port->fp_mutex); 1208 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP; 1209 mutex_exit(&port->fp_mutex); 1210 } 1211 1212 ddi_report_dev(dip); 1213 1214 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH); 1215 1216 return (DDI_SUCCESS); 1217 1218 /* 1219 * Unwind any/all preceeding allocations in the event of an error. 1220 */ 1221 1222 alloc_els_packet_failed: 1223 1224 if (port->fp_fca_handle != NULL) { 1225 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1226 port->fp_fca_handle = NULL; 1227 } 1228 1229 if (port->fp_ub_tokens != NULL) { 1230 (void) fc_ulp_ubfree(port, port->fp_ub_count, 1231 port->fp_ub_tokens); 1232 kmem_free(port->fp_ub_tokens, 1233 port->fp_ub_count * sizeof (*port->fp_ub_tokens)); 1234 port->fp_ub_tokens = NULL; 1235 } 1236 1237 if (port->fp_els_resp_pkt != NULL) { 1238 fp_free_pkt(port->fp_els_resp_pkt); 1239 port->fp_els_resp_pkt = NULL; 1240 } 1241 1242 bind_callbacks_failed: 1243 1244 if (port->fp_taskq != NULL) { 1245 taskq_destroy(port->fp_taskq); 1246 } 1247 1248 if (port->fp_pwwn_table != NULL) { 1249 kmem_free(port->fp_pwwn_table, 1250 pwwn_table_size * sizeof (struct pwwn_hash)); 1251 port->fp_pwwn_table = NULL; 1252 } 1253 1254 if (port->fp_did_table != NULL) { 1255 kmem_free(port->fp_did_table, 1256 did_table_size * sizeof (struct d_id_hash)); 1257 port->fp_did_table = NULL; 1258 } 1259 1260 if (port->fp_pkt_cache != NULL) { 1261 kmem_cache_destroy(port->fp_pkt_cache); 1262 port->fp_pkt_cache = NULL; 1263 } 1264 1265 cache_alloc_failed: 1266 1267 cv_destroy(&port->fp_attach_cv); 1268 cv_destroy(&port->fp_cv); 1269 mutex_destroy(&port->fp_mutex); 1270 ddi_remove_minor_node(port->fp_port_dip, NULL); 1271 ddi_soft_state_free(fp_driver_softstate, instance); 1272 ddi_prop_remove_all(dip); 1273 1274 return (DDI_FAILURE); 1275 } 1276 1277 1278 /* 1279 * Handle DDI_RESUME request 1280 */ 1281 static int 1282 fp_resume_handler(dev_info_t *dip) 1283 { 1284 int rval; 1285 fc_local_port_t *port; 1286 1287 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 1288 1289 ASSERT(port != NULL); 1290 1291 #ifdef DEBUG 1292 mutex_enter(&port->fp_mutex); 1293 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND); 1294 mutex_exit(&port->fp_mutex); 1295 #endif 1296 1297 /* 1298 * If the port was power suspended, raise the power level 1299 */ 1300 mutex_enter(&port->fp_mutex); 1301 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 1302 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 1303 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 1304 1305 mutex_exit(&port->fp_mutex); 1306 if (pm_raise_power(dip, FP_PM_COMPONENT, 1307 FP_PM_PORT_UP) != DDI_SUCCESS) { 1308 FP_TRACE(FP_NHEAD2(9, 0), 1309 "Failed to raise the power level"); 1310 return (DDI_FAILURE); 1311 } 1312 mutex_enter(&port->fp_mutex); 1313 } 1314 port->fp_soft_state &= ~FP_SOFT_SUSPEND; 1315 mutex_exit(&port->fp_mutex); 1316 1317 /* 1318 * All the discovery is initiated and handled by per-port thread. 1319 * Further all the discovery is done in handled in callback mode 1320 * (not polled mode); In a specific case such as this, the discovery 1321 * is required to happen in polled mode. The easiest way out is 1322 * to bail out port thread and get started. Come back and fix this 1323 * to do on demand discovery initiated by ULPs. ULPs such as FCP 1324 * will do on-demand discovery during pre-power-up busctl handling 1325 * which will only be possible when SCSA provides a new HBA vector 1326 * for sending down the PM busctl requests. 1327 */ 1328 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME); 1329 1330 rval = fp_resume_all(port, FC_CMD_RESUME); 1331 if (rval != DDI_SUCCESS) { 1332 mutex_enter(&port->fp_mutex); 1333 port->fp_soft_state |= FP_SOFT_SUSPEND; 1334 mutex_exit(&port->fp_mutex); 1335 (void) callb_generic_cpr(&port->fp_cpr_info, 1336 CB_CODE_CPR_CHKPT); 1337 } 1338 1339 return (rval); 1340 } 1341 1342 /* 1343 * Perform FC Port power on initialization 1344 */ 1345 static int 1346 fp_power_up(fc_local_port_t *port) 1347 { 1348 int rval; 1349 1350 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1351 1352 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0); 1353 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN); 1354 1355 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1356 1357 mutex_exit(&port->fp_mutex); 1358 1359 rval = fp_resume_all(port, FC_CMD_POWER_UP); 1360 if (rval != DDI_SUCCESS) { 1361 mutex_enter(&port->fp_mutex); 1362 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1363 } else { 1364 mutex_enter(&port->fp_mutex); 1365 } 1366 1367 return (rval); 1368 } 1369 1370 1371 /* 1372 * It is important to note that the power may possibly be removed between 1373 * SUSPEND and the ensuing RESUME operation. In such a context the underlying 1374 * FC port hardware would have gone through an OFFLINE to ONLINE transition 1375 * (hardware state). In this case, the port driver may need to rediscover the 1376 * topology, perform LOGINs, register with the name server again and perform 1377 * any such port initialization procedures. To perform LOGINs, the driver could 1378 * use the port device handle to see if a LOGIN needs to be performed and use 1379 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured 1380 * or removed) which will be reflected in the map the ULPs will see. 1381 */ 1382 static int 1383 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd) 1384 { 1385 1386 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1387 1388 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1389 return (DDI_FAILURE); 1390 } 1391 1392 mutex_enter(&port->fp_mutex); 1393 1394 /* 1395 * If there are commands queued for delayed retry, instead of 1396 * working the hard way to figure out which ones are good for 1397 * restart and which ones not (ELSs are definitely not good 1398 * as the port will have to go through a new spin of rediscovery 1399 * now), so just flush them out. 1400 */ 1401 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) { 1402 fp_cmd_t *cmd; 1403 1404 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT; 1405 1406 mutex_exit(&port->fp_mutex); 1407 while ((cmd = fp_deque_cmd(port)) != NULL) { 1408 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 1409 fp_iodone(cmd); 1410 } 1411 mutex_enter(&port->fp_mutex); 1412 } 1413 1414 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) { 1415 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) || 1416 port->fp_dev_count) { 1417 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1418 port->fp_offline_tid = timeout(fp_offline_timeout, 1419 (caddr_t)port, fp_offline_ticks); 1420 } 1421 if (port->fp_job_head) { 1422 cv_signal(&port->fp_cv); 1423 } 1424 mutex_exit(&port->fp_mutex); 1425 fctl_attach_ulps(port, cmd, &modlinkage); 1426 } else { 1427 struct job_request *job; 1428 1429 /* 1430 * If an OFFLINE timer was running at the time of 1431 * suspending, there is no need to restart it as 1432 * the port is ONLINE now. 1433 */ 1434 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1435 if (port->fp_statec_busy == 0) { 1436 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 1437 } 1438 port->fp_statec_busy++; 1439 mutex_exit(&port->fp_mutex); 1440 1441 job = fctl_alloc_job(JOB_PORT_ONLINE, 1442 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP); 1443 fctl_enque_job(port, job); 1444 1445 fctl_jobwait(job); 1446 fctl_remove_oldies(port); 1447 1448 fctl_attach_ulps(port, cmd, &modlinkage); 1449 fctl_dealloc_job(job); 1450 } 1451 1452 return (DDI_SUCCESS); 1453 } 1454 1455 1456 /* 1457 * At this time, there shouldn't be any I/O requests on this port. 1458 * But the unsolicited callbacks from the underlying FCA port need 1459 * to be handled very carefully. The steps followed to handle the 1460 * DDI_DETACH are: 1461 * + Grab the port driver mutex, check if the unsolicited 1462 * callback is currently under processing. If true, fail 1463 * the DDI_DETACH request by printing a message; If false 1464 * mark the DDI_DETACH as under progress, so that any 1465 * further unsolicited callbacks get bounced. 1466 * + Perform PRLO/LOGO if necessary, cleanup all the data 1467 * structures. 1468 * + Get the job_handler thread to gracefully exit. 1469 * + Unregister callbacks with the FCA port. 1470 * + Now that some peace is found, notify all the ULPs of 1471 * DDI_DETACH request (using ulp_port_detach entry point) 1472 * + Free all mutexes, semaphores, conditional variables. 1473 * + Free the soft state, return success. 1474 * 1475 * Important considerations: 1476 * Port driver de-registers state change and unsolicited 1477 * callbacks before taking up the task of notifying ULPs 1478 * and performing PRLO and LOGOs. 1479 * 1480 * A port may go offline at the time PRLO/LOGO is being 1481 * requested. It is expected of all FCA drivers to fail 1482 * such requests either immediately with a FC_OFFLINE 1483 * return code to fc_fca_transport() or return the packet 1484 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE 1485 */ 1486 static int 1487 fp_detach_handler(fc_local_port_t *port) 1488 { 1489 job_request_t *job; 1490 uint32_t delay_count; 1491 fc_orphan_t *orp, *tmporp; 1492 1493 /* 1494 * In a Fabric topology with many host ports connected to 1495 * a switch, another detaching instance of fp might have 1496 * triggered a LOGO (which is an unsolicited request to 1497 * this instance). So in order to be able to successfully 1498 * detach by taking care of such cases a delay of about 1499 * 30 seconds is introduced. 1500 */ 1501 delay_count = 0; 1502 mutex_enter(&port->fp_mutex); 1503 while ((port->fp_soft_state & 1504 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) && 1505 (delay_count < 30)) { 1506 mutex_exit(&port->fp_mutex); 1507 delay_count++; 1508 delay(drv_usectohz(1000000)); 1509 mutex_enter(&port->fp_mutex); 1510 } 1511 1512 if (port->fp_soft_state & 1513 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) { 1514 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1515 mutex_exit(&port->fp_mutex); 1516 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1517 " Failing detach", port->fp_instance); 1518 return (DDI_FAILURE); 1519 } 1520 1521 port->fp_soft_state |= FP_SOFT_IN_DETACH; 1522 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1523 mutex_exit(&port->fp_mutex); 1524 1525 /* 1526 * If we're powered down, we need to raise power prior to submitting 1527 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never 1528 * process the shutdown job. 1529 */ 1530 if (fctl_busy_port(port) != 0) { 1531 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed", 1532 port->fp_instance); 1533 mutex_enter(&port->fp_mutex); 1534 port->fp_soft_state &= ~FP_SOFT_IN_DETACH; 1535 mutex_exit(&port->fp_mutex); 1536 return (DDI_FAILURE); 1537 } 1538 1539 /* 1540 * This will deallocate data structs and cause the "job" thread 1541 * to exit, in preparation for DDI_DETACH on the instance. 1542 * This can sleep for an arbitrary duration, since it waits for 1543 * commands over the wire, timeout(9F) callbacks, etc. 1544 * 1545 * CAUTION: There is still a race here, where the "job" thread 1546 * can still be executing code even tho the fctl_jobwait() call 1547 * below has returned to us. In theory the fp driver could even be 1548 * modunloaded even tho the job thread isn't done executing. 1549 * without creating the race condition. 1550 */ 1551 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL, 1552 (opaque_t)port, KM_SLEEP); 1553 fctl_enque_job(port, job); 1554 fctl_jobwait(job); 1555 fctl_dealloc_job(job); 1556 1557 1558 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT, 1559 FP_PM_PORT_DOWN); 1560 1561 if (port->fp_taskq) { 1562 taskq_destroy(port->fp_taskq); 1563 } 1564 1565 ddi_prop_remove_all(port->fp_port_dip); 1566 1567 ddi_remove_minor_node(port->fp_port_dip, NULL); 1568 1569 fctl_remove_port(port); 1570 1571 fp_free_pkt(port->fp_els_resp_pkt); 1572 1573 if (port->fp_ub_tokens) { 1574 if (fc_ulp_ubfree(port, port->fp_ub_count, 1575 port->fp_ub_tokens) != FC_SUCCESS) { 1576 cmn_err(CE_WARN, "fp(%d): couldn't free " 1577 " unsolicited buffers", port->fp_instance); 1578 } 1579 kmem_free(port->fp_ub_tokens, 1580 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1581 port->fp_ub_tokens = NULL; 1582 } 1583 1584 if (port->fp_pkt_cache != NULL) { 1585 kmem_cache_destroy(port->fp_pkt_cache); 1586 } 1587 1588 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1589 1590 mutex_enter(&port->fp_mutex); 1591 if (port->fp_did_table) { 1592 kmem_free(port->fp_did_table, did_table_size * 1593 sizeof (struct d_id_hash)); 1594 } 1595 1596 if (port->fp_pwwn_table) { 1597 kmem_free(port->fp_pwwn_table, pwwn_table_size * 1598 sizeof (struct pwwn_hash)); 1599 } 1600 orp = port->fp_orphan_list; 1601 while (orp) { 1602 tmporp = orp; 1603 orp = orp->orp_next; 1604 kmem_free(tmporp, sizeof (*orp)); 1605 } 1606 1607 mutex_exit(&port->fp_mutex); 1608 1609 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH); 1610 1611 mutex_destroy(&port->fp_mutex); 1612 cv_destroy(&port->fp_attach_cv); 1613 cv_destroy(&port->fp_cv); 1614 ddi_soft_state_free(fp_driver_softstate, port->fp_instance); 1615 1616 return (DDI_SUCCESS); 1617 } 1618 1619 1620 /* 1621 * Steps to perform DDI_SUSPEND operation on a FC port 1622 * 1623 * - If already suspended return DDI_FAILURE 1624 * - If already power-suspended return DDI_SUCCESS 1625 * - If an unsolicited callback or state change handling is in 1626 * in progress, throw a warning message, return DDI_FAILURE 1627 * - Cancel timeouts 1628 * - SUSPEND the job_handler thread (means do nothing as it is 1629 * taken care of by the CPR frame work) 1630 */ 1631 static int 1632 fp_suspend_handler(fc_local_port_t *port) 1633 { 1634 uint32_t delay_count; 1635 1636 mutex_enter(&port->fp_mutex); 1637 1638 /* 1639 * The following should never happen, but 1640 * let the driver be more defensive here 1641 */ 1642 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1643 mutex_exit(&port->fp_mutex); 1644 return (DDI_FAILURE); 1645 } 1646 1647 /* 1648 * If the port is already power suspended, there 1649 * is nothing else to do, So return DDI_SUCCESS, 1650 * but mark the SUSPEND bit in the soft state 1651 * before leaving. 1652 */ 1653 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1654 port->fp_soft_state |= FP_SOFT_SUSPEND; 1655 mutex_exit(&port->fp_mutex); 1656 return (DDI_SUCCESS); 1657 } 1658 1659 /* 1660 * Check if an unsolicited callback or state change handling is 1661 * in progress. If true, fail the suspend operation; also throw 1662 * a warning message notifying the failure. Note that Sun PCI 1663 * hotplug spec recommends messages in cases of failure (but 1664 * not flooding the console) 1665 * 1666 * Busy waiting for a short interval (500 millisecond ?) to see 1667 * if the callback processing completes may be another idea. Since 1668 * most of the callback processing involves a lot of work, it 1669 * is safe to just fail the SUSPEND operation. It is definitely 1670 * not bad to fail the SUSPEND operation if the driver is busy. 1671 */ 1672 delay_count = 0; 1673 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1674 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) { 1675 mutex_exit(&port->fp_mutex); 1676 delay_count++; 1677 delay(drv_usectohz(1000000)); 1678 mutex_enter(&port->fp_mutex); 1679 } 1680 1681 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1682 FP_SOFT_IN_UNSOL_CB)) { 1683 mutex_exit(&port->fp_mutex); 1684 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1685 " Failing suspend", port->fp_instance); 1686 return (DDI_FAILURE); 1687 } 1688 1689 /* 1690 * Check of FC port thread is busy 1691 */ 1692 if (port->fp_job_head) { 1693 mutex_exit(&port->fp_mutex); 1694 FP_TRACE(FP_NHEAD2(9, 0), 1695 "FC port thread is busy: Failing suspend"); 1696 return (DDI_FAILURE); 1697 } 1698 port->fp_soft_state |= FP_SOFT_SUSPEND; 1699 1700 fp_suspend_all(port); 1701 mutex_exit(&port->fp_mutex); 1702 1703 return (DDI_SUCCESS); 1704 } 1705 1706 1707 /* 1708 * Prepare for graceful power down of a FC port 1709 */ 1710 static int 1711 fp_power_down(fc_local_port_t *port) 1712 { 1713 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1714 1715 /* 1716 * Power down request followed by a DDI_SUSPEND should 1717 * never happen; If it does return DDI_SUCCESS 1718 */ 1719 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1720 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1721 return (DDI_SUCCESS); 1722 } 1723 1724 /* 1725 * If the port is already power suspended, there 1726 * is nothing else to do, So return DDI_SUCCESS, 1727 */ 1728 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1729 return (DDI_SUCCESS); 1730 } 1731 1732 /* 1733 * Check if an unsolicited callback or state change handling 1734 * is in progress. If true, fail the PM suspend operation. 1735 * But don't print a message unless the verbosity of the 1736 * driver desires otherwise. 1737 */ 1738 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) || 1739 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) { 1740 FP_TRACE(FP_NHEAD2(9, 0), 1741 "Unsolicited callback in progress: Failing power down"); 1742 return (DDI_FAILURE); 1743 } 1744 1745 /* 1746 * Check of FC port thread is busy 1747 */ 1748 if (port->fp_job_head) { 1749 FP_TRACE(FP_NHEAD2(9, 0), 1750 "FC port thread is busy: Failing power down"); 1751 return (DDI_FAILURE); 1752 } 1753 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1754 1755 /* 1756 * check if the ULPs are ready for power down 1757 */ 1758 mutex_exit(&port->fp_mutex); 1759 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN, 1760 &modlinkage) != FC_SUCCESS) { 1761 mutex_enter(&port->fp_mutex); 1762 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1763 mutex_exit(&port->fp_mutex); 1764 1765 /* 1766 * Power back up the obedient ULPs that went down 1767 */ 1768 fp_attach_ulps(port, FC_CMD_POWER_UP); 1769 1770 FP_TRACE(FP_NHEAD2(9, 0), 1771 "ULP(s) busy, detach_ulps failed. Failing power down"); 1772 mutex_enter(&port->fp_mutex); 1773 return (DDI_FAILURE); 1774 } 1775 mutex_enter(&port->fp_mutex); 1776 1777 fp_suspend_all(port); 1778 1779 return (DDI_SUCCESS); 1780 } 1781 1782 1783 /* 1784 * Suspend the entire FC port 1785 */ 1786 static void 1787 fp_suspend_all(fc_local_port_t *port) 1788 { 1789 int index; 1790 struct pwwn_hash *head; 1791 fc_remote_port_t *pd; 1792 1793 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1794 1795 if (port->fp_wait_tid != 0) { 1796 timeout_id_t tid; 1797 1798 tid = port->fp_wait_tid; 1799 port->fp_wait_tid = (timeout_id_t)NULL; 1800 mutex_exit(&port->fp_mutex); 1801 (void) untimeout(tid); 1802 mutex_enter(&port->fp_mutex); 1803 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT; 1804 } 1805 1806 if (port->fp_offline_tid) { 1807 timeout_id_t tid; 1808 1809 tid = port->fp_offline_tid; 1810 port->fp_offline_tid = (timeout_id_t)NULL; 1811 mutex_exit(&port->fp_mutex); 1812 (void) untimeout(tid); 1813 mutex_enter(&port->fp_mutex); 1814 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT; 1815 } 1816 mutex_exit(&port->fp_mutex); 1817 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1818 mutex_enter(&port->fp_mutex); 1819 1820 /* 1821 * Mark all devices as OLD, and reset the LOGIN state as well 1822 * (this will force the ULPs to perform a LOGIN after calling 1823 * fc_portgetmap() during RESUME/PM_RESUME) 1824 */ 1825 for (index = 0; index < pwwn_table_size; index++) { 1826 head = &port->fp_pwwn_table[index]; 1827 pd = head->pwwn_head; 1828 while (pd != NULL) { 1829 mutex_enter(&pd->pd_mutex); 1830 fp_remote_port_offline(pd); 1831 fctl_delist_did_table(port, pd); 1832 pd->pd_state = PORT_DEVICE_VALID; 1833 pd->pd_login_count = 0; 1834 mutex_exit(&pd->pd_mutex); 1835 pd = pd->pd_wwn_hnext; 1836 } 1837 } 1838 } 1839 1840 1841 /* 1842 * fp_cache_constructor: Constructor function for kmem_cache_create(9F). 1843 * Performs intializations for fc_packet_t structs. 1844 * Returns 0 for success or -1 for failure. 1845 * 1846 * This function allocates DMA handles for both command and responses. 1847 * Most of the ELSs used have both command and responses so it is strongly 1848 * desired to move them to cache constructor routine. 1849 * 1850 * Context: Can sleep iff called with KM_SLEEP flag. 1851 */ 1852 static int 1853 fp_cache_constructor(void *buf, void *cdarg, int kmflags) 1854 { 1855 int (*cb) (caddr_t); 1856 fc_packet_t *pkt; 1857 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1858 fc_local_port_t *port = (fc_local_port_t *)cdarg; 1859 1860 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1861 1862 cmd->cmd_next = NULL; 1863 cmd->cmd_flags = 0; 1864 cmd->cmd_dflags = 0; 1865 cmd->cmd_job = NULL; 1866 cmd->cmd_port = port; 1867 pkt = &cmd->cmd_pkt; 1868 1869 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1870 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1871 &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 1872 return (-1); 1873 } 1874 1875 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1876 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1877 &pkt->pkt_resp_dma) != DDI_SUCCESS) { 1878 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1879 return (-1); 1880 } 1881 1882 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL; 1883 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt = 1884 pkt->pkt_data_cookie_cnt = 0; 1885 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie = 1886 pkt->pkt_data_cookie = NULL; 1887 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t); 1888 1889 return (0); 1890 } 1891 1892 1893 /* 1894 * fp_cache_destructor: Destructor function for kmem_cache_create(). 1895 * Performs un-intializations for fc_packet_t structs. 1896 */ 1897 /* ARGSUSED */ 1898 static void 1899 fp_cache_destructor(void *buf, void *cdarg) 1900 { 1901 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1902 fc_packet_t *pkt; 1903 1904 pkt = &cmd->cmd_pkt; 1905 if (pkt->pkt_cmd_dma) { 1906 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1907 } 1908 1909 if (pkt->pkt_resp_dma) { 1910 ddi_dma_free_handle(&pkt->pkt_resp_dma); 1911 } 1912 } 1913 1914 1915 /* 1916 * Packet allocation for ELS and any other port driver commands 1917 * 1918 * Some ELSs like FLOGI and PLOGI are critical for topology and 1919 * device discovery and a system's inability to allocate memory 1920 * or DVMA resources while performing some of these critical ELSs 1921 * cause a lot of problem. While memory allocation failures are 1922 * rare, DVMA resource failures are common as the applications 1923 * are becoming more and more powerful on huge servers. So it 1924 * is desirable to have a framework support to reserve a fragment 1925 * of DVMA. So until this is fixed the correct way, the suffering 1926 * is huge whenever a LIP happens at a time DVMA resources are 1927 * drained out completely - So an attempt needs to be made to 1928 * KM_SLEEP while requesting for these resources, hoping that 1929 * the requests won't hang forever. 1930 * 1931 * The fc_remote_port_t argument is stored into the pkt_pd field in the 1932 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This 1933 * ensures that the pd_ref_count for the fc_remote_port_t is valid. 1934 * If there is no fc_remote_port_t associated with the fc_packet_t, then 1935 * fp_alloc_pkt() must be called with pd set to NULL. 1936 */ 1937 1938 static fp_cmd_t * 1939 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags, 1940 fc_remote_port_t *pd) 1941 { 1942 int rval; 1943 ulong_t real_len; 1944 fp_cmd_t *cmd; 1945 fc_packet_t *pkt; 1946 int (*cb) (caddr_t); 1947 ddi_dma_cookie_t pkt_cookie; 1948 ddi_dma_cookie_t *cp; 1949 uint32_t cnt; 1950 1951 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1952 1953 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1954 1955 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags); 1956 if (cmd == NULL) { 1957 return (cmd); 1958 } 1959 1960 cmd->cmd_ulp_pkt = NULL; 1961 cmd->cmd_flags = 0; 1962 pkt = &cmd->cmd_pkt; 1963 ASSERT(cmd->cmd_dflags == 0); 1964 1965 pkt->pkt_datalen = 0; 1966 pkt->pkt_data = NULL; 1967 pkt->pkt_state = 0; 1968 pkt->pkt_action = 0; 1969 pkt->pkt_reason = 0; 1970 pkt->pkt_expln = 0; 1971 1972 /* 1973 * Init pkt_pd with the given pointer; this must be done _before_ 1974 * the call to fc_ulp_init_packet(). 1975 */ 1976 pkt->pkt_pd = pd; 1977 1978 /* Now call the FCA driver to init its private, per-packet fields */ 1979 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) { 1980 goto alloc_pkt_failed; 1981 } 1982 1983 if (cmd_len) { 1984 ASSERT(pkt->pkt_cmd_dma != NULL); 1985 1986 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len, 1987 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT, 1988 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len, 1989 &pkt->pkt_cmd_acc); 1990 1991 if (rval != DDI_SUCCESS) { 1992 goto alloc_pkt_failed; 1993 } 1994 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM; 1995 1996 if (real_len < cmd_len) { 1997 goto alloc_pkt_failed; 1998 } 1999 2000 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 2001 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | 2002 DDI_DMA_CONSISTENT, cb, NULL, 2003 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt); 2004 2005 if (rval != DDI_DMA_MAPPED) { 2006 goto alloc_pkt_failed; 2007 } 2008 2009 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND; 2010 2011 if (pkt->pkt_cmd_cookie_cnt > 2012 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2013 goto alloc_pkt_failed; 2014 } 2015 2016 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2017 2018 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2019 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie), 2020 KM_NOSLEEP); 2021 2022 if (cp == NULL) { 2023 goto alloc_pkt_failed; 2024 } 2025 2026 *cp = pkt_cookie; 2027 cp++; 2028 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) { 2029 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie); 2030 *cp = pkt_cookie; 2031 } 2032 } 2033 2034 if (resp_len) { 2035 ASSERT(pkt->pkt_resp_dma != NULL); 2036 2037 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len, 2038 port->fp_fca_tran->fca_acc_attr, 2039 DDI_DMA_CONSISTENT, cb, NULL, 2040 (caddr_t *)&pkt->pkt_resp, &real_len, 2041 &pkt->pkt_resp_acc); 2042 2043 if (rval != DDI_SUCCESS) { 2044 goto alloc_pkt_failed; 2045 } 2046 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM; 2047 2048 if (real_len < resp_len) { 2049 goto alloc_pkt_failed; 2050 } 2051 2052 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 2053 pkt->pkt_resp, real_len, DDI_DMA_READ | 2054 DDI_DMA_CONSISTENT, cb, NULL, 2055 &pkt_cookie, &pkt->pkt_resp_cookie_cnt); 2056 2057 if (rval != DDI_DMA_MAPPED) { 2058 goto alloc_pkt_failed; 2059 } 2060 2061 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND; 2062 2063 if (pkt->pkt_resp_cookie_cnt > 2064 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2065 goto alloc_pkt_failed; 2066 } 2067 2068 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2069 2070 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2071 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie), 2072 KM_NOSLEEP); 2073 2074 if (cp == NULL) { 2075 goto alloc_pkt_failed; 2076 } 2077 2078 *cp = pkt_cookie; 2079 cp++; 2080 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) { 2081 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie); 2082 *cp = pkt_cookie; 2083 } 2084 } 2085 2086 pkt->pkt_cmdlen = cmd_len; 2087 pkt->pkt_rsplen = resp_len; 2088 pkt->pkt_ulp_private = cmd; 2089 2090 return (cmd); 2091 2092 alloc_pkt_failed: 2093 2094 fp_free_dma(cmd); 2095 2096 if (pkt->pkt_cmd_cookie != NULL) { 2097 kmem_free(pkt->pkt_cmd_cookie, 2098 pkt->pkt_cmd_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2099 pkt->pkt_cmd_cookie = NULL; 2100 } 2101 2102 if (pkt->pkt_resp_cookie != NULL) { 2103 kmem_free(pkt->pkt_resp_cookie, 2104 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2105 pkt->pkt_resp_cookie = NULL; 2106 } 2107 2108 kmem_cache_free(port->fp_pkt_cache, cmd); 2109 2110 return (NULL); 2111 } 2112 2113 2114 /* 2115 * Free FC packet 2116 */ 2117 static void 2118 fp_free_pkt(fp_cmd_t *cmd) 2119 { 2120 fc_local_port_t *port; 2121 fc_packet_t *pkt; 2122 2123 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex)); 2124 2125 cmd->cmd_next = NULL; 2126 cmd->cmd_job = NULL; 2127 pkt = &cmd->cmd_pkt; 2128 pkt->pkt_ulp_private = 0; 2129 pkt->pkt_tran_flags = 0; 2130 pkt->pkt_tran_type = 0; 2131 port = cmd->cmd_port; 2132 2133 if (pkt->pkt_cmd_cookie != NULL) { 2134 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt * 2135 sizeof (ddi_dma_cookie_t)); 2136 pkt->pkt_cmd_cookie = NULL; 2137 } 2138 2139 if (pkt->pkt_resp_cookie != NULL) { 2140 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt * 2141 sizeof (ddi_dma_cookie_t)); 2142 pkt->pkt_resp_cookie = NULL; 2143 } 2144 2145 fp_free_dma(cmd); 2146 (void) fc_ulp_uninit_packet((opaque_t)port, pkt); 2147 kmem_cache_free(port->fp_pkt_cache, (void *)cmd); 2148 } 2149 2150 2151 /* 2152 * Release DVMA resources 2153 */ 2154 static void 2155 fp_free_dma(fp_cmd_t *cmd) 2156 { 2157 fc_packet_t *pkt = &cmd->cmd_pkt; 2158 2159 pkt->pkt_cmdlen = 0; 2160 pkt->pkt_rsplen = 0; 2161 pkt->pkt_tran_type = 0; 2162 pkt->pkt_tran_flags = 0; 2163 2164 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) { 2165 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 2166 } 2167 2168 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) { 2169 if (pkt->pkt_cmd_acc) { 2170 ddi_dma_mem_free(&pkt->pkt_cmd_acc); 2171 } 2172 } 2173 2174 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) { 2175 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 2176 } 2177 2178 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) { 2179 if (pkt->pkt_resp_acc) { 2180 ddi_dma_mem_free(&pkt->pkt_resp_acc); 2181 } 2182 } 2183 cmd->cmd_dflags = 0; 2184 } 2185 2186 2187 /* 2188 * Dedicated thread to perform various activities. One thread for 2189 * each fc_local_port_t (driver soft state) instance. 2190 * Note, this effectively works out to one thread for each local 2191 * port, but there are also some Solaris taskq threads in use on a per-local 2192 * port basis; these also need to be taken into consideration. 2193 */ 2194 static void 2195 fp_job_handler(fc_local_port_t *port) 2196 { 2197 int rval; 2198 uint32_t *d_id; 2199 fc_remote_port_t *pd; 2200 job_request_t *job; 2201 2202 #ifndef __lock_lint 2203 /* 2204 * Solaris-internal stuff for proper operation of kernel threads 2205 * with Solaris CPR. 2206 */ 2207 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex, 2208 callb_generic_cpr, "fp_job_handler"); 2209 #endif 2210 2211 2212 /* Loop forever waiting for work to do */ 2213 for (;;) { 2214 2215 mutex_enter(&port->fp_mutex); 2216 2217 /* 2218 * Sleep if no work to do right now, or if we want 2219 * to suspend or power-down. 2220 */ 2221 while (port->fp_job_head == NULL || 2222 (port->fp_soft_state & (FP_SOFT_POWER_DOWN | 2223 FP_SOFT_SUSPEND))) { 2224 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info); 2225 cv_wait(&port->fp_cv, &port->fp_mutex); 2226 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex); 2227 } 2228 2229 /* 2230 * OK, we've just been woken up, so retrieve the next entry 2231 * from the head of the job queue for this local port. 2232 */ 2233 job = fctl_deque_job(port); 2234 2235 /* 2236 * Handle all the fp driver's supported job codes here 2237 * in this big honkin' switch. 2238 */ 2239 switch (job->job_code) { 2240 case JOB_PORT_SHUTDOWN: 2241 /* 2242 * fp_port_shutdown() is only called from here. This 2243 * will prepare the local port instance (softstate) 2244 * for detaching. This cancels timeout callbacks, 2245 * executes LOGOs with remote ports, cleans up tables, 2246 * and deallocates data structs. 2247 */ 2248 fp_port_shutdown(port, job); 2249 2250 /* 2251 * This will exit the job thread. 2252 */ 2253 #ifndef __lock_lint 2254 CALLB_CPR_EXIT(&(port->fp_cpr_info)); 2255 #else 2256 mutex_exit(&port->fp_mutex); 2257 #endif 2258 fctl_jobdone(job); 2259 thread_exit(); 2260 2261 /* NOTREACHED */ 2262 2263 case JOB_ATTACH_ULP: { 2264 /* 2265 * This job is spawned in response to a ULP calling 2266 * fc_ulp_add(). 2267 */ 2268 2269 boolean_t do_attach_ulps = B_TRUE; 2270 2271 /* 2272 * If fp is detaching, we don't want to call 2273 * fp_startup_done as this asynchronous 2274 * notification may interfere with the re-attach. 2275 */ 2276 2277 if (port->fp_soft_state & (FP_DETACH_INPROGRESS | 2278 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) { 2279 do_attach_ulps = B_FALSE; 2280 } else { 2281 /* 2282 * We are going to force the transport 2283 * to attach to the ULPs, so set 2284 * fp_ulp_attach. This will keep any 2285 * potential detach from occurring until 2286 * we are done. 2287 */ 2288 port->fp_ulp_attach = 1; 2289 } 2290 2291 mutex_exit(&port->fp_mutex); 2292 2293 /* 2294 * NOTE: Since we just dropped the mutex, there is now 2295 * a race window where the fp_soft_state check above 2296 * could change here. This race is covered because an 2297 * additional check was added in the functions hidden 2298 * under fp_startup_done(). 2299 */ 2300 if (do_attach_ulps == B_TRUE) { 2301 /* 2302 * This goes thru a bit of a convoluted call 2303 * chain before spawning off a DDI taskq 2304 * request to perform the actual attach 2305 * operations. Blocking can occur at a number 2306 * of points. 2307 */ 2308 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 2309 } 2310 job->job_result = FC_SUCCESS; 2311 fctl_jobdone(job); 2312 break; 2313 } 2314 2315 case JOB_ULP_NOTIFY: { 2316 /* 2317 * Pass state change notifications up to any/all 2318 * registered ULPs. 2319 */ 2320 uint32_t statec; 2321 2322 statec = job->job_ulp_listlen; 2323 if (statec == FC_STATE_RESET_REQUESTED) { 2324 port->fp_last_task = port->fp_task; 2325 port->fp_task = FP_TASK_OFFLINE; 2326 fp_port_offline(port, 0); 2327 port->fp_task = port->fp_last_task; 2328 port->fp_last_task = FP_TASK_IDLE; 2329 } 2330 2331 if (--port->fp_statec_busy == 0) { 2332 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2333 } 2334 2335 mutex_exit(&port->fp_mutex); 2336 2337 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP); 2338 fctl_jobdone(job); 2339 break; 2340 } 2341 2342 case JOB_PLOGI_ONE: 2343 /* 2344 * Issue a PLOGI to a single remote port. Multiple 2345 * PLOGIs to different remote ports may occur in 2346 * parallel. 2347 * This can create the fc_remote_port_t if it does not 2348 * already exist. 2349 */ 2350 2351 mutex_exit(&port->fp_mutex); 2352 d_id = (uint32_t *)job->job_private; 2353 pd = fctl_get_remote_port_by_did(port, *d_id); 2354 2355 if (pd) { 2356 mutex_enter(&pd->pd_mutex); 2357 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 2358 pd->pd_login_count++; 2359 mutex_exit(&pd->pd_mutex); 2360 job->job_result = FC_SUCCESS; 2361 fctl_jobdone(job); 2362 break; 2363 } 2364 mutex_exit(&pd->pd_mutex); 2365 } else { 2366 mutex_enter(&port->fp_mutex); 2367 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2368 mutex_exit(&port->fp_mutex); 2369 pd = fp_create_remote_port_by_ns(port, 2370 *d_id, KM_SLEEP); 2371 if (pd == NULL) { 2372 job->job_result = FC_FAILURE; 2373 fctl_jobdone(job); 2374 break; 2375 } 2376 } else { 2377 mutex_exit(&port->fp_mutex); 2378 } 2379 } 2380 2381 job->job_flags |= JOB_TYPE_FP_ASYNC; 2382 job->job_counter = 1; 2383 2384 rval = fp_port_login(port, *d_id, job, 2385 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 2386 2387 if (rval != FC_SUCCESS) { 2388 job->job_result = rval; 2389 fctl_jobdone(job); 2390 } 2391 break; 2392 2393 case JOB_LOGO_ONE: { 2394 /* 2395 * Issue a PLOGO to a single remote port. Multiple 2396 * PLOGOs to different remote ports may occur in 2397 * parallel. 2398 */ 2399 fc_remote_port_t *pd; 2400 2401 #ifndef __lock_lint 2402 ASSERT(job->job_counter > 0); 2403 #endif 2404 2405 pd = (fc_remote_port_t *)job->job_ulp_pkts; 2406 2407 mutex_enter(&pd->pd_mutex); 2408 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 2409 mutex_exit(&pd->pd_mutex); 2410 job->job_result = FC_LOGINREQ; 2411 mutex_exit(&port->fp_mutex); 2412 fctl_jobdone(job); 2413 break; 2414 } 2415 if (pd->pd_login_count > 1) { 2416 pd->pd_login_count--; 2417 mutex_exit(&pd->pd_mutex); 2418 job->job_result = FC_SUCCESS; 2419 mutex_exit(&port->fp_mutex); 2420 fctl_jobdone(job); 2421 break; 2422 } 2423 mutex_exit(&pd->pd_mutex); 2424 mutex_exit(&port->fp_mutex); 2425 job->job_flags |= JOB_TYPE_FP_ASYNC; 2426 (void) fp_logout(port, pd, job); 2427 break; 2428 } 2429 2430 case JOB_FCIO_LOGIN: 2431 /* 2432 * PLOGI initiated at ioctl request. 2433 */ 2434 mutex_exit(&port->fp_mutex); 2435 job->job_result = 2436 fp_fcio_login(port, job->job_private, job); 2437 fctl_jobdone(job); 2438 break; 2439 2440 case JOB_FCIO_LOGOUT: 2441 /* 2442 * PLOGO initiated at ioctl request. 2443 */ 2444 mutex_exit(&port->fp_mutex); 2445 job->job_result = 2446 fp_fcio_logout(port, job->job_private, job); 2447 fctl_jobdone(job); 2448 break; 2449 2450 case JOB_PORT_GETMAP: 2451 case JOB_PORT_GETMAP_PLOGI_ALL: { 2452 port->fp_last_task = port->fp_task; 2453 port->fp_task = FP_TASK_GETMAP; 2454 2455 switch (port->fp_topology) { 2456 case FC_TOP_PRIVATE_LOOP: 2457 job->job_counter = 1; 2458 2459 fp_get_loopmap(port, job); 2460 mutex_exit(&port->fp_mutex); 2461 fp_jobwait(job); 2462 fctl_fillout_map(port, 2463 (fc_portmap_t **)job->job_private, 2464 (uint32_t *)job->job_arg, 1, 0, 0); 2465 fctl_jobdone(job); 2466 mutex_enter(&port->fp_mutex); 2467 break; 2468 2469 case FC_TOP_PUBLIC_LOOP: 2470 case FC_TOP_FABRIC: 2471 mutex_exit(&port->fp_mutex); 2472 job->job_counter = 1; 2473 2474 job->job_result = fp_ns_getmap(port, 2475 job, (fc_portmap_t **)job->job_private, 2476 (uint32_t *)job->job_arg, 2477 FCTL_GAN_START_ID); 2478 fctl_jobdone(job); 2479 mutex_enter(&port->fp_mutex); 2480 break; 2481 2482 case FC_TOP_PT_PT: 2483 mutex_exit(&port->fp_mutex); 2484 fctl_fillout_map(port, 2485 (fc_portmap_t **)job->job_private, 2486 (uint32_t *)job->job_arg, 1, 0, 0); 2487 fctl_jobdone(job); 2488 mutex_enter(&port->fp_mutex); 2489 break; 2490 2491 default: 2492 mutex_exit(&port->fp_mutex); 2493 fctl_jobdone(job); 2494 mutex_enter(&port->fp_mutex); 2495 break; 2496 } 2497 port->fp_task = port->fp_last_task; 2498 port->fp_last_task = FP_TASK_IDLE; 2499 mutex_exit(&port->fp_mutex); 2500 break; 2501 } 2502 2503 case JOB_PORT_OFFLINE: { 2504 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE); 2505 2506 port->fp_last_task = port->fp_task; 2507 port->fp_task = FP_TASK_OFFLINE; 2508 2509 if (port->fp_statec_busy > 2) { 2510 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2511 fp_port_offline(port, 0); 2512 if (--port->fp_statec_busy == 0) { 2513 port->fp_soft_state &= 2514 ~FP_SOFT_IN_STATEC_CB; 2515 } 2516 } else { 2517 fp_port_offline(port, 1); 2518 } 2519 2520 port->fp_task = port->fp_last_task; 2521 port->fp_last_task = FP_TASK_IDLE; 2522 2523 mutex_exit(&port->fp_mutex); 2524 2525 fctl_jobdone(job); 2526 break; 2527 } 2528 2529 case JOB_PORT_STARTUP: { 2530 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2531 if (port->fp_statec_busy > 1) { 2532 mutex_exit(&port->fp_mutex); 2533 break; 2534 } 2535 mutex_exit(&port->fp_mutex); 2536 2537 FP_TRACE(FP_NHEAD2(9, rval), 2538 "Topology discovery failed"); 2539 break; 2540 } 2541 2542 /* 2543 * Attempt building device handles in case 2544 * of private Loop. 2545 */ 2546 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) { 2547 job->job_counter = 1; 2548 2549 fp_get_loopmap(port, job); 2550 mutex_exit(&port->fp_mutex); 2551 fp_jobwait(job); 2552 mutex_enter(&port->fp_mutex); 2553 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 2554 ASSERT(port->fp_total_devices == 0); 2555 port->fp_total_devices = 2556 port->fp_dev_count; 2557 } 2558 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2559 /* 2560 * Hack to avoid state changes going up early 2561 */ 2562 port->fp_statec_busy++; 2563 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 2564 2565 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2566 fp_fabric_online(port, job); 2567 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION; 2568 } 2569 mutex_exit(&port->fp_mutex); 2570 fctl_jobdone(job); 2571 break; 2572 } 2573 2574 case JOB_PORT_ONLINE: { 2575 char *newtop; 2576 char *oldtop; 2577 uint32_t old_top; 2578 2579 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE); 2580 2581 /* 2582 * Bail out early if there are a lot of 2583 * state changes in the pipeline 2584 */ 2585 if (port->fp_statec_busy > 1) { 2586 --port->fp_statec_busy; 2587 mutex_exit(&port->fp_mutex); 2588 fctl_jobdone(job); 2589 break; 2590 } 2591 2592 switch (old_top = port->fp_topology) { 2593 case FC_TOP_PRIVATE_LOOP: 2594 oldtop = "Private Loop"; 2595 break; 2596 2597 case FC_TOP_PUBLIC_LOOP: 2598 oldtop = "Public Loop"; 2599 break; 2600 2601 case FC_TOP_PT_PT: 2602 oldtop = "Point to Point"; 2603 break; 2604 2605 case FC_TOP_FABRIC: 2606 oldtop = "Fabric"; 2607 break; 2608 2609 default: 2610 oldtop = NULL; 2611 break; 2612 } 2613 2614 port->fp_last_task = port->fp_task; 2615 port->fp_task = FP_TASK_ONLINE; 2616 2617 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2618 2619 port->fp_task = port->fp_last_task; 2620 port->fp_last_task = FP_TASK_IDLE; 2621 2622 if (port->fp_statec_busy > 1) { 2623 --port->fp_statec_busy; 2624 mutex_exit(&port->fp_mutex); 2625 break; 2626 } 2627 2628 port->fp_state = FC_STATE_OFFLINE; 2629 2630 FP_TRACE(FP_NHEAD2(9, rval), 2631 "Topology discovery failed"); 2632 2633 if (--port->fp_statec_busy == 0) { 2634 port->fp_soft_state &= 2635 ~FP_SOFT_IN_STATEC_CB; 2636 } 2637 2638 if (port->fp_offline_tid == NULL) { 2639 port->fp_offline_tid = 2640 timeout(fp_offline_timeout, 2641 (caddr_t)port, fp_offline_ticks); 2642 } 2643 2644 mutex_exit(&port->fp_mutex); 2645 break; 2646 } 2647 2648 switch (port->fp_topology) { 2649 case FC_TOP_PRIVATE_LOOP: 2650 newtop = "Private Loop"; 2651 break; 2652 2653 case FC_TOP_PUBLIC_LOOP: 2654 newtop = "Public Loop"; 2655 break; 2656 2657 case FC_TOP_PT_PT: 2658 newtop = "Point to Point"; 2659 break; 2660 2661 case FC_TOP_FABRIC: 2662 newtop = "Fabric"; 2663 break; 2664 2665 default: 2666 newtop = NULL; 2667 break; 2668 } 2669 2670 if (oldtop && newtop && strcmp(oldtop, newtop)) { 2671 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2672 "Change in FC Topology old = %s new = %s", 2673 oldtop, newtop); 2674 } 2675 2676 switch (port->fp_topology) { 2677 case FC_TOP_PRIVATE_LOOP: { 2678 int orphan = (old_top == FC_TOP_FABRIC || 2679 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0; 2680 2681 mutex_exit(&port->fp_mutex); 2682 fp_loop_online(port, job, orphan); 2683 break; 2684 } 2685 2686 case FC_TOP_PUBLIC_LOOP: 2687 /* FALLTHROUGH */ 2688 case FC_TOP_FABRIC: 2689 fp_fabric_online(port, job); 2690 mutex_exit(&port->fp_mutex); 2691 break; 2692 2693 case FC_TOP_PT_PT: 2694 fp_p2p_online(port, job); 2695 mutex_exit(&port->fp_mutex); 2696 break; 2697 2698 default: 2699 if (--port->fp_statec_busy != 0) { 2700 /* 2701 * Watch curiously at what the next 2702 * state transition can do. 2703 */ 2704 mutex_exit(&port->fp_mutex); 2705 break; 2706 } 2707 2708 FP_TRACE(FP_NHEAD2(9, 0), 2709 "Topology Unknown, Offlining the port.."); 2710 2711 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2712 port->fp_state = FC_STATE_OFFLINE; 2713 2714 if (port->fp_offline_tid == NULL) { 2715 port->fp_offline_tid = 2716 timeout(fp_offline_timeout, 2717 (caddr_t)port, fp_offline_ticks); 2718 } 2719 mutex_exit(&port->fp_mutex); 2720 break; 2721 } 2722 2723 mutex_enter(&port->fp_mutex); 2724 2725 port->fp_task = port->fp_last_task; 2726 port->fp_last_task = FP_TASK_IDLE; 2727 2728 mutex_exit(&port->fp_mutex); 2729 2730 fctl_jobdone(job); 2731 break; 2732 } 2733 2734 case JOB_PLOGI_GROUP: { 2735 mutex_exit(&port->fp_mutex); 2736 fp_plogi_group(port, job); 2737 break; 2738 } 2739 2740 case JOB_UNSOL_REQUEST: { 2741 mutex_exit(&port->fp_mutex); 2742 fp_handle_unsol_buf(port, 2743 (fc_unsol_buf_t *)job->job_private, job); 2744 fctl_dealloc_job(job); 2745 break; 2746 } 2747 2748 case JOB_NS_CMD: { 2749 fctl_ns_req_t *ns_cmd; 2750 2751 mutex_exit(&port->fp_mutex); 2752 2753 job->job_flags |= JOB_TYPE_FP_ASYNC; 2754 ns_cmd = (fctl_ns_req_t *)job->job_private; 2755 if (ns_cmd->ns_cmd_code < NS_GA_NXT || 2756 ns_cmd->ns_cmd_code > NS_DA_ID) { 2757 job->job_result = FC_BADCMD; 2758 fctl_jobdone(job); 2759 break; 2760 } 2761 2762 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) { 2763 if (ns_cmd->ns_pd != NULL) { 2764 job->job_result = FC_BADOBJECT; 2765 fctl_jobdone(job); 2766 break; 2767 } 2768 2769 job->job_counter = 1; 2770 2771 rval = fp_ns_reg(port, ns_cmd->ns_pd, 2772 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP); 2773 2774 if (rval != FC_SUCCESS) { 2775 job->job_result = rval; 2776 fctl_jobdone(job); 2777 } 2778 break; 2779 } 2780 job->job_result = FC_SUCCESS; 2781 job->job_counter = 1; 2782 2783 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP); 2784 if (rval != FC_SUCCESS) { 2785 fctl_jobdone(job); 2786 } 2787 break; 2788 } 2789 2790 case JOB_LINK_RESET: { 2791 la_wwn_t *pwwn; 2792 uint32_t topology; 2793 2794 pwwn = (la_wwn_t *)job->job_private; 2795 ASSERT(pwwn != NULL); 2796 2797 topology = port->fp_topology; 2798 mutex_exit(&port->fp_mutex); 2799 2800 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS || 2801 topology == FC_TOP_PRIVATE_LOOP) { 2802 job->job_flags |= JOB_TYPE_FP_ASYNC; 2803 rval = port->fp_fca_tran->fca_reset( 2804 port->fp_fca_handle, FC_FCA_LINK_RESET); 2805 job->job_result = rval; 2806 fp_jobdone(job); 2807 } else { 2808 ASSERT((job->job_flags & 2809 JOB_TYPE_FP_ASYNC) == 0); 2810 2811 if (FC_IS_TOP_SWITCH(topology)) { 2812 rval = fp_remote_lip(port, pwwn, 2813 KM_SLEEP, job); 2814 } else { 2815 rval = FC_FAILURE; 2816 } 2817 if (rval != FC_SUCCESS) { 2818 job->job_result = rval; 2819 } 2820 fctl_jobdone(job); 2821 } 2822 break; 2823 } 2824 2825 default: 2826 mutex_exit(&port->fp_mutex); 2827 job->job_result = FC_BADCMD; 2828 fctl_jobdone(job); 2829 break; 2830 } 2831 } 2832 /* NOTREACHED */ 2833 } 2834 2835 2836 /* 2837 * Perform FC port bring up initialization 2838 */ 2839 static int 2840 fp_port_startup(fc_local_port_t *port, job_request_t *job) 2841 { 2842 int rval; 2843 uint32_t state; 2844 uint32_t src_id; 2845 fc_lilpmap_t *lilp_map; 2846 2847 ASSERT(MUTEX_HELD(&port->fp_mutex)); 2848 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 2849 2850 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;" 2851 " port=%p, job=%p", port, job); 2852 2853 port->fp_topology = FC_TOP_UNKNOWN; 2854 port->fp_port_id.port_id = 0; 2855 state = FC_PORT_STATE_MASK(port->fp_state); 2856 2857 if (state == FC_STATE_OFFLINE) { 2858 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2859 job->job_result = FC_OFFLINE; 2860 mutex_exit(&port->fp_mutex); 2861 fctl_jobdone(job); 2862 mutex_enter(&port->fp_mutex); 2863 return (FC_OFFLINE); 2864 } 2865 2866 if (state == FC_STATE_LOOP) { 2867 port->fp_port_type.port_type = FC_NS_PORT_NL; 2868 mutex_exit(&port->fp_mutex); 2869 2870 lilp_map = &port->fp_lilp_map; 2871 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) { 2872 job->job_result = FC_FAILURE; 2873 fctl_jobdone(job); 2874 2875 FP_TRACE(FP_NHEAD1(9, rval), 2876 "LILP map Invalid or not present"); 2877 mutex_enter(&port->fp_mutex); 2878 return (FC_FAILURE); 2879 } 2880 2881 if (lilp_map->lilp_length == 0) { 2882 job->job_result = FC_NO_MAP; 2883 fctl_jobdone(job); 2884 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2885 "LILP map length zero"); 2886 mutex_enter(&port->fp_mutex); 2887 return (FC_NO_MAP); 2888 } 2889 src_id = lilp_map->lilp_myalpa & 0xFF; 2890 } else { 2891 fc_remote_port_t *pd; 2892 fc_fca_pm_t pm; 2893 fc_fca_p2p_info_t p2p_info; 2894 int pd_recepient; 2895 2896 /* 2897 * Get P2P remote port info if possible 2898 */ 2899 bzero((caddr_t)&pm, sizeof (pm)); 2900 2901 pm.pm_cmd_flags = FC_FCA_PM_READ; 2902 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO; 2903 pm.pm_data_len = sizeof (fc_fca_p2p_info_t); 2904 pm.pm_data_buf = (caddr_t)&p2p_info; 2905 2906 rval = port->fp_fca_tran->fca_port_manage( 2907 port->fp_fca_handle, &pm); 2908 2909 if (rval == FC_SUCCESS) { 2910 port->fp_port_id.port_id = p2p_info.fca_d_id; 2911 port->fp_port_type.port_type = FC_NS_PORT_N; 2912 port->fp_topology = FC_TOP_PT_PT; 2913 port->fp_total_devices = 1; 2914 pd_recepient = fctl_wwn_cmp( 2915 &port->fp_service_params.nport_ww_name, 2916 &p2p_info.pwwn) < 0 ? 2917 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR; 2918 mutex_exit(&port->fp_mutex); 2919 pd = fctl_create_remote_port(port, 2920 &p2p_info.nwwn, 2921 &p2p_info.pwwn, 2922 p2p_info.d_id, 2923 pd_recepient, KM_NOSLEEP); 2924 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;" 2925 " P2P port=%p pd=%p", port, pd); 2926 mutex_enter(&port->fp_mutex); 2927 return (FC_SUCCESS); 2928 } 2929 port->fp_port_type.port_type = FC_NS_PORT_N; 2930 mutex_exit(&port->fp_mutex); 2931 src_id = 0; 2932 } 2933 2934 job->job_counter = 1; 2935 job->job_result = FC_SUCCESS; 2936 2937 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE, 2938 KM_SLEEP)) != FC_SUCCESS) { 2939 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2940 job->job_result = FC_FAILURE; 2941 fctl_jobdone(job); 2942 2943 mutex_enter(&port->fp_mutex); 2944 if (port->fp_statec_busy <= 1) { 2945 mutex_exit(&port->fp_mutex); 2946 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL, 2947 "Couldn't transport FLOGI"); 2948 mutex_enter(&port->fp_mutex); 2949 } 2950 return (FC_FAILURE); 2951 } 2952 2953 fp_jobwait(job); 2954 2955 mutex_enter(&port->fp_mutex); 2956 if (job->job_result == FC_SUCCESS) { 2957 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2958 mutex_exit(&port->fp_mutex); 2959 fp_ns_init(port, job, KM_SLEEP); 2960 mutex_enter(&port->fp_mutex); 2961 } 2962 } else { 2963 if (state == FC_STATE_LOOP) { 2964 port->fp_topology = FC_TOP_PRIVATE_LOOP; 2965 port->fp_port_id.port_id = 2966 port->fp_lilp_map.lilp_myalpa & 0xFF; 2967 } 2968 } 2969 2970 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p", 2971 port, job); 2972 2973 return (FC_SUCCESS); 2974 } 2975 2976 2977 /* 2978 * Perform ULP invocations following FC port startup 2979 */ 2980 /* ARGSUSED */ 2981 static void 2982 fp_startup_done(opaque_t arg, uchar_t result) 2983 { 2984 fc_local_port_t *port = arg; 2985 2986 fp_attach_ulps(port, FC_CMD_ATTACH); 2987 2988 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port); 2989 } 2990 2991 2992 /* 2993 * Perform ULP port attach 2994 */ 2995 static void 2996 fp_ulp_port_attach(void *arg) 2997 { 2998 fp_soft_attach_t *att = (fp_soft_attach_t *)arg; 2999 fc_local_port_t *port = att->att_port; 3000 3001 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3002 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd); 3003 3004 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage); 3005 3006 if (att->att_need_pm_idle == B_TRUE) { 3007 fctl_idle_port(port); 3008 } 3009 3010 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3011 " ULPs end; port=%p, cmd=%x", port, att->att_cmd); 3012 3013 mutex_enter(&att->att_port->fp_mutex); 3014 att->att_port->fp_ulp_attach = 0; 3015 3016 port->fp_task = port->fp_last_task; 3017 port->fp_last_task = FP_TASK_IDLE; 3018 3019 cv_signal(&att->att_port->fp_attach_cv); 3020 3021 mutex_exit(&att->att_port->fp_mutex); 3022 3023 kmem_free(att, sizeof (fp_soft_attach_t)); 3024 } 3025 3026 /* 3027 * Entry point to funnel all requests down to FCAs 3028 */ 3029 static int 3030 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle) 3031 { 3032 int rval; 3033 3034 mutex_enter(&port->fp_mutex); 3035 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL && 3036 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) == 3037 FC_STATE_OFFLINE))) { 3038 /* 3039 * This means there is more than one state change 3040 * at this point of time - Since they are processed 3041 * serially, any processing of the current one should 3042 * be failed, failed and move up in processing the next 3043 */ 3044 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS; 3045 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3046 if (cmd->cmd_job) { 3047 /* 3048 * A state change that is going to be invalidated 3049 * by another one already in the port driver's queue 3050 * need not go up to all ULPs. This will minimize 3051 * needless processing and ripples in ULP modules 3052 */ 3053 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3054 } 3055 mutex_exit(&port->fp_mutex); 3056 return (FC_STATEC_BUSY); 3057 } 3058 3059 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3060 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE; 3061 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3062 mutex_exit(&port->fp_mutex); 3063 3064 return (FC_OFFLINE); 3065 } 3066 mutex_exit(&port->fp_mutex); 3067 3068 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt); 3069 if (rval != FC_SUCCESS) { 3070 if (rval == FC_TRAN_BUSY) { 3071 cmd->cmd_retry_interval = fp_retry_delay; 3072 rval = fp_retry_cmd(&cmd->cmd_pkt); 3073 if (rval == FC_FAILURE) { 3074 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY; 3075 } 3076 } 3077 } 3078 3079 return (rval); 3080 } 3081 3082 3083 /* 3084 * Each time a timeout kicks in, walk the wait queue, decrement the 3085 * the retry_interval, when the retry_interval becomes less than 3086 * or equal to zero, re-transport the command: If the re-transport 3087 * fails with BUSY, enqueue the command in the wait queue. 3088 * 3089 * In order to prevent looping forever because of commands enqueued 3090 * from within this function itself, save the current tail pointer 3091 * (in cur_tail) and exit the loop after serving this command. 3092 */ 3093 static void 3094 fp_resendcmd(void *port_handle) 3095 { 3096 int rval; 3097 fc_local_port_t *port; 3098 fp_cmd_t *cmd; 3099 fp_cmd_t *cur_tail; 3100 3101 port = port_handle; 3102 mutex_enter(&port->fp_mutex); 3103 cur_tail = port->fp_wait_tail; 3104 mutex_exit(&port->fp_mutex); 3105 3106 while ((cmd = fp_deque_cmd(port)) != NULL) { 3107 cmd->cmd_retry_interval -= fp_retry_ticker; 3108 /* Check if we are detaching */ 3109 if (port->fp_soft_state & 3110 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) { 3111 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 3112 cmd->cmd_pkt.pkt_reason = 0; 3113 fp_iodone(cmd); 3114 } else if (cmd->cmd_retry_interval <= 0) { 3115 rval = cmd->cmd_transport(port->fp_fca_handle, 3116 &cmd->cmd_pkt); 3117 3118 if (rval != FC_SUCCESS) { 3119 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) { 3120 if (--cmd->cmd_retry_count) { 3121 fp_enque_cmd(port, cmd); 3122 if (cmd == cur_tail) { 3123 break; 3124 } 3125 continue; 3126 } 3127 cmd->cmd_pkt.pkt_state = 3128 FC_PKT_TRAN_BSY; 3129 } else { 3130 cmd->cmd_pkt.pkt_state = 3131 FC_PKT_TRAN_ERROR; 3132 } 3133 cmd->cmd_pkt.pkt_reason = 0; 3134 fp_iodone(cmd); 3135 } 3136 } else { 3137 fp_enque_cmd(port, cmd); 3138 } 3139 3140 if (cmd == cur_tail) { 3141 break; 3142 } 3143 } 3144 3145 mutex_enter(&port->fp_mutex); 3146 if (port->fp_wait_head) { 3147 timeout_id_t tid; 3148 3149 mutex_exit(&port->fp_mutex); 3150 tid = timeout(fp_resendcmd, (caddr_t)port, 3151 fp_retry_ticks); 3152 mutex_enter(&port->fp_mutex); 3153 port->fp_wait_tid = tid; 3154 } else { 3155 port->fp_wait_tid = NULL; 3156 } 3157 mutex_exit(&port->fp_mutex); 3158 } 3159 3160 3161 /* 3162 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here. 3163 * 3164 * Yes, as you can see below, cmd_retry_count is used here too. That means 3165 * the retries for BUSY are less if there were transport failures (transport 3166 * failure means fca_transport failure). The goal is not to exceed overall 3167 * retries set in the cmd_retry_count (whatever may be the reason for retry) 3168 * 3169 * Return Values: 3170 * FC_SUCCESS 3171 * FC_FAILURE 3172 */ 3173 static int 3174 fp_retry_cmd(fc_packet_t *pkt) 3175 { 3176 fp_cmd_t *cmd; 3177 3178 cmd = pkt->pkt_ulp_private; 3179 3180 if (--cmd->cmd_retry_count) { 3181 fp_enque_cmd(cmd->cmd_port, cmd); 3182 return (FC_SUCCESS); 3183 } else { 3184 return (FC_FAILURE); 3185 } 3186 } 3187 3188 3189 /* 3190 * Queue up FC packet for deferred retry 3191 */ 3192 static void 3193 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd) 3194 { 3195 timeout_id_t tid; 3196 3197 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3198 3199 #ifdef DEBUG 3200 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt, 3201 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id); 3202 #endif 3203 3204 mutex_enter(&port->fp_mutex); 3205 if (port->fp_wait_tail) { 3206 port->fp_wait_tail->cmd_next = cmd; 3207 port->fp_wait_tail = cmd; 3208 } else { 3209 ASSERT(port->fp_wait_head == NULL); 3210 port->fp_wait_head = port->fp_wait_tail = cmd; 3211 if (port->fp_wait_tid == NULL) { 3212 mutex_exit(&port->fp_mutex); 3213 tid = timeout(fp_resendcmd, (caddr_t)port, 3214 fp_retry_ticks); 3215 mutex_enter(&port->fp_mutex); 3216 port->fp_wait_tid = tid; 3217 } 3218 } 3219 mutex_exit(&port->fp_mutex); 3220 } 3221 3222 3223 /* 3224 * Handle all RJT codes 3225 */ 3226 static int 3227 fp_handle_reject(fc_packet_t *pkt) 3228 { 3229 int rval = FC_FAILURE; 3230 uchar_t next_class; 3231 fp_cmd_t *cmd; 3232 fc_local_port_t *port; 3233 3234 cmd = pkt->pkt_ulp_private; 3235 port = cmd->cmd_port; 3236 3237 switch (pkt->pkt_state) { 3238 case FC_PKT_FABRIC_RJT: 3239 case FC_PKT_NPORT_RJT: 3240 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) { 3241 next_class = fp_get_nextclass(cmd->cmd_port, 3242 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 3243 3244 if (next_class == FC_TRAN_CLASS_INVALID) { 3245 return (rval); 3246 } 3247 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class; 3248 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 3249 3250 rval = fp_sendcmd(cmd->cmd_port, cmd, 3251 cmd->cmd_port->fp_fca_handle); 3252 3253 if (rval != FC_SUCCESS) { 3254 pkt->pkt_state = FC_PKT_TRAN_ERROR; 3255 } 3256 } 3257 break; 3258 3259 case FC_PKT_LS_RJT: 3260 case FC_PKT_BA_RJT: 3261 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) || 3262 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) { 3263 cmd->cmd_retry_interval = fp_retry_delay; 3264 rval = fp_retry_cmd(pkt); 3265 } 3266 break; 3267 3268 case FC_PKT_FS_RJT: 3269 if (pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) { 3270 cmd->cmd_retry_interval = fp_retry_delay; 3271 rval = fp_retry_cmd(pkt); 3272 } 3273 break; 3274 3275 case FC_PKT_LOCAL_RJT: 3276 if (pkt->pkt_reason == FC_REASON_QFULL) { 3277 cmd->cmd_retry_interval = fp_retry_delay; 3278 rval = fp_retry_cmd(pkt); 3279 } 3280 break; 3281 3282 default: 3283 FP_TRACE(FP_NHEAD1(1, 0), 3284 "fp_handle_reject(): Invalid pkt_state"); 3285 break; 3286 } 3287 3288 return (rval); 3289 } 3290 3291 3292 /* 3293 * Return the next class of service supported by the FCA 3294 */ 3295 static uchar_t 3296 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class) 3297 { 3298 uchar_t next_class; 3299 3300 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3301 3302 switch (cur_class) { 3303 case FC_TRAN_CLASS_INVALID: 3304 if (port->fp_cos & FC_NS_CLASS1) { 3305 next_class = FC_TRAN_CLASS1; 3306 break; 3307 } 3308 /* FALLTHROUGH */ 3309 3310 case FC_TRAN_CLASS1: 3311 if (port->fp_cos & FC_NS_CLASS2) { 3312 next_class = FC_TRAN_CLASS2; 3313 break; 3314 } 3315 /* FALLTHROUGH */ 3316 3317 case FC_TRAN_CLASS2: 3318 if (port->fp_cos & FC_NS_CLASS3) { 3319 next_class = FC_TRAN_CLASS3; 3320 break; 3321 } 3322 /* FALLTHROUGH */ 3323 3324 case FC_TRAN_CLASS3: 3325 default: 3326 next_class = FC_TRAN_CLASS_INVALID; 3327 break; 3328 } 3329 3330 return (next_class); 3331 } 3332 3333 3334 /* 3335 * Determine if a class of service is supported by the FCA 3336 */ 3337 static int 3338 fp_is_class_supported(uint32_t cos, uchar_t tran_class) 3339 { 3340 int rval; 3341 3342 switch (tran_class) { 3343 case FC_TRAN_CLASS1: 3344 if (cos & FC_NS_CLASS1) { 3345 rval = FC_SUCCESS; 3346 } else { 3347 rval = FC_FAILURE; 3348 } 3349 break; 3350 3351 case FC_TRAN_CLASS2: 3352 if (cos & FC_NS_CLASS2) { 3353 rval = FC_SUCCESS; 3354 } else { 3355 rval = FC_FAILURE; 3356 } 3357 break; 3358 3359 case FC_TRAN_CLASS3: 3360 if (cos & FC_NS_CLASS3) { 3361 rval = FC_SUCCESS; 3362 } else { 3363 rval = FC_FAILURE; 3364 } 3365 break; 3366 3367 default: 3368 rval = FC_FAILURE; 3369 break; 3370 } 3371 3372 return (rval); 3373 } 3374 3375 3376 /* 3377 * Dequeue FC packet for retry 3378 */ 3379 static fp_cmd_t * 3380 fp_deque_cmd(fc_local_port_t *port) 3381 { 3382 fp_cmd_t *cmd; 3383 3384 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3385 3386 mutex_enter(&port->fp_mutex); 3387 3388 if (port->fp_wait_head == NULL) { 3389 /* 3390 * To avoid races, NULL the fp_wait_tid as 3391 * we are about to exit the timeout thread. 3392 */ 3393 port->fp_wait_tid = NULL; 3394 mutex_exit(&port->fp_mutex); 3395 return (NULL); 3396 } 3397 3398 cmd = port->fp_wait_head; 3399 port->fp_wait_head = cmd->cmd_next; 3400 cmd->cmd_next = NULL; 3401 3402 if (port->fp_wait_head == NULL) { 3403 port->fp_wait_tail = NULL; 3404 } 3405 mutex_exit(&port->fp_mutex); 3406 3407 return (cmd); 3408 } 3409 3410 3411 /* 3412 * Wait for job completion 3413 */ 3414 static void 3415 fp_jobwait(job_request_t *job) 3416 { 3417 sema_p(&job->job_port_sema); 3418 } 3419 3420 3421 /* 3422 * Convert FC packet state to FC errno 3423 */ 3424 int 3425 fp_state_to_rval(uchar_t state) 3426 { 3427 int count; 3428 3429 for (count = 0; count < sizeof (fp_xlat) / 3430 sizeof (fp_xlat[0]); count++) { 3431 if (fp_xlat[count].xlat_state == state) { 3432 return (fp_xlat[count].xlat_rval); 3433 } 3434 } 3435 3436 return (FC_FAILURE); 3437 } 3438 3439 3440 /* 3441 * For Synchronous I/O requests, the caller is 3442 * expected to do fctl_jobdone(if necessary) 3443 * 3444 * We want to preserve at least one failure in the 3445 * job_result if it happens. 3446 * 3447 */ 3448 static void 3449 fp_iodone(fp_cmd_t *cmd) 3450 { 3451 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt; 3452 job_request_t *job = cmd->cmd_job; 3453 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd; 3454 3455 ASSERT(job != NULL); 3456 ASSERT(cmd->cmd_port != NULL); 3457 ASSERT(&cmd->cmd_pkt != NULL); 3458 3459 mutex_enter(&job->job_mutex); 3460 if (job->job_result == FC_SUCCESS) { 3461 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state); 3462 } 3463 mutex_exit(&job->job_mutex); 3464 3465 if (pd) { 3466 mutex_enter(&pd->pd_mutex); 3467 pd->pd_flags = PD_IDLE; 3468 mutex_exit(&pd->pd_mutex); 3469 } 3470 3471 if (ulp_pkt) { 3472 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR && 3473 FP_IS_PKT_ERROR(ulp_pkt)) { 3474 fc_local_port_t *port; 3475 fc_remote_node_t *node; 3476 3477 port = cmd->cmd_port; 3478 3479 mutex_enter(&pd->pd_mutex); 3480 pd->pd_state = PORT_DEVICE_INVALID; 3481 pd->pd_ref_count--; 3482 node = pd->pd_remote_nodep; 3483 mutex_exit(&pd->pd_mutex); 3484 3485 ASSERT(node != NULL); 3486 ASSERT(port != NULL); 3487 3488 if (fctl_destroy_remote_port(port, pd) == 0) { 3489 fctl_destroy_remote_node(node); 3490 } 3491 3492 ulp_pkt->pkt_pd = NULL; 3493 } 3494 3495 ulp_pkt->pkt_comp(ulp_pkt); 3496 } 3497 3498 fp_free_pkt(cmd); 3499 fp_jobdone(job); 3500 } 3501 3502 3503 /* 3504 * Job completion handler 3505 */ 3506 static void 3507 fp_jobdone(job_request_t *job) 3508 { 3509 mutex_enter(&job->job_mutex); 3510 ASSERT(job->job_counter > 0); 3511 3512 if (--job->job_counter != 0) { 3513 mutex_exit(&job->job_mutex); 3514 return; 3515 } 3516 3517 if (job->job_ulp_pkts) { 3518 ASSERT(job->job_ulp_listlen > 0); 3519 kmem_free(job->job_ulp_pkts, 3520 sizeof (fc_packet_t *) * job->job_ulp_listlen); 3521 } 3522 3523 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3524 mutex_exit(&job->job_mutex); 3525 fctl_jobdone(job); 3526 } else { 3527 mutex_exit(&job->job_mutex); 3528 sema_v(&job->job_port_sema); 3529 } 3530 } 3531 3532 3533 /* 3534 * Try to perform shutdown of a port during a detach. No return 3535 * value since the detach should not fail because the port shutdown 3536 * failed. 3537 */ 3538 static void 3539 fp_port_shutdown(fc_local_port_t *port, job_request_t *job) 3540 { 3541 int index; 3542 int count; 3543 int flags; 3544 fp_cmd_t *cmd; 3545 struct pwwn_hash *head; 3546 fc_remote_port_t *pd; 3547 3548 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3549 3550 job->job_result = FC_SUCCESS; 3551 3552 if (port->fp_taskq) { 3553 /* 3554 * We must release the mutex here to ensure that other 3555 * potential jobs can complete their processing. Many 3556 * also need this mutex. 3557 */ 3558 mutex_exit(&port->fp_mutex); 3559 taskq_wait(port->fp_taskq); 3560 mutex_enter(&port->fp_mutex); 3561 } 3562 3563 if (port->fp_offline_tid) { 3564 timeout_id_t tid; 3565 3566 tid = port->fp_offline_tid; 3567 port->fp_offline_tid = NULL; 3568 mutex_exit(&port->fp_mutex); 3569 (void) untimeout(tid); 3570 mutex_enter(&port->fp_mutex); 3571 } 3572 3573 if (port->fp_wait_tid) { 3574 timeout_id_t tid; 3575 3576 tid = port->fp_wait_tid; 3577 port->fp_wait_tid = NULL; 3578 mutex_exit(&port->fp_mutex); 3579 (void) untimeout(tid); 3580 } else { 3581 mutex_exit(&port->fp_mutex); 3582 } 3583 3584 /* 3585 * While we cancel the timeout, let's also return the 3586 * the outstanding requests back to the callers. 3587 */ 3588 while ((cmd = fp_deque_cmd(port)) != NULL) { 3589 ASSERT(cmd->cmd_job != NULL); 3590 cmd->cmd_job->job_result = FC_OFFLINE; 3591 fp_iodone(cmd); 3592 } 3593 3594 /* 3595 * Gracefully LOGO with all the devices logged in. 3596 */ 3597 mutex_enter(&port->fp_mutex); 3598 3599 for (count = index = 0; index < pwwn_table_size; index++) { 3600 head = &port->fp_pwwn_table[index]; 3601 pd = head->pwwn_head; 3602 while (pd != NULL) { 3603 mutex_enter(&pd->pd_mutex); 3604 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3605 count++; 3606 } 3607 mutex_exit(&pd->pd_mutex); 3608 pd = pd->pd_wwn_hnext; 3609 } 3610 } 3611 3612 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3613 flags = job->job_flags; 3614 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 3615 } else { 3616 flags = 0; 3617 } 3618 if (count) { 3619 job->job_counter = count; 3620 3621 for (index = 0; index < pwwn_table_size; index++) { 3622 head = &port->fp_pwwn_table[index]; 3623 pd = head->pwwn_head; 3624 while (pd != NULL) { 3625 mutex_enter(&pd->pd_mutex); 3626 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3627 ASSERT(pd->pd_login_count > 0); 3628 /* 3629 * Force the counter to ONE in order 3630 * for us to really send LOGO els. 3631 */ 3632 pd->pd_login_count = 1; 3633 mutex_exit(&pd->pd_mutex); 3634 mutex_exit(&port->fp_mutex); 3635 (void) fp_logout(port, pd, job); 3636 mutex_enter(&port->fp_mutex); 3637 } else { 3638 mutex_exit(&pd->pd_mutex); 3639 } 3640 pd = pd->pd_wwn_hnext; 3641 } 3642 } 3643 mutex_exit(&port->fp_mutex); 3644 fp_jobwait(job); 3645 } else { 3646 mutex_exit(&port->fp_mutex); 3647 } 3648 3649 if (job->job_result != FC_SUCCESS) { 3650 FP_TRACE(FP_NHEAD1(9, 0), 3651 "Can't logout all devices. Proceeding with" 3652 " port shutdown"); 3653 job->job_result = FC_SUCCESS; 3654 } 3655 3656 fctl_destroy_all_remote_ports(port); 3657 3658 mutex_enter(&port->fp_mutex); 3659 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3660 mutex_exit(&port->fp_mutex); 3661 fp_ns_fini(port, job); 3662 } else { 3663 mutex_exit(&port->fp_mutex); 3664 } 3665 3666 if (flags) { 3667 job->job_flags = flags; 3668 } 3669 3670 mutex_enter(&port->fp_mutex); 3671 3672 } 3673 3674 3675 /* 3676 * Build the port driver's data structures based on the AL_PA list 3677 */ 3678 static void 3679 fp_get_loopmap(fc_local_port_t *port, job_request_t *job) 3680 { 3681 int rval; 3682 int flag; 3683 int count; 3684 uint32_t d_id; 3685 fc_remote_port_t *pd; 3686 fc_lilpmap_t *lilp_map; 3687 3688 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3689 3690 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3691 job->job_result = FC_OFFLINE; 3692 mutex_exit(&port->fp_mutex); 3693 fp_jobdone(job); 3694 mutex_enter(&port->fp_mutex); 3695 return; 3696 } 3697 3698 if (port->fp_lilp_map.lilp_length == 0) { 3699 mutex_exit(&port->fp_mutex); 3700 job->job_result = FC_NO_MAP; 3701 fp_jobdone(job); 3702 mutex_enter(&port->fp_mutex); 3703 return; 3704 } 3705 mutex_exit(&port->fp_mutex); 3706 3707 lilp_map = &port->fp_lilp_map; 3708 job->job_counter = lilp_map->lilp_length; 3709 3710 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) { 3711 flag = FP_CMD_PLOGI_RETAIN; 3712 } else { 3713 flag = FP_CMD_PLOGI_DONT_CARE; 3714 } 3715 3716 for (count = 0; count < lilp_map->lilp_length; count++) { 3717 d_id = lilp_map->lilp_alpalist[count]; 3718 3719 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3720 fp_jobdone(job); 3721 continue; 3722 } 3723 3724 pd = fctl_get_remote_port_by_did(port, d_id); 3725 if (pd) { 3726 mutex_enter(&pd->pd_mutex); 3727 if (flag == FP_CMD_PLOGI_DONT_CARE || 3728 pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3729 mutex_exit(&pd->pd_mutex); 3730 fp_jobdone(job); 3731 continue; 3732 } 3733 mutex_exit(&pd->pd_mutex); 3734 } 3735 3736 rval = fp_port_login(port, d_id, job, flag, 3737 KM_SLEEP, pd, NULL); 3738 if (rval != FC_SUCCESS) { 3739 fp_jobdone(job); 3740 } 3741 } 3742 3743 mutex_enter(&port->fp_mutex); 3744 } 3745 3746 3747 /* 3748 * Perform loop ONLINE processing 3749 */ 3750 static void 3751 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan) 3752 { 3753 int count; 3754 int rval; 3755 uint32_t d_id; 3756 uint32_t listlen; 3757 fc_lilpmap_t *lilp_map; 3758 fc_remote_port_t *pd; 3759 fc_portmap_t *changelist; 3760 3761 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3762 3763 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p", 3764 port, job); 3765 3766 lilp_map = &port->fp_lilp_map; 3767 3768 if (lilp_map->lilp_length) { 3769 mutex_enter(&port->fp_mutex); 3770 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 3771 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 3772 mutex_exit(&port->fp_mutex); 3773 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000)); 3774 } else { 3775 mutex_exit(&port->fp_mutex); 3776 } 3777 3778 job->job_counter = lilp_map->lilp_length; 3779 3780 for (count = 0; count < lilp_map->lilp_length; count++) { 3781 d_id = lilp_map->lilp_alpalist[count]; 3782 3783 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3784 fp_jobdone(job); 3785 continue; 3786 } 3787 3788 pd = fctl_get_remote_port_by_did(port, d_id); 3789 if (pd != NULL) { 3790 #ifdef DEBUG 3791 mutex_enter(&pd->pd_mutex); 3792 if (pd->pd_recepient == PD_PLOGI_INITIATOR) { 3793 ASSERT(pd->pd_type != PORT_DEVICE_OLD); 3794 } 3795 mutex_exit(&pd->pd_mutex); 3796 #endif 3797 fp_jobdone(job); 3798 continue; 3799 } 3800 3801 rval = fp_port_login(port, d_id, job, 3802 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL); 3803 3804 if (rval != FC_SUCCESS) { 3805 fp_jobdone(job); 3806 } 3807 } 3808 fp_jobwait(job); 3809 } 3810 listlen = 0; 3811 changelist = NULL; 3812 3813 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3814 mutex_enter(&port->fp_mutex); 3815 ASSERT(port->fp_statec_busy > 0); 3816 if (port->fp_statec_busy == 1) { 3817 mutex_exit(&port->fp_mutex); 3818 fctl_fillout_map(port, &changelist, &listlen, 3819 1, 0, orphan); 3820 3821 mutex_enter(&port->fp_mutex); 3822 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 3823 ASSERT(port->fp_total_devices == 0); 3824 port->fp_total_devices = port->fp_dev_count; 3825 } 3826 } else { 3827 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3828 } 3829 mutex_exit(&port->fp_mutex); 3830 } 3831 3832 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3833 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 3834 listlen, listlen, KM_SLEEP); 3835 } else { 3836 mutex_enter(&port->fp_mutex); 3837 if (--port->fp_statec_busy == 0) { 3838 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 3839 } 3840 ASSERT(changelist == NULL && listlen == 0); 3841 mutex_exit(&port->fp_mutex); 3842 } 3843 3844 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p", 3845 port, job); 3846 } 3847 3848 3849 /* 3850 * Get an Arbitrated Loop map from the underlying FCA 3851 */ 3852 static int 3853 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map) 3854 { 3855 int rval; 3856 3857 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p", 3858 port, lilp_map); 3859 3860 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t)); 3861 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map); 3862 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */ 3863 3864 if (rval != FC_SUCCESS) { 3865 rval = FC_NO_MAP; 3866 } else if (lilp_map->lilp_length == 0 && 3867 (lilp_map->lilp_magic >= MAGIC_LISM && 3868 lilp_map->lilp_magic < MAGIC_LIRP)) { 3869 uchar_t lilp_length; 3870 3871 /* 3872 * Since the map length is zero, provide all 3873 * the valid AL_PAs for NL_ports discovery. 3874 */ 3875 lilp_length = sizeof (fp_valid_alpas) / 3876 sizeof (fp_valid_alpas[0]); 3877 lilp_map->lilp_length = lilp_length; 3878 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist, 3879 lilp_length); 3880 } else { 3881 rval = fp_validate_lilp_map(lilp_map); 3882 3883 if (rval == FC_SUCCESS) { 3884 mutex_enter(&port->fp_mutex); 3885 port->fp_total_devices = lilp_map->lilp_length - 1; 3886 mutex_exit(&port->fp_mutex); 3887 } 3888 } 3889 3890 mutex_enter(&port->fp_mutex); 3891 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) { 3892 port->fp_soft_state |= FP_SOFT_BAD_LINK; 3893 mutex_exit(&port->fp_mutex); 3894 3895 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle, 3896 FC_FCA_RESET_CORE) != FC_SUCCESS) { 3897 FP_TRACE(FP_NHEAD1(9, 0), 3898 "FCA reset failed after LILP map was found" 3899 " to be invalid"); 3900 } 3901 } else if (rval == FC_SUCCESS) { 3902 port->fp_soft_state &= ~FP_SOFT_BAD_LINK; 3903 mutex_exit(&port->fp_mutex); 3904 } else { 3905 mutex_exit(&port->fp_mutex); 3906 } 3907 3908 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port, 3909 lilp_map); 3910 3911 return (rval); 3912 } 3913 3914 3915 /* 3916 * Perform Fabric Login: 3917 * 3918 * Return Values: 3919 * FC_SUCCESS 3920 * FC_FAILURE 3921 * FC_NOMEM 3922 * FC_TRANSPORT_ERROR 3923 * and a lot others defined in fc_error.h 3924 */ 3925 static int 3926 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job, 3927 int flag, int sleep) 3928 { 3929 int rval; 3930 fp_cmd_t *cmd; 3931 uchar_t class; 3932 3933 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3934 3935 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p", 3936 port, job); 3937 3938 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 3939 if (class == FC_TRAN_CLASS_INVALID) { 3940 return (FC_ELS_BAD); 3941 } 3942 3943 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 3944 sizeof (la_els_logi_t), sleep, NULL); 3945 if (cmd == NULL) { 3946 return (FC_NOMEM); 3947 } 3948 3949 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 3950 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 3951 cmd->cmd_flags = flag; 3952 cmd->cmd_retry_count = fp_retry_count; 3953 cmd->cmd_ulp_pkt = NULL; 3954 3955 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr, 3956 job, LA_ELS_FLOGI); 3957 3958 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 3959 if (rval != FC_SUCCESS) { 3960 fp_free_pkt(cmd); 3961 } 3962 3963 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p", 3964 port, job); 3965 3966 return (rval); 3967 } 3968 3969 3970 /* 3971 * In some scenarios such as private loop device discovery period 3972 * the fc_remote_port_t data structure isn't allocated. The allocation 3973 * is done when the PLOGI is successful. In some other scenarios 3974 * such as Fabric topology, the fc_remote_port_t is already created 3975 * and initialized with appropriate values (as the NS provides 3976 * them) 3977 */ 3978 static int 3979 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job, 3980 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt) 3981 { 3982 uchar_t class; 3983 fp_cmd_t *cmd; 3984 uint32_t src_id; 3985 fc_remote_port_t *tmp_pd; 3986 int relogin; 3987 int found = 0; 3988 3989 #ifdef DEBUG 3990 if (pd == NULL) { 3991 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL); 3992 } 3993 #endif 3994 ASSERT(job->job_counter > 0); 3995 3996 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 3997 if (class == FC_TRAN_CLASS_INVALID) { 3998 return (FC_ELS_BAD); 3999 } 4000 4001 mutex_enter(&port->fp_mutex); 4002 tmp_pd = fctl_lookup_pd_by_did(port, d_id); 4003 mutex_exit(&port->fp_mutex); 4004 4005 relogin = 1; 4006 if (tmp_pd) { 4007 mutex_enter(&tmp_pd->pd_mutex); 4008 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) && 4009 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) { 4010 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN; 4011 relogin = 0; 4012 } 4013 mutex_exit(&tmp_pd->pd_mutex); 4014 } 4015 4016 if (!relogin) { 4017 mutex_enter(&tmp_pd->pd_mutex); 4018 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4019 cmd_flag |= FP_CMD_PLOGI_RETAIN; 4020 } 4021 mutex_exit(&tmp_pd->pd_mutex); 4022 4023 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 4024 sizeof (la_els_adisc_t), sleep, tmp_pd); 4025 if (cmd == NULL) { 4026 return (FC_NOMEM); 4027 } 4028 4029 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4030 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4031 cmd->cmd_flags = cmd_flag; 4032 cmd->cmd_retry_count = fp_retry_count; 4033 cmd->cmd_ulp_pkt = ulp_pkt; 4034 4035 mutex_enter(&port->fp_mutex); 4036 mutex_enter(&tmp_pd->pd_mutex); 4037 fp_adisc_init(cmd, job); 4038 mutex_exit(&tmp_pd->pd_mutex); 4039 mutex_exit(&port->fp_mutex); 4040 4041 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t); 4042 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t); 4043 4044 } else { 4045 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4046 sizeof (la_els_logi_t), sleep, pd); 4047 if (cmd == NULL) { 4048 return (FC_NOMEM); 4049 } 4050 4051 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4052 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4053 cmd->cmd_flags = cmd_flag; 4054 cmd->cmd_retry_count = fp_retry_count; 4055 cmd->cmd_ulp_pkt = ulp_pkt; 4056 4057 mutex_enter(&port->fp_mutex); 4058 src_id = port->fp_port_id.port_id; 4059 mutex_exit(&port->fp_mutex); 4060 4061 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr, 4062 job, LA_ELS_PLOGI); 4063 } 4064 4065 if (pd) { 4066 mutex_enter(&pd->pd_mutex); 4067 pd->pd_flags = PD_ELS_IN_PROGRESS; 4068 mutex_exit(&pd->pd_mutex); 4069 } 4070 4071 /* npiv check to make sure we don't log into ourself */ 4072 if (relogin && (port->fp_topology == FC_TOP_FABRIC)) { 4073 if ((d_id & 0xffff00) == 4074 (port->fp_port_id.port_id & 0xffff00)) { 4075 found = 1; 4076 } 4077 } 4078 4079 if (found || 4080 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) { 4081 if (found) { 4082 fc_packet_t *pkt = &cmd->cmd_pkt; 4083 pkt->pkt_state = FC_PKT_NPORT_RJT; 4084 } 4085 if (pd) { 4086 mutex_enter(&pd->pd_mutex); 4087 pd->pd_flags = PD_IDLE; 4088 mutex_exit(&pd->pd_mutex); 4089 } 4090 4091 if (ulp_pkt) { 4092 fc_packet_t *pkt = &cmd->cmd_pkt; 4093 4094 ulp_pkt->pkt_state = pkt->pkt_state; 4095 ulp_pkt->pkt_reason = pkt->pkt_reason; 4096 ulp_pkt->pkt_action = pkt->pkt_action; 4097 ulp_pkt->pkt_expln = pkt->pkt_expln; 4098 } 4099 4100 fp_iodone(cmd); 4101 } 4102 4103 return (FC_SUCCESS); 4104 } 4105 4106 4107 /* 4108 * Register the LOGIN parameters with a port device 4109 */ 4110 static void 4111 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 4112 la_els_logi_t *acc, uchar_t class) 4113 { 4114 fc_remote_node_t *node; 4115 4116 ASSERT(pd != NULL); 4117 4118 mutex_enter(&pd->pd_mutex); 4119 node = pd->pd_remote_nodep; 4120 if (pd->pd_login_count == 0) { 4121 pd->pd_login_count++; 4122 } 4123 4124 if (handle) { 4125 ddi_rep_get8(*handle, (uint8_t *)&pd->pd_csp, 4126 (uint8_t *)&acc->common_service, 4127 sizeof (acc->common_service), DDI_DEV_AUTOINCR); 4128 ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp1, 4129 (uint8_t *)&acc->class_1, sizeof (acc->class_1), 4130 DDI_DEV_AUTOINCR); 4131 ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp2, 4132 (uint8_t *)&acc->class_2, sizeof (acc->class_2), 4133 DDI_DEV_AUTOINCR); 4134 ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp3, 4135 (uint8_t *)&acc->class_3, sizeof (acc->class_3), 4136 DDI_DEV_AUTOINCR); 4137 } else { 4138 pd->pd_csp = acc->common_service; 4139 pd->pd_clsp1 = acc->class_1; 4140 pd->pd_clsp2 = acc->class_2; 4141 pd->pd_clsp3 = acc->class_3; 4142 } 4143 4144 pd->pd_state = PORT_DEVICE_LOGGED_IN; 4145 pd->pd_login_class = class; 4146 mutex_exit(&pd->pd_mutex); 4147 4148 #ifndef __lock_lint 4149 ASSERT(fctl_get_remote_port_by_did(pd->pd_port, 4150 pd->pd_port_id.port_id) == pd); 4151 #endif 4152 4153 mutex_enter(&node->fd_mutex); 4154 if (handle) { 4155 ddi_rep_get8(*handle, (uint8_t *)node->fd_vv, 4156 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv), 4157 DDI_DEV_AUTOINCR); 4158 } else { 4159 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv)); 4160 } 4161 mutex_exit(&node->fd_mutex); 4162 } 4163 4164 4165 /* 4166 * Mark the remote port as OFFLINE 4167 */ 4168 static void 4169 fp_remote_port_offline(fc_remote_port_t *pd) 4170 { 4171 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4172 if (pd->pd_login_count && 4173 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) { 4174 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4175 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4176 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4177 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4178 pd->pd_login_class = 0; 4179 } 4180 pd->pd_type = PORT_DEVICE_OLD; 4181 pd->pd_flags = PD_IDLE; 4182 fctl_tc_reset(&pd->pd_logo_tc); 4183 } 4184 4185 4186 /* 4187 * Deregistration of a port device 4188 */ 4189 static void 4190 fp_unregister_login(fc_remote_port_t *pd) 4191 { 4192 fc_remote_node_t *node; 4193 4194 ASSERT(pd != NULL); 4195 4196 mutex_enter(&pd->pd_mutex); 4197 pd->pd_login_count = 0; 4198 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4199 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4200 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4201 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4202 4203 pd->pd_state = PORT_DEVICE_VALID; 4204 pd->pd_login_class = 0; 4205 node = pd->pd_remote_nodep; 4206 mutex_exit(&pd->pd_mutex); 4207 4208 mutex_enter(&node->fd_mutex); 4209 bzero(node->fd_vv, sizeof (node->fd_vv)); 4210 mutex_exit(&node->fd_mutex); 4211 } 4212 4213 4214 /* 4215 * Handle OFFLINE state of an FCA port 4216 */ 4217 static void 4218 fp_port_offline(fc_local_port_t *port, int notify) 4219 { 4220 int index; 4221 int statec; 4222 timeout_id_t tid; 4223 struct pwwn_hash *head; 4224 fc_remote_port_t *pd; 4225 4226 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4227 4228 for (index = 0; index < pwwn_table_size; index++) { 4229 head = &port->fp_pwwn_table[index]; 4230 pd = head->pwwn_head; 4231 while (pd != NULL) { 4232 mutex_enter(&pd->pd_mutex); 4233 fp_remote_port_offline(pd); 4234 fctl_delist_did_table(port, pd); 4235 mutex_exit(&pd->pd_mutex); 4236 pd = pd->pd_wwn_hnext; 4237 } 4238 } 4239 port->fp_total_devices = 0; 4240 4241 statec = 0; 4242 if (notify) { 4243 /* 4244 * Decrement the statec busy counter as we 4245 * are almost done with handling the state 4246 * change 4247 */ 4248 ASSERT(port->fp_statec_busy > 0); 4249 if (--port->fp_statec_busy == 0) { 4250 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4251 } 4252 mutex_exit(&port->fp_mutex); 4253 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL, 4254 0, 0, KM_SLEEP); 4255 mutex_enter(&port->fp_mutex); 4256 4257 if (port->fp_statec_busy) { 4258 statec++; 4259 } 4260 } else if (port->fp_statec_busy > 1) { 4261 statec++; 4262 } 4263 4264 if ((tid = port->fp_offline_tid) != NULL) { 4265 mutex_exit(&port->fp_mutex); 4266 (void) untimeout(tid); 4267 mutex_enter(&port->fp_mutex); 4268 } 4269 4270 if (!statec) { 4271 port->fp_offline_tid = timeout(fp_offline_timeout, 4272 (caddr_t)port, fp_offline_ticks); 4273 } 4274 } 4275 4276 4277 /* 4278 * Offline devices and send up a state change notification to ULPs 4279 */ 4280 static void 4281 fp_offline_timeout(void *port_handle) 4282 { 4283 int ret; 4284 fc_local_port_t *port = port_handle; 4285 uint32_t listlen = 0; 4286 fc_portmap_t *changelist = NULL; 4287 4288 mutex_enter(&port->fp_mutex); 4289 4290 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) || 4291 (port->fp_soft_state & 4292 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 4293 port->fp_dev_count == 0 || port->fp_statec_busy) { 4294 port->fp_offline_tid = NULL; 4295 mutex_exit(&port->fp_mutex); 4296 return; 4297 } 4298 4299 mutex_exit(&port->fp_mutex); 4300 4301 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout"); 4302 4303 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) { 4304 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4305 FC_FCA_CORE)) != FC_SUCCESS) { 4306 FP_TRACE(FP_NHEAD1(9, ret), 4307 "Failed to force adapter dump"); 4308 } else { 4309 FP_TRACE(FP_NHEAD1(9, 0), 4310 "Forced adapter dump successfully"); 4311 } 4312 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) { 4313 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4314 FC_FCA_RESET_CORE)) != FC_SUCCESS) { 4315 FP_TRACE(FP_NHEAD1(9, ret), 4316 "Failed to force adapter dump and reset"); 4317 } else { 4318 FP_TRACE(FP_NHEAD1(9, 0), 4319 "Forced adapter dump and reset successfully"); 4320 } 4321 } 4322 4323 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 4324 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist, 4325 listlen, listlen, KM_SLEEP); 4326 4327 mutex_enter(&port->fp_mutex); 4328 port->fp_offline_tid = NULL; 4329 mutex_exit(&port->fp_mutex); 4330 } 4331 4332 4333 /* 4334 * Perform general purpose ELS request initialization 4335 */ 4336 static void 4337 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id, 4338 void (*comp) (), job_request_t *job) 4339 { 4340 fc_packet_t *pkt; 4341 4342 pkt = &cmd->cmd_pkt; 4343 cmd->cmd_job = job; 4344 4345 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; 4346 pkt->pkt_cmd_fhdr.d_id = d_id; 4347 pkt->pkt_cmd_fhdr.s_id = s_id; 4348 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 4349 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ; 4350 pkt->pkt_cmd_fhdr.seq_id = 0; 4351 pkt->pkt_cmd_fhdr.df_ctl = 0; 4352 pkt->pkt_cmd_fhdr.seq_cnt = 0; 4353 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 4354 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 4355 pkt->pkt_cmd_fhdr.ro = 0; 4356 pkt->pkt_cmd_fhdr.rsvd = 0; 4357 pkt->pkt_comp = comp; 4358 pkt->pkt_timeout = FP_ELS_TIMEOUT; 4359 } 4360 4361 4362 /* 4363 * Initialize PLOGI/FLOGI ELS request 4364 */ 4365 static void 4366 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id, 4367 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code) 4368 { 4369 ls_code_t payload; 4370 4371 fp_els_init(cmd, s_id, d_id, intr, job); 4372 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4373 4374 payload.ls_code = ls_code; 4375 payload.mbz = 0; 4376 4377 ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc, 4378 (uint8_t *)&port->fp_service_params, 4379 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params), 4380 DDI_DEV_AUTOINCR); 4381 4382 ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload, 4383 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload), 4384 DDI_DEV_AUTOINCR); 4385 } 4386 4387 4388 /* 4389 * Initialize LOGO ELS request 4390 */ 4391 static void 4392 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job) 4393 { 4394 fc_local_port_t *port; 4395 fc_packet_t *pkt; 4396 la_els_logo_t payload; 4397 4398 port = pd->pd_port; 4399 pkt = &cmd->cmd_pkt; 4400 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4401 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4402 4403 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4404 fp_logo_intr, job); 4405 4406 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4407 4408 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4409 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4410 4411 payload.ls_code.ls_code = LA_ELS_LOGO; 4412 payload.ls_code.mbz = 0; 4413 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 4414 payload.nport_id = port->fp_port_id; 4415 4416 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 4417 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4418 } 4419 4420 /* 4421 * Initialize RNID ELS request 4422 */ 4423 static void 4424 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job) 4425 { 4426 fc_local_port_t *port; 4427 fc_packet_t *pkt; 4428 la_els_rnid_t payload; 4429 fc_remote_port_t *pd; 4430 4431 pkt = &cmd->cmd_pkt; 4432 pd = pkt->pkt_pd; 4433 port = pd->pd_port; 4434 4435 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4436 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4437 4438 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4439 fp_rnid_intr, job); 4440 4441 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4442 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4443 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4444 4445 payload.ls_code.ls_code = LA_ELS_RNID; 4446 payload.ls_code.mbz = 0; 4447 payload.data_format = flag; 4448 4449 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 4450 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4451 } 4452 4453 /* 4454 * Initialize RLS ELS request 4455 */ 4456 static void 4457 fp_rls_init(fp_cmd_t *cmd, job_request_t *job) 4458 { 4459 fc_local_port_t *port; 4460 fc_packet_t *pkt; 4461 la_els_rls_t payload; 4462 fc_remote_port_t *pd; 4463 4464 pkt = &cmd->cmd_pkt; 4465 pd = pkt->pkt_pd; 4466 port = pd->pd_port; 4467 4468 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4469 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4470 4471 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4472 fp_rls_intr, job); 4473 4474 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4475 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4476 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4477 4478 payload.ls_code.ls_code = LA_ELS_RLS; 4479 payload.ls_code.mbz = 0; 4480 payload.rls_portid = port->fp_port_id; 4481 4482 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 4483 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4484 } 4485 4486 4487 /* 4488 * Initialize an ADISC ELS request 4489 */ 4490 static void 4491 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job) 4492 { 4493 fc_local_port_t *port; 4494 fc_packet_t *pkt; 4495 la_els_adisc_t payload; 4496 fc_remote_port_t *pd; 4497 4498 pkt = &cmd->cmd_pkt; 4499 pd = pkt->pkt_pd; 4500 port = pd->pd_port; 4501 4502 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4503 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex)); 4504 4505 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4506 fp_adisc_intr, job); 4507 4508 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4509 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4510 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4511 4512 payload.ls_code.ls_code = LA_ELS_ADISC; 4513 payload.ls_code.mbz = 0; 4514 payload.nport_id = port->fp_port_id; 4515 payload.port_wwn = port->fp_service_params.nport_ww_name; 4516 payload.node_wwn = port->fp_service_params.node_ww_name; 4517 payload.hard_addr = port->fp_hard_addr; 4518 4519 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 4520 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4521 } 4522 4523 4524 /* 4525 * Send up a state change notification to ULPs. 4526 * Spawns a call to fctl_ulp_statec_cb in a taskq thread. 4527 */ 4528 static int 4529 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state, 4530 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep) 4531 { 4532 fc_port_clist_t *clist; 4533 fc_remote_port_t *pd; 4534 int count; 4535 4536 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4537 4538 clist = kmem_zalloc(sizeof (*clist), sleep); 4539 if (clist == NULL) { 4540 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4541 return (FC_NOMEM); 4542 } 4543 4544 clist->clist_state = state; 4545 4546 mutex_enter(&port->fp_mutex); 4547 clist->clist_flags = port->fp_topology; 4548 mutex_exit(&port->fp_mutex); 4549 4550 clist->clist_port = (opaque_t)port; 4551 clist->clist_len = listlen; 4552 clist->clist_size = alloc_len; 4553 clist->clist_map = changelist; 4554 4555 /* 4556 * Bump the reference count of each fc_remote_port_t in this changelist. 4557 * This is necessary since these devices will be sitting in a taskq 4558 * and referenced later. When the state change notification is 4559 * complete, the reference counts will be decremented. 4560 */ 4561 for (count = 0; count < clist->clist_len; count++) { 4562 pd = clist->clist_map[count].map_pd; 4563 4564 if (pd != NULL) { 4565 mutex_enter(&pd->pd_mutex); 4566 ASSERT((pd->pd_ref_count >= 0) || 4567 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4568 pd->pd_ref_count++; 4569 4570 if (clist->clist_map[count].map_state != 4571 PORT_DEVICE_INVALID) { 4572 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4573 } 4574 4575 mutex_exit(&pd->pd_mutex); 4576 } 4577 } 4578 4579 #ifdef DEBUG 4580 /* 4581 * Sanity check for presence of OLD devices in the hash lists 4582 */ 4583 if (clist->clist_size) { 4584 ASSERT(clist->clist_map != NULL); 4585 for (count = 0; count < clist->clist_len; count++) { 4586 if (clist->clist_map[count].map_state == 4587 PORT_DEVICE_INVALID) { 4588 la_wwn_t pwwn; 4589 fc_portid_t d_id; 4590 4591 pd = clist->clist_map[count].map_pd; 4592 ASSERT(pd != NULL); 4593 4594 mutex_enter(&pd->pd_mutex); 4595 pwwn = pd->pd_port_name; 4596 d_id = pd->pd_port_id; 4597 mutex_exit(&pd->pd_mutex); 4598 4599 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4600 ASSERT(pd != clist->clist_map[count].map_pd); 4601 4602 pd = fctl_get_remote_port_by_did(port, 4603 d_id.port_id); 4604 ASSERT(pd != clist->clist_map[count].map_pd); 4605 } 4606 } 4607 } 4608 #endif 4609 4610 mutex_enter(&port->fp_mutex); 4611 4612 if (state == FC_STATE_ONLINE) { 4613 if (--port->fp_statec_busy == 0) { 4614 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4615 } 4616 } 4617 mutex_exit(&port->fp_mutex); 4618 4619 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 4620 clist, KM_SLEEP); 4621 4622 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p," 4623 "state=%x, len=%d", port, state, listlen); 4624 4625 return (FC_SUCCESS); 4626 } 4627 4628 4629 /* 4630 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs 4631 */ 4632 static int 4633 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist, 4634 uint32_t listlen, uint32_t alloc_len, int sleep, int sync) 4635 { 4636 int ret; 4637 fc_port_clist_t *clist; 4638 4639 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4640 4641 clist = kmem_zalloc(sizeof (*clist), sleep); 4642 if (clist == NULL) { 4643 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4644 return (FC_NOMEM); 4645 } 4646 4647 clist->clist_state = FC_STATE_DEVICE_CHANGE; 4648 4649 mutex_enter(&port->fp_mutex); 4650 clist->clist_flags = port->fp_topology; 4651 mutex_exit(&port->fp_mutex); 4652 4653 clist->clist_port = (opaque_t)port; 4654 clist->clist_len = listlen; 4655 clist->clist_size = alloc_len; 4656 clist->clist_map = changelist; 4657 4658 /* Send sysevents for target state changes */ 4659 4660 if (clist->clist_size) { 4661 int count; 4662 fc_remote_port_t *pd; 4663 4664 ASSERT(clist->clist_map != NULL); 4665 for (count = 0; count < clist->clist_len; count++) { 4666 pd = clist->clist_map[count].map_pd; 4667 4668 /* 4669 * Bump reference counts on all fc_remote_port_t 4670 * structs in this list. We don't know when the task 4671 * will fire, and we don't need these fc_remote_port_t 4672 * structs going away behind our back. 4673 */ 4674 if (pd) { 4675 mutex_enter(&pd->pd_mutex); 4676 ASSERT((pd->pd_ref_count >= 0) || 4677 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4678 pd->pd_ref_count++; 4679 mutex_exit(&pd->pd_mutex); 4680 } 4681 4682 if (clist->clist_map[count].map_state == 4683 PORT_DEVICE_VALID) { 4684 if (clist->clist_map[count].map_type == 4685 PORT_DEVICE_NEW) { 4686 /* Update our state change counter */ 4687 mutex_enter(&port->fp_mutex); 4688 port->fp_last_change++; 4689 mutex_exit(&port->fp_mutex); 4690 4691 /* Additions */ 4692 fp_log_target_event(port, 4693 ESC_SUNFC_TARGET_ADD, 4694 clist->clist_map[count].map_pwwn, 4695 clist->clist_map[count].map_did. 4696 port_id); 4697 } 4698 4699 } else if ((clist->clist_map[count].map_type == 4700 PORT_DEVICE_OLD) && 4701 (clist->clist_map[count].map_state == 4702 PORT_DEVICE_INVALID)) { 4703 /* Update our state change counter */ 4704 mutex_enter(&port->fp_mutex); 4705 port->fp_last_change++; 4706 mutex_exit(&port->fp_mutex); 4707 4708 /* 4709 * For removals, we don't decrement 4710 * pd_ref_count until after the ULP's 4711 * state change callback function has 4712 * completed. 4713 */ 4714 4715 /* Removals */ 4716 fp_log_target_event(port, 4717 ESC_SUNFC_TARGET_REMOVE, 4718 clist->clist_map[count].map_pwwn, 4719 clist->clist_map[count].map_did.port_id); 4720 } 4721 4722 if (clist->clist_map[count].map_state != 4723 PORT_DEVICE_INVALID) { 4724 /* 4725 * Indicate that the ULPs are now aware of 4726 * this device. 4727 */ 4728 4729 mutex_enter(&pd->pd_mutex); 4730 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4731 mutex_exit(&pd->pd_mutex); 4732 } 4733 4734 #ifdef DEBUG 4735 /* 4736 * Sanity check for OLD devices in the hash lists 4737 */ 4738 if (pd && clist->clist_map[count].map_state == 4739 PORT_DEVICE_INVALID) { 4740 la_wwn_t pwwn; 4741 fc_portid_t d_id; 4742 4743 mutex_enter(&pd->pd_mutex); 4744 pwwn = pd->pd_port_name; 4745 d_id = pd->pd_port_id; 4746 mutex_exit(&pd->pd_mutex); 4747 4748 /* 4749 * This overwrites the 'pd' local variable. 4750 * Beware of this if 'pd' ever gets 4751 * referenced below this block. 4752 */ 4753 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4754 ASSERT(pd != clist->clist_map[count].map_pd); 4755 4756 pd = fctl_get_remote_port_by_did(port, 4757 d_id.port_id); 4758 ASSERT(pd != clist->clist_map[count].map_pd); 4759 } 4760 #endif 4761 } 4762 } 4763 4764 if (sync) { 4765 clist->clist_wait = 1; 4766 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL); 4767 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL); 4768 } 4769 4770 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep); 4771 if (sync && ret) { 4772 mutex_enter(&clist->clist_mutex); 4773 while (clist->clist_wait) { 4774 cv_wait(&clist->clist_cv, &clist->clist_mutex); 4775 } 4776 mutex_exit(&clist->clist_mutex); 4777 4778 mutex_destroy(&clist->clist_mutex); 4779 cv_destroy(&clist->clist_cv); 4780 kmem_free(clist, sizeof (*clist)); 4781 } 4782 4783 if (!ret) { 4784 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; " 4785 "port=%p", port); 4786 kmem_free(clist->clist_map, 4787 sizeof (*(clist->clist_map)) * clist->clist_size); 4788 kmem_free(clist, sizeof (*clist)); 4789 } else { 4790 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d", 4791 port, listlen); 4792 } 4793 4794 return (FC_SUCCESS); 4795 } 4796 4797 4798 /* 4799 * Perform PLOGI to the group of devices for ULPs 4800 */ 4801 static void 4802 fp_plogi_group(fc_local_port_t *port, job_request_t *job) 4803 { 4804 int offline; 4805 int count; 4806 int rval; 4807 uint32_t listlen; 4808 uint32_t done; 4809 uint32_t d_id; 4810 fc_remote_node_t *node; 4811 fc_remote_port_t *pd; 4812 fc_remote_port_t *tmp_pd; 4813 fc_packet_t *ulp_pkt; 4814 la_els_logi_t *els_data; 4815 ls_code_t ls_code; 4816 4817 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p", 4818 port, job); 4819 4820 done = 0; 4821 listlen = job->job_ulp_listlen; 4822 job->job_counter = job->job_ulp_listlen; 4823 4824 mutex_enter(&port->fp_mutex); 4825 offline = (port->fp_statec_busy || 4826 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0; 4827 mutex_exit(&port->fp_mutex); 4828 4829 for (count = 0; count < listlen; count++) { 4830 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >= 4831 sizeof (la_els_logi_t)); 4832 4833 ulp_pkt = job->job_ulp_pkts[count]; 4834 pd = ulp_pkt->pkt_pd; 4835 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 4836 4837 if (offline) { 4838 done++; 4839 4840 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 4841 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4842 ulp_pkt->pkt_pd = NULL; 4843 ulp_pkt->pkt_comp(ulp_pkt); 4844 4845 job->job_ulp_pkts[count] = NULL; 4846 4847 fp_jobdone(job); 4848 continue; 4849 } 4850 4851 if (pd == NULL) { 4852 pd = fctl_get_remote_port_by_did(port, d_id); 4853 if (pd == NULL) { /* reset later */ 4854 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4855 continue; 4856 } 4857 mutex_enter(&pd->pd_mutex); 4858 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 4859 mutex_exit(&pd->pd_mutex); 4860 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 4861 done++; 4862 ulp_pkt->pkt_comp(ulp_pkt); 4863 job->job_ulp_pkts[count] = NULL; 4864 fp_jobdone(job); 4865 } else { 4866 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4867 mutex_exit(&pd->pd_mutex); 4868 } 4869 continue; 4870 } 4871 4872 switch (ulp_pkt->pkt_state) { 4873 case FC_PKT_ELS_IN_PROGRESS: 4874 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4875 /* FALLTHRU */ 4876 case FC_PKT_LOCAL_RJT: 4877 done++; 4878 ulp_pkt->pkt_comp(ulp_pkt); 4879 job->job_ulp_pkts[count] = NULL; 4880 fp_jobdone(job); 4881 continue; 4882 default: 4883 break; 4884 } 4885 4886 /* 4887 * Validate the pd corresponding to the d_id passed 4888 * by the ULPs 4889 */ 4890 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 4891 if ((tmp_pd == NULL) || (pd != tmp_pd)) { 4892 done++; 4893 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4894 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION; 4895 ulp_pkt->pkt_pd = NULL; 4896 ulp_pkt->pkt_comp(ulp_pkt); 4897 job->job_ulp_pkts[count] = NULL; 4898 fp_jobdone(job); 4899 continue; 4900 } 4901 4902 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; " 4903 "port=%p, pd=%p", port, pd); 4904 4905 mutex_enter(&pd->pd_mutex); 4906 4907 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4908 done++; 4909 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp; 4910 4911 ls_code.ls_code = LA_ELS_ACC; 4912 ls_code.mbz = 0; 4913 4914 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4915 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code, 4916 sizeof (ls_code_t), DDI_DEV_AUTOINCR); 4917 4918 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4919 (uint8_t *)&pd->pd_csp, 4920 (uint8_t *)&els_data->common_service, 4921 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR); 4922 4923 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4924 (uint8_t *)&pd->pd_port_name, 4925 (uint8_t *)&els_data->nport_ww_name, 4926 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR); 4927 4928 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4929 (uint8_t *)&pd->pd_clsp1, 4930 (uint8_t *)&els_data->class_1, 4931 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR); 4932 4933 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4934 (uint8_t *)&pd->pd_clsp2, 4935 (uint8_t *)&els_data->class_2, 4936 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR); 4937 4938 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4939 (uint8_t *)&pd->pd_clsp3, 4940 (uint8_t *)&els_data->class_3, 4941 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR); 4942 4943 node = pd->pd_remote_nodep; 4944 pd->pd_login_count++; 4945 pd->pd_flags = PD_IDLE; 4946 ulp_pkt->pkt_pd = pd; 4947 mutex_exit(&pd->pd_mutex); 4948 4949 mutex_enter(&node->fd_mutex); 4950 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4951 (uint8_t *)&node->fd_node_name, 4952 (uint8_t *)(&els_data->node_ww_name), 4953 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR); 4954 4955 4956 ddi_rep_put8(ulp_pkt->pkt_resp_acc, 4957 (uint8_t *)&node->fd_vv, 4958 (uint8_t *)(&els_data->vendor_version), 4959 sizeof (node->fd_vv), DDI_DEV_AUTOINCR); 4960 4961 mutex_exit(&node->fd_mutex); 4962 ulp_pkt->pkt_state = FC_PKT_SUCCESS; 4963 } else { 4964 4965 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */ 4966 mutex_exit(&pd->pd_mutex); 4967 } 4968 4969 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) { 4970 ulp_pkt->pkt_comp(ulp_pkt); 4971 job->job_ulp_pkts[count] = NULL; 4972 fp_jobdone(job); 4973 } 4974 } 4975 4976 if (done == listlen) { 4977 fp_jobwait(job); 4978 fctl_jobdone(job); 4979 return; 4980 } 4981 4982 job->job_counter = listlen - done; 4983 4984 for (count = 0; count < listlen; count++) { 4985 int cmd_flags; 4986 4987 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) { 4988 continue; 4989 } 4990 4991 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE); 4992 4993 cmd_flags = FP_CMD_PLOGI_RETAIN; 4994 4995 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 4996 ASSERT(d_id != 0); 4997 4998 pd = fctl_get_remote_port_by_did(port, d_id); 4999 ulp_pkt->pkt_pd = pd; 5000 5001 if (pd != NULL) { 5002 mutex_enter(&pd->pd_mutex); 5003 d_id = pd->pd_port_id.port_id; 5004 pd->pd_flags = PD_ELS_IN_PROGRESS; 5005 mutex_exit(&pd->pd_mutex); 5006 } else { 5007 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5008 #ifdef DEBUG 5009 pd = fctl_get_remote_port_by_did(port, d_id); 5010 ASSERT(pd == NULL); 5011 #endif 5012 /* 5013 * In the Fabric topology, use NS to create 5014 * port device, and if that fails still try 5015 * with PLOGI - which will make yet another 5016 * attempt to create after successful PLOGI 5017 */ 5018 mutex_enter(&port->fp_mutex); 5019 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 5020 mutex_exit(&port->fp_mutex); 5021 pd = fp_create_remote_port_by_ns(port, 5022 d_id, KM_SLEEP); 5023 if (pd) { 5024 cmd_flags |= FP_CMD_DELDEV_ON_ERROR; 5025 5026 mutex_enter(&pd->pd_mutex); 5027 pd->pd_flags = PD_ELS_IN_PROGRESS; 5028 mutex_exit(&pd->pd_mutex); 5029 5030 FP_TRACE(FP_NHEAD1(3, 0), 5031 "fp_plogi_group;" 5032 " NS created PD port=%p, job=%p," 5033 " pd=%p", port, job, pd); 5034 } 5035 } else { 5036 mutex_exit(&port->fp_mutex); 5037 } 5038 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) { 5039 FP_TRACE(FP_NHEAD1(3, 0), 5040 "fp_plogi_group;" 5041 "ulp_pkt's pd is NULL, get a pd %p", 5042 pd); 5043 mutex_enter(&pd->pd_mutex); 5044 pd->pd_ref_count++; 5045 mutex_exit(&pd->pd_mutex); 5046 } 5047 ulp_pkt->pkt_pd = pd; 5048 } 5049 5050 rval = fp_port_login(port, d_id, job, cmd_flags, 5051 KM_SLEEP, pd, ulp_pkt); 5052 5053 if (rval == FC_SUCCESS) { 5054 continue; 5055 } 5056 5057 if (rval == FC_STATEC_BUSY) { 5058 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5059 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5060 } else { 5061 ulp_pkt->pkt_state = FC_PKT_FAILURE; 5062 } 5063 5064 if (pd) { 5065 mutex_enter(&pd->pd_mutex); 5066 pd->pd_flags = PD_IDLE; 5067 mutex_exit(&pd->pd_mutex); 5068 } 5069 5070 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) { 5071 ASSERT(pd != NULL); 5072 5073 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created," 5074 " PD removed; port=%p, job=%p", port, job); 5075 5076 mutex_enter(&pd->pd_mutex); 5077 pd->pd_ref_count--; 5078 node = pd->pd_remote_nodep; 5079 mutex_exit(&pd->pd_mutex); 5080 5081 ASSERT(node != NULL); 5082 5083 if (fctl_destroy_remote_port(port, pd) == 0) { 5084 fctl_destroy_remote_node(node); 5085 } 5086 ulp_pkt->pkt_pd = NULL; 5087 } 5088 ulp_pkt->pkt_comp(ulp_pkt); 5089 fp_jobdone(job); 5090 } 5091 5092 fp_jobwait(job); 5093 fctl_jobdone(job); 5094 5095 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p", 5096 port, job); 5097 } 5098 5099 5100 /* 5101 * Name server request initialization 5102 */ 5103 static void 5104 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep) 5105 { 5106 int rval; 5107 int count; 5108 int size; 5109 5110 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5111 5112 job->job_counter = 1; 5113 job->job_result = FC_SUCCESS; 5114 5115 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN, 5116 KM_SLEEP, NULL, NULL); 5117 5118 if (rval != FC_SUCCESS) { 5119 mutex_enter(&port->fp_mutex); 5120 port->fp_topology = FC_TOP_NO_NS; 5121 mutex_exit(&port->fp_mutex); 5122 return; 5123 } 5124 5125 fp_jobwait(job); 5126 5127 if (job->job_result != FC_SUCCESS) { 5128 mutex_enter(&port->fp_mutex); 5129 port->fp_topology = FC_TOP_NO_NS; 5130 mutex_exit(&port->fp_mutex); 5131 return; 5132 } 5133 5134 /* 5135 * At this time, we'll do NS registration for objects in the 5136 * ns_reg_cmds (see top of this file) array. 5137 * 5138 * Each time a ULP module registers with the transport, the 5139 * appropriate fc4 bit is set fc4 types and registered with 5140 * the NS for this support. Also, ULPs and FC admin utilities 5141 * may do registration for objects like IP address, symbolic 5142 * port/node name, Initial process associator at run time. 5143 */ 5144 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]); 5145 job->job_counter = size; 5146 job->job_result = FC_SUCCESS; 5147 5148 for (count = 0; count < size; count++) { 5149 if (fp_ns_reg(port, NULL, ns_reg_cmds[count], 5150 job, 0, sleep) != FC_SUCCESS) { 5151 fp_jobdone(job); 5152 } 5153 } 5154 if (size) { 5155 fp_jobwait(job); 5156 } 5157 5158 job->job_result = FC_SUCCESS; 5159 5160 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 5161 5162 if (port->fp_dev_count < FP_MAX_DEVICES) { 5163 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP); 5164 } 5165 5166 job->job_counter = 1; 5167 5168 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION, 5169 sleep) == FC_SUCCESS) { 5170 fp_jobwait(job); 5171 } 5172 } 5173 5174 5175 /* 5176 * Name server finish: 5177 * Unregister for RSCNs 5178 * Unregister all the host port objects in the Name Server 5179 * Perform LOGO with the NS; 5180 */ 5181 static void 5182 fp_ns_fini(fc_local_port_t *port, job_request_t *job) 5183 { 5184 fp_cmd_t *cmd; 5185 uchar_t class; 5186 uint32_t s_id; 5187 fc_packet_t *pkt; 5188 la_els_logo_t payload; 5189 5190 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5191 5192 job->job_counter = 1; 5193 5194 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) != 5195 FC_SUCCESS) { 5196 fp_jobdone(job); 5197 } 5198 fp_jobwait(job); 5199 5200 job->job_counter = 1; 5201 5202 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) { 5203 fp_jobdone(job); 5204 } 5205 fp_jobwait(job); 5206 5207 job->job_counter = 1; 5208 5209 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 5210 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL); 5211 pkt = &cmd->cmd_pkt; 5212 5213 mutex_enter(&port->fp_mutex); 5214 class = port->fp_ns_login_class; 5215 s_id = port->fp_port_id.port_id; 5216 payload.nport_id = port->fp_port_id; 5217 mutex_exit(&port->fp_mutex); 5218 5219 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 5220 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 5221 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 5222 cmd->cmd_retry_count = 1; 5223 cmd->cmd_ulp_pkt = NULL; 5224 5225 if (port->fp_npiv_type == FC_NPIV_PORT) { 5226 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job); 5227 } else { 5228 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job); 5229 } 5230 5231 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 5232 5233 payload.ls_code.ls_code = LA_ELS_LOGO; 5234 payload.ls_code.mbz = 0; 5235 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 5236 5237 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 5238 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 5239 5240 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 5241 fp_iodone(cmd); 5242 } 5243 fp_jobwait(job); 5244 } 5245 5246 5247 /* 5248 * NS Registration function. 5249 * 5250 * It should be seriously noted that FC-GS-2 currently doesn't support 5251 * an Object Registration by a D_ID other than the owner of the object. 5252 * What we are aiming at currently is to at least allow Symbolic Node/Port 5253 * Name registration for any N_Port Identifier by the host software. 5254 * 5255 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this 5256 * function treats the request as Host NS Object. 5257 */ 5258 static int 5259 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code, 5260 job_request_t *job, int polled, int sleep) 5261 { 5262 int rval; 5263 fc_portid_t s_id; 5264 fc_packet_t *pkt; 5265 fp_cmd_t *cmd; 5266 5267 if (pd == NULL) { 5268 mutex_enter(&port->fp_mutex); 5269 s_id = port->fp_port_id; 5270 mutex_exit(&port->fp_mutex); 5271 } else { 5272 mutex_enter(&pd->pd_mutex); 5273 s_id = pd->pd_port_id; 5274 mutex_exit(&pd->pd_mutex); 5275 } 5276 5277 if (polled) { 5278 job->job_counter = 1; 5279 } 5280 5281 switch (cmd_code) { 5282 case NS_RPN_ID: 5283 case NS_RNN_ID: { 5284 ns_rxn_req_t rxn; 5285 5286 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5287 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL); 5288 if (cmd == NULL) { 5289 return (FC_NOMEM); 5290 } 5291 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5292 pkt = &cmd->cmd_pkt; 5293 5294 if (pd == NULL) { 5295 rxn.rxn_xname = (cmd_code == NS_RPN_ID) ? 5296 (port->fp_service_params.nport_ww_name) : 5297 (port->fp_service_params.node_ww_name); 5298 } else { 5299 if (cmd_code == NS_RPN_ID) { 5300 mutex_enter(&pd->pd_mutex); 5301 rxn.rxn_xname = pd->pd_port_name; 5302 mutex_exit(&pd->pd_mutex); 5303 } else { 5304 fc_remote_node_t *node; 5305 5306 mutex_enter(&pd->pd_mutex); 5307 node = pd->pd_remote_nodep; 5308 mutex_exit(&pd->pd_mutex); 5309 5310 mutex_enter(&node->fd_mutex); 5311 rxn.rxn_xname = node->fd_node_name; 5312 mutex_exit(&node->fd_mutex); 5313 } 5314 } 5315 rxn.rxn_port_id = s_id; 5316 5317 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rxn, 5318 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5319 sizeof (rxn), DDI_DEV_AUTOINCR); 5320 5321 break; 5322 } 5323 5324 case NS_RCS_ID: { 5325 ns_rcos_t rcos; 5326 5327 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5328 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL); 5329 if (cmd == NULL) { 5330 return (FC_NOMEM); 5331 } 5332 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5333 pkt = &cmd->cmd_pkt; 5334 5335 if (pd == NULL) { 5336 rcos.rcos_cos = port->fp_cos; 5337 } else { 5338 mutex_enter(&pd->pd_mutex); 5339 rcos.rcos_cos = pd->pd_cos; 5340 mutex_exit(&pd->pd_mutex); 5341 } 5342 rcos.rcos_port_id = s_id; 5343 5344 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rcos, 5345 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5346 sizeof (rcos), DDI_DEV_AUTOINCR); 5347 5348 break; 5349 } 5350 5351 case NS_RFT_ID: { 5352 ns_rfc_type_t rfc; 5353 5354 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5355 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep, 5356 NULL); 5357 if (cmd == NULL) { 5358 return (FC_NOMEM); 5359 } 5360 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5361 pkt = &cmd->cmd_pkt; 5362 5363 if (pd == NULL) { 5364 mutex_enter(&port->fp_mutex); 5365 bcopy(port->fp_fc4_types, rfc.rfc_types, 5366 sizeof (port->fp_fc4_types)); 5367 mutex_exit(&port->fp_mutex); 5368 } else { 5369 mutex_enter(&pd->pd_mutex); 5370 bcopy(pd->pd_fc4types, rfc.rfc_types, 5371 sizeof (pd->pd_fc4types)); 5372 mutex_exit(&pd->pd_mutex); 5373 } 5374 rfc.rfc_port_id = s_id; 5375 5376 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rfc, 5377 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5378 sizeof (rfc), DDI_DEV_AUTOINCR); 5379 5380 break; 5381 } 5382 5383 case NS_RSPN_ID: { 5384 uchar_t name_len; 5385 int pl_size; 5386 fc_portid_t spn; 5387 5388 if (pd == NULL) { 5389 mutex_enter(&port->fp_mutex); 5390 name_len = port->fp_sym_port_namelen; 5391 mutex_exit(&port->fp_mutex); 5392 } else { 5393 mutex_enter(&pd->pd_mutex); 5394 name_len = pd->pd_spn_len; 5395 mutex_exit(&pd->pd_mutex); 5396 } 5397 5398 pl_size = sizeof (fc_portid_t) + name_len + 1; 5399 5400 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size, 5401 sizeof (fc_reg_resp_t), sleep, NULL); 5402 if (cmd == NULL) { 5403 return (FC_NOMEM); 5404 } 5405 5406 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5407 5408 pkt = &cmd->cmd_pkt; 5409 5410 spn = s_id; 5411 5412 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *) 5413 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn), 5414 DDI_DEV_AUTOINCR); 5415 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5416 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) 5417 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR); 5418 5419 if (pd == NULL) { 5420 mutex_enter(&port->fp_mutex); 5421 ddi_rep_put8(pkt->pkt_cmd_acc, 5422 (uint8_t *)port->fp_sym_port_name, (uint8_t *) 5423 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5424 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5425 mutex_exit(&port->fp_mutex); 5426 } else { 5427 mutex_enter(&pd->pd_mutex); 5428 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)pd->pd_spn, 5429 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5430 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5431 mutex_exit(&pd->pd_mutex); 5432 } 5433 break; 5434 } 5435 5436 case NS_RPT_ID: { 5437 ns_rpt_t rpt; 5438 5439 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5440 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL); 5441 if (cmd == NULL) { 5442 return (FC_NOMEM); 5443 } 5444 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5445 pkt = &cmd->cmd_pkt; 5446 5447 if (pd == NULL) { 5448 rpt.rpt_type = port->fp_port_type; 5449 } else { 5450 mutex_enter(&pd->pd_mutex); 5451 rpt.rpt_type = pd->pd_porttype; 5452 mutex_exit(&pd->pd_mutex); 5453 } 5454 rpt.rpt_port_id = s_id; 5455 5456 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rpt, 5457 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5458 sizeof (rpt), DDI_DEV_AUTOINCR); 5459 5460 break; 5461 } 5462 5463 case NS_RIP_NN: { 5464 ns_rip_t rip; 5465 5466 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5467 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL); 5468 if (cmd == NULL) { 5469 return (FC_NOMEM); 5470 } 5471 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5472 pkt = &cmd->cmd_pkt; 5473 5474 if (pd == NULL) { 5475 rip.rip_node_name = 5476 port->fp_service_params.node_ww_name; 5477 bcopy(port->fp_ip_addr, rip.rip_ip_addr, 5478 sizeof (port->fp_ip_addr)); 5479 } else { 5480 fc_remote_node_t *node; 5481 5482 /* 5483 * The most correct implementation should have the IP 5484 * address in the fc_remote_node_t structure; I believe 5485 * Node WWN and IP address should have one to one 5486 * correlation (but guess what this is changing in 5487 * FC-GS-2 latest draft) 5488 */ 5489 mutex_enter(&pd->pd_mutex); 5490 node = pd->pd_remote_nodep; 5491 bcopy(pd->pd_ip_addr, rip.rip_ip_addr, 5492 sizeof (pd->pd_ip_addr)); 5493 mutex_exit(&pd->pd_mutex); 5494 5495 mutex_enter(&node->fd_mutex); 5496 rip.rip_node_name = node->fd_node_name; 5497 mutex_exit(&node->fd_mutex); 5498 } 5499 5500 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rip, 5501 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5502 sizeof (rip), DDI_DEV_AUTOINCR); 5503 5504 break; 5505 } 5506 5507 case NS_RIPA_NN: { 5508 ns_ipa_t ipa; 5509 5510 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5511 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL); 5512 if (cmd == NULL) { 5513 return (FC_NOMEM); 5514 } 5515 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5516 pkt = &cmd->cmd_pkt; 5517 5518 if (pd == NULL) { 5519 ipa.ipa_node_name = 5520 port->fp_service_params.node_ww_name; 5521 bcopy(port->fp_ipa, ipa.ipa_value, 5522 sizeof (port->fp_ipa)); 5523 } else { 5524 fc_remote_node_t *node; 5525 5526 mutex_enter(&pd->pd_mutex); 5527 node = pd->pd_remote_nodep; 5528 mutex_exit(&pd->pd_mutex); 5529 5530 mutex_enter(&node->fd_mutex); 5531 ipa.ipa_node_name = node->fd_node_name; 5532 bcopy(node->fd_ipa, ipa.ipa_value, 5533 sizeof (node->fd_ipa)); 5534 mutex_exit(&node->fd_mutex); 5535 } 5536 5537 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ipa, 5538 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5539 sizeof (ipa), DDI_DEV_AUTOINCR); 5540 5541 break; 5542 } 5543 5544 case NS_RSNN_NN: { 5545 uchar_t name_len; 5546 int pl_size; 5547 la_wwn_t snn; 5548 fc_remote_node_t *node = NULL; 5549 5550 if (pd == NULL) { 5551 mutex_enter(&port->fp_mutex); 5552 name_len = port->fp_sym_node_namelen; 5553 mutex_exit(&port->fp_mutex); 5554 } else { 5555 mutex_enter(&pd->pd_mutex); 5556 node = pd->pd_remote_nodep; 5557 mutex_exit(&pd->pd_mutex); 5558 5559 mutex_enter(&node->fd_mutex); 5560 name_len = node->fd_snn_len; 5561 mutex_exit(&node->fd_mutex); 5562 } 5563 5564 pl_size = sizeof (la_wwn_t) + name_len + 1; 5565 5566 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5567 pl_size, sizeof (fc_reg_resp_t), sleep, NULL); 5568 if (cmd == NULL) { 5569 return (FC_NOMEM); 5570 } 5571 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5572 5573 pkt = &cmd->cmd_pkt; 5574 5575 bcopy(&port->fp_service_params.node_ww_name, 5576 &snn, sizeof (la_wwn_t)); 5577 5578 if (pd == NULL) { 5579 mutex_enter(&port->fp_mutex); 5580 ddi_rep_put8(pkt->pkt_cmd_acc, 5581 (uint8_t *)port->fp_sym_node_name, (uint8_t *) 5582 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5583 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5584 mutex_exit(&port->fp_mutex); 5585 } else { 5586 ASSERT(node != NULL); 5587 mutex_enter(&node->fd_mutex); 5588 ddi_rep_put8(pkt->pkt_cmd_acc, 5589 (uint8_t *)node->fd_snn, 5590 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5591 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5592 mutex_exit(&node->fd_mutex); 5593 } 5594 5595 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&snn, 5596 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5597 sizeof (snn), DDI_DEV_AUTOINCR); 5598 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5599 (uint8_t *)(pkt->pkt_cmd 5600 + sizeof (fc_ct_header_t) + sizeof (snn)), 5601 1, DDI_DEV_AUTOINCR); 5602 5603 break; 5604 } 5605 5606 case NS_DA_ID: { 5607 ns_remall_t rall; 5608 char tmp[4] = {0}; 5609 char *ptr; 5610 5611 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5612 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL); 5613 5614 if (cmd == NULL) { 5615 return (FC_NOMEM); 5616 } 5617 5618 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5619 pkt = &cmd->cmd_pkt; 5620 5621 ptr = (char *)(&s_id); 5622 tmp[3] = *ptr++; 5623 tmp[2] = *ptr++; 5624 tmp[1] = *ptr++; 5625 tmp[0] = *ptr; 5626 #if defined(_BIT_FIELDS_LTOH) 5627 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4); 5628 #else 5629 rall.rem_port_id = s_id; 5630 #endif 5631 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rall, 5632 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5633 sizeof (rall), DDI_DEV_AUTOINCR); 5634 5635 break; 5636 } 5637 5638 default: 5639 return (FC_FAILURE); 5640 } 5641 5642 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 5643 5644 if (rval != FC_SUCCESS) { 5645 job->job_result = rval; 5646 fp_iodone(cmd); 5647 } 5648 5649 if (polled) { 5650 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5651 fp_jobwait(job); 5652 } else { 5653 rval = FC_SUCCESS; 5654 } 5655 5656 return (rval); 5657 } 5658 5659 5660 /* 5661 * Common interrupt handler 5662 */ 5663 static int 5664 fp_common_intr(fc_packet_t *pkt, int iodone) 5665 { 5666 int rval = FC_FAILURE; 5667 fp_cmd_t *cmd; 5668 fc_local_port_t *port; 5669 5670 cmd = pkt->pkt_ulp_private; 5671 port = cmd->cmd_port; 5672 5673 /* 5674 * Fail fast the upper layer requests if 5675 * a state change has occurred amidst. 5676 */ 5677 mutex_enter(&port->fp_mutex); 5678 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) { 5679 mutex_exit(&port->fp_mutex); 5680 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5681 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5682 } else if (!(port->fp_soft_state & 5683 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) { 5684 mutex_exit(&port->fp_mutex); 5685 5686 switch (pkt->pkt_state) { 5687 case FC_PKT_LOCAL_BSY: 5688 case FC_PKT_FABRIC_BSY: 5689 case FC_PKT_NPORT_BSY: 5690 case FC_PKT_TIMEOUT: 5691 cmd->cmd_retry_interval = (pkt->pkt_state == 5692 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay; 5693 rval = fp_retry_cmd(pkt); 5694 break; 5695 5696 case FC_PKT_FABRIC_RJT: 5697 case FC_PKT_NPORT_RJT: 5698 case FC_PKT_LOCAL_RJT: 5699 case FC_PKT_LS_RJT: 5700 case FC_PKT_FS_RJT: 5701 case FC_PKT_BA_RJT: 5702 rval = fp_handle_reject(pkt); 5703 break; 5704 5705 default: 5706 if (pkt->pkt_resp_resid) { 5707 cmd->cmd_retry_interval = 0; 5708 rval = fp_retry_cmd(pkt); 5709 } 5710 break; 5711 } 5712 } else { 5713 mutex_exit(&port->fp_mutex); 5714 } 5715 5716 if (rval != FC_SUCCESS && iodone) { 5717 fp_iodone(cmd); 5718 rval = FC_SUCCESS; 5719 } 5720 5721 return (rval); 5722 } 5723 5724 5725 /* 5726 * Some not so long winding theory on point to point topology: 5727 * 5728 * In the ACC payload, if the D_ID is ZERO and the common service 5729 * parameters indicate N_Port, then the topology is POINT TO POINT. 5730 * 5731 * In a point to point topology with an N_Port, during Fabric Login, 5732 * the destination N_Port will check with our WWN and decide if it 5733 * needs to issue PLOGI or not. That means, FLOGI could potentially 5734 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited 5735 * PLOGI creates the device handles. 5736 * 5737 * Assuming that the host port WWN is greater than the other N_Port 5738 * WWN, then we become the master (be aware that this isn't the word 5739 * used in the FC standards) and initiate the PLOGI. 5740 * 5741 */ 5742 static void 5743 fp_flogi_intr(fc_packet_t *pkt) 5744 { 5745 int state; 5746 int f_port; 5747 uint32_t s_id; 5748 uint32_t d_id; 5749 fp_cmd_t *cmd; 5750 fc_local_port_t *port; 5751 la_wwn_t *swwn; 5752 la_wwn_t dwwn; 5753 la_wwn_t nwwn; 5754 fc_remote_port_t *pd; 5755 la_els_logi_t *acc; 5756 com_svc_t csp; 5757 ls_code_t resp; 5758 5759 cmd = pkt->pkt_ulp_private; 5760 port = cmd->cmd_port; 5761 5762 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x", 5763 port, pkt, pkt->pkt_state); 5764 5765 if (FP_IS_PKT_ERROR(pkt)) { 5766 (void) fp_common_intr(pkt, 1); 5767 return; 5768 } 5769 5770 /* 5771 * Currently, we don't need to swap bytes here because qlc is faking the 5772 * response for us and so endianness is getting taken care of. But we 5773 * have to fix this and generalize this at some point 5774 */ 5775 acc = (la_els_logi_t *)pkt->pkt_resp; 5776 5777 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 5778 sizeof (resp), DDI_DEV_AUTOINCR); 5779 5780 ASSERT(resp.ls_code == LA_ELS_ACC); 5781 if (resp.ls_code != LA_ELS_ACC) { 5782 (void) fp_common_intr(pkt, 1); 5783 return; 5784 } 5785 5786 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&csp, 5787 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR); 5788 5789 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0; 5790 5791 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 5792 5793 mutex_enter(&port->fp_mutex); 5794 state = FC_PORT_STATE_MASK(port->fp_state); 5795 mutex_exit(&port->fp_mutex); 5796 5797 if (pkt->pkt_resp_fhdr.d_id == 0) { 5798 if (f_port == 0 && state != FC_STATE_LOOP) { 5799 swwn = &port->fp_service_params.nport_ww_name; 5800 5801 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&dwwn, 5802 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 5803 DDI_DEV_AUTOINCR); 5804 5805 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn, 5806 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 5807 DDI_DEV_AUTOINCR); 5808 5809 mutex_enter(&port->fp_mutex); 5810 5811 port->fp_topology = FC_TOP_PT_PT; 5812 port->fp_total_devices = 1; 5813 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) { 5814 port->fp_ptpt_master = 1; 5815 /* 5816 * Let us choose 'X' as S_ID and 'Y' 5817 * as D_ID and that'll work; hopefully 5818 * If not, it will get changed. 5819 */ 5820 s_id = port->fp_instance + FP_DEFAULT_SID; 5821 d_id = port->fp_instance + FP_DEFAULT_DID; 5822 port->fp_port_id.port_id = s_id; 5823 mutex_exit(&port->fp_mutex); 5824 5825 pd = fctl_create_remote_port(port, 5826 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR, 5827 KM_NOSLEEP); 5828 if (pd == NULL) { 5829 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 5830 0, NULL, "couldn't create device" 5831 " d_id=%X", d_id); 5832 fp_iodone(cmd); 5833 return; 5834 } 5835 5836 cmd->cmd_pkt.pkt_tran_flags = 5837 pkt->pkt_tran_flags; 5838 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type; 5839 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN; 5840 cmd->cmd_retry_count = fp_retry_count; 5841 5842 fp_xlogi_init(port, cmd, s_id, d_id, 5843 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI); 5844 5845 (&cmd->cmd_pkt)->pkt_pd = pd; 5846 5847 /* 5848 * We've just created this fc_remote_port_t, and 5849 * we're about to use it to send a PLOGI, so 5850 * bump the reference count right now. When 5851 * the packet is freed, the reference count will 5852 * be decremented. The ULP may also start using 5853 * it, so mark it as given away as well. 5854 */ 5855 pd->pd_ref_count++; 5856 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 5857 5858 if (fp_sendcmd(port, cmd, 5859 port->fp_fca_handle) == FC_SUCCESS) { 5860 return; 5861 } 5862 } else { 5863 /* 5864 * The device handles will be created when the 5865 * unsolicited PLOGI is completed successfully 5866 */ 5867 port->fp_ptpt_master = 0; 5868 mutex_exit(&port->fp_mutex); 5869 } 5870 } 5871 pkt->pkt_state = FC_PKT_FAILURE; 5872 } else { 5873 if (f_port) { 5874 mutex_enter(&port->fp_mutex); 5875 if (state == FC_STATE_LOOP) { 5876 port->fp_topology = FC_TOP_PUBLIC_LOOP; 5877 } else { 5878 port->fp_topology = FC_TOP_FABRIC; 5879 5880 ddi_rep_get8(pkt->pkt_resp_acc, 5881 (uint8_t *)&port->fp_fabric_name, 5882 (uint8_t *)&acc->node_ww_name, 5883 sizeof (la_wwn_t), 5884 DDI_DEV_AUTOINCR); 5885 } 5886 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id; 5887 mutex_exit(&port->fp_mutex); 5888 } else { 5889 pkt->pkt_state = FC_PKT_FAILURE; 5890 } 5891 } 5892 fp_iodone(cmd); 5893 } 5894 5895 5896 /* 5897 * Handle solicited PLOGI response 5898 */ 5899 static void 5900 fp_plogi_intr(fc_packet_t *pkt) 5901 { 5902 int nl_port; 5903 int bailout; 5904 uint32_t d_id; 5905 fp_cmd_t *cmd; 5906 la_els_logi_t *acc; 5907 fc_local_port_t *port; 5908 fc_remote_port_t *pd; 5909 la_wwn_t nwwn; 5910 la_wwn_t pwwn; 5911 ls_code_t resp; 5912 5913 nl_port = 0; 5914 cmd = pkt->pkt_ulp_private; 5915 port = cmd->cmd_port; 5916 d_id = pkt->pkt_cmd_fhdr.d_id; 5917 5918 #ifndef __lock_lint 5919 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 5920 #endif 5921 5922 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x," 5923 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id, 5924 cmd->cmd_job->job_counter, pkt, pkt->pkt_state); 5925 5926 /* 5927 * Bail out early on ULP initiated requests if the 5928 * state change has occurred 5929 */ 5930 mutex_enter(&port->fp_mutex); 5931 bailout = ((port->fp_statec_busy || 5932 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 5933 cmd->cmd_ulp_pkt) ? 1 : 0; 5934 mutex_exit(&port->fp_mutex); 5935 5936 if (FP_IS_PKT_ERROR(pkt) || bailout) { 5937 int skip_msg = 0; 5938 int giveup = 0; 5939 5940 if (cmd->cmd_ulp_pkt) { 5941 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 5942 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason; 5943 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 5944 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 5945 } 5946 5947 /* 5948 * If an unsolicited cross login already created 5949 * a device speed up the discovery by not retrying 5950 * the command mindlessly. 5951 */ 5952 if (pkt->pkt_pd == NULL && 5953 fctl_get_remote_port_by_did(port, d_id) != NULL) { 5954 fp_iodone(cmd); 5955 return; 5956 } 5957 5958 if (pkt->pkt_pd != NULL) { 5959 giveup = (pkt->pkt_pd->pd_recepient == 5960 PD_PLOGI_RECEPIENT) ? 1 : 0; 5961 if (giveup) { 5962 /* 5963 * This pd is marked as plogi 5964 * recipient, stop retrying 5965 */ 5966 FP_TRACE(FP_NHEAD1(3, 0), 5967 "fp_plogi_intr: stop retry as" 5968 " a cross login was accepted" 5969 " from d_id=%x, port=%p.", 5970 d_id, port); 5971 fp_iodone(cmd); 5972 return; 5973 } 5974 } 5975 5976 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 5977 return; 5978 } 5979 5980 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) { 5981 mutex_enter(&pd->pd_mutex); 5982 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 5983 skip_msg++; 5984 } 5985 mutex_exit(&pd->pd_mutex); 5986 } 5987 5988 mutex_enter(&port->fp_mutex); 5989 if (!bailout && !(skip_msg && port->fp_statec_busy) && 5990 port->fp_statec_busy <= 1 && 5991 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) { 5992 mutex_exit(&port->fp_mutex); 5993 /* 5994 * In case of Login Collisions, JNI HBAs returns the 5995 * FC pkt back to the Initiator with the state set to 5996 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR. 5997 * QLC HBAs handles such cases in the FW and doesnot 5998 * return the LS_RJT with Logical error when 5999 * login collision happens. 6000 */ 6001 if ((pkt->pkt_state != FC_PKT_LS_RJT) || 6002 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) { 6003 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6004 "PLOGI to %x failed", d_id); 6005 } 6006 FP_TRACE(FP_NHEAD2(9, 0), 6007 "PLOGI to %x failed. state=%x reason=%x.", 6008 d_id, pkt->pkt_state, pkt->pkt_reason); 6009 } else { 6010 mutex_exit(&port->fp_mutex); 6011 } 6012 6013 fp_iodone(cmd); 6014 return; 6015 } 6016 6017 acc = (la_els_logi_t *)pkt->pkt_resp; 6018 6019 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 6020 sizeof (resp), DDI_DEV_AUTOINCR); 6021 6022 ASSERT(resp.ls_code == LA_ELS_ACC); 6023 if (resp.ls_code != LA_ELS_ACC) { 6024 (void) fp_common_intr(pkt, 1); 6025 return; 6026 } 6027 6028 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) { 6029 mutex_enter(&port->fp_mutex); 6030 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags); 6031 mutex_exit(&port->fp_mutex); 6032 fp_iodone(cmd); 6033 return; 6034 } 6035 6036 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp); 6037 6038 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn, 6039 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 6040 DDI_DEV_AUTOINCR); 6041 6042 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn, 6043 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 6044 DDI_DEV_AUTOINCR); 6045 6046 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE); 6047 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE); 6048 6049 if ((pd = pkt->pkt_pd) == NULL) { 6050 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6051 if (pd == NULL) { 6052 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id, 6053 PD_PLOGI_INITIATOR, KM_NOSLEEP); 6054 if (pd == NULL) { 6055 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6056 "couldn't create port device handles" 6057 " d_id=%x", d_id); 6058 fp_iodone(cmd); 6059 return; 6060 } 6061 } else { 6062 fc_remote_port_t *tmp_pd; 6063 6064 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6065 if (tmp_pd != NULL) { 6066 fp_iodone(cmd); 6067 return; 6068 } 6069 6070 mutex_enter(&port->fp_mutex); 6071 mutex_enter(&pd->pd_mutex); 6072 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) || 6073 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6074 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN; 6075 } 6076 6077 if (pd->pd_type == PORT_DEVICE_OLD) { 6078 if (pd->pd_port_id.port_id != d_id) { 6079 fctl_delist_did_table(port, pd); 6080 pd->pd_type = PORT_DEVICE_CHANGED; 6081 pd->pd_port_id.port_id = d_id; 6082 } else { 6083 pd->pd_type = PORT_DEVICE_NOCHANGE; 6084 } 6085 } 6086 6087 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6088 char ww_name[17]; 6089 6090 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6091 6092 mutex_exit(&pd->pd_mutex); 6093 mutex_exit(&port->fp_mutex); 6094 FP_TRACE(FP_NHEAD2(9, 0), 6095 "Possible Duplicate name or address" 6096 " identifiers in the PLOGI response" 6097 " D_ID=%x, PWWN=%s: Please check the" 6098 " configuration", d_id, ww_name); 6099 fp_iodone(cmd); 6100 return; 6101 } 6102 fctl_enlist_did_table(port, pd); 6103 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6104 mutex_exit(&pd->pd_mutex); 6105 mutex_exit(&port->fp_mutex); 6106 } 6107 } else { 6108 fc_remote_port_t *tmp_pd, *new_wwn_pd; 6109 6110 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6111 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6112 6113 mutex_enter(&port->fp_mutex); 6114 mutex_enter(&pd->pd_mutex); 6115 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) { 6116 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x," 6117 " pd_state=%x pd_type=%x", d_id, pd->pd_state, 6118 pd->pd_type); 6119 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN && 6120 pd->pd_type == PORT_DEVICE_OLD) || 6121 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6122 pd->pd_type = PORT_DEVICE_NOCHANGE; 6123 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 6124 pd->pd_type = PORT_DEVICE_NEW; 6125 } 6126 } else { 6127 char old_name[17]; 6128 char new_name[17]; 6129 6130 fc_wwn_to_str(&pd->pd_port_name, old_name); 6131 fc_wwn_to_str(&pwwn, new_name); 6132 6133 FP_TRACE(FP_NHEAD1(9, 0), 6134 "fp_plogi_intr: PWWN of a device with D_ID=%x " 6135 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p " 6136 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x", 6137 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd, 6138 cmd->cmd_ulp_pkt, bailout); 6139 6140 FP_TRACE(FP_NHEAD2(9, 0), 6141 "PWWN of a device with D_ID=%x changed." 6142 " New PWWN = %s, OLD PWWN = %s", d_id, 6143 new_name, old_name); 6144 6145 if (cmd->cmd_ulp_pkt && !bailout) { 6146 fc_remote_node_t *rnodep; 6147 fc_portmap_t *changelist; 6148 fc_portmap_t *listptr; 6149 int len = 1; 6150 /* # entries in changelist */ 6151 6152 fctl_delist_pwwn_table(port, pd); 6153 6154 /* 6155 * Lets now check if there already is a pd with 6156 * this new WWN in the table. If so, we'll mark 6157 * it as invalid 6158 */ 6159 6160 if (new_wwn_pd) { 6161 /* 6162 * There is another pd with in the pwwn 6163 * table with the same WWN that we got 6164 * in the PLOGI payload. We have to get 6165 * it out of the pwwn table, update the 6166 * pd's state (fp_fillout_old_map does 6167 * this for us) and add it to the 6168 * changelist that goes up to ULPs. 6169 * 6170 * len is length of changelist and so 6171 * increment it. 6172 */ 6173 len++; 6174 6175 if (tmp_pd != pd) { 6176 /* 6177 * Odd case where pwwn and did 6178 * tables are out of sync but 6179 * we will handle that too. See 6180 * more comments below. 6181 * 6182 * One more device that ULPs 6183 * should know about and so len 6184 * gets incremented again. 6185 */ 6186 len++; 6187 } 6188 6189 listptr = changelist = kmem_zalloc(len * 6190 sizeof (*changelist), KM_SLEEP); 6191 6192 mutex_enter(&new_wwn_pd->pd_mutex); 6193 rnodep = new_wwn_pd->pd_remote_nodep; 6194 mutex_exit(&new_wwn_pd->pd_mutex); 6195 6196 /* 6197 * Hold the fd_mutex since 6198 * fctl_copy_portmap_held expects it. 6199 * Preserve lock hierarchy by grabbing 6200 * fd_mutex before pd_mutex 6201 */ 6202 if (rnodep) { 6203 mutex_enter(&rnodep->fd_mutex); 6204 } 6205 mutex_enter(&new_wwn_pd->pd_mutex); 6206 fp_fillout_old_map_held(listptr++, 6207 new_wwn_pd, 0); 6208 mutex_exit(&new_wwn_pd->pd_mutex); 6209 if (rnodep) { 6210 mutex_exit(&rnodep->fd_mutex); 6211 } 6212 6213 /* 6214 * Safety check : 6215 * Lets ensure that the pwwn and did 6216 * tables are in sync. Ideally, we 6217 * should not find that these two pd's 6218 * are different. 6219 */ 6220 if (tmp_pd != pd) { 6221 mutex_enter(&tmp_pd->pd_mutex); 6222 rnodep = 6223 tmp_pd->pd_remote_nodep; 6224 mutex_exit(&tmp_pd->pd_mutex); 6225 6226 /* As above grab fd_mutex */ 6227 if (rnodep) { 6228 mutex_enter(&rnodep-> 6229 fd_mutex); 6230 } 6231 mutex_enter(&tmp_pd->pd_mutex); 6232 6233 fp_fillout_old_map_held( 6234 listptr++, tmp_pd, 0); 6235 6236 mutex_exit(&tmp_pd->pd_mutex); 6237 if (rnodep) { 6238 mutex_exit(&rnodep-> 6239 fd_mutex); 6240 } 6241 6242 /* 6243 * Now add "pd" (not tmp_pd) 6244 * to fp_did_table to sync it up 6245 * with fp_pwwn_table 6246 * 6247 * pd->pd_mutex is already held 6248 * at this point 6249 */ 6250 fctl_enlist_did_table(port, pd); 6251 } 6252 } else { 6253 listptr = changelist = kmem_zalloc( 6254 sizeof (*changelist), KM_SLEEP); 6255 } 6256 6257 ASSERT(changelist != NULL); 6258 6259 fp_fillout_changed_map(listptr, pd, &d_id, 6260 &pwwn); 6261 fctl_enlist_pwwn_table(port, pd); 6262 6263 mutex_exit(&pd->pd_mutex); 6264 mutex_exit(&port->fp_mutex); 6265 6266 fp_iodone(cmd); 6267 6268 (void) fp_ulp_devc_cb(port, changelist, len, 6269 len, KM_NOSLEEP, 0); 6270 6271 return; 6272 } 6273 } 6274 6275 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) { 6276 nl_port = 1; 6277 } 6278 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) 6279 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6280 6281 mutex_exit(&pd->pd_mutex); 6282 mutex_exit(&port->fp_mutex); 6283 6284 if (tmp_pd == NULL) { 6285 mutex_enter(&port->fp_mutex); 6286 mutex_enter(&pd->pd_mutex); 6287 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6288 char ww_name[17]; 6289 6290 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6291 mutex_exit(&pd->pd_mutex); 6292 mutex_exit(&port->fp_mutex); 6293 FP_TRACE(FP_NHEAD2(9, 0), 6294 "Possible Duplicate name or address" 6295 " identifiers in the PLOGI response" 6296 " D_ID=%x, PWWN=%s: Please check the" 6297 " configuration", d_id, ww_name); 6298 fp_iodone(cmd); 6299 return; 6300 } 6301 fctl_enlist_did_table(port, pd); 6302 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6303 mutex_exit(&pd->pd_mutex); 6304 mutex_exit(&port->fp_mutex); 6305 } 6306 } 6307 fp_register_login(&pkt->pkt_resp_acc, pd, acc, 6308 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 6309 6310 if (cmd->cmd_ulp_pkt) { 6311 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6312 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6313 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6314 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6315 if (pd != NULL) { 6316 FP_TRACE(FP_NHEAD1(9, 0), 6317 "fp_plogi_intr;" 6318 "ulp_pkt's pd is NULL, get a pd %p", 6319 pd); 6320 mutex_enter(&pd->pd_mutex); 6321 pd->pd_ref_count++; 6322 mutex_exit(&pd->pd_mutex); 6323 } 6324 cmd->cmd_ulp_pkt->pkt_pd = pd; 6325 } 6326 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6327 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6328 sizeof (fc_frame_hdr_t)); 6329 bcopy((caddr_t)pkt->pkt_resp, 6330 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6331 sizeof (la_els_logi_t)); 6332 } 6333 6334 mutex_enter(&port->fp_mutex); 6335 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) { 6336 mutex_enter(&pd->pd_mutex); 6337 6338 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6339 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6340 cmd->cmd_retry_count = fp_retry_count; 6341 6342 /* 6343 * If the fc_remote_port_t pointer is not set in the given 6344 * fc_packet_t, then this fc_remote_port_t must have just 6345 * been created. Save the pointer and also increment the 6346 * fc_remote_port_t reference count. 6347 */ 6348 if (pkt->pkt_pd == NULL) { 6349 pkt->pkt_pd = pd; 6350 pd->pd_ref_count++; /* It's in use! */ 6351 } 6352 6353 fp_adisc_init(cmd, cmd->cmd_job); 6354 6355 pkt->pkt_cmdlen = sizeof (la_els_adisc_t); 6356 pkt->pkt_rsplen = sizeof (la_els_adisc_t); 6357 6358 mutex_exit(&pd->pd_mutex); 6359 mutex_exit(&port->fp_mutex); 6360 6361 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6362 return; 6363 } 6364 } else { 6365 mutex_exit(&port->fp_mutex); 6366 } 6367 6368 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6369 mutex_enter(&port->fp_mutex); 6370 mutex_enter(&pd->pd_mutex); 6371 6372 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6373 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6374 cmd->cmd_retry_count = fp_retry_count; 6375 6376 fp_logo_init(pd, cmd, cmd->cmd_job); 6377 6378 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6379 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6380 6381 mutex_exit(&pd->pd_mutex); 6382 mutex_exit(&port->fp_mutex); 6383 6384 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6385 return; 6386 } 6387 6388 } 6389 fp_iodone(cmd); 6390 } 6391 6392 6393 /* 6394 * Handle solicited ADISC response 6395 */ 6396 static void 6397 fp_adisc_intr(fc_packet_t *pkt) 6398 { 6399 int rval; 6400 int bailout; 6401 fp_cmd_t *cmd; 6402 fc_local_port_t *port; 6403 fc_remote_port_t *pd; 6404 la_els_adisc_t *acc; 6405 ls_code_t resp; 6406 fc_hardaddr_t ha; 6407 fc_portmap_t *changelist; 6408 int initiator, adiscfail = 0; 6409 6410 pd = pkt->pkt_pd; 6411 cmd = pkt->pkt_ulp_private; 6412 port = cmd->cmd_port; 6413 6414 #ifndef __lock_lint 6415 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6416 #endif 6417 6418 ASSERT(pd != NULL && port != NULL && cmd != NULL); 6419 6420 mutex_enter(&port->fp_mutex); 6421 bailout = ((port->fp_statec_busy || 6422 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6423 cmd->cmd_ulp_pkt) ? 1 : 0; 6424 mutex_exit(&port->fp_mutex); 6425 6426 if (bailout) { 6427 fp_iodone(cmd); 6428 return; 6429 } 6430 6431 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) { 6432 acc = (la_els_adisc_t *)pkt->pkt_resp; 6433 6434 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, 6435 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR); 6436 6437 if (resp.ls_code == LA_ELS_ACC) { 6438 int is_private; 6439 6440 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&ha, 6441 (uint8_t *)&acc->hard_addr, sizeof (ha), 6442 DDI_DEV_AUTOINCR); 6443 6444 mutex_enter(&port->fp_mutex); 6445 6446 is_private = 6447 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0; 6448 6449 mutex_enter(&pd->pd_mutex); 6450 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) { 6451 fctl_enlist_did_table(port, pd); 6452 } 6453 mutex_exit(&pd->pd_mutex); 6454 6455 mutex_exit(&port->fp_mutex); 6456 6457 mutex_enter(&pd->pd_mutex); 6458 if (pd->pd_type != PORT_DEVICE_NEW) { 6459 if (is_private && (pd->pd_hard_addr.hard_addr != 6460 ha.hard_addr)) { 6461 pd->pd_type = PORT_DEVICE_CHANGED; 6462 } else { 6463 pd->pd_type = PORT_DEVICE_NOCHANGE; 6464 } 6465 } 6466 6467 if (is_private && (ha.hard_addr && 6468 pd->pd_port_id.port_id != ha.hard_addr)) { 6469 char ww_name[17]; 6470 6471 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6472 6473 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6474 "NL_Port Identifier %x doesn't match" 6475 " with Hard Address %x, Will use Port" 6476 " WWN %s", pd->pd_port_id.port_id, 6477 ha.hard_addr, ww_name); 6478 6479 pd->pd_hard_addr.hard_addr = 0; 6480 } else { 6481 pd->pd_hard_addr.hard_addr = ha.hard_addr; 6482 } 6483 mutex_exit(&pd->pd_mutex); 6484 } else { 6485 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6486 return; 6487 } 6488 } 6489 } else { 6490 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6491 return; 6492 } 6493 6494 mutex_enter(&port->fp_mutex); 6495 if (port->fp_statec_busy <= 1) { 6496 mutex_exit(&port->fp_mutex); 6497 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6498 "ADISC to %x failed, cmd_flags=%x", 6499 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags); 6500 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN; 6501 adiscfail = 1; 6502 } else { 6503 mutex_exit(&port->fp_mutex); 6504 } 6505 } 6506 6507 if (cmd->cmd_ulp_pkt) { 6508 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6509 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6510 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6511 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6512 cmd->cmd_ulp_pkt->pkt_pd = pd; 6513 FP_TRACE(FP_NHEAD1(9, 0), 6514 "fp_adisc__intr;" 6515 "ulp_pkt's pd is NULL, get a pd %p", 6516 pd); 6517 6518 } 6519 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6520 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6521 sizeof (fc_frame_hdr_t)); 6522 bcopy((caddr_t)pkt->pkt_resp, 6523 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6524 sizeof (la_els_logi_t)); 6525 } 6526 6527 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6528 FP_TRACE(FP_NHEAD1(9, 0), 6529 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, " 6530 "fp_retry_count=%x, ulp_pkt=%p", 6531 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt); 6532 6533 mutex_enter(&port->fp_mutex); 6534 mutex_enter(&pd->pd_mutex); 6535 6536 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6537 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6538 cmd->cmd_retry_count = fp_retry_count; 6539 6540 fp_logo_init(pd, cmd, cmd->cmd_job); 6541 6542 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6543 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6544 6545 mutex_exit(&pd->pd_mutex); 6546 mutex_exit(&port->fp_mutex); 6547 6548 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 6549 if (adiscfail) { 6550 mutex_enter(&pd->pd_mutex); 6551 initiator = 6552 (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 6553 pd->pd_state = PORT_DEVICE_VALID; 6554 pd->pd_aux_flags |= PD_LOGGED_OUT; 6555 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) 6556 pd->pd_type = PORT_DEVICE_NEW; 6557 else 6558 pd->pd_type = PORT_DEVICE_NOCHANGE; 6559 mutex_exit(&pd->pd_mutex); 6560 6561 changelist = 6562 kmem_zalloc(sizeof (*changelist), KM_SLEEP); 6563 6564 if (initiator) { 6565 fp_unregister_login(pd); 6566 fctl_copy_portmap(changelist, pd); 6567 } else { 6568 fp_fillout_old_map(changelist, pd, 0); 6569 } 6570 6571 FP_TRACE(FP_NHEAD1(9, 0), 6572 "fp_adisc_intr: Dev change notification " 6573 "to ULP port=%p, pd=%p, map_type=%x map_state=%x " 6574 "map_flags=%x initiator=%d", port, pd, 6575 changelist->map_type, changelist->map_state, 6576 changelist->map_flags, initiator); 6577 6578 (void) fp_ulp_devc_cb(port, changelist, 6579 1, 1, KM_SLEEP, 0); 6580 } 6581 if (rval == FC_SUCCESS) { 6582 return; 6583 } 6584 } 6585 fp_iodone(cmd); 6586 } 6587 6588 6589 /* 6590 * Handle solicited LOGO response 6591 */ 6592 static void 6593 fp_logo_intr(fc_packet_t *pkt) 6594 { 6595 ls_code_t resp; 6596 6597 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, 6598 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6599 6600 if (FP_IS_PKT_ERROR(pkt)) { 6601 (void) fp_common_intr(pkt, 1); 6602 return; 6603 } 6604 6605 ASSERT(resp.ls_code == LA_ELS_ACC); 6606 if (resp.ls_code != LA_ELS_ACC) { 6607 (void) fp_common_intr(pkt, 1); 6608 return; 6609 } 6610 6611 if (pkt->pkt_pd != NULL) { 6612 fp_unregister_login(pkt->pkt_pd); 6613 } 6614 fp_iodone(pkt->pkt_ulp_private); 6615 } 6616 6617 6618 /* 6619 * Handle solicited RNID response 6620 */ 6621 static void 6622 fp_rnid_intr(fc_packet_t *pkt) 6623 { 6624 ls_code_t resp; 6625 job_request_t *job; 6626 fp_cmd_t *cmd; 6627 la_els_rnid_acc_t *acc; 6628 6629 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, 6630 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6631 6632 cmd = pkt->pkt_ulp_private; 6633 job = cmd->cmd_job; 6634 ASSERT(job->job_private != NULL); 6635 6636 /* If failure or LS_RJT then retry the packet, if needed */ 6637 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) { 6638 (void) fp_common_intr(pkt, 1); 6639 return; 6640 } 6641 6642 /* Save node_id memory allocated in ioctl code */ 6643 acc = (la_els_rnid_acc_t *)pkt->pkt_resp; 6644 6645 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6646 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR); 6647 6648 /* wakeup the ioctl thread and free the pkt */ 6649 fp_iodone(cmd); 6650 } 6651 6652 6653 /* 6654 * Handle solicited RLS response 6655 */ 6656 static void 6657 fp_rls_intr(fc_packet_t *pkt) 6658 { 6659 ls_code_t resp; 6660 job_request_t *job; 6661 fp_cmd_t *cmd; 6662 la_els_rls_acc_t *acc; 6663 6664 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, 6665 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6666 6667 cmd = pkt->pkt_ulp_private; 6668 job = cmd->cmd_job; 6669 ASSERT(job->job_private != NULL); 6670 6671 /* If failure or LS_RJT then retry the packet, if needed */ 6672 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) { 6673 (void) fp_common_intr(pkt, 1); 6674 return; 6675 } 6676 6677 /* Save link error status block in memory allocated in ioctl code */ 6678 acc = (la_els_rls_acc_t *)pkt->pkt_resp; 6679 6680 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6681 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t), 6682 DDI_DEV_AUTOINCR); 6683 6684 /* wakeup the ioctl thread and free the pkt */ 6685 fp_iodone(cmd); 6686 } 6687 6688 6689 /* 6690 * A solicited command completion interrupt (mostly for commands 6691 * that require almost no post processing such as SCR ELS) 6692 */ 6693 static void 6694 fp_intr(fc_packet_t *pkt) 6695 { 6696 if (FP_IS_PKT_ERROR(pkt)) { 6697 (void) fp_common_intr(pkt, 1); 6698 return; 6699 } 6700 fp_iodone(pkt->pkt_ulp_private); 6701 } 6702 6703 6704 /* 6705 * Handle the underlying port's state change 6706 */ 6707 static void 6708 fp_statec_cb(opaque_t port_handle, uint32_t state) 6709 { 6710 fc_local_port_t *port = port_handle; 6711 job_request_t *job; 6712 6713 /* 6714 * If it is not possible to process the callbacks 6715 * just drop the callback on the floor; Don't bother 6716 * to do something that isn't safe at this time 6717 */ 6718 mutex_enter(&port->fp_mutex); 6719 if ((port->fp_soft_state & 6720 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 6721 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) { 6722 mutex_exit(&port->fp_mutex); 6723 return; 6724 } 6725 6726 if (port->fp_statec_busy == 0) { 6727 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 6728 #ifdef DEBUG 6729 } else { 6730 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB); 6731 #endif 6732 } 6733 6734 port->fp_statec_busy++; 6735 6736 /* 6737 * For now, force the trusted method of device authentication (by 6738 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition. 6739 */ 6740 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP || 6741 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) { 6742 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP; 6743 fp_port_offline(port, 0); 6744 } 6745 mutex_exit(&port->fp_mutex); 6746 6747 switch (FC_PORT_STATE_MASK(state)) { 6748 case FC_STATE_OFFLINE: 6749 job = fctl_alloc_job(JOB_PORT_OFFLINE, 6750 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6751 if (job == NULL) { 6752 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6753 " fp_statec_cb() couldn't submit a job " 6754 " to the thread: failing.."); 6755 mutex_enter(&port->fp_mutex); 6756 if (--port->fp_statec_busy == 0) { 6757 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6758 } 6759 mutex_exit(&port->fp_mutex); 6760 return; 6761 } 6762 mutex_enter(&port->fp_mutex); 6763 /* 6764 * Zero out this field so that we do not retain 6765 * the fabric name as its no longer valid 6766 */ 6767 bzero(&port->fp_fabric_name, sizeof (la_wwn_t)); 6768 port->fp_state = state; 6769 mutex_exit(&port->fp_mutex); 6770 6771 fctl_enque_job(port, job); 6772 break; 6773 6774 case FC_STATE_ONLINE: 6775 case FC_STATE_LOOP: 6776 mutex_enter(&port->fp_mutex); 6777 port->fp_state = state; 6778 6779 if (port->fp_offline_tid) { 6780 timeout_id_t tid; 6781 6782 tid = port->fp_offline_tid; 6783 port->fp_offline_tid = NULL; 6784 mutex_exit(&port->fp_mutex); 6785 (void) untimeout(tid); 6786 } else { 6787 mutex_exit(&port->fp_mutex); 6788 } 6789 6790 job = fctl_alloc_job(JOB_PORT_ONLINE, 6791 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6792 if (job == NULL) { 6793 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6794 "fp_statec_cb() couldn't submit a job " 6795 "to the thread: failing.."); 6796 6797 mutex_enter(&port->fp_mutex); 6798 if (--port->fp_statec_busy == 0) { 6799 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6800 } 6801 mutex_exit(&port->fp_mutex); 6802 return; 6803 } 6804 fctl_enque_job(port, job); 6805 break; 6806 6807 case FC_STATE_RESET_REQUESTED: 6808 mutex_enter(&port->fp_mutex); 6809 port->fp_state = FC_STATE_OFFLINE; 6810 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET; 6811 mutex_exit(&port->fp_mutex); 6812 /* FALLTHROUGH */ 6813 6814 case FC_STATE_RESET: 6815 job = fctl_alloc_job(JOB_ULP_NOTIFY, 6816 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6817 if (job == NULL) { 6818 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6819 "fp_statec_cb() couldn't submit a job" 6820 " to the thread: failing.."); 6821 6822 mutex_enter(&port->fp_mutex); 6823 if (--port->fp_statec_busy == 0) { 6824 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6825 } 6826 mutex_exit(&port->fp_mutex); 6827 return; 6828 } 6829 6830 /* squeeze into some field in the job structure */ 6831 job->job_ulp_listlen = FC_PORT_STATE_MASK(state); 6832 fctl_enque_job(port, job); 6833 break; 6834 6835 case FC_STATE_TARGET_PORT_RESET: 6836 (void) fp_ulp_notify(port, state, KM_NOSLEEP); 6837 /* FALLTHROUGH */ 6838 6839 case FC_STATE_NAMESERVICE: 6840 /* FALLTHROUGH */ 6841 6842 default: 6843 mutex_enter(&port->fp_mutex); 6844 if (--port->fp_statec_busy == 0) { 6845 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6846 } 6847 mutex_exit(&port->fp_mutex); 6848 break; 6849 } 6850 } 6851 6852 6853 /* 6854 * Register with the Name Server for RSCNs 6855 */ 6856 static int 6857 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func, 6858 int sleep) 6859 { 6860 uint32_t s_id; 6861 uchar_t class; 6862 fc_scr_req_t payload; 6863 fp_cmd_t *cmd; 6864 fc_packet_t *pkt; 6865 6866 mutex_enter(&port->fp_mutex); 6867 s_id = port->fp_port_id.port_id; 6868 class = port->fp_ns_login_class; 6869 mutex_exit(&port->fp_mutex); 6870 6871 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t), 6872 sizeof (fc_scr_resp_t), sleep, NULL); 6873 if (cmd == NULL) { 6874 return (FC_NOMEM); 6875 } 6876 6877 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 6878 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6879 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 6880 cmd->cmd_retry_count = fp_retry_count; 6881 cmd->cmd_ulp_pkt = NULL; 6882 6883 pkt = &cmd->cmd_pkt; 6884 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 6885 6886 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job); 6887 6888 payload.ls_code.ls_code = LA_ELS_SCR; 6889 payload.ls_code.mbz = 0; 6890 payload.scr_rsvd = 0; 6891 payload.scr_func = scr_func; 6892 6893 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 6894 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 6895 6896 job->job_counter = 1; 6897 6898 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 6899 fp_iodone(cmd); 6900 } 6901 6902 return (FC_SUCCESS); 6903 } 6904 6905 6906 /* 6907 * There are basically two methods to determine the total number of 6908 * devices out in the NS database; Reading the details of the two 6909 * methods described below, it shouldn't be hard to identify which 6910 * of the two methods is better. 6911 * 6912 * Method 1. 6913 * Iteratively issue GANs until all ports identifiers are walked 6914 * 6915 * Method 2. 6916 * Issue GID_PT (get port Identifiers) with Maximum residual 6917 * field in the request CT HEADER set to accommodate only the 6918 * CT HEADER in the response frame. And if FC-GS2 has been 6919 * carefully read, the NS here has a chance to FS_ACC the 6920 * request and indicate the residual size in the FS_ACC. 6921 * 6922 * Method 2 is wonderful, although it's not mandatory for the NS 6923 * to update the Maximum/Residual Field as can be seen in 4.3.1.6 6924 * (note with particular care the use of the auxiliary verb 'may') 6925 * 6926 */ 6927 static int 6928 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create, 6929 int sleep) 6930 { 6931 int flags; 6932 int rval; 6933 uint32_t src_id; 6934 fctl_ns_req_t *ns_cmd; 6935 6936 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 6937 6938 mutex_enter(&port->fp_mutex); 6939 src_id = port->fp_port_id.port_id; 6940 mutex_exit(&port->fp_mutex); 6941 6942 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 6943 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t), 6944 sizeof (ns_resp_gid_pt_t), 0, 6945 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep); 6946 6947 if (ns_cmd == NULL) { 6948 return (FC_NOMEM); 6949 } 6950 6951 ns_cmd->ns_cmd_code = NS_GID_PT; 6952 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type 6953 = FC_NS_PORT_NX; /* All port types */ 6954 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0; 6955 6956 } else { 6957 uint32_t ns_flags; 6958 6959 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF; 6960 if (create) { 6961 ns_flags |= FCTL_NS_CREATE_DEVICE; 6962 } 6963 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 6964 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep); 6965 6966 if (ns_cmd == NULL) { 6967 return (FC_NOMEM); 6968 } 6969 ns_cmd->ns_gan_index = 0; 6970 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 6971 ns_cmd->ns_cmd_code = NS_GA_NXT; 6972 ns_cmd->ns_gan_max = 0xFFFF; 6973 6974 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id; 6975 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 6976 } 6977 6978 flags = job->job_flags; 6979 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 6980 job->job_counter = 1; 6981 6982 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 6983 job->job_flags = flags; 6984 6985 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 6986 uint16_t max_resid; 6987 6988 /* 6989 * Revert to scanning the NS if NS_GID_PT isn't 6990 * helping us figure out total number of devices. 6991 */ 6992 if (job->job_result != FC_SUCCESS || 6993 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) { 6994 mutex_enter(&port->fp_mutex); 6995 port->fp_options &= ~FP_NS_SMART_COUNT; 6996 mutex_exit(&port->fp_mutex); 6997 6998 fctl_free_ns_cmd(ns_cmd); 6999 return (fp_ns_get_devcount(port, job, create, sleep)); 7000 } 7001 7002 mutex_enter(&port->fp_mutex); 7003 port->fp_total_devices = 1; 7004 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize; 7005 if (max_resid) { 7006 /* 7007 * Since port identifier is 4 bytes and max_resid 7008 * is also in WORDS, max_resid simply indicates 7009 * the total number of port identifiers not 7010 * transferred 7011 */ 7012 port->fp_total_devices += max_resid; 7013 } 7014 mutex_exit(&port->fp_mutex); 7015 } 7016 mutex_enter(&port->fp_mutex); 7017 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf); 7018 mutex_exit(&port->fp_mutex); 7019 fctl_free_ns_cmd(ns_cmd); 7020 7021 return (rval); 7022 } 7023 7024 /* 7025 * One heck of a function to serve userland. 7026 */ 7027 static int 7028 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 7029 { 7030 int rval = 0; 7031 int jcode; 7032 uint32_t ret; 7033 uchar_t open_flag; 7034 fcio_t *kfcio; 7035 job_request_t *job; 7036 boolean_t use32 = B_FALSE; 7037 7038 #ifdef _MULTI_DATAMODEL 7039 switch (ddi_model_convert_from(mode & FMODELS)) { 7040 case DDI_MODEL_ILP32: 7041 use32 = B_TRUE; 7042 break; 7043 7044 case DDI_MODEL_NONE: 7045 default: 7046 break; 7047 } 7048 #endif 7049 7050 mutex_enter(&port->fp_mutex); 7051 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 7052 FP_SOFT_IN_UNSOL_CB)) { 7053 fcio->fcio_errno = FC_STATEC_BUSY; 7054 mutex_exit(&port->fp_mutex); 7055 rval = EAGAIN; 7056 if (fp_fcio_copyout(fcio, data, mode)) { 7057 rval = EFAULT; 7058 } 7059 return (rval); 7060 } 7061 open_flag = port->fp_flag; 7062 mutex_exit(&port->fp_mutex); 7063 7064 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) { 7065 fcio->fcio_errno = FC_FAILURE; 7066 rval = EACCES; 7067 if (fp_fcio_copyout(fcio, data, mode)) { 7068 rval = EFAULT; 7069 } 7070 return (rval); 7071 } 7072 7073 /* 7074 * If an exclusive open was demanded during open, don't let 7075 * either innocuous or devil threads to share the file 7076 * descriptor and fire down exclusive access commands 7077 */ 7078 mutex_enter(&port->fp_mutex); 7079 if (port->fp_flag & FP_EXCL) { 7080 if (port->fp_flag & FP_EXCL_BUSY) { 7081 mutex_exit(&port->fp_mutex); 7082 fcio->fcio_errno = FC_FAILURE; 7083 return (EBUSY); 7084 } 7085 port->fp_flag |= FP_EXCL_BUSY; 7086 } 7087 mutex_exit(&port->fp_mutex); 7088 7089 switch (fcio->fcio_cmd) { 7090 case FCIO_GET_HOST_PARAMS: { 7091 fc_port_dev_t *val; 7092 fc_port_dev32_t *val32; 7093 int index; 7094 int lilp_device_count; 7095 fc_lilpmap_t *lilp_map; 7096 uchar_t *alpa_list; 7097 7098 if (use32 == B_TRUE) { 7099 if (fcio->fcio_olen != sizeof (*val32) || 7100 fcio->fcio_xfer != FCIO_XFER_READ) { 7101 rval = EINVAL; 7102 break; 7103 } 7104 } else { 7105 if (fcio->fcio_olen != sizeof (*val) || 7106 fcio->fcio_xfer != FCIO_XFER_READ) { 7107 rval = EINVAL; 7108 break; 7109 } 7110 } 7111 7112 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7113 7114 mutex_enter(&port->fp_mutex); 7115 val->dev_did = port->fp_port_id; 7116 val->dev_hard_addr = port->fp_hard_addr; 7117 val->dev_pwwn = port->fp_service_params.nport_ww_name; 7118 val->dev_nwwn = port->fp_service_params.node_ww_name; 7119 val->dev_state = port->fp_state; 7120 7121 lilp_map = &port->fp_lilp_map; 7122 alpa_list = &lilp_map->lilp_alpalist[0]; 7123 lilp_device_count = lilp_map->lilp_length; 7124 for (index = 0; index < lilp_device_count; index++) { 7125 uint32_t d_id; 7126 7127 d_id = alpa_list[index]; 7128 if (d_id == port->fp_port_id.port_id) { 7129 break; 7130 } 7131 } 7132 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff); 7133 7134 bcopy(port->fp_fc4_types, val->dev_type, 7135 sizeof (port->fp_fc4_types)); 7136 mutex_exit(&port->fp_mutex); 7137 7138 if (use32 == B_TRUE) { 7139 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7140 7141 val32->dev_did = val->dev_did; 7142 val32->dev_hard_addr = val->dev_hard_addr; 7143 val32->dev_pwwn = val->dev_pwwn; 7144 val32->dev_nwwn = val->dev_nwwn; 7145 val32->dev_state = val->dev_state; 7146 val32->dev_did.priv_lilp_posit = 7147 val->dev_did.priv_lilp_posit; 7148 7149 bcopy(val->dev_type, val32->dev_type, 7150 sizeof (port->fp_fc4_types)); 7151 7152 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7153 fcio->fcio_olen, mode) == 0) { 7154 if (fp_fcio_copyout(fcio, data, mode)) { 7155 rval = EFAULT; 7156 } 7157 } else { 7158 rval = EFAULT; 7159 } 7160 7161 kmem_free(val32, sizeof (*val32)); 7162 } else { 7163 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7164 fcio->fcio_olen, mode) == 0) { 7165 if (fp_fcio_copyout(fcio, data, mode)) { 7166 rval = EFAULT; 7167 } 7168 } else { 7169 rval = EFAULT; 7170 } 7171 } 7172 7173 /* need to free "val" here */ 7174 kmem_free(val, sizeof (*val)); 7175 break; 7176 } 7177 7178 case FCIO_GET_OTHER_ADAPTER_PORTS: { 7179 uint32_t index; 7180 char *tmpPath; 7181 fc_local_port_t *tmpPort; 7182 7183 if (fcio->fcio_olen < MAXPATHLEN || 7184 fcio->fcio_ilen != sizeof (uint32_t)) { 7185 rval = EINVAL; 7186 break; 7187 } 7188 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7189 rval = EFAULT; 7190 break; 7191 } 7192 7193 tmpPort = fctl_get_adapter_port_by_index(port, index); 7194 if (tmpPort == NULL) { 7195 FP_TRACE(FP_NHEAD1(9, 0), 7196 "User supplied index out of range"); 7197 fcio->fcio_errno = FC_BADPORT; 7198 rval = EFAULT; 7199 if (fp_fcio_copyout(fcio, data, mode)) { 7200 rval = EFAULT; 7201 } 7202 break; 7203 } 7204 7205 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7206 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath); 7207 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf, 7208 MAXPATHLEN, mode) == 0) { 7209 if (fp_fcio_copyout(fcio, data, mode)) { 7210 rval = EFAULT; 7211 } 7212 } else { 7213 rval = EFAULT; 7214 } 7215 kmem_free(tmpPath, MAXPATHLEN); 7216 break; 7217 } 7218 7219 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES: 7220 case FCIO_GET_ADAPTER_ATTRIBUTES: { 7221 fc_hba_adapter_attributes_t *val; 7222 fc_hba_adapter_attributes32_t *val32; 7223 7224 if (use32 == B_TRUE) { 7225 if (fcio->fcio_olen < sizeof (*val32) || 7226 fcio->fcio_xfer != FCIO_XFER_READ) { 7227 rval = EINVAL; 7228 break; 7229 } 7230 } else { 7231 if (fcio->fcio_olen < sizeof (*val) || 7232 fcio->fcio_xfer != FCIO_XFER_READ) { 7233 rval = EINVAL; 7234 break; 7235 } 7236 } 7237 7238 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7239 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; 7240 mutex_enter(&port->fp_mutex); 7241 bcopy(port->fp_hba_port_attrs.manufacturer, 7242 val->Manufacturer, 7243 sizeof (val->Manufacturer)); 7244 bcopy(port->fp_hba_port_attrs.serial_number, 7245 val->SerialNumber, 7246 sizeof (val->SerialNumber)); 7247 bcopy(port->fp_hba_port_attrs.model, 7248 val->Model, 7249 sizeof (val->Model)); 7250 bcopy(port->fp_hba_port_attrs.model_description, 7251 val->ModelDescription, 7252 sizeof (val->ModelDescription)); 7253 bcopy(port->fp_sym_node_name, val->NodeSymbolicName, 7254 sizeof (val->NodeSymbolicName)); 7255 bcopy(port->fp_hba_port_attrs.hardware_version, 7256 val->HardwareVersion, 7257 sizeof (val->HardwareVersion)); 7258 bcopy(port->fp_hba_port_attrs.option_rom_version, 7259 val->OptionROMVersion, 7260 sizeof (val->OptionROMVersion)); 7261 bcopy(port->fp_hba_port_attrs.firmware_version, 7262 val->FirmwareVersion, 7263 sizeof (val->FirmwareVersion)); 7264 val->VendorSpecificID = 7265 port->fp_hba_port_attrs.vendor_specific_id; 7266 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7267 &val->NodeWWN.raw_wwn, 7268 sizeof (val->NodeWWN.raw_wwn)); 7269 7270 7271 bcopy(port->fp_hba_port_attrs.driver_name, 7272 val->DriverName, 7273 sizeof (val->DriverName)); 7274 bcopy(port->fp_hba_port_attrs.driver_version, 7275 val->DriverVersion, 7276 sizeof (val->DriverVersion)); 7277 mutex_exit(&port->fp_mutex); 7278 7279 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) { 7280 val->NumberOfPorts = fctl_count_fru_ports(port, 0); 7281 } else { 7282 val->NumberOfPorts = fctl_count_fru_ports(port, 1); 7283 } 7284 7285 if (use32 == B_TRUE) { 7286 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7287 val32->version = val->version; 7288 bcopy(val->Manufacturer, val32->Manufacturer, 7289 sizeof (val->Manufacturer)); 7290 bcopy(val->SerialNumber, val32->SerialNumber, 7291 sizeof (val->SerialNumber)); 7292 bcopy(val->Model, val32->Model, 7293 sizeof (val->Model)); 7294 bcopy(val->ModelDescription, val32->ModelDescription, 7295 sizeof (val->ModelDescription)); 7296 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName, 7297 sizeof (val->NodeSymbolicName)); 7298 bcopy(val->HardwareVersion, val32->HardwareVersion, 7299 sizeof (val->HardwareVersion)); 7300 bcopy(val->OptionROMVersion, val32->OptionROMVersion, 7301 sizeof (val->OptionROMVersion)); 7302 bcopy(val->FirmwareVersion, val32->FirmwareVersion, 7303 sizeof (val->FirmwareVersion)); 7304 val32->VendorSpecificID = val->VendorSpecificID; 7305 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7306 sizeof (val->NodeWWN.raw_wwn)); 7307 bcopy(val->DriverName, val32->DriverName, 7308 sizeof (val->DriverName)); 7309 bcopy(val->DriverVersion, val32->DriverVersion, 7310 sizeof (val->DriverVersion)); 7311 7312 val32->NumberOfPorts = val->NumberOfPorts; 7313 7314 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7315 fcio->fcio_olen, mode) == 0) { 7316 if (fp_fcio_copyout(fcio, data, mode)) { 7317 rval = EFAULT; 7318 } 7319 } else { 7320 rval = EFAULT; 7321 } 7322 7323 kmem_free(val32, sizeof (*val32)); 7324 } else { 7325 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7326 fcio->fcio_olen, mode) == 0) { 7327 if (fp_fcio_copyout(fcio, data, mode)) { 7328 rval = EFAULT; 7329 } 7330 } else { 7331 rval = EFAULT; 7332 } 7333 } 7334 7335 kmem_free(val, sizeof (*val)); 7336 break; 7337 } 7338 7339 case FCIO_GET_NPIV_ATTRIBUTES: { 7340 fc_hba_npiv_attributes_t *attrs; 7341 7342 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP); 7343 mutex_enter(&port->fp_mutex); 7344 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7345 &attrs->NodeWWN.raw_wwn, 7346 sizeof (attrs->NodeWWN.raw_wwn)); 7347 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7348 &attrs->PortWWN.raw_wwn, 7349 sizeof (attrs->PortWWN.raw_wwn)); 7350 mutex_exit(&port->fp_mutex); 7351 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf, 7352 fcio->fcio_olen, mode) == 0) { 7353 if (fp_fcio_copyout(fcio, data, mode)) { 7354 rval = EFAULT; 7355 } 7356 } else { 7357 rval = EFAULT; 7358 } 7359 kmem_free(attrs, sizeof (*attrs)); 7360 break; 7361 } 7362 7363 case FCIO_DELETE_NPIV_PORT: { 7364 fc_local_port_t *tmpport; 7365 char ww_pname[17]; 7366 la_wwn_t vwwn[1]; 7367 7368 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port"); 7369 if (ddi_copyin(fcio->fcio_ibuf, 7370 &vwwn, sizeof (la_wwn_t), mode)) { 7371 rval = EFAULT; 7372 break; 7373 } 7374 7375 fc_wwn_to_str(&vwwn[0], ww_pname); 7376 FP_TRACE(FP_NHEAD1(3, 0), 7377 "Delete NPIV Port %s", ww_pname); 7378 tmpport = fc_delete_npiv_port(port, &vwwn[0]); 7379 if (tmpport == NULL) { 7380 FP_TRACE(FP_NHEAD1(3, 0), 7381 "Delete NPIV Port : no found"); 7382 rval = EFAULT; 7383 } else { 7384 fc_local_port_t *nextport = tmpport->fp_port_next; 7385 fc_local_port_t *prevport = tmpport->fp_port_prev; 7386 int portlen, portindex, ret; 7387 7388 portlen = sizeof (portindex); 7389 ret = ddi_prop_op(DDI_DEV_T_ANY, 7390 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF, 7391 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 7392 (caddr_t)&portindex, &portlen); 7393 if (ret != DDI_SUCCESS) { 7394 rval = EFAULT; 7395 break; 7396 } 7397 if (ndi_devi_offline(tmpport->fp_port_dip, 7398 NDI_DEVI_REMOVE) != DDI_SUCCESS) { 7399 FP_TRACE(FP_NHEAD1(1, 0), 7400 "Delete NPIV Port failed"); 7401 mutex_enter(&port->fp_mutex); 7402 tmpport->fp_npiv_state = 0; 7403 mutex_exit(&port->fp_mutex); 7404 rval = EFAULT; 7405 } else { 7406 mutex_enter(&port->fp_mutex); 7407 nextport->fp_port_prev = prevport; 7408 prevport->fp_port_next = nextport; 7409 if (port == port->fp_port_next) { 7410 port->fp_port_next = 7411 port->fp_port_prev = NULL; 7412 } 7413 port->fp_npiv_portnum--; 7414 FP_TRACE(FP_NHEAD1(3, 0), 7415 "Delete NPIV Port %d", portindex); 7416 port->fp_npiv_portindex[portindex-1] = 0; 7417 mutex_exit(&port->fp_mutex); 7418 } 7419 } 7420 break; 7421 } 7422 7423 case FCIO_CREATE_NPIV_PORT: { 7424 char ww_nname[17], ww_pname[17]; 7425 la_npiv_create_entry_t entrybuf; 7426 uint32_t vportindex = 0; 7427 int npiv_ret = 0; 7428 char *portname, *fcaname; 7429 7430 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7431 (void) ddi_pathname(port->fp_port_dip, portname); 7432 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7433 (void) ddi_pathname(port->fp_fca_dip, fcaname); 7434 FP_TRACE(FP_NHEAD1(1, 0), 7435 "Create NPIV port %s %s %s", portname, fcaname, 7436 ddi_driver_name(port->fp_fca_dip)); 7437 kmem_free(portname, MAXPATHLEN); 7438 kmem_free(fcaname, MAXPATHLEN); 7439 if (ddi_copyin(fcio->fcio_ibuf, 7440 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) { 7441 rval = EFAULT; 7442 break; 7443 } 7444 7445 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname); 7446 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname); 7447 vportindex = entrybuf.vindex; 7448 FP_TRACE(FP_NHEAD1(3, 0), 7449 "Create NPIV Port %s %s %d", 7450 ww_nname, ww_pname, vportindex); 7451 7452 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) { 7453 rval = EFAULT; 7454 break; 7455 } 7456 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip, 7457 port->fp_port_dip, ww_nname, ww_pname, &vportindex); 7458 if (npiv_ret == NDI_SUCCESS) { 7459 mutex_enter(&port->fp_mutex); 7460 port->fp_npiv_portnum++; 7461 mutex_exit(&port->fp_mutex); 7462 if (fp_copyout((void *)&vportindex, 7463 (void *)fcio->fcio_obuf, 7464 fcio->fcio_olen, mode) == 0) { 7465 if (fp_fcio_copyout(fcio, data, mode)) { 7466 rval = EFAULT; 7467 } 7468 } else { 7469 rval = EFAULT; 7470 } 7471 } else { 7472 rval = EFAULT; 7473 } 7474 FP_TRACE(FP_NHEAD1(3, 0), 7475 "Create NPIV Port %d %d", npiv_ret, vportindex); 7476 break; 7477 } 7478 7479 case FCIO_GET_NPIV_PORT_LIST: { 7480 fc_hba_npiv_port_list_t *list; 7481 int count; 7482 7483 if ((fcio->fcio_xfer != FCIO_XFER_READ) || 7484 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { 7485 rval = EINVAL; 7486 break; 7487 } 7488 7489 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 7490 list->version = FC_HBA_LIST_VERSION; 7491 /* build npiv port list */ 7492 count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths); 7493 if (count < 0) { 7494 rval = ENXIO; 7495 FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error"); 7496 kmem_free(list, fcio->fcio_olen); 7497 break; 7498 } 7499 list->numAdapters = count; 7500 7501 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf, 7502 fcio->fcio_olen, mode) == 0) { 7503 if (fp_fcio_copyout(fcio, data, mode)) { 7504 FP_TRACE(FP_NHEAD1(1, 0), 7505 "Copy NPIV Port data error"); 7506 rval = EFAULT; 7507 } 7508 } else { 7509 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error"); 7510 rval = EFAULT; 7511 } 7512 kmem_free(list, fcio->fcio_olen); 7513 break; 7514 } 7515 7516 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: { 7517 fc_hba_port_npiv_attributes_t *val; 7518 7519 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7520 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION; 7521 7522 mutex_enter(&port->fp_mutex); 7523 val->npivflag = port->fp_npiv_flag; 7524 val->lastChange = port->fp_last_change; 7525 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7526 &val->PortWWN.raw_wwn, 7527 sizeof (val->PortWWN.raw_wwn)); 7528 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7529 &val->NodeWWN.raw_wwn, 7530 sizeof (val->NodeWWN.raw_wwn)); 7531 mutex_exit(&port->fp_mutex); 7532 7533 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port); 7534 if (port->fp_npiv_type != FC_NPIV_PORT) { 7535 val->MaxNumberOfNPIVPorts = 7536 port->fp_fca_tran->fca_num_npivports; 7537 } else { 7538 val->MaxNumberOfNPIVPorts = 0; 7539 } 7540 7541 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7542 fcio->fcio_olen, mode) == 0) { 7543 if (fp_fcio_copyout(fcio, data, mode)) { 7544 rval = EFAULT; 7545 } 7546 } else { 7547 rval = EFAULT; 7548 } 7549 kmem_free(val, sizeof (*val)); 7550 break; 7551 } 7552 7553 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: { 7554 fc_hba_port_attributes_t *val; 7555 fc_hba_port_attributes32_t *val32; 7556 7557 if (use32 == B_TRUE) { 7558 if (fcio->fcio_olen < sizeof (*val32) || 7559 fcio->fcio_xfer != FCIO_XFER_READ) { 7560 rval = EINVAL; 7561 break; 7562 } 7563 } else { 7564 if (fcio->fcio_olen < sizeof (*val) || 7565 fcio->fcio_xfer != FCIO_XFER_READ) { 7566 rval = EINVAL; 7567 break; 7568 } 7569 } 7570 7571 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7572 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7573 mutex_enter(&port->fp_mutex); 7574 val->lastChange = port->fp_last_change; 7575 val->fp_minor = port->fp_instance; 7576 7577 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7578 &val->PortWWN.raw_wwn, 7579 sizeof (val->PortWWN.raw_wwn)); 7580 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7581 &val->NodeWWN.raw_wwn, 7582 sizeof (val->NodeWWN.raw_wwn)); 7583 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn, 7584 sizeof (val->FabricName.raw_wwn)); 7585 7586 val->PortFcId = port->fp_port_id.port_id; 7587 7588 switch (FC_PORT_STATE_MASK(port->fp_state)) { 7589 case FC_STATE_OFFLINE: 7590 val->PortState = FC_HBA_PORTSTATE_OFFLINE; 7591 break; 7592 case FC_STATE_ONLINE: 7593 case FC_STATE_LOOP: 7594 case FC_STATE_NAMESERVICE: 7595 val->PortState = FC_HBA_PORTSTATE_ONLINE; 7596 break; 7597 default: 7598 val->PortState = FC_HBA_PORTSTATE_UNKNOWN; 7599 break; 7600 } 7601 7602 /* Translate from LV to FC-HBA port type codes */ 7603 switch (port->fp_port_type.port_type) { 7604 case FC_NS_PORT_N: 7605 val->PortType = FC_HBA_PORTTYPE_NPORT; 7606 break; 7607 case FC_NS_PORT_NL: /* Actually means loop for us */ 7608 val->PortType = FC_HBA_PORTTYPE_LPORT; 7609 break; 7610 case FC_NS_PORT_F: 7611 val->PortType = FC_HBA_PORTTYPE_FPORT; 7612 break; 7613 case FC_NS_PORT_FL: 7614 val->PortType = FC_HBA_PORTTYPE_FLPORT; 7615 break; 7616 case FC_NS_PORT_E: 7617 val->PortType = FC_HBA_PORTTYPE_EPORT; 7618 break; 7619 default: 7620 val->PortType = FC_HBA_PORTTYPE_OTHER; 7621 break; 7622 } 7623 7624 7625 /* 7626 * If fp has decided that the topology is public loop, 7627 * we will indicate that using the appropriate 7628 * FC HBA API constant. 7629 */ 7630 switch (port->fp_topology) { 7631 case FC_TOP_PUBLIC_LOOP: 7632 val->PortType = FC_HBA_PORTTYPE_NLPORT; 7633 break; 7634 7635 case FC_TOP_PT_PT: 7636 val->PortType = FC_HBA_PORTTYPE_PTP; 7637 break; 7638 7639 case FC_TOP_UNKNOWN: 7640 /* 7641 * This should cover the case where nothing is connected 7642 * to the port. Crystal+ is p'bly an exception here. 7643 * For Crystal+, port 0 will come up as private loop 7644 * (i.e fp_bind_state will be FC_STATE_LOOP) even when 7645 * nothing is connected to it. 7646 * Current plan is to let userland handle this. 7647 */ 7648 if (port->fp_bind_state == FC_STATE_OFFLINE) 7649 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7650 break; 7651 7652 default: 7653 /* 7654 * Do Nothing. 7655 * Unused: 7656 * val->PortType = FC_HBA_PORTTYPE_GPORT; 7657 */ 7658 break; 7659 } 7660 7661 val->PortSupportedClassofService = 7662 port->fp_hba_port_attrs.supported_cos; 7663 val->PortSupportedFc4Types[0] = 0; 7664 bcopy(port->fp_fc4_types, val->PortActiveFc4Types, 7665 sizeof (val->PortActiveFc4Types)); 7666 bcopy(port->fp_sym_port_name, val->PortSymbolicName, 7667 sizeof (val->PortSymbolicName)); 7668 val->PortSupportedSpeed = 7669 port->fp_hba_port_attrs.supported_speed; 7670 7671 switch (FC_PORT_SPEED_MASK(port->fp_state)) { 7672 case FC_STATE_1GBIT_SPEED: 7673 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT; 7674 break; 7675 case FC_STATE_2GBIT_SPEED: 7676 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT; 7677 break; 7678 case FC_STATE_4GBIT_SPEED: 7679 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT; 7680 break; 7681 case FC_STATE_8GBIT_SPEED: 7682 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT; 7683 break; 7684 case FC_STATE_10GBIT_SPEED: 7685 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT; 7686 break; 7687 case FC_STATE_16GBIT_SPEED: 7688 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT; 7689 break; 7690 default: 7691 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7692 break; 7693 } 7694 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size; 7695 val->NumberofDiscoveredPorts = port->fp_dev_count; 7696 mutex_exit(&port->fp_mutex); 7697 7698 if (use32 == B_TRUE) { 7699 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7700 val32->version = val->version; 7701 val32->lastChange = val->lastChange; 7702 val32->fp_minor = val->fp_minor; 7703 7704 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn, 7705 sizeof (val->PortWWN.raw_wwn)); 7706 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7707 sizeof (val->NodeWWN.raw_wwn)); 7708 val32->PortFcId = val->PortFcId; 7709 val32->PortState = val->PortState; 7710 val32->PortType = val->PortType; 7711 7712 val32->PortSupportedClassofService = 7713 val->PortSupportedClassofService; 7714 bcopy(val->PortActiveFc4Types, 7715 val32->PortActiveFc4Types, 7716 sizeof (val->PortActiveFc4Types)); 7717 bcopy(val->PortSymbolicName, val32->PortSymbolicName, 7718 sizeof (val->PortSymbolicName)); 7719 bcopy(&val->FabricName, &val32->FabricName, 7720 sizeof (val->FabricName.raw_wwn)); 7721 val32->PortSupportedSpeed = val->PortSupportedSpeed; 7722 val32->PortSpeed = val->PortSpeed; 7723 7724 val32->PortMaxFrameSize = val->PortMaxFrameSize; 7725 val32->NumberofDiscoveredPorts = 7726 val->NumberofDiscoveredPorts; 7727 7728 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7729 fcio->fcio_olen, mode) == 0) { 7730 if (fp_fcio_copyout(fcio, data, mode)) { 7731 rval = EFAULT; 7732 } 7733 } else { 7734 rval = EFAULT; 7735 } 7736 7737 kmem_free(val32, sizeof (*val32)); 7738 } else { 7739 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7740 fcio->fcio_olen, mode) == 0) { 7741 if (fp_fcio_copyout(fcio, data, mode)) { 7742 rval = EFAULT; 7743 } 7744 } else { 7745 rval = EFAULT; 7746 } 7747 } 7748 7749 kmem_free(val, sizeof (*val)); 7750 break; 7751 } 7752 7753 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: { 7754 fc_hba_port_attributes_t *val; 7755 fc_hba_port_attributes32_t *val32; 7756 uint32_t index = 0; 7757 fc_remote_port_t *tmp_pd; 7758 7759 if (use32 == B_TRUE) { 7760 if (fcio->fcio_olen < sizeof (*val32) || 7761 fcio->fcio_xfer != FCIO_XFER_READ) { 7762 rval = EINVAL; 7763 break; 7764 } 7765 } else { 7766 if (fcio->fcio_olen < sizeof (*val) || 7767 fcio->fcio_xfer != FCIO_XFER_READ) { 7768 rval = EINVAL; 7769 break; 7770 } 7771 } 7772 7773 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7774 rval = EFAULT; 7775 break; 7776 } 7777 7778 if (index >= port->fp_dev_count) { 7779 FP_TRACE(FP_NHEAD1(9, 0), 7780 "User supplied index out of range"); 7781 fcio->fcio_errno = FC_OUTOFBOUNDS; 7782 rval = EINVAL; 7783 if (fp_fcio_copyout(fcio, data, mode)) { 7784 rval = EFAULT; 7785 } 7786 break; 7787 } 7788 7789 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7790 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7791 7792 mutex_enter(&port->fp_mutex); 7793 tmp_pd = fctl_lookup_pd_by_index(port, index); 7794 7795 if (tmp_pd == NULL) { 7796 fcio->fcio_errno = FC_BADPORT; 7797 rval = EINVAL; 7798 } else { 7799 val->lastChange = port->fp_last_change; 7800 val->fp_minor = port->fp_instance; 7801 7802 mutex_enter(&tmp_pd->pd_mutex); 7803 bcopy(&tmp_pd->pd_port_name.raw_wwn, 7804 &val->PortWWN.raw_wwn, 7805 sizeof (val->PortWWN.raw_wwn)); 7806 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 7807 &val->NodeWWN.raw_wwn, 7808 sizeof (val->NodeWWN.raw_wwn)); 7809 val->PortFcId = tmp_pd->pd_port_id.port_id; 7810 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 7811 sizeof (val->PortSymbolicName)); 7812 val->PortSupportedClassofService = tmp_pd->pd_cos; 7813 /* 7814 * we will assume the sizeof these pd_fc4types and 7815 * portActiveFc4Types will remain the same. we could 7816 * add in a check for it, but we decided it was unneeded 7817 */ 7818 bcopy((caddr_t)tmp_pd->pd_fc4types, 7819 val->PortActiveFc4Types, 7820 sizeof (tmp_pd->pd_fc4types)); 7821 val->PortState = 7822 fp_map_remote_port_state(tmp_pd->pd_state); 7823 mutex_exit(&tmp_pd->pd_mutex); 7824 7825 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7826 val->PortSupportedFc4Types[0] = 0; 7827 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7828 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7829 val->PortMaxFrameSize = 0; 7830 val->NumberofDiscoveredPorts = 0; 7831 7832 if (use32 == B_TRUE) { 7833 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7834 val32->version = val->version; 7835 val32->lastChange = val->lastChange; 7836 val32->fp_minor = val->fp_minor; 7837 7838 bcopy(&val->PortWWN.raw_wwn, 7839 &val32->PortWWN.raw_wwn, 7840 sizeof (val->PortWWN.raw_wwn)); 7841 bcopy(&val->NodeWWN.raw_wwn, 7842 &val32->NodeWWN.raw_wwn, 7843 sizeof (val->NodeWWN.raw_wwn)); 7844 val32->PortFcId = val->PortFcId; 7845 bcopy(val->PortSymbolicName, 7846 val32->PortSymbolicName, 7847 sizeof (val->PortSymbolicName)); 7848 val32->PortSupportedClassofService = 7849 val->PortSupportedClassofService; 7850 bcopy(val->PortActiveFc4Types, 7851 val32->PortActiveFc4Types, 7852 sizeof (tmp_pd->pd_fc4types)); 7853 7854 val32->PortType = val->PortType; 7855 val32->PortState = val->PortState; 7856 val32->PortSupportedFc4Types[0] = 7857 val->PortSupportedFc4Types[0]; 7858 val32->PortSupportedSpeed = 7859 val->PortSupportedSpeed; 7860 val32->PortSpeed = val->PortSpeed; 7861 val32->PortMaxFrameSize = 7862 val->PortMaxFrameSize; 7863 val32->NumberofDiscoveredPorts = 7864 val->NumberofDiscoveredPorts; 7865 7866 if (fp_copyout((void *)val32, 7867 (void *)fcio->fcio_obuf, 7868 fcio->fcio_olen, mode) == 0) { 7869 if (fp_fcio_copyout(fcio, 7870 data, mode)) { 7871 rval = EFAULT; 7872 } 7873 } else { 7874 rval = EFAULT; 7875 } 7876 7877 kmem_free(val32, sizeof (*val32)); 7878 } else { 7879 if (fp_copyout((void *)val, 7880 (void *)fcio->fcio_obuf, 7881 fcio->fcio_olen, mode) == 0) { 7882 if (fp_fcio_copyout(fcio, data, mode)) { 7883 rval = EFAULT; 7884 } 7885 } else { 7886 rval = EFAULT; 7887 } 7888 } 7889 } 7890 7891 mutex_exit(&port->fp_mutex); 7892 kmem_free(val, sizeof (*val)); 7893 break; 7894 } 7895 7896 case FCIO_GET_PORT_ATTRIBUTES: { 7897 fc_hba_port_attributes_t *val; 7898 fc_hba_port_attributes32_t *val32; 7899 la_wwn_t wwn; 7900 fc_remote_port_t *tmp_pd; 7901 7902 if (use32 == B_TRUE) { 7903 if (fcio->fcio_olen < sizeof (*val32) || 7904 fcio->fcio_xfer != FCIO_XFER_READ) { 7905 rval = EINVAL; 7906 break; 7907 } 7908 } else { 7909 if (fcio->fcio_olen < sizeof (*val) || 7910 fcio->fcio_xfer != FCIO_XFER_READ) { 7911 rval = EINVAL; 7912 break; 7913 } 7914 } 7915 7916 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) { 7917 rval = EFAULT; 7918 break; 7919 } 7920 7921 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7922 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7923 7924 mutex_enter(&port->fp_mutex); 7925 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn); 7926 val->lastChange = port->fp_last_change; 7927 val->fp_minor = port->fp_instance; 7928 mutex_exit(&port->fp_mutex); 7929 7930 if (tmp_pd == NULL) { 7931 fcio->fcio_errno = FC_BADWWN; 7932 rval = EINVAL; 7933 } else { 7934 mutex_enter(&tmp_pd->pd_mutex); 7935 bcopy(&tmp_pd->pd_port_name.raw_wwn, 7936 &val->PortWWN.raw_wwn, 7937 sizeof (val->PortWWN.raw_wwn)); 7938 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 7939 &val->NodeWWN.raw_wwn, 7940 sizeof (val->NodeWWN.raw_wwn)); 7941 val->PortFcId = tmp_pd->pd_port_id.port_id; 7942 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 7943 sizeof (val->PortSymbolicName)); 7944 val->PortSupportedClassofService = tmp_pd->pd_cos; 7945 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7946 val->PortState = 7947 fp_map_remote_port_state(tmp_pd->pd_state); 7948 val->PortSupportedFc4Types[0] = 0; 7949 /* 7950 * we will assume the sizeof these pd_fc4types and 7951 * portActiveFc4Types will remain the same. we could 7952 * add in a check for it, but we decided it was unneeded 7953 */ 7954 bcopy((caddr_t)tmp_pd->pd_fc4types, 7955 val->PortActiveFc4Types, 7956 sizeof (tmp_pd->pd_fc4types)); 7957 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7958 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7959 val->PortMaxFrameSize = 0; 7960 val->NumberofDiscoveredPorts = 0; 7961 mutex_exit(&tmp_pd->pd_mutex); 7962 7963 if (use32 == B_TRUE) { 7964 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7965 val32->version = val->version; 7966 val32->lastChange = val->lastChange; 7967 val32->fp_minor = val->fp_minor; 7968 bcopy(&val->PortWWN.raw_wwn, 7969 &val32->PortWWN.raw_wwn, 7970 sizeof (val->PortWWN.raw_wwn)); 7971 bcopy(&val->NodeWWN.raw_wwn, 7972 &val32->NodeWWN.raw_wwn, 7973 sizeof (val->NodeWWN.raw_wwn)); 7974 val32->PortFcId = val->PortFcId; 7975 bcopy(val->PortSymbolicName, 7976 val32->PortSymbolicName, 7977 sizeof (val->PortSymbolicName)); 7978 val32->PortSupportedClassofService = 7979 val->PortSupportedClassofService; 7980 val32->PortType = val->PortType; 7981 val32->PortState = val->PortState; 7982 val32->PortSupportedFc4Types[0] = 7983 val->PortSupportedFc4Types[0]; 7984 bcopy(val->PortActiveFc4Types, 7985 val32->PortActiveFc4Types, 7986 sizeof (tmp_pd->pd_fc4types)); 7987 val32->PortSupportedSpeed = 7988 val->PortSupportedSpeed; 7989 val32->PortSpeed = val->PortSpeed; 7990 val32->PortMaxFrameSize = val->PortMaxFrameSize; 7991 val32->NumberofDiscoveredPorts = 7992 val->NumberofDiscoveredPorts; 7993 7994 if (fp_copyout((void *)val32, 7995 (void *)fcio->fcio_obuf, 7996 fcio->fcio_olen, mode) == 0) { 7997 if (fp_fcio_copyout(fcio, data, mode)) { 7998 rval = EFAULT; 7999 } 8000 } else { 8001 rval = EFAULT; 8002 } 8003 8004 kmem_free(val32, sizeof (*val32)); 8005 } else { 8006 if (fp_copyout((void *)val, 8007 (void *)fcio->fcio_obuf, 8008 fcio->fcio_olen, mode) == 0) { 8009 if (fp_fcio_copyout(fcio, data, mode)) { 8010 rval = EFAULT; 8011 } 8012 } else { 8013 rval = EFAULT; 8014 } 8015 } 8016 } 8017 kmem_free(val, sizeof (*val)); 8018 break; 8019 } 8020 8021 case FCIO_GET_NUM_DEVS: { 8022 int num_devices; 8023 8024 if (fcio->fcio_olen != sizeof (num_devices) || 8025 fcio->fcio_xfer != FCIO_XFER_READ) { 8026 rval = EINVAL; 8027 break; 8028 } 8029 8030 mutex_enter(&port->fp_mutex); 8031 switch (port->fp_topology) { 8032 case FC_TOP_PRIVATE_LOOP: 8033 case FC_TOP_PT_PT: 8034 num_devices = port->fp_total_devices; 8035 fcio->fcio_errno = FC_SUCCESS; 8036 break; 8037 8038 case FC_TOP_PUBLIC_LOOP: 8039 case FC_TOP_FABRIC: 8040 mutex_exit(&port->fp_mutex); 8041 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, 8042 NULL, KM_SLEEP); 8043 ASSERT(job != NULL); 8044 8045 /* 8046 * In FC-GS-2 the Name Server doesn't send out 8047 * RSCNs for any Name Server Database updates 8048 * When it is finally fixed there is no need 8049 * to probe as below and should be removed. 8050 */ 8051 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 8052 fctl_dealloc_job(job); 8053 8054 mutex_enter(&port->fp_mutex); 8055 num_devices = port->fp_total_devices; 8056 fcio->fcio_errno = FC_SUCCESS; 8057 break; 8058 8059 case FC_TOP_NO_NS: 8060 /* FALLTHROUGH */ 8061 case FC_TOP_UNKNOWN: 8062 /* FALLTHROUGH */ 8063 default: 8064 num_devices = 0; 8065 fcio->fcio_errno = FC_SUCCESS; 8066 break; 8067 } 8068 mutex_exit(&port->fp_mutex); 8069 8070 if (fp_copyout((void *)&num_devices, 8071 (void *)fcio->fcio_obuf, fcio->fcio_olen, 8072 mode) == 0) { 8073 if (fp_fcio_copyout(fcio, data, mode)) { 8074 rval = EFAULT; 8075 } 8076 } else { 8077 rval = EFAULT; 8078 } 8079 break; 8080 } 8081 8082 case FCIO_GET_DEV_LIST: { 8083 int num_devices; 8084 int new_count; 8085 int map_size; 8086 8087 if (fcio->fcio_xfer != FCIO_XFER_READ || 8088 fcio->fcio_alen != sizeof (new_count)) { 8089 rval = EINVAL; 8090 break; 8091 } 8092 8093 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 8094 8095 mutex_enter(&port->fp_mutex); 8096 if (num_devices < port->fp_total_devices) { 8097 fcio->fcio_errno = FC_TOOMANY; 8098 new_count = port->fp_total_devices; 8099 mutex_exit(&port->fp_mutex); 8100 8101 if (fp_copyout((void *)&new_count, 8102 (void *)fcio->fcio_abuf, 8103 sizeof (new_count), mode)) { 8104 rval = EFAULT; 8105 break; 8106 } 8107 8108 if (fp_fcio_copyout(fcio, data, mode)) { 8109 rval = EFAULT; 8110 break; 8111 } 8112 rval = EINVAL; 8113 break; 8114 } 8115 8116 if (port->fp_total_devices <= 0) { 8117 fcio->fcio_errno = FC_NO_MAP; 8118 new_count = port->fp_total_devices; 8119 mutex_exit(&port->fp_mutex); 8120 8121 if (fp_copyout((void *)&new_count, 8122 (void *)fcio->fcio_abuf, 8123 sizeof (new_count), mode)) { 8124 rval = EFAULT; 8125 break; 8126 } 8127 8128 if (fp_fcio_copyout(fcio, data, mode)) { 8129 rval = EFAULT; 8130 break; 8131 } 8132 rval = EINVAL; 8133 break; 8134 } 8135 8136 switch (port->fp_topology) { 8137 case FC_TOP_PRIVATE_LOOP: 8138 if (fp_fillout_loopmap(port, fcio, 8139 mode) != FC_SUCCESS) { 8140 rval = EFAULT; 8141 break; 8142 } 8143 if (fp_fcio_copyout(fcio, data, mode)) { 8144 rval = EFAULT; 8145 } 8146 break; 8147 8148 case FC_TOP_PT_PT: 8149 if (fp_fillout_p2pmap(port, fcio, 8150 mode) != FC_SUCCESS) { 8151 rval = EFAULT; 8152 break; 8153 } 8154 if (fp_fcio_copyout(fcio, data, mode)) { 8155 rval = EFAULT; 8156 } 8157 break; 8158 8159 case FC_TOP_PUBLIC_LOOP: 8160 case FC_TOP_FABRIC: { 8161 fctl_ns_req_t *ns_cmd; 8162 8163 map_size = 8164 sizeof (fc_port_dev_t) * port->fp_total_devices; 8165 8166 mutex_exit(&port->fp_mutex); 8167 8168 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 8169 sizeof (ns_resp_gan_t), map_size, 8170 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND), 8171 KM_SLEEP); 8172 ASSERT(ns_cmd != NULL); 8173 8174 ns_cmd->ns_gan_index = 0; 8175 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 8176 ns_cmd->ns_cmd_code = NS_GA_NXT; 8177 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t); 8178 8179 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, 8180 NULL, KM_SLEEP); 8181 ASSERT(job != NULL); 8182 8183 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 8184 8185 if (ret != FC_SUCCESS || 8186 job->job_result != FC_SUCCESS) { 8187 fctl_free_ns_cmd(ns_cmd); 8188 8189 fcio->fcio_errno = job->job_result; 8190 new_count = 0; 8191 if (fp_copyout((void *)&new_count, 8192 (void *)fcio->fcio_abuf, 8193 sizeof (new_count), mode)) { 8194 fctl_dealloc_job(job); 8195 mutex_enter(&port->fp_mutex); 8196 rval = EFAULT; 8197 break; 8198 } 8199 8200 if (fp_fcio_copyout(fcio, data, mode)) { 8201 fctl_dealloc_job(job); 8202 mutex_enter(&port->fp_mutex); 8203 rval = EFAULT; 8204 break; 8205 } 8206 rval = EIO; 8207 mutex_enter(&port->fp_mutex); 8208 break; 8209 } 8210 fctl_dealloc_job(job); 8211 8212 new_count = ns_cmd->ns_gan_index; 8213 if (fp_copyout((void *)&new_count, 8214 (void *)fcio->fcio_abuf, sizeof (new_count), 8215 mode)) { 8216 rval = EFAULT; 8217 fctl_free_ns_cmd(ns_cmd); 8218 mutex_enter(&port->fp_mutex); 8219 break; 8220 } 8221 8222 if (fp_copyout((void *)ns_cmd->ns_data_buf, 8223 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) * 8224 ns_cmd->ns_gan_index, mode)) { 8225 rval = EFAULT; 8226 fctl_free_ns_cmd(ns_cmd); 8227 mutex_enter(&port->fp_mutex); 8228 break; 8229 } 8230 fctl_free_ns_cmd(ns_cmd); 8231 8232 if (fp_fcio_copyout(fcio, data, mode)) { 8233 rval = EFAULT; 8234 } 8235 mutex_enter(&port->fp_mutex); 8236 break; 8237 } 8238 8239 case FC_TOP_NO_NS: 8240 /* FALLTHROUGH */ 8241 case FC_TOP_UNKNOWN: 8242 /* FALLTHROUGH */ 8243 default: 8244 fcio->fcio_errno = FC_NO_MAP; 8245 num_devices = port->fp_total_devices; 8246 8247 if (fp_copyout((void *)&new_count, 8248 (void *)fcio->fcio_abuf, 8249 sizeof (new_count), mode)) { 8250 rval = EFAULT; 8251 break; 8252 } 8253 8254 if (fp_fcio_copyout(fcio, data, mode)) { 8255 rval = EFAULT; 8256 break; 8257 } 8258 rval = EINVAL; 8259 break; 8260 } 8261 mutex_exit(&port->fp_mutex); 8262 break; 8263 } 8264 8265 case FCIO_GET_SYM_PNAME: { 8266 rval = ENOTSUP; 8267 break; 8268 } 8269 8270 case FCIO_GET_SYM_NNAME: { 8271 rval = ENOTSUP; 8272 break; 8273 } 8274 8275 case FCIO_SET_SYM_PNAME: { 8276 rval = ENOTSUP; 8277 break; 8278 } 8279 8280 case FCIO_SET_SYM_NNAME: { 8281 rval = ENOTSUP; 8282 break; 8283 } 8284 8285 case FCIO_GET_LOGI_PARAMS: { 8286 la_wwn_t pwwn; 8287 la_wwn_t *my_pwwn; 8288 la_els_logi_t *params; 8289 la_els_logi32_t *params32; 8290 fc_remote_node_t *node; 8291 fc_remote_port_t *pd; 8292 8293 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8294 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || 8295 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { 8296 rval = EINVAL; 8297 break; 8298 } 8299 8300 if (use32 == B_TRUE) { 8301 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) { 8302 rval = EINVAL; 8303 break; 8304 } 8305 } else { 8306 if (fcio->fcio_olen != sizeof (la_els_logi_t)) { 8307 rval = EINVAL; 8308 break; 8309 } 8310 } 8311 8312 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8313 rval = EFAULT; 8314 break; 8315 } 8316 8317 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8318 if (pd == NULL) { 8319 mutex_enter(&port->fp_mutex); 8320 my_pwwn = &port->fp_service_params.nport_ww_name; 8321 mutex_exit(&port->fp_mutex); 8322 8323 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) { 8324 rval = ENXIO; 8325 break; 8326 } 8327 8328 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8329 mutex_enter(&port->fp_mutex); 8330 *params = port->fp_service_params; 8331 mutex_exit(&port->fp_mutex); 8332 } else { 8333 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8334 8335 mutex_enter(&pd->pd_mutex); 8336 params->ls_code.mbz = params->ls_code.ls_code = 0; 8337 params->common_service = pd->pd_csp; 8338 params->nport_ww_name = pd->pd_port_name; 8339 params->class_1 = pd->pd_clsp1; 8340 params->class_2 = pd->pd_clsp2; 8341 params->class_3 = pd->pd_clsp3; 8342 node = pd->pd_remote_nodep; 8343 mutex_exit(&pd->pd_mutex); 8344 8345 bzero(params->reserved, sizeof (params->reserved)); 8346 8347 mutex_enter(&node->fd_mutex); 8348 bcopy(node->fd_vv, params->vendor_version, 8349 sizeof (node->fd_vv)); 8350 params->node_ww_name = node->fd_node_name; 8351 mutex_exit(&node->fd_mutex); 8352 8353 fctl_release_remote_port(pd); 8354 } 8355 8356 if (use32 == B_TRUE) { 8357 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP); 8358 8359 params32->ls_code.mbz = params->ls_code.mbz; 8360 params32->common_service = params->common_service; 8361 params32->nport_ww_name = params->nport_ww_name; 8362 params32->class_1 = params->class_1; 8363 params32->class_2 = params->class_2; 8364 params32->class_3 = params->class_3; 8365 bzero(params32->reserved, sizeof (params32->reserved)); 8366 bcopy(params->vendor_version, params32->vendor_version, 8367 sizeof (node->fd_vv)); 8368 params32->node_ww_name = params->node_ww_name; 8369 8370 if (ddi_copyout((void *)params32, 8371 (void *)fcio->fcio_obuf, 8372 sizeof (*params32), mode)) { 8373 rval = EFAULT; 8374 } 8375 8376 kmem_free(params32, sizeof (*params32)); 8377 } else { 8378 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf, 8379 sizeof (*params), mode)) { 8380 rval = EFAULT; 8381 } 8382 } 8383 8384 kmem_free(params, sizeof (*params)); 8385 if (fp_fcio_copyout(fcio, data, mode)) { 8386 rval = EFAULT; 8387 } 8388 break; 8389 } 8390 8391 case FCIO_DEV_LOGOUT: 8392 case FCIO_DEV_LOGIN: 8393 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8394 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8395 rval = EINVAL; 8396 8397 if (fp_fcio_copyout(fcio, data, mode)) { 8398 rval = EFAULT; 8399 } 8400 break; 8401 } 8402 8403 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) { 8404 jcode = JOB_FCIO_LOGIN; 8405 } else { 8406 jcode = JOB_FCIO_LOGOUT; 8407 } 8408 8409 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP); 8410 bcopy(fcio, kfcio, sizeof (*fcio)); 8411 8412 if (kfcio->fcio_ilen) { 8413 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen, 8414 KM_SLEEP); 8415 8416 if (ddi_copyin((void *)fcio->fcio_ibuf, 8417 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen, 8418 mode)) { 8419 rval = EFAULT; 8420 8421 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8422 kmem_free(kfcio, sizeof (*kfcio)); 8423 fcio->fcio_errno = job->job_result; 8424 if (fp_fcio_copyout(fcio, data, mode)) { 8425 rval = EFAULT; 8426 } 8427 break; 8428 } 8429 } 8430 8431 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP); 8432 job->job_private = kfcio; 8433 8434 fctl_enque_job(port, job); 8435 fctl_jobwait(job); 8436 8437 rval = job->job_result; 8438 8439 fcio->fcio_errno = kfcio->fcio_errno; 8440 if (fp_fcio_copyout(fcio, data, mode)) { 8441 rval = EFAULT; 8442 } 8443 8444 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8445 kmem_free(kfcio, sizeof (*kfcio)); 8446 fctl_dealloc_job(job); 8447 break; 8448 8449 case FCIO_GET_STATE: { 8450 la_wwn_t pwwn; 8451 uint32_t state; 8452 fc_remote_port_t *pd; 8453 fctl_ns_req_t *ns_cmd; 8454 8455 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8456 fcio->fcio_olen != sizeof (state) || 8457 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 || 8458 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { 8459 rval = EINVAL; 8460 break; 8461 } 8462 8463 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8464 rval = EFAULT; 8465 break; 8466 } 8467 fcio->fcio_errno = 0; 8468 8469 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8470 if (pd == NULL) { 8471 mutex_enter(&port->fp_mutex); 8472 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 8473 mutex_exit(&port->fp_mutex); 8474 job = fctl_alloc_job(JOB_PLOGI_ONE, 0, 8475 NULL, NULL, KM_SLEEP); 8476 8477 job->job_counter = 1; 8478 job->job_result = FC_SUCCESS; 8479 8480 ns_cmd = fctl_alloc_ns_cmd( 8481 sizeof (ns_req_gid_pn_t), 8482 sizeof (ns_resp_gid_pn_t), 8483 sizeof (ns_resp_gid_pn_t), 8484 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 8485 ASSERT(ns_cmd != NULL); 8486 8487 ns_cmd->ns_cmd_code = NS_GID_PN; 8488 ((ns_req_gid_pn_t *) 8489 (ns_cmd->ns_cmd_buf))->pwwn = pwwn; 8490 8491 ret = fp_ns_query(port, ns_cmd, job, 8492 1, KM_SLEEP); 8493 8494 if (ret != FC_SUCCESS || job->job_result != 8495 FC_SUCCESS) { 8496 if (ret != FC_SUCCESS) { 8497 fcio->fcio_errno = ret; 8498 } else { 8499 fcio->fcio_errno = 8500 job->job_result; 8501 } 8502 rval = EIO; 8503 } else { 8504 state = PORT_DEVICE_INVALID; 8505 } 8506 fctl_free_ns_cmd(ns_cmd); 8507 fctl_dealloc_job(job); 8508 } else { 8509 mutex_exit(&port->fp_mutex); 8510 fcio->fcio_errno = FC_BADWWN; 8511 rval = ENXIO; 8512 } 8513 } else { 8514 mutex_enter(&pd->pd_mutex); 8515 state = pd->pd_state; 8516 mutex_exit(&pd->pd_mutex); 8517 8518 fctl_release_remote_port(pd); 8519 } 8520 8521 if (!rval) { 8522 if (ddi_copyout((void *)&state, 8523 (void *)fcio->fcio_obuf, sizeof (state), 8524 mode)) { 8525 rval = EFAULT; 8526 } 8527 } 8528 if (fp_fcio_copyout(fcio, data, mode)) { 8529 rval = EFAULT; 8530 } 8531 break; 8532 } 8533 8534 case FCIO_DEV_REMOVE: { 8535 la_wwn_t pwwn; 8536 fc_portmap_t *changelist; 8537 fc_remote_port_t *pd; 8538 8539 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8540 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8541 rval = EINVAL; 8542 break; 8543 } 8544 8545 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8546 rval = EFAULT; 8547 break; 8548 } 8549 8550 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8551 if (pd == NULL) { 8552 rval = ENXIO; 8553 fcio->fcio_errno = FC_BADWWN; 8554 if (fp_fcio_copyout(fcio, data, mode)) { 8555 rval = EFAULT; 8556 } 8557 break; 8558 } 8559 8560 mutex_enter(&pd->pd_mutex); 8561 if (pd->pd_ref_count > 1) { 8562 mutex_exit(&pd->pd_mutex); 8563 8564 rval = EBUSY; 8565 fcio->fcio_errno = FC_FAILURE; 8566 fctl_release_remote_port(pd); 8567 8568 if (fp_fcio_copyout(fcio, data, mode)) { 8569 rval = EFAULT; 8570 } 8571 break; 8572 } 8573 mutex_exit(&pd->pd_mutex); 8574 8575 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 8576 8577 fctl_copy_portmap(changelist, pd); 8578 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 8579 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 8580 8581 fctl_release_remote_port(pd); 8582 break; 8583 } 8584 8585 case FCIO_GET_FCODE_REV: { 8586 caddr_t fcode_rev; 8587 fc_fca_pm_t pm; 8588 8589 if (fcio->fcio_olen < FC_FCODE_REV_SIZE || 8590 fcio->fcio_xfer != FCIO_XFER_READ) { 8591 rval = EINVAL; 8592 break; 8593 } 8594 bzero((caddr_t)&pm, sizeof (pm)); 8595 8596 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8597 8598 pm.pm_cmd_flags = FC_FCA_PM_READ; 8599 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV; 8600 pm.pm_data_len = fcio->fcio_olen; 8601 pm.pm_data_buf = fcode_rev; 8602 8603 ret = port->fp_fca_tran->fca_port_manage( 8604 port->fp_fca_handle, &pm); 8605 8606 if (ret == FC_SUCCESS) { 8607 if (ddi_copyout((void *)fcode_rev, 8608 (void *)fcio->fcio_obuf, 8609 fcio->fcio_olen, mode) == 0) { 8610 if (fp_fcio_copyout(fcio, data, mode)) { 8611 rval = EFAULT; 8612 } 8613 } else { 8614 rval = EFAULT; 8615 } 8616 } else { 8617 /* 8618 * check if buffer was not large enough to obtain 8619 * FCODE version. 8620 */ 8621 if (pm.pm_data_len > fcio->fcio_olen) { 8622 rval = ENOMEM; 8623 } else { 8624 rval = EIO; 8625 } 8626 fcio->fcio_errno = ret; 8627 if (fp_fcio_copyout(fcio, data, mode)) { 8628 rval = EFAULT; 8629 } 8630 } 8631 kmem_free(fcode_rev, fcio->fcio_olen); 8632 break; 8633 } 8634 8635 case FCIO_GET_FW_REV: { 8636 caddr_t fw_rev; 8637 fc_fca_pm_t pm; 8638 8639 if (fcio->fcio_olen < FC_FW_REV_SIZE || 8640 fcio->fcio_xfer != FCIO_XFER_READ) { 8641 rval = EINVAL; 8642 break; 8643 } 8644 bzero((caddr_t)&pm, sizeof (pm)); 8645 8646 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8647 8648 pm.pm_cmd_flags = FC_FCA_PM_READ; 8649 pm.pm_cmd_code = FC_PORT_GET_FW_REV; 8650 pm.pm_data_len = fcio->fcio_olen; 8651 pm.pm_data_buf = fw_rev; 8652 8653 ret = port->fp_fca_tran->fca_port_manage( 8654 port->fp_fca_handle, &pm); 8655 8656 if (ret == FC_SUCCESS) { 8657 if (ddi_copyout((void *)fw_rev, 8658 (void *)fcio->fcio_obuf, 8659 fcio->fcio_olen, mode) == 0) { 8660 if (fp_fcio_copyout(fcio, data, mode)) { 8661 rval = EFAULT; 8662 } 8663 } else { 8664 rval = EFAULT; 8665 } 8666 } else { 8667 if (fp_fcio_copyout(fcio, data, mode)) { 8668 rval = EFAULT; 8669 } 8670 rval = EIO; 8671 } 8672 kmem_free(fw_rev, fcio->fcio_olen); 8673 break; 8674 } 8675 8676 case FCIO_GET_DUMP_SIZE: { 8677 uint32_t dump_size; 8678 fc_fca_pm_t pm; 8679 8680 if (fcio->fcio_olen != sizeof (dump_size) || 8681 fcio->fcio_xfer != FCIO_XFER_READ) { 8682 rval = EINVAL; 8683 break; 8684 } 8685 bzero((caddr_t)&pm, sizeof (pm)); 8686 pm.pm_cmd_flags = FC_FCA_PM_READ; 8687 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8688 pm.pm_data_len = sizeof (dump_size); 8689 pm.pm_data_buf = (caddr_t)&dump_size; 8690 8691 ret = port->fp_fca_tran->fca_port_manage( 8692 port->fp_fca_handle, &pm); 8693 8694 if (ret == FC_SUCCESS) { 8695 if (ddi_copyout((void *)&dump_size, 8696 (void *)fcio->fcio_obuf, sizeof (dump_size), 8697 mode) == 0) { 8698 if (fp_fcio_copyout(fcio, data, mode)) { 8699 rval = EFAULT; 8700 } 8701 } else { 8702 rval = EFAULT; 8703 } 8704 } else { 8705 fcio->fcio_errno = ret; 8706 rval = EIO; 8707 if (fp_fcio_copyout(fcio, data, mode)) { 8708 rval = EFAULT; 8709 } 8710 } 8711 break; 8712 } 8713 8714 case FCIO_DOWNLOAD_FW: { 8715 caddr_t firmware; 8716 fc_fca_pm_t pm; 8717 8718 if (fcio->fcio_ilen <= 0 || 8719 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8720 rval = EINVAL; 8721 break; 8722 } 8723 8724 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8725 if (ddi_copyin(fcio->fcio_ibuf, firmware, 8726 fcio->fcio_ilen, mode)) { 8727 rval = EFAULT; 8728 kmem_free(firmware, fcio->fcio_ilen); 8729 break; 8730 } 8731 8732 bzero((caddr_t)&pm, sizeof (pm)); 8733 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8734 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW; 8735 pm.pm_data_len = fcio->fcio_ilen; 8736 pm.pm_data_buf = firmware; 8737 8738 ret = port->fp_fca_tran->fca_port_manage( 8739 port->fp_fca_handle, &pm); 8740 8741 kmem_free(firmware, fcio->fcio_ilen); 8742 8743 if (ret != FC_SUCCESS) { 8744 fcio->fcio_errno = ret; 8745 rval = EIO; 8746 if (fp_fcio_copyout(fcio, data, mode)) { 8747 rval = EFAULT; 8748 } 8749 } 8750 break; 8751 } 8752 8753 case FCIO_DOWNLOAD_FCODE: { 8754 caddr_t fcode; 8755 fc_fca_pm_t pm; 8756 8757 if (fcio->fcio_ilen <= 0 || 8758 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8759 rval = EINVAL; 8760 break; 8761 } 8762 8763 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8764 if (ddi_copyin(fcio->fcio_ibuf, fcode, 8765 fcio->fcio_ilen, mode)) { 8766 rval = EFAULT; 8767 kmem_free(fcode, fcio->fcio_ilen); 8768 break; 8769 } 8770 8771 bzero((caddr_t)&pm, sizeof (pm)); 8772 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8773 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE; 8774 pm.pm_data_len = fcio->fcio_ilen; 8775 pm.pm_data_buf = fcode; 8776 8777 ret = port->fp_fca_tran->fca_port_manage( 8778 port->fp_fca_handle, &pm); 8779 8780 kmem_free(fcode, fcio->fcio_ilen); 8781 8782 if (ret != FC_SUCCESS) { 8783 fcio->fcio_errno = ret; 8784 rval = EIO; 8785 if (fp_fcio_copyout(fcio, data, mode)) { 8786 rval = EFAULT; 8787 } 8788 } 8789 break; 8790 } 8791 8792 case FCIO_FORCE_DUMP: 8793 ret = port->fp_fca_tran->fca_reset( 8794 port->fp_fca_handle, FC_FCA_CORE); 8795 8796 if (ret != FC_SUCCESS) { 8797 fcio->fcio_errno = ret; 8798 rval = EIO; 8799 if (fp_fcio_copyout(fcio, data, mode)) { 8800 rval = EFAULT; 8801 } 8802 } 8803 break; 8804 8805 case FCIO_GET_DUMP: { 8806 caddr_t dump; 8807 uint32_t dump_size; 8808 fc_fca_pm_t pm; 8809 8810 if (fcio->fcio_xfer != FCIO_XFER_READ) { 8811 rval = EINVAL; 8812 break; 8813 } 8814 bzero((caddr_t)&pm, sizeof (pm)); 8815 8816 pm.pm_cmd_flags = FC_FCA_PM_READ; 8817 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8818 pm.pm_data_len = sizeof (dump_size); 8819 pm.pm_data_buf = (caddr_t)&dump_size; 8820 8821 ret = port->fp_fca_tran->fca_port_manage( 8822 port->fp_fca_handle, &pm); 8823 8824 if (ret != FC_SUCCESS) { 8825 fcio->fcio_errno = ret; 8826 rval = EIO; 8827 if (fp_fcio_copyout(fcio, data, mode)) { 8828 rval = EFAULT; 8829 } 8830 break; 8831 } 8832 if (fcio->fcio_olen != dump_size) { 8833 fcio->fcio_errno = FC_NOMEM; 8834 rval = EINVAL; 8835 if (fp_fcio_copyout(fcio, data, mode)) { 8836 rval = EFAULT; 8837 } 8838 break; 8839 } 8840 8841 dump = kmem_zalloc(dump_size, KM_SLEEP); 8842 8843 bzero((caddr_t)&pm, sizeof (pm)); 8844 pm.pm_cmd_flags = FC_FCA_PM_READ; 8845 pm.pm_cmd_code = FC_PORT_GET_DUMP; 8846 pm.pm_data_len = dump_size; 8847 pm.pm_data_buf = dump; 8848 8849 ret = port->fp_fca_tran->fca_port_manage( 8850 port->fp_fca_handle, &pm); 8851 8852 if (ret == FC_SUCCESS) { 8853 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf, 8854 dump_size, mode) == 0) { 8855 if (fp_fcio_copyout(fcio, data, mode)) { 8856 rval = EFAULT; 8857 } 8858 } else { 8859 rval = EFAULT; 8860 } 8861 } else { 8862 fcio->fcio_errno = ret; 8863 rval = EIO; 8864 if (fp_fcio_copyout(fcio, data, mode)) { 8865 rval = EFAULT; 8866 } 8867 } 8868 kmem_free(dump, dump_size); 8869 break; 8870 } 8871 8872 case FCIO_GET_TOPOLOGY: { 8873 uint32_t user_topology; 8874 8875 if (fcio->fcio_xfer != FCIO_XFER_READ || 8876 fcio->fcio_olen != sizeof (user_topology)) { 8877 rval = EINVAL; 8878 break; 8879 } 8880 8881 mutex_enter(&port->fp_mutex); 8882 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 8883 user_topology = FC_TOP_UNKNOWN; 8884 } else { 8885 user_topology = port->fp_topology; 8886 } 8887 mutex_exit(&port->fp_mutex); 8888 8889 if (ddi_copyout((void *)&user_topology, 8890 (void *)fcio->fcio_obuf, sizeof (user_topology), 8891 mode)) { 8892 rval = EFAULT; 8893 } 8894 break; 8895 } 8896 8897 case FCIO_RESET_LINK: { 8898 la_wwn_t pwwn; 8899 8900 /* 8901 * Look at the output buffer field; if this field has zero 8902 * bytes then attempt to reset the local link/loop. If the 8903 * fcio_ibuf field points to a WWN, see if it's an NL_Port, 8904 * and if yes, determine the LFA and reset the remote LIP 8905 * by LINIT ELS. 8906 */ 8907 8908 if (fcio->fcio_xfer != FCIO_XFER_WRITE || 8909 fcio->fcio_ilen != sizeof (pwwn)) { 8910 rval = EINVAL; 8911 break; 8912 } 8913 8914 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 8915 sizeof (pwwn), mode)) { 8916 rval = EFAULT; 8917 break; 8918 } 8919 8920 mutex_enter(&port->fp_mutex); 8921 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 8922 mutex_exit(&port->fp_mutex); 8923 break; 8924 } 8925 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 8926 mutex_exit(&port->fp_mutex); 8927 8928 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP); 8929 if (job == NULL) { 8930 rval = ENOMEM; 8931 break; 8932 } 8933 job->job_counter = 1; 8934 job->job_private = (void *)&pwwn; 8935 8936 fctl_enque_job(port, job); 8937 fctl_jobwait(job); 8938 8939 mutex_enter(&port->fp_mutex); 8940 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 8941 mutex_exit(&port->fp_mutex); 8942 8943 if (job->job_result != FC_SUCCESS) { 8944 fcio->fcio_errno = job->job_result; 8945 rval = EIO; 8946 if (fp_fcio_copyout(fcio, data, mode)) { 8947 rval = EFAULT; 8948 } 8949 } 8950 fctl_dealloc_job(job); 8951 break; 8952 } 8953 8954 case FCIO_RESET_HARD: 8955 ret = port->fp_fca_tran->fca_reset( 8956 port->fp_fca_handle, FC_FCA_RESET); 8957 if (ret != FC_SUCCESS) { 8958 fcio->fcio_errno = ret; 8959 rval = EIO; 8960 if (fp_fcio_copyout(fcio, data, mode)) { 8961 rval = EFAULT; 8962 } 8963 } 8964 break; 8965 8966 case FCIO_RESET_HARD_CORE: 8967 ret = port->fp_fca_tran->fca_reset( 8968 port->fp_fca_handle, FC_FCA_RESET_CORE); 8969 if (ret != FC_SUCCESS) { 8970 rval = EIO; 8971 fcio->fcio_errno = ret; 8972 if (fp_fcio_copyout(fcio, data, mode)) { 8973 rval = EFAULT; 8974 } 8975 } 8976 break; 8977 8978 case FCIO_DIAG: { 8979 fc_fca_pm_t pm; 8980 8981 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); 8982 8983 /* Validate user buffer from ioctl call. */ 8984 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) || 8985 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) || 8986 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) || 8987 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) || 8988 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) || 8989 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) { 8990 rval = EFAULT; 8991 break; 8992 } 8993 8994 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) { 8995 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8996 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf, 8997 fcio->fcio_ilen, mode)) { 8998 rval = EFAULT; 8999 goto fp_fcio_diag_cleanup; 9000 } 9001 } 9002 9003 if ((pm.pm_data_len = fcio->fcio_alen) > 0) { 9004 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP); 9005 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf, 9006 fcio->fcio_alen, mode)) { 9007 rval = EFAULT; 9008 goto fp_fcio_diag_cleanup; 9009 } 9010 } 9011 9012 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) { 9013 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 9014 } 9015 9016 pm.pm_cmd_code = FC_PORT_DIAG; 9017 pm.pm_cmd_flags = fcio->fcio_cmd_flags; 9018 9019 ret = port->fp_fca_tran->fca_port_manage( 9020 port->fp_fca_handle, &pm); 9021 9022 if (ret != FC_SUCCESS) { 9023 if (ret == FC_INVALID_REQUEST) { 9024 rval = ENOTTY; 9025 } else { 9026 rval = EIO; 9027 } 9028 9029 fcio->fcio_errno = ret; 9030 if (fp_fcio_copyout(fcio, data, mode)) { 9031 rval = EFAULT; 9032 } 9033 goto fp_fcio_diag_cleanup; 9034 } 9035 9036 /* 9037 * pm_stat_len will contain the number of status bytes 9038 * an FCA driver requires to return the complete status 9039 * of the requested diag operation. If the user buffer 9040 * is not large enough to hold the entire status, We 9041 * copy only the portion of data the fits in the buffer and 9042 * return a ENOMEM to the user application. 9043 */ 9044 if (pm.pm_stat_len > fcio->fcio_olen) { 9045 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 9046 "fp:FCIO_DIAG:status buffer too small\n"); 9047 9048 rval = ENOMEM; 9049 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9050 fcio->fcio_olen, mode)) { 9051 rval = EFAULT; 9052 goto fp_fcio_diag_cleanup; 9053 } 9054 } else { 9055 /* 9056 * Copy only data pm_stat_len bytes of data 9057 */ 9058 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9059 pm.pm_stat_len, mode)) { 9060 rval = EFAULT; 9061 goto fp_fcio_diag_cleanup; 9062 } 9063 } 9064 9065 if (fp_fcio_copyout(fcio, data, mode)) { 9066 rval = EFAULT; 9067 } 9068 9069 fp_fcio_diag_cleanup: 9070 if (pm.pm_cmd_buf != NULL) { 9071 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen); 9072 } 9073 if (pm.pm_data_buf != NULL) { 9074 kmem_free(pm.pm_data_buf, fcio->fcio_alen); 9075 } 9076 if (pm.pm_stat_buf != NULL) { 9077 kmem_free(pm.pm_stat_buf, fcio->fcio_olen); 9078 } 9079 9080 break; 9081 } 9082 9083 case FCIO_GET_NODE_ID: { 9084 /* validate parameters */ 9085 if (fcio->fcio_xfer != FCIO_XFER_READ || 9086 fcio->fcio_olen < sizeof (fc_rnid_t)) { 9087 rval = EINVAL; 9088 break; 9089 } 9090 9091 rval = fp_get_rnid(port, data, mode, fcio); 9092 9093 /* ioctl handling is over */ 9094 break; 9095 } 9096 9097 case FCIO_SEND_NODE_ID: { 9098 la_wwn_t pwwn; 9099 9100 /* validate parameters */ 9101 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 9102 fcio->fcio_xfer != FCIO_XFER_READ) { 9103 rval = EINVAL; 9104 break; 9105 } 9106 9107 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9108 sizeof (la_wwn_t), mode)) { 9109 rval = EFAULT; 9110 break; 9111 } 9112 9113 rval = fp_send_rnid(port, data, mode, fcio, &pwwn); 9114 9115 /* ioctl handling is over */ 9116 break; 9117 } 9118 9119 case FCIO_SET_NODE_ID: { 9120 if (fcio->fcio_ilen != sizeof (fc_rnid_t) || 9121 (fcio->fcio_xfer != FCIO_XFER_WRITE)) { 9122 rval = EINVAL; 9123 break; 9124 } 9125 9126 rval = fp_set_rnid(port, data, mode, fcio); 9127 break; 9128 } 9129 9130 case FCIO_LINK_STATUS: { 9131 fc_portid_t rls_req; 9132 fc_rls_acc_t *rls_acc; 9133 fc_fca_pm_t pm; 9134 uint32_t dest, src_id; 9135 fp_cmd_t *cmd; 9136 fc_remote_port_t *pd; 9137 uchar_t pd_flags; 9138 9139 /* validate parameters */ 9140 if (fcio->fcio_ilen != sizeof (fc_portid_t) || 9141 fcio->fcio_olen != sizeof (fc_rls_acc_t) || 9142 fcio->fcio_xfer != FCIO_XFER_RW) { 9143 rval = EINVAL; 9144 break; 9145 } 9146 9147 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && 9148 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { 9149 rval = EINVAL; 9150 break; 9151 } 9152 9153 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req, 9154 sizeof (fc_portid_t), mode)) { 9155 rval = EFAULT; 9156 break; 9157 } 9158 9159 9160 /* Determine the destination of the RLS frame */ 9161 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) { 9162 dest = FS_FABRIC_F_PORT; 9163 } else { 9164 dest = rls_req.port_id; 9165 } 9166 9167 mutex_enter(&port->fp_mutex); 9168 src_id = port->fp_port_id.port_id; 9169 mutex_exit(&port->fp_mutex); 9170 9171 /* If dest is zero OR same as FCA ID, then use port_manage() */ 9172 if (dest == 0 || dest == src_id) { 9173 9174 /* Allocate memory for link error status block */ 9175 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9176 ASSERT(rls_acc != NULL); 9177 9178 /* Prepare the port management structure */ 9179 bzero((caddr_t)&pm, sizeof (pm)); 9180 9181 pm.pm_cmd_flags = FC_FCA_PM_READ; 9182 pm.pm_cmd_code = FC_PORT_RLS; 9183 pm.pm_data_len = sizeof (*rls_acc); 9184 pm.pm_data_buf = (caddr_t)rls_acc; 9185 9186 /* Get the adapter's link error status block */ 9187 ret = port->fp_fca_tran->fca_port_manage( 9188 port->fp_fca_handle, &pm); 9189 9190 if (ret == FC_SUCCESS) { 9191 /* xfer link status block to userland */ 9192 if (ddi_copyout((void *)rls_acc, 9193 (void *)fcio->fcio_obuf, 9194 sizeof (*rls_acc), mode) == 0) { 9195 if (fp_fcio_copyout(fcio, data, 9196 mode)) { 9197 rval = EFAULT; 9198 } 9199 } else { 9200 rval = EFAULT; 9201 } 9202 } else { 9203 rval = EIO; 9204 fcio->fcio_errno = ret; 9205 if (fp_fcio_copyout(fcio, data, mode)) { 9206 rval = EFAULT; 9207 } 9208 } 9209 9210 kmem_free(rls_acc, sizeof (*rls_acc)); 9211 9212 /* ioctl handling is over */ 9213 break; 9214 } 9215 9216 /* 9217 * Send RLS to the destination port. 9218 * Having RLS frame destination is as FPORT is not yet 9219 * supported and will be implemented in future, if needed. 9220 * Following call to get "pd" will fail if dest is FPORT 9221 */ 9222 pd = fctl_hold_remote_port_by_did(port, dest); 9223 if (pd == NULL) { 9224 fcio->fcio_errno = FC_BADOBJECT; 9225 rval = ENXIO; 9226 if (fp_fcio_copyout(fcio, data, mode)) { 9227 rval = EFAULT; 9228 } 9229 break; 9230 } 9231 9232 mutex_enter(&pd->pd_mutex); 9233 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 9234 mutex_exit(&pd->pd_mutex); 9235 fctl_release_remote_port(pd); 9236 9237 fcio->fcio_errno = FC_LOGINREQ; 9238 rval = EINVAL; 9239 if (fp_fcio_copyout(fcio, data, mode)) { 9240 rval = EFAULT; 9241 } 9242 break; 9243 } 9244 ASSERT(pd->pd_login_count >= 1); 9245 mutex_exit(&pd->pd_mutex); 9246 9247 /* 9248 * Allocate job structure and set job_code as DUMMY, 9249 * because we will not go through the job thread. 9250 * Instead fp_sendcmd() is called directly here. 9251 */ 9252 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9253 NULL, NULL, KM_SLEEP); 9254 ASSERT(job != NULL); 9255 9256 job->job_counter = 1; 9257 9258 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t), 9259 sizeof (la_els_rls_acc_t), KM_SLEEP, pd); 9260 if (cmd == NULL) { 9261 fcio->fcio_errno = FC_NOMEM; 9262 rval = ENOMEM; 9263 9264 fctl_release_remote_port(pd); 9265 9266 fctl_dealloc_job(job); 9267 if (fp_fcio_copyout(fcio, data, mode)) { 9268 rval = EFAULT; 9269 } 9270 break; 9271 } 9272 9273 /* Allocate memory for link error status block */ 9274 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9275 9276 mutex_enter(&port->fp_mutex); 9277 mutex_enter(&pd->pd_mutex); 9278 9279 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9280 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9281 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9282 cmd->cmd_retry_count = 1; 9283 cmd->cmd_ulp_pkt = NULL; 9284 9285 fp_rls_init(cmd, job); 9286 9287 job->job_private = (void *)rls_acc; 9288 9289 pd_flags = pd->pd_flags; 9290 pd->pd_flags = PD_ELS_IN_PROGRESS; 9291 9292 mutex_exit(&pd->pd_mutex); 9293 mutex_exit(&port->fp_mutex); 9294 9295 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9296 fctl_jobwait(job); 9297 9298 fcio->fcio_errno = job->job_result; 9299 if (job->job_result == FC_SUCCESS) { 9300 ASSERT(pd != NULL); 9301 /* 9302 * link error status block is now available. 9303 * Copy it to userland 9304 */ 9305 ASSERT(job->job_private == (void *)rls_acc); 9306 if (ddi_copyout((void *)rls_acc, 9307 (void *)fcio->fcio_obuf, 9308 sizeof (*rls_acc), mode) == 0) { 9309 if (fp_fcio_copyout(fcio, data, 9310 mode)) { 9311 rval = EFAULT; 9312 } 9313 } else { 9314 rval = EFAULT; 9315 } 9316 } else { 9317 rval = EIO; 9318 } 9319 } else { 9320 rval = EIO; 9321 fp_free_pkt(cmd); 9322 } 9323 9324 if (rval) { 9325 mutex_enter(&port->fp_mutex); 9326 mutex_enter(&pd->pd_mutex); 9327 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 9328 pd->pd_flags = pd_flags; 9329 } 9330 mutex_exit(&pd->pd_mutex); 9331 mutex_exit(&port->fp_mutex); 9332 } 9333 9334 fctl_release_remote_port(pd); 9335 fctl_dealloc_job(job); 9336 kmem_free(rls_acc, sizeof (*rls_acc)); 9337 9338 if (fp_fcio_copyout(fcio, data, mode)) { 9339 rval = EFAULT; 9340 } 9341 break; 9342 } 9343 9344 case FCIO_NS: { 9345 fc_ns_cmd_t *ns_req; 9346 fc_ns_cmd32_t *ns_req32; 9347 fctl_ns_req_t *ns_cmd; 9348 9349 if (use32 == B_TRUE) { 9350 if (fcio->fcio_ilen != sizeof (*ns_req32)) { 9351 rval = EINVAL; 9352 break; 9353 } 9354 9355 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9356 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP); 9357 9358 if (ddi_copyin(fcio->fcio_ibuf, ns_req32, 9359 sizeof (*ns_req32), mode)) { 9360 rval = EFAULT; 9361 kmem_free(ns_req, sizeof (*ns_req)); 9362 kmem_free(ns_req32, sizeof (*ns_req32)); 9363 break; 9364 } 9365 9366 ns_req->ns_flags = ns_req32->ns_flags; 9367 ns_req->ns_cmd = ns_req32->ns_cmd; 9368 ns_req->ns_req_len = ns_req32->ns_req_len; 9369 ns_req->ns_req_payload = ns_req32->ns_req_payload; 9370 ns_req->ns_resp_len = ns_req32->ns_resp_len; 9371 ns_req->ns_resp_payload = ns_req32->ns_resp_payload; 9372 ns_req->ns_fctl_private = ns_req32->ns_fctl_private; 9373 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr; 9374 9375 kmem_free(ns_req32, sizeof (*ns_req32)); 9376 } else { 9377 if (fcio->fcio_ilen != sizeof (*ns_req)) { 9378 rval = EINVAL; 9379 break; 9380 } 9381 9382 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9383 9384 if (ddi_copyin(fcio->fcio_ibuf, ns_req, 9385 sizeof (fc_ns_cmd_t), mode)) { 9386 rval = EFAULT; 9387 kmem_free(ns_req, sizeof (*ns_req)); 9388 break; 9389 } 9390 } 9391 9392 if (ns_req->ns_req_len <= 0) { 9393 rval = EINVAL; 9394 kmem_free(ns_req, sizeof (*ns_req)); 9395 break; 9396 } 9397 9398 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 9399 ASSERT(job != NULL); 9400 9401 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 9402 ns_req->ns_resp_len, ns_req->ns_resp_len, 9403 FCTL_NS_FILL_NS_MAP, KM_SLEEP); 9404 ASSERT(ns_cmd != NULL); 9405 ns_cmd->ns_cmd_code = ns_req->ns_cmd; 9406 9407 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 9408 ns_cmd->ns_gan_max = 1; 9409 ns_cmd->ns_gan_index = 0; 9410 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 9411 } 9412 9413 if (ddi_copyin(ns_req->ns_req_payload, 9414 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) { 9415 rval = EFAULT; 9416 fctl_free_ns_cmd(ns_cmd); 9417 fctl_dealloc_job(job); 9418 kmem_free(ns_req, sizeof (*ns_req)); 9419 break; 9420 } 9421 9422 job->job_private = (void *)ns_cmd; 9423 fctl_enque_job(port, job); 9424 fctl_jobwait(job); 9425 rval = job->job_result; 9426 9427 if (rval == FC_SUCCESS) { 9428 if (ns_req->ns_resp_len) { 9429 if (ddi_copyout(ns_cmd->ns_data_buf, 9430 ns_req->ns_resp_payload, 9431 ns_cmd->ns_data_len, mode)) { 9432 rval = EFAULT; 9433 fctl_free_ns_cmd(ns_cmd); 9434 fctl_dealloc_job(job); 9435 kmem_free(ns_req, sizeof (*ns_req)); 9436 break; 9437 } 9438 } 9439 } else { 9440 rval = EIO; 9441 } 9442 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr; 9443 fctl_free_ns_cmd(ns_cmd); 9444 fctl_dealloc_job(job); 9445 kmem_free(ns_req, sizeof (*ns_req)); 9446 9447 if (fp_fcio_copyout(fcio, data, mode)) { 9448 rval = EFAULT; 9449 } 9450 break; 9451 } 9452 9453 default: 9454 rval = ENOTTY; 9455 break; 9456 } 9457 9458 /* 9459 * If set, reset the EXCL busy bit to 9460 * receive other exclusive access commands 9461 */ 9462 mutex_enter(&port->fp_mutex); 9463 if (port->fp_flag & FP_EXCL_BUSY) { 9464 port->fp_flag &= ~FP_EXCL_BUSY; 9465 } 9466 mutex_exit(&port->fp_mutex); 9467 9468 return (rval); 9469 } 9470 9471 9472 /* 9473 * This function assumes that the response length 9474 * is same regardless of data model (LP32 or LP64) 9475 * which is true for all the ioctls currently 9476 * supported. 9477 */ 9478 static int 9479 fp_copyout(void *from, void *to, size_t len, int mode) 9480 { 9481 return (ddi_copyout(from, to, len, mode)); 9482 } 9483 9484 /* 9485 * This function does the set rnid 9486 */ 9487 static int 9488 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9489 { 9490 int rval = 0; 9491 fc_rnid_t *rnid; 9492 fc_fca_pm_t pm; 9493 9494 /* Allocate memory for node id block */ 9495 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9496 9497 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) { 9498 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT); 9499 kmem_free(rnid, sizeof (fc_rnid_t)); 9500 return (EFAULT); 9501 } 9502 9503 /* Prepare the port management structure */ 9504 bzero((caddr_t)&pm, sizeof (pm)); 9505 9506 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 9507 pm.pm_cmd_code = FC_PORT_SET_NODE_ID; 9508 pm.pm_data_len = sizeof (*rnid); 9509 pm.pm_data_buf = (caddr_t)rnid; 9510 9511 /* Get the adapter's node data */ 9512 rval = port->fp_fca_tran->fca_port_manage( 9513 port->fp_fca_handle, &pm); 9514 9515 if (rval != FC_SUCCESS) { 9516 fcio->fcio_errno = rval; 9517 rval = EIO; 9518 if (fp_fcio_copyout(fcio, data, mode)) { 9519 rval = EFAULT; 9520 } 9521 } else { 9522 mutex_enter(&port->fp_mutex); 9523 /* copy to the port structure */ 9524 bcopy(rnid, &port->fp_rnid_params, 9525 sizeof (port->fp_rnid_params)); 9526 mutex_exit(&port->fp_mutex); 9527 } 9528 9529 kmem_free(rnid, sizeof (fc_rnid_t)); 9530 9531 if (rval != FC_SUCCESS) { 9532 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval); 9533 } 9534 9535 return (rval); 9536 } 9537 9538 /* 9539 * This function does the local pwwn get rnid 9540 */ 9541 static int 9542 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9543 { 9544 fc_rnid_t *rnid; 9545 fc_fca_pm_t pm; 9546 int rval = 0; 9547 uint32_t ret; 9548 9549 /* Allocate memory for rnid data block */ 9550 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9551 9552 mutex_enter(&port->fp_mutex); 9553 if (port->fp_rnid_init == 1) { 9554 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t)); 9555 mutex_exit(&port->fp_mutex); 9556 /* xfer node info to userland */ 9557 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf, 9558 sizeof (*rnid), mode) == 0) { 9559 if (fp_fcio_copyout(fcio, data, mode)) { 9560 rval = EFAULT; 9561 } 9562 } else { 9563 rval = EFAULT; 9564 } 9565 9566 kmem_free(rnid, sizeof (fc_rnid_t)); 9567 9568 if (rval != FC_SUCCESS) { 9569 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", 9570 rval); 9571 } 9572 9573 return (rval); 9574 } 9575 mutex_exit(&port->fp_mutex); 9576 9577 /* Prepare the port management structure */ 9578 bzero((caddr_t)&pm, sizeof (pm)); 9579 9580 pm.pm_cmd_flags = FC_FCA_PM_READ; 9581 pm.pm_cmd_code = FC_PORT_GET_NODE_ID; 9582 pm.pm_data_len = sizeof (fc_rnid_t); 9583 pm.pm_data_buf = (caddr_t)rnid; 9584 9585 /* Get the adapter's node data */ 9586 ret = port->fp_fca_tran->fca_port_manage( 9587 port->fp_fca_handle, 9588 &pm); 9589 9590 if (ret == FC_SUCCESS) { 9591 /* initialize in the port_info */ 9592 mutex_enter(&port->fp_mutex); 9593 port->fp_rnid_init = 1; 9594 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid)); 9595 mutex_exit(&port->fp_mutex); 9596 9597 /* xfer node info to userland */ 9598 if (ddi_copyout((void *)rnid, 9599 (void *)fcio->fcio_obuf, 9600 sizeof (*rnid), mode) == 0) { 9601 if (fp_fcio_copyout(fcio, data, 9602 mode)) { 9603 rval = EFAULT; 9604 } 9605 } else { 9606 rval = EFAULT; 9607 } 9608 } else { 9609 rval = EIO; 9610 fcio->fcio_errno = ret; 9611 if (fp_fcio_copyout(fcio, data, mode)) { 9612 rval = EFAULT; 9613 } 9614 } 9615 9616 kmem_free(rnid, sizeof (fc_rnid_t)); 9617 9618 if (rval != FC_SUCCESS) { 9619 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval); 9620 } 9621 9622 return (rval); 9623 } 9624 9625 static int 9626 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio, 9627 la_wwn_t *pwwn) 9628 { 9629 int rval = 0; 9630 fc_remote_port_t *pd; 9631 fp_cmd_t *cmd; 9632 job_request_t *job; 9633 la_els_rnid_acc_t *rnid_acc; 9634 9635 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 9636 if (pd == NULL) { 9637 /* 9638 * We can safely assume that the destination port 9639 * is logged in. Either the user land will explicitly 9640 * login before issuing RNID ioctl or the device would 9641 * have been configured, meaning already logged in. 9642 */ 9643 9644 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO); 9645 9646 return (ENXIO); 9647 } 9648 /* 9649 * Allocate job structure and set job_code as DUMMY, 9650 * because we will not go thorugh the job thread. 9651 * Instead fp_sendcmd() is called directly here. 9652 */ 9653 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9654 NULL, NULL, KM_SLEEP); 9655 9656 ASSERT(job != NULL); 9657 9658 job->job_counter = 1; 9659 9660 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t), 9661 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd); 9662 if (cmd == NULL) { 9663 fcio->fcio_errno = FC_NOMEM; 9664 rval = ENOMEM; 9665 9666 fctl_dealloc_job(job); 9667 if (fp_fcio_copyout(fcio, data, mode)) { 9668 rval = EFAULT; 9669 } 9670 9671 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9672 9673 return (rval); 9674 } 9675 9676 /* Allocate memory for node id accept block */ 9677 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP); 9678 9679 mutex_enter(&port->fp_mutex); 9680 mutex_enter(&pd->pd_mutex); 9681 9682 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9683 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9684 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9685 cmd->cmd_retry_count = 1; 9686 cmd->cmd_ulp_pkt = NULL; 9687 9688 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job); 9689 9690 job->job_private = (void *)rnid_acc; 9691 9692 pd->pd_flags = PD_ELS_IN_PROGRESS; 9693 9694 mutex_exit(&pd->pd_mutex); 9695 mutex_exit(&port->fp_mutex); 9696 9697 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9698 fctl_jobwait(job); 9699 fcio->fcio_errno = job->job_result; 9700 if (job->job_result == FC_SUCCESS) { 9701 int rnid_cnt; 9702 ASSERT(pd != NULL); 9703 /* 9704 * node id block is now available. 9705 * Copy it to userland 9706 */ 9707 ASSERT(job->job_private == (void *)rnid_acc); 9708 9709 /* get the response length */ 9710 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) + 9711 rnid_acc->hdr.cmn_len + 9712 rnid_acc->hdr.specific_len; 9713 9714 if (fcio->fcio_olen < rnid_cnt) { 9715 rval = EINVAL; 9716 } else if (ddi_copyout((void *)rnid_acc, 9717 (void *)fcio->fcio_obuf, 9718 rnid_cnt, mode) == 0) { 9719 if (fp_fcio_copyout(fcio, data, 9720 mode)) { 9721 rval = EFAULT; 9722 } 9723 } else { 9724 rval = EFAULT; 9725 } 9726 } else { 9727 rval = EIO; 9728 } 9729 } else { 9730 rval = EIO; 9731 if (pd) { 9732 mutex_enter(&pd->pd_mutex); 9733 pd->pd_flags = PD_IDLE; 9734 mutex_exit(&pd->pd_mutex); 9735 } 9736 fp_free_pkt(cmd); 9737 } 9738 9739 fctl_dealloc_job(job); 9740 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t)); 9741 9742 if (fp_fcio_copyout(fcio, data, mode)) { 9743 rval = EFAULT; 9744 } 9745 9746 if (rval != FC_SUCCESS) { 9747 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9748 } 9749 9750 return (rval); 9751 } 9752 9753 /* 9754 * Copy out to userland 9755 */ 9756 static int 9757 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode) 9758 { 9759 int rval; 9760 9761 #ifdef _MULTI_DATAMODEL 9762 switch (ddi_model_convert_from(mode & FMODELS)) { 9763 case DDI_MODEL_ILP32: { 9764 struct fcio32 fcio32; 9765 9766 fcio32.fcio_xfer = fcio->fcio_xfer; 9767 fcio32.fcio_cmd = fcio->fcio_cmd; 9768 fcio32.fcio_flags = fcio->fcio_flags; 9769 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags; 9770 fcio32.fcio_ilen = fcio->fcio_ilen; 9771 fcio32.fcio_ibuf = 9772 (caddr32_t)(uintptr_t)fcio->fcio_ibuf; 9773 fcio32.fcio_olen = fcio->fcio_olen; 9774 fcio32.fcio_obuf = 9775 (caddr32_t)(uintptr_t)fcio->fcio_obuf; 9776 fcio32.fcio_alen = fcio->fcio_alen; 9777 fcio32.fcio_abuf = 9778 (caddr32_t)(uintptr_t)fcio->fcio_abuf; 9779 fcio32.fcio_errno = fcio->fcio_errno; 9780 9781 rval = ddi_copyout((void *)&fcio32, (void *)data, 9782 sizeof (struct fcio32), mode); 9783 break; 9784 } 9785 case DDI_MODEL_NONE: 9786 rval = ddi_copyout((void *)fcio, (void *)data, 9787 sizeof (fcio_t), mode); 9788 break; 9789 } 9790 #else 9791 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode); 9792 #endif 9793 9794 return (rval); 9795 } 9796 9797 9798 static void 9799 fp_p2p_online(fc_local_port_t *port, job_request_t *job) 9800 { 9801 uint32_t listlen; 9802 fc_portmap_t *changelist; 9803 9804 ASSERT(MUTEX_HELD(&port->fp_mutex)); 9805 ASSERT(port->fp_topology == FC_TOP_PT_PT); 9806 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 9807 9808 listlen = 0; 9809 changelist = NULL; 9810 9811 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 9812 if (port->fp_statec_busy > 1) { 9813 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 9814 } 9815 } 9816 mutex_exit(&port->fp_mutex); 9817 9818 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 9819 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 9820 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 9821 listlen, listlen, KM_SLEEP); 9822 9823 mutex_enter(&port->fp_mutex); 9824 } else { 9825 ASSERT(changelist == NULL && listlen == 0); 9826 mutex_enter(&port->fp_mutex); 9827 if (--port->fp_statec_busy == 0) { 9828 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 9829 } 9830 } 9831 } 9832 9833 static int 9834 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode) 9835 { 9836 int rval; 9837 int count; 9838 int index; 9839 int num_devices; 9840 fc_remote_node_t *node; 9841 fc_port_dev_t *devlist; 9842 struct pwwn_hash *head; 9843 fc_remote_port_t *pd; 9844 9845 ASSERT(MUTEX_HELD(&port->fp_mutex)); 9846 9847 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 9848 9849 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP); 9850 9851 for (count = index = 0; index < pwwn_table_size; index++) { 9852 head = &port->fp_pwwn_table[index]; 9853 pd = head->pwwn_head; 9854 while (pd != NULL) { 9855 mutex_enter(&pd->pd_mutex); 9856 if (pd->pd_state == PORT_DEVICE_INVALID) { 9857 mutex_exit(&pd->pd_mutex); 9858 pd = pd->pd_wwn_hnext; 9859 continue; 9860 } 9861 9862 devlist[count].dev_state = pd->pd_state; 9863 devlist[count].dev_hard_addr = pd->pd_hard_addr; 9864 devlist[count].dev_did = pd->pd_port_id; 9865 devlist[count].dev_did.priv_lilp_posit = 9866 (uint8_t)(index & 0xff); 9867 bcopy((caddr_t)pd->pd_fc4types, 9868 (caddr_t)devlist[count].dev_type, 9869 sizeof (pd->pd_fc4types)); 9870 9871 bcopy((caddr_t)&pd->pd_port_name, 9872 (caddr_t)&devlist[count].dev_pwwn, 9873 sizeof (la_wwn_t)); 9874 9875 node = pd->pd_remote_nodep; 9876 mutex_exit(&pd->pd_mutex); 9877 9878 if (node) { 9879 mutex_enter(&node->fd_mutex); 9880 bcopy((caddr_t)&node->fd_node_name, 9881 (caddr_t)&devlist[count].dev_nwwn, 9882 sizeof (la_wwn_t)); 9883 mutex_exit(&node->fd_mutex); 9884 } 9885 count++; 9886 if (count >= num_devices) { 9887 goto found; 9888 } 9889 } 9890 } 9891 found: 9892 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 9893 sizeof (count), mode)) { 9894 rval = FC_FAILURE; 9895 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 9896 sizeof (fc_port_dev_t) * num_devices, mode)) { 9897 rval = FC_FAILURE; 9898 } else { 9899 rval = FC_SUCCESS; 9900 } 9901 9902 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices); 9903 9904 return (rval); 9905 } 9906 9907 9908 /* 9909 * Handle Fabric ONLINE 9910 */ 9911 static void 9912 fp_fabric_online(fc_local_port_t *port, job_request_t *job) 9913 { 9914 int index; 9915 int rval; 9916 int dbg_count; 9917 int count = 0; 9918 char ww_name[17]; 9919 uint32_t d_id; 9920 uint32_t listlen; 9921 fctl_ns_req_t *ns_cmd; 9922 struct pwwn_hash *head; 9923 fc_remote_port_t *pd; 9924 fc_remote_port_t *npd; 9925 fc_portmap_t *changelist; 9926 9927 ASSERT(MUTEX_HELD(&port->fp_mutex)); 9928 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 9929 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 9930 9931 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 9932 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 9933 0, KM_SLEEP); 9934 9935 ASSERT(ns_cmd != NULL); 9936 9937 ns_cmd->ns_cmd_code = NS_GID_PN; 9938 9939 /* 9940 * Check if orphans are showing up now 9941 */ 9942 if (port->fp_orphan_count) { 9943 fc_orphan_t *orp; 9944 fc_orphan_t *norp = NULL; 9945 fc_orphan_t *prev = NULL; 9946 9947 for (orp = port->fp_orphan_list; orp; orp = norp) { 9948 norp = orp->orp_next; 9949 mutex_exit(&port->fp_mutex); 9950 orp->orp_nscan++; 9951 9952 job->job_counter = 1; 9953 job->job_result = FC_SUCCESS; 9954 9955 ((ns_req_gid_pn_t *) 9956 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn; 9957 ((ns_resp_gid_pn_t *) 9958 ns_cmd->ns_data_buf)->pid.port_id = 0; 9959 ((ns_resp_gid_pn_t *) 9960 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 9961 9962 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 9963 if (rval == FC_SUCCESS) { 9964 d_id = 9965 BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 9966 pd = fp_create_remote_port_by_ns(port, 9967 d_id, KM_SLEEP); 9968 9969 if (pd != NULL) { 9970 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 9971 9972 fp_printf(port, CE_WARN, FP_LOG_ONLY, 9973 0, NULL, "N_x Port with D_ID=%x," 9974 " PWWN=%s reappeared in fabric", 9975 d_id, ww_name); 9976 9977 mutex_enter(&port->fp_mutex); 9978 if (prev) { 9979 prev->orp_next = orp->orp_next; 9980 } else { 9981 ASSERT(orp == 9982 port->fp_orphan_list); 9983 port->fp_orphan_list = 9984 orp->orp_next; 9985 } 9986 port->fp_orphan_count--; 9987 mutex_exit(&port->fp_mutex); 9988 kmem_free(orp, sizeof (*orp)); 9989 count++; 9990 9991 mutex_enter(&pd->pd_mutex); 9992 pd->pd_flags = PD_ELS_MARK; 9993 9994 mutex_exit(&pd->pd_mutex); 9995 } else { 9996 prev = orp; 9997 } 9998 } else { 9999 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) { 10000 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10001 10002 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, 10003 NULL, 10004 " Port WWN %s removed from orphan" 10005 " list after %d scans", ww_name, 10006 orp->orp_nscan); 10007 10008 mutex_enter(&port->fp_mutex); 10009 if (prev) { 10010 prev->orp_next = orp->orp_next; 10011 } else { 10012 ASSERT(orp == 10013 port->fp_orphan_list); 10014 port->fp_orphan_list = 10015 orp->orp_next; 10016 } 10017 port->fp_orphan_count--; 10018 mutex_exit(&port->fp_mutex); 10019 10020 kmem_free(orp, sizeof (*orp)); 10021 } else { 10022 prev = orp; 10023 } 10024 } 10025 mutex_enter(&port->fp_mutex); 10026 } 10027 } 10028 10029 /* 10030 * Walk the Port WWN hash table, reestablish LOGIN 10031 * if a LOGIN is already performed on a particular 10032 * device; Any failure to LOGIN should mark the 10033 * port device OLD. 10034 */ 10035 for (index = 0; index < pwwn_table_size; index++) { 10036 head = &port->fp_pwwn_table[index]; 10037 npd = head->pwwn_head; 10038 10039 while ((pd = npd) != NULL) { 10040 la_wwn_t *pwwn; 10041 10042 npd = pd->pd_wwn_hnext; 10043 10044 /* 10045 * Don't count in the port devices that are new 10046 * unless the total number of devices visible 10047 * through this port is less than FP_MAX_DEVICES 10048 */ 10049 mutex_enter(&pd->pd_mutex); 10050 if (port->fp_dev_count >= FP_MAX_DEVICES || 10051 (port->fp_options & FP_TARGET_MODE)) { 10052 if (pd->pd_type == PORT_DEVICE_NEW || 10053 pd->pd_flags == PD_ELS_MARK || 10054 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10055 mutex_exit(&pd->pd_mutex); 10056 continue; 10057 } 10058 } else { 10059 if (pd->pd_flags == PD_ELS_MARK || 10060 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10061 mutex_exit(&pd->pd_mutex); 10062 continue; 10063 } 10064 pd->pd_type = PORT_DEVICE_OLD; 10065 } 10066 count++; 10067 10068 /* 10069 * Consult with the name server about D_ID changes 10070 */ 10071 job->job_counter = 1; 10072 job->job_result = FC_SUCCESS; 10073 10074 ((ns_req_gid_pn_t *) 10075 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name; 10076 ((ns_resp_gid_pn_t *) 10077 ns_cmd->ns_data_buf)->pid.port_id = 0; 10078 10079 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)-> 10080 pid.priv_lilp_posit = 0; 10081 10082 pwwn = &pd->pd_port_name; 10083 pd->pd_flags = PD_ELS_MARK; 10084 10085 mutex_exit(&pd->pd_mutex); 10086 mutex_exit(&port->fp_mutex); 10087 10088 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10089 if (rval != FC_SUCCESS) { 10090 fc_wwn_to_str(pwwn, ww_name); 10091 10092 mutex_enter(&pd->pd_mutex); 10093 d_id = pd->pd_port_id.port_id; 10094 pd->pd_type = PORT_DEVICE_DELETE; 10095 mutex_exit(&pd->pd_mutex); 10096 10097 FP_TRACE(FP_NHEAD1(3, 0), 10098 "fp_fabric_online: PD " 10099 "disappeared; d_id=%x, PWWN=%s", 10100 d_id, ww_name); 10101 10102 FP_TRACE(FP_NHEAD2(9, 0), 10103 "N_x Port with D_ID=%x, PWWN=%s" 10104 " disappeared from fabric", d_id, 10105 ww_name); 10106 10107 mutex_enter(&port->fp_mutex); 10108 continue; 10109 } 10110 10111 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10112 10113 mutex_enter(&port->fp_mutex); 10114 mutex_enter(&pd->pd_mutex); 10115 if (d_id != pd->pd_port_id.port_id) { 10116 fctl_delist_did_table(port, pd); 10117 fc_wwn_to_str(pwwn, ww_name); 10118 10119 FP_TRACE(FP_NHEAD2(9, 0), 10120 "D_ID of a device with PWWN %s changed." 10121 " New D_ID = %x, OLD D_ID = %x", ww_name, 10122 d_id, pd->pd_port_id.port_id); 10123 10124 pd->pd_port_id.port_id = BE_32(d_id); 10125 pd->pd_type = PORT_DEVICE_CHANGED; 10126 fctl_enlist_did_table(port, pd); 10127 } 10128 mutex_exit(&pd->pd_mutex); 10129 10130 } 10131 } 10132 10133 if (ns_cmd) { 10134 fctl_free_ns_cmd(ns_cmd); 10135 } 10136 10137 listlen = 0; 10138 changelist = NULL; 10139 if (count) { 10140 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 10141 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 10142 mutex_exit(&port->fp_mutex); 10143 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000)); 10144 mutex_enter(&port->fp_mutex); 10145 } 10146 10147 dbg_count = 0; 10148 10149 job->job_counter = count; 10150 10151 for (index = 0; index < pwwn_table_size; index++) { 10152 head = &port->fp_pwwn_table[index]; 10153 npd = head->pwwn_head; 10154 10155 while ((pd = npd) != NULL) { 10156 npd = pd->pd_wwn_hnext; 10157 10158 mutex_enter(&pd->pd_mutex); 10159 if (pd->pd_flags != PD_ELS_MARK) { 10160 mutex_exit(&pd->pd_mutex); 10161 continue; 10162 } 10163 10164 dbg_count++; 10165 10166 /* 10167 * If it is already marked deletion, nothing 10168 * else to do. 10169 */ 10170 if (pd->pd_type == PORT_DEVICE_DELETE) { 10171 pd->pd_type = PORT_DEVICE_OLD; 10172 10173 mutex_exit(&pd->pd_mutex); 10174 mutex_exit(&port->fp_mutex); 10175 fp_jobdone(job); 10176 mutex_enter(&port->fp_mutex); 10177 10178 continue; 10179 } 10180 10181 /* 10182 * If it is freshly discovered out of 10183 * the orphan list, nothing else to do 10184 */ 10185 if (pd->pd_type == PORT_DEVICE_NEW) { 10186 pd->pd_flags = PD_IDLE; 10187 10188 mutex_exit(&pd->pd_mutex); 10189 mutex_exit(&port->fp_mutex); 10190 fp_jobdone(job); 10191 mutex_enter(&port->fp_mutex); 10192 10193 continue; 10194 } 10195 10196 pd->pd_flags = PD_IDLE; 10197 d_id = pd->pd_port_id.port_id; 10198 10199 /* 10200 * Explicitly mark all devices OLD; successful 10201 * PLOGI should reset this to either NO_CHANGE 10202 * or CHANGED. 10203 */ 10204 if (pd->pd_type != PORT_DEVICE_CHANGED) { 10205 pd->pd_type = PORT_DEVICE_OLD; 10206 } 10207 10208 mutex_exit(&pd->pd_mutex); 10209 mutex_exit(&port->fp_mutex); 10210 10211 rval = fp_port_login(port, d_id, job, 10212 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 10213 10214 if (rval != FC_SUCCESS) { 10215 fp_jobdone(job); 10216 } 10217 mutex_enter(&port->fp_mutex); 10218 } 10219 } 10220 mutex_exit(&port->fp_mutex); 10221 10222 ASSERT(dbg_count == count); 10223 fp_jobwait(job); 10224 10225 mutex_enter(&port->fp_mutex); 10226 10227 ASSERT(port->fp_statec_busy > 0); 10228 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10229 if (port->fp_statec_busy > 1) { 10230 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10231 } 10232 } 10233 mutex_exit(&port->fp_mutex); 10234 } else { 10235 ASSERT(port->fp_statec_busy > 0); 10236 if (port->fp_statec_busy > 1) { 10237 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10238 } 10239 mutex_exit(&port->fp_mutex); 10240 } 10241 10242 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10243 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10244 10245 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10246 listlen, listlen, KM_SLEEP); 10247 10248 mutex_enter(&port->fp_mutex); 10249 } else { 10250 ASSERT(changelist == NULL && listlen == 0); 10251 mutex_enter(&port->fp_mutex); 10252 if (--port->fp_statec_busy == 0) { 10253 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10254 } 10255 } 10256 } 10257 10258 10259 /* 10260 * Fill out device list for userland ioctl in private loop 10261 */ 10262 static int 10263 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10264 { 10265 int rval; 10266 int count; 10267 int index; 10268 int num_devices; 10269 fc_remote_node_t *node; 10270 fc_port_dev_t *devlist; 10271 int lilp_device_count; 10272 fc_lilpmap_t *lilp_map; 10273 uchar_t *alpa_list; 10274 10275 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10276 10277 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10278 if (port->fp_total_devices > port->fp_dev_count && 10279 num_devices >= port->fp_total_devices) { 10280 job_request_t *job; 10281 10282 mutex_exit(&port->fp_mutex); 10283 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP); 10284 job->job_counter = 1; 10285 10286 mutex_enter(&port->fp_mutex); 10287 fp_get_loopmap(port, job); 10288 mutex_exit(&port->fp_mutex); 10289 10290 fp_jobwait(job); 10291 fctl_dealloc_job(job); 10292 } else { 10293 mutex_exit(&port->fp_mutex); 10294 } 10295 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP); 10296 10297 mutex_enter(&port->fp_mutex); 10298 10299 /* 10300 * Applications are accustomed to getting the device list in 10301 * LILP map order. The HBA firmware usually returns the device 10302 * map in the LILP map order and diagnostic applications would 10303 * prefer to receive in the device list in that order too 10304 */ 10305 lilp_map = &port->fp_lilp_map; 10306 alpa_list = &lilp_map->lilp_alpalist[0]; 10307 10308 /* 10309 * the length field corresponds to the offset in the LILP frame 10310 * which begins with 1. The thing to note here is that the 10311 * lilp_device_count is 1 more than fp->fp_total_devices since 10312 * the host adapter's alpa also shows up in the lilp map. We 10313 * don't however return details of the host adapter since 10314 * fctl_get_remote_port_by_did fails for the host adapter's ALPA 10315 * and applications are required to issue the FCIO_GET_HOST_PARAMS 10316 * ioctl to obtain details about the host adapter port. 10317 */ 10318 lilp_device_count = lilp_map->lilp_length; 10319 10320 for (count = index = 0; index < lilp_device_count && 10321 count < num_devices; index++) { 10322 uint32_t d_id; 10323 fc_remote_port_t *pd; 10324 10325 d_id = alpa_list[index]; 10326 10327 mutex_exit(&port->fp_mutex); 10328 pd = fctl_get_remote_port_by_did(port, d_id); 10329 mutex_enter(&port->fp_mutex); 10330 10331 if (pd != NULL) { 10332 mutex_enter(&pd->pd_mutex); 10333 10334 if (pd->pd_state == PORT_DEVICE_INVALID) { 10335 mutex_exit(&pd->pd_mutex); 10336 continue; 10337 } 10338 10339 devlist[count].dev_state = pd->pd_state; 10340 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10341 devlist[count].dev_did = pd->pd_port_id; 10342 devlist[count].dev_did.priv_lilp_posit = 10343 (uint8_t)(index & 0xff); 10344 bcopy((caddr_t)pd->pd_fc4types, 10345 (caddr_t)devlist[count].dev_type, 10346 sizeof (pd->pd_fc4types)); 10347 10348 bcopy((caddr_t)&pd->pd_port_name, 10349 (caddr_t)&devlist[count].dev_pwwn, 10350 sizeof (la_wwn_t)); 10351 10352 node = pd->pd_remote_nodep; 10353 mutex_exit(&pd->pd_mutex); 10354 10355 if (node) { 10356 mutex_enter(&node->fd_mutex); 10357 bcopy((caddr_t)&node->fd_node_name, 10358 (caddr_t)&devlist[count].dev_nwwn, 10359 sizeof (la_wwn_t)); 10360 mutex_exit(&node->fd_mutex); 10361 } 10362 count++; 10363 } 10364 } 10365 10366 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10367 sizeof (count), mode)) { 10368 rval = FC_FAILURE; 10369 } 10370 10371 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10372 sizeof (fc_port_dev_t) * num_devices, mode)) { 10373 rval = FC_FAILURE; 10374 } else { 10375 rval = FC_SUCCESS; 10376 } 10377 10378 kmem_free(devlist, sizeof (*devlist) * num_devices); 10379 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10380 10381 return (rval); 10382 } 10383 10384 10385 /* 10386 * Completion function for responses to unsolicited commands 10387 */ 10388 static void 10389 fp_unsol_intr(fc_packet_t *pkt) 10390 { 10391 fp_cmd_t *cmd; 10392 fc_local_port_t *port; 10393 10394 cmd = pkt->pkt_ulp_private; 10395 port = cmd->cmd_port; 10396 10397 if (pkt->pkt_state != FC_PKT_SUCCESS) { 10398 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt, 10399 "couldn't post response to unsolicited request;" 10400 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id, 10401 pkt->pkt_resp_fhdr.rx_id); 10402 } 10403 10404 if (cmd == port->fp_els_resp_pkt) { 10405 mutex_enter(&port->fp_mutex); 10406 port->fp_els_resp_pkt_busy = 0; 10407 mutex_exit(&port->fp_mutex); 10408 return; 10409 } 10410 10411 fp_free_pkt(cmd); 10412 } 10413 10414 10415 /* 10416 * solicited LINIT ELS completion function 10417 */ 10418 static void 10419 fp_linit_intr(fc_packet_t *pkt) 10420 { 10421 fp_cmd_t *cmd; 10422 job_request_t *job; 10423 fc_linit_resp_t acc; 10424 10425 if (FP_IS_PKT_ERROR(pkt)) { 10426 (void) fp_common_intr(pkt, 1); 10427 return; 10428 } 10429 10430 cmd = pkt->pkt_ulp_private; 10431 job = cmd->cmd_job; 10432 10433 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&acc, 10434 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR); 10435 10436 if (acc.status != FC_LINIT_SUCCESS) { 10437 job->job_result = FC_FAILURE; 10438 } else { 10439 job->job_result = FC_SUCCESS; 10440 } 10441 fp_iodone(cmd); 10442 } 10443 10444 10445 /* 10446 * Decode the unsolicited request; For FC-4 Device and Link data frames 10447 * notify the registered ULP of this FC-4 type right here. For Unsolicited 10448 * ELS requests, submit a request to the job_handler thread to work on it. 10449 * The intent is to act quickly on the FC-4 unsolicited link and data frames 10450 * and save much of the interrupt time processing of unsolicited ELS requests 10451 * and hand it off to the job_handler thread. 10452 */ 10453 static void 10454 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type) 10455 { 10456 uchar_t r_ctl; 10457 uchar_t ls_code; 10458 uint32_t s_id; 10459 uint32_t rscn_count = FC_INVALID_RSCN_COUNT; 10460 uint32_t cb_arg; 10461 fp_cmd_t *cmd; 10462 fc_local_port_t *port; 10463 job_request_t *job; 10464 fc_remote_port_t *pd; 10465 10466 port = port_handle; 10467 10468 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x," 10469 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x" 10470 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x" 10471 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10472 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl, 10473 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt, 10474 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro, 10475 buf->ub_buffer[0]); 10476 10477 if (type & 0x80000000) { 10478 /* 10479 * Huh ? Nothing much can be done without 10480 * a valid buffer. So just exit. 10481 */ 10482 return; 10483 } 10484 /* 10485 * If the unsolicited interrupts arrive while it isn't 10486 * safe to handle unsolicited callbacks; Drop them, yes, 10487 * drop them on the floor 10488 */ 10489 mutex_enter(&port->fp_mutex); 10490 port->fp_active_ubs++; 10491 if ((port->fp_soft_state & 10492 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 10493 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 10494 10495 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is " 10496 "not ONLINE. s_id=%x, d_id=%x, type=%x, " 10497 "seq_id=%x, ox_id=%x, rx_id=%x" 10498 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10499 buf->ub_frame.type, buf->ub_frame.seq_id, 10500 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 10501 10502 ASSERT(port->fp_active_ubs > 0); 10503 if (--(port->fp_active_ubs) == 0) { 10504 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10505 } 10506 10507 mutex_exit(&port->fp_mutex); 10508 10509 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10510 1, &buf->ub_token); 10511 10512 return; 10513 } 10514 10515 r_ctl = buf->ub_frame.r_ctl; 10516 s_id = buf->ub_frame.s_id; 10517 if (port->fp_active_ubs == 1) { 10518 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB; 10519 } 10520 10521 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO && 10522 port->fp_statec_busy) { 10523 mutex_exit(&port->fp_mutex); 10524 pd = fctl_get_remote_port_by_did(port, s_id); 10525 if (pd) { 10526 mutex_enter(&pd->pd_mutex); 10527 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10528 FP_TRACE(FP_NHEAD1(3, 0), 10529 "LOGO for LOGGED IN D_ID %x", 10530 buf->ub_frame.s_id); 10531 pd->pd_state = PORT_DEVICE_VALID; 10532 } 10533 mutex_exit(&pd->pd_mutex); 10534 } 10535 10536 mutex_enter(&port->fp_mutex); 10537 ASSERT(port->fp_active_ubs > 0); 10538 if (--(port->fp_active_ubs) == 0) { 10539 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10540 } 10541 mutex_exit(&port->fp_mutex); 10542 10543 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10544 1, &buf->ub_token); 10545 10546 FP_TRACE(FP_NHEAD1(3, 0), 10547 "fp_unsol_cb() bailing out LOGO for D_ID %x", 10548 buf->ub_frame.s_id); 10549 return; 10550 } 10551 10552 if (port->fp_els_resp_pkt_busy == 0) { 10553 if (r_ctl == R_CTL_ELS_REQ) { 10554 ls_code = buf->ub_buffer[0]; 10555 10556 switch (ls_code) { 10557 case LA_ELS_PLOGI: 10558 case LA_ELS_FLOGI: 10559 port->fp_els_resp_pkt_busy = 1; 10560 mutex_exit(&port->fp_mutex); 10561 fp_i_handle_unsol_els(port, buf); 10562 10563 mutex_enter(&port->fp_mutex); 10564 ASSERT(port->fp_active_ubs > 0); 10565 if (--(port->fp_active_ubs) == 0) { 10566 port->fp_soft_state &= 10567 ~FP_SOFT_IN_UNSOL_CB; 10568 } 10569 mutex_exit(&port->fp_mutex); 10570 port->fp_fca_tran->fca_ub_release( 10571 port->fp_fca_handle, 1, &buf->ub_token); 10572 10573 return; 10574 case LA_ELS_RSCN: 10575 if (++(port)->fp_rscn_count == 10576 FC_INVALID_RSCN_COUNT) { 10577 ++(port)->fp_rscn_count; 10578 } 10579 rscn_count = port->fp_rscn_count; 10580 break; 10581 10582 default: 10583 break; 10584 } 10585 } 10586 } else if ((r_ctl == R_CTL_ELS_REQ) && 10587 (buf->ub_buffer[0] == LA_ELS_RSCN)) { 10588 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10589 ++port->fp_rscn_count; 10590 } 10591 rscn_count = port->fp_rscn_count; 10592 } 10593 10594 mutex_exit(&port->fp_mutex); 10595 10596 switch (r_ctl & R_CTL_ROUTING) { 10597 case R_CTL_DEVICE_DATA: 10598 /* 10599 * If the unsolicited buffer is a CT IU, 10600 * have the job_handler thread work on it. 10601 */ 10602 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 10603 break; 10604 } 10605 /* FALLTHROUGH */ 10606 10607 case R_CTL_FC4_SVC: { 10608 int sendup = 0; 10609 10610 /* 10611 * If a LOGIN isn't performed before this request 10612 * shut the door on this port with a reply that a 10613 * LOGIN is required. We make an exception however 10614 * for IP broadcast packets and pass them through 10615 * to the IP ULP(s) to handle broadcast requests. 10616 * This is not a problem for private loop devices 10617 * but for fabric topologies we don't log into the 10618 * remote ports during port initialization and 10619 * the ULPs need to log into requesting ports on 10620 * demand. 10621 */ 10622 pd = fctl_get_remote_port_by_did(port, s_id); 10623 if (pd) { 10624 mutex_enter(&pd->pd_mutex); 10625 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10626 sendup++; 10627 } 10628 mutex_exit(&pd->pd_mutex); 10629 } else if ((pd == NULL) && 10630 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) && 10631 (buf->ub_frame.d_id == 0xffffff || 10632 buf->ub_frame.d_id == 0x00)) { 10633 /* brodacst IP frame - so sendup via job thread */ 10634 break; 10635 } 10636 10637 /* 10638 * Send all FC4 services via job thread too 10639 */ 10640 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) { 10641 break; 10642 } 10643 10644 if (sendup || !FC_IS_REAL_DEVICE(s_id)) { 10645 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type); 10646 return; 10647 } 10648 10649 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10650 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10651 0, KM_NOSLEEP, pd); 10652 if (cmd != NULL) { 10653 fp_els_rjt_init(port, cmd, buf, 10654 FC_ACTION_NON_RETRYABLE, 10655 FC_REASON_LOGIN_REQUIRED, NULL); 10656 10657 if (fp_sendcmd(port, cmd, 10658 port->fp_fca_handle) != FC_SUCCESS) { 10659 fp_free_pkt(cmd); 10660 } 10661 } 10662 } 10663 10664 mutex_enter(&port->fp_mutex); 10665 ASSERT(port->fp_active_ubs > 0); 10666 if (--(port->fp_active_ubs) == 0) { 10667 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10668 } 10669 mutex_exit(&port->fp_mutex); 10670 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10671 1, &buf->ub_token); 10672 10673 return; 10674 } 10675 10676 default: 10677 break; 10678 } 10679 10680 /* 10681 * Submit a Request to the job_handler thread to work 10682 * on the unsolicited request. The potential side effect 10683 * of this is that the unsolicited buffer takes a little 10684 * longer to get released but we save interrupt time in 10685 * the bargain. 10686 */ 10687 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count; 10688 10689 /* 10690 * One way that the rscn_count will get used is described below : 10691 * 10692 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count. 10693 * 2. Before mutex is released, a copy of it is stored in rscn_count. 10694 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below) 10695 * by overloading the job_cb_arg to pass the rscn_count 10696 * 4. When one of the routines processing the RSCN picks it up (ex: 10697 * fp_validate_rscn_page()), it passes this count in the map 10698 * structure (as part of the map_rscn_info structure member) to the 10699 * ULPs. 10700 * 5. When ULPs make calls back to the transport (example interfaces for 10701 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they 10702 * can now pass back this count as part of the fc_packet's 10703 * pkt_ulp_rscn_count member. fcp does this currently. 10704 * 6. When transport gets a call to transport a command on the wire, it 10705 * will check to see if there is a valid pkt_ulp_rsvd1 field in the 10706 * fc_packet. If there is, it will match that info with the current 10707 * rscn_count on that instance of the port. If they don't match up 10708 * then there was a newer RSCN. The ULP gets back an error code which 10709 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN. 10710 * 7. At this point the ULP is free to make up its own mind as to how to 10711 * handle this. Currently, fcp will reset its retry counters and keep 10712 * retrying the operation it was doing in anticipation of getting a 10713 * new state change call back for the new RSCN. 10714 */ 10715 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL, 10716 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP); 10717 if (job == NULL) { 10718 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() " 10719 "couldn't submit a job to the thread, failing.."); 10720 10721 mutex_enter(&port->fp_mutex); 10722 10723 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10724 --port->fp_rscn_count; 10725 } 10726 10727 ASSERT(port->fp_active_ubs > 0); 10728 if (--(port->fp_active_ubs) == 0) { 10729 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10730 } 10731 10732 mutex_exit(&port->fp_mutex); 10733 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10734 1, &buf->ub_token); 10735 10736 return; 10737 } 10738 job->job_private = (void *)buf; 10739 fctl_enque_job(port, job); 10740 } 10741 10742 10743 /* 10744 * Handle unsolicited requests 10745 */ 10746 static void 10747 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf, 10748 job_request_t *job) 10749 { 10750 uchar_t r_ctl; 10751 uchar_t ls_code; 10752 uint32_t s_id; 10753 fp_cmd_t *cmd; 10754 fc_remote_port_t *pd; 10755 fp_unsol_spec_t *ub_spec; 10756 10757 r_ctl = buf->ub_frame.r_ctl; 10758 s_id = buf->ub_frame.s_id; 10759 10760 switch (r_ctl & R_CTL_ROUTING) { 10761 case R_CTL_EXTENDED_SVC: 10762 if (r_ctl != R_CTL_ELS_REQ) { 10763 break; 10764 } 10765 10766 ls_code = buf->ub_buffer[0]; 10767 switch (ls_code) { 10768 case LA_ELS_LOGO: 10769 case LA_ELS_ADISC: 10770 case LA_ELS_PRLO: 10771 pd = fctl_get_remote_port_by_did(port, s_id); 10772 if (pd == NULL) { 10773 if (!FC_IS_REAL_DEVICE(s_id)) { 10774 break; 10775 } 10776 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10777 break; 10778 } 10779 if ((cmd = fp_alloc_pkt(port, 10780 sizeof (la_els_rjt_t), 0, KM_SLEEP, 10781 NULL)) == NULL) { 10782 /* 10783 * Can this actually fail when 10784 * given KM_SLEEP? (Could be used 10785 * this way in a number of places.) 10786 */ 10787 break; 10788 } 10789 10790 fp_els_rjt_init(port, cmd, buf, 10791 FC_ACTION_NON_RETRYABLE, 10792 FC_REASON_INVALID_LINK_CTRL, job); 10793 10794 if (fp_sendcmd(port, cmd, 10795 port->fp_fca_handle) != FC_SUCCESS) { 10796 fp_free_pkt(cmd); 10797 } 10798 10799 break; 10800 } 10801 if (ls_code == LA_ELS_LOGO) { 10802 fp_handle_unsol_logo(port, buf, pd, job); 10803 } else if (ls_code == LA_ELS_ADISC) { 10804 fp_handle_unsol_adisc(port, buf, pd, job); 10805 } else { 10806 fp_handle_unsol_prlo(port, buf, pd, job); 10807 } 10808 break; 10809 10810 case LA_ELS_PLOGI: 10811 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP); 10812 break; 10813 10814 case LA_ELS_FLOGI: 10815 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP); 10816 break; 10817 10818 case LA_ELS_RSCN: 10819 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP); 10820 break; 10821 10822 default: 10823 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 10824 ub_spec->port = port; 10825 ub_spec->buf = buf; 10826 10827 (void) taskq_dispatch(port->fp_taskq, 10828 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 10829 return; 10830 } 10831 break; 10832 10833 case R_CTL_BASIC_SVC: 10834 /* 10835 * The unsolicited basic link services could be ABTS 10836 * and RMC (Or even a NOP). Just BA_RJT them until 10837 * such time there arises a need to handle them more 10838 * carefully. 10839 */ 10840 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10841 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t), 10842 0, KM_SLEEP, NULL); 10843 if (cmd != NULL) { 10844 fp_ba_rjt_init(port, cmd, buf, job); 10845 if (fp_sendcmd(port, cmd, 10846 port->fp_fca_handle) != FC_SUCCESS) { 10847 fp_free_pkt(cmd); 10848 } 10849 } 10850 } 10851 break; 10852 10853 case R_CTL_DEVICE_DATA: 10854 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 10855 /* 10856 * Mostly this is of type FC_TYPE_FC_SERVICES. 10857 * As we don't like any Unsolicited FC services 10858 * requests, we would do well to RJT them as 10859 * well. 10860 */ 10861 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10862 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10863 0, KM_SLEEP, NULL); 10864 if (cmd != NULL) { 10865 fp_els_rjt_init(port, cmd, buf, 10866 FC_ACTION_NON_RETRYABLE, 10867 FC_REASON_INVALID_LINK_CTRL, job); 10868 10869 if (fp_sendcmd(port, cmd, 10870 port->fp_fca_handle) != 10871 FC_SUCCESS) { 10872 fp_free_pkt(cmd); 10873 } 10874 } 10875 } 10876 break; 10877 } 10878 /* FALLTHROUGH */ 10879 10880 case R_CTL_FC4_SVC: 10881 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 10882 ub_spec->port = port; 10883 ub_spec->buf = buf; 10884 10885 (void) taskq_dispatch(port->fp_taskq, 10886 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 10887 return; 10888 10889 case R_CTL_LINK_CTL: 10890 /* 10891 * Turn deaf ear on unsolicited link control frames. 10892 * Typical unsolicited link control Frame is an LCR 10893 * (to reset End to End credit to the default login 10894 * value and abort current sequences for all classes) 10895 * An intelligent microcode/firmware should handle 10896 * this transparently at its level and not pass all 10897 * the way up here. 10898 * 10899 * Possible responses to LCR are R_RDY, F_RJT, P_RJT 10900 * or F_BSY. P_RJT is chosen to be the most appropriate 10901 * at this time. 10902 */ 10903 /* FALLTHROUGH */ 10904 10905 default: 10906 /* 10907 * Just reject everything else as an invalid request. 10908 */ 10909 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10910 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10911 0, KM_SLEEP, NULL); 10912 if (cmd != NULL) { 10913 fp_els_rjt_init(port, cmd, buf, 10914 FC_ACTION_NON_RETRYABLE, 10915 FC_REASON_INVALID_LINK_CTRL, job); 10916 10917 if (fp_sendcmd(port, cmd, 10918 port->fp_fca_handle) != FC_SUCCESS) { 10919 fp_free_pkt(cmd); 10920 } 10921 } 10922 } 10923 break; 10924 } 10925 10926 mutex_enter(&port->fp_mutex); 10927 ASSERT(port->fp_active_ubs > 0); 10928 if (--(port->fp_active_ubs) == 0) { 10929 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10930 } 10931 mutex_exit(&port->fp_mutex); 10932 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10933 1, &buf->ub_token); 10934 } 10935 10936 10937 /* 10938 * Prepare a BA_RJT and send it over. 10939 */ 10940 static void 10941 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 10942 job_request_t *job) 10943 { 10944 fc_packet_t *pkt; 10945 la_ba_rjt_t payload; 10946 10947 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 10948 10949 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 10950 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 10951 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 10952 cmd->cmd_retry_count = 1; 10953 cmd->cmd_ulp_pkt = NULL; 10954 10955 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 10956 cmd->cmd_job = job; 10957 10958 pkt = &cmd->cmd_pkt; 10959 10960 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS); 10961 10962 payload.reserved = 0; 10963 payload.reason_code = FC_REASON_CMD_UNSUPPORTED; 10964 payload.explanation = FC_EXPLN_NONE; 10965 payload.vendor = 0; 10966 10967 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 10968 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 10969 } 10970 10971 10972 /* 10973 * Prepare an LS_RJT and send it over 10974 */ 10975 static void 10976 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 10977 uchar_t action, uchar_t reason, job_request_t *job) 10978 { 10979 fc_packet_t *pkt; 10980 la_els_rjt_t payload; 10981 10982 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 10983 10984 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 10985 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 10986 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 10987 cmd->cmd_retry_count = 1; 10988 cmd->cmd_ulp_pkt = NULL; 10989 10990 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 10991 cmd->cmd_job = job; 10992 10993 pkt = &cmd->cmd_pkt; 10994 10995 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 10996 10997 payload.ls_code.ls_code = LA_ELS_RJT; 10998 payload.ls_code.mbz = 0; 10999 payload.action = action; 11000 payload.reason = reason; 11001 payload.reserved = 0; 11002 payload.vu = 0; 11003 11004 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 11005 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11006 } 11007 11008 /* 11009 * Function: fp_prlo_acc_init 11010 * 11011 * Description: Initializes an Link Service Accept for a PRLO. 11012 * 11013 * Arguments: *port Local port through which the PRLO was 11014 * received. 11015 * cmd Command that will carry the accept. 11016 * *buf Unsolicited buffer containing the PRLO 11017 * request. 11018 * job Job request. 11019 * sleep Allocation mode. 11020 * 11021 * Return Value: *cmd Command containing the response. 11022 * 11023 * Context: Depends on the parameter sleep. 11024 */ 11025 fp_cmd_t * 11026 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd, 11027 fc_unsol_buf_t *buf, job_request_t *job, int sleep) 11028 { 11029 fp_cmd_t *cmd; 11030 fc_packet_t *pkt; 11031 la_els_prlo_t *req; 11032 size_t len; 11033 uint16_t flags; 11034 11035 req = (la_els_prlo_t *)buf->ub_buffer; 11036 len = (size_t)ntohs(req->payload_length); 11037 11038 /* 11039 * The payload of the accept to a PRLO has to be the exact match of 11040 * the payload of the request (at the exception of the code). 11041 */ 11042 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd); 11043 11044 if (cmd) { 11045 /* 11046 * The fp command was successfully allocated. 11047 */ 11048 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11049 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11050 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11051 cmd->cmd_retry_count = 1; 11052 cmd->cmd_ulp_pkt = NULL; 11053 11054 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11055 cmd->cmd_job = job; 11056 11057 pkt = &cmd->cmd_pkt; 11058 11059 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, 11060 FC_TYPE_EXTENDED_LS); 11061 11062 /* The code is overwritten for the copy. */ 11063 req->ls_code = LA_ELS_ACC; 11064 /* Response code is set. */ 11065 flags = ntohs(req->flags); 11066 flags &= ~SP_RESP_CODE_MASK; 11067 flags |= SP_RESP_CODE_REQ_EXECUTED; 11068 req->flags = htons(flags); 11069 11070 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)req, 11071 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR); 11072 } 11073 return (cmd); 11074 } 11075 11076 /* 11077 * Prepare an ACC response to an ELS request 11078 */ 11079 static void 11080 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11081 job_request_t *job) 11082 { 11083 fc_packet_t *pkt; 11084 ls_code_t payload; 11085 11086 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11087 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11088 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11089 cmd->cmd_retry_count = 1; 11090 cmd->cmd_ulp_pkt = NULL; 11091 11092 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11093 cmd->cmd_job = job; 11094 11095 pkt = &cmd->cmd_pkt; 11096 11097 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11098 11099 payload.ls_code = LA_ELS_ACC; 11100 payload.mbz = 0; 11101 11102 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 11103 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11104 } 11105 11106 /* 11107 * Unsolicited PRLO handler 11108 * 11109 * A Process Logout should be handled by the ULP that established it. However, 11110 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens 11111 * when a device implicitly logs out an initiator (for whatever reason) and 11112 * tries to get that initiator to restablish the connection (PLOGI and PRLI). 11113 * The logical thing to do for the device would be to send a LOGO in response 11114 * to any FC4 frame sent by the initiator. Some devices choose, however, to send 11115 * a PRLO instead. 11116 * 11117 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to 11118 * think that the Port Login has been lost. If we follow the Fibre Channel 11119 * protocol to the letter a PRLI should be sent after accepting the PRLO. If 11120 * the Port Login has also been lost, the remote port will reject the PRLI 11121 * indicating that we must PLOGI first. The initiator will then turn around and 11122 * send a PLOGI. The way Leadville is layered and the way the ULP interface 11123 * is defined doesn't allow this scenario to be followed easily. If FCP were to 11124 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is 11125 * needed would be received by FCP. FCP would have, then, to tell the transport 11126 * (fp) to PLOGI. The problem is, the transport would still think the Port 11127 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even 11128 * if you think it's not necessary". To work around that difficulty, the PRLO 11129 * is treated by the transport as a LOGO. The downside to it is a Port Login 11130 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that 11131 * has nothing to do with the PRLO) may be impacted. However, this is a 11132 * scenario very unlikely to happen. As of today the only ULP in Leadville 11133 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be 11134 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very 11135 * unlikely). 11136 */ 11137 static void 11138 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11139 fc_remote_port_t *pd, job_request_t *job) 11140 { 11141 int busy; 11142 int rval; 11143 int retain; 11144 fp_cmd_t *cmd; 11145 fc_portmap_t *listptr; 11146 boolean_t tolerance; 11147 la_els_prlo_t *req; 11148 11149 req = (la_els_prlo_t *)buf->ub_buffer; 11150 11151 if ((ntohs(req->payload_length) != 11152 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) || 11153 (req->page_length != sizeof (service_parameter_page_t))) { 11154 /* 11155 * We are being very restrictive. Only on page per 11156 * payload. If it is not the case we reject the ELS although 11157 * we should reply indicating we handle only single page 11158 * per PRLO. 11159 */ 11160 goto fp_reject_prlo; 11161 } 11162 11163 if (ntohs(req->payload_length) > buf->ub_bufsize) { 11164 /* 11165 * This is in case the payload advertizes a size bigger than 11166 * what it really is. 11167 */ 11168 goto fp_reject_prlo; 11169 } 11170 11171 mutex_enter(&port->fp_mutex); 11172 busy = port->fp_statec_busy; 11173 mutex_exit(&port->fp_mutex); 11174 11175 mutex_enter(&pd->pd_mutex); 11176 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11177 if (!busy) { 11178 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11179 pd->pd_state == PORT_DEVICE_INVALID || 11180 pd->pd_flags == PD_ELS_IN_PROGRESS || 11181 pd->pd_type == PORT_DEVICE_OLD) { 11182 busy++; 11183 } 11184 } 11185 11186 if (busy) { 11187 mutex_exit(&pd->pd_mutex); 11188 11189 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11190 "pd=%p - busy", 11191 pd->pd_port_id.port_id, pd); 11192 11193 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11194 goto fp_reject_prlo; 11195 } 11196 } else { 11197 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11198 11199 if (tolerance) { 11200 fctl_tc_reset(&pd->pd_logo_tc); 11201 retain = 0; 11202 pd->pd_state = PORT_DEVICE_INVALID; 11203 } 11204 11205 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11206 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11207 tolerance, retain); 11208 11209 pd->pd_aux_flags |= PD_LOGGED_OUT; 11210 mutex_exit(&pd->pd_mutex); 11211 11212 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP); 11213 if (cmd == NULL) { 11214 return; 11215 } 11216 11217 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11218 if (rval != FC_SUCCESS) { 11219 fp_free_pkt(cmd); 11220 return; 11221 } 11222 11223 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11224 11225 if (retain) { 11226 fp_unregister_login(pd); 11227 fctl_copy_portmap(listptr, pd); 11228 } else { 11229 uint32_t d_id; 11230 char ww_name[17]; 11231 11232 mutex_enter(&pd->pd_mutex); 11233 d_id = pd->pd_port_id.port_id; 11234 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11235 mutex_exit(&pd->pd_mutex); 11236 11237 FP_TRACE(FP_NHEAD2(9, 0), 11238 "N_x Port with D_ID=%x, PWWN=%s logged out" 11239 " %d times in %d us; Giving up", d_id, ww_name, 11240 FC_LOGO_TOLERANCE_LIMIT, 11241 FC_LOGO_TOLERANCE_TIME_LIMIT); 11242 11243 fp_fillout_old_map(listptr, pd, 0); 11244 listptr->map_type = PORT_DEVICE_OLD; 11245 } 11246 11247 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11248 return; 11249 } 11250 11251 fp_reject_prlo: 11252 11253 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd); 11254 if (cmd != NULL) { 11255 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE, 11256 FC_REASON_INVALID_LINK_CTRL, job); 11257 11258 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11259 fp_free_pkt(cmd); 11260 } 11261 } 11262 } 11263 11264 /* 11265 * Unsolicited LOGO handler 11266 */ 11267 static void 11268 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11269 fc_remote_port_t *pd, job_request_t *job) 11270 { 11271 int busy; 11272 int rval; 11273 int retain; 11274 fp_cmd_t *cmd; 11275 fc_portmap_t *listptr; 11276 boolean_t tolerance; 11277 11278 mutex_enter(&port->fp_mutex); 11279 busy = port->fp_statec_busy; 11280 mutex_exit(&port->fp_mutex); 11281 11282 mutex_enter(&pd->pd_mutex); 11283 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11284 if (!busy) { 11285 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11286 pd->pd_state == PORT_DEVICE_INVALID || 11287 pd->pd_flags == PD_ELS_IN_PROGRESS || 11288 pd->pd_type == PORT_DEVICE_OLD) { 11289 busy++; 11290 } 11291 } 11292 11293 if (busy) { 11294 mutex_exit(&pd->pd_mutex); 11295 11296 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11297 "pd=%p - busy", 11298 pd->pd_port_id.port_id, pd); 11299 11300 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11301 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11302 0, KM_SLEEP, pd); 11303 if (cmd != NULL) { 11304 fp_els_rjt_init(port, cmd, buf, 11305 FC_ACTION_NON_RETRYABLE, 11306 FC_REASON_INVALID_LINK_CTRL, job); 11307 11308 if (fp_sendcmd(port, cmd, 11309 port->fp_fca_handle) != FC_SUCCESS) { 11310 fp_free_pkt(cmd); 11311 } 11312 } 11313 } 11314 } else { 11315 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11316 11317 if (tolerance) { 11318 fctl_tc_reset(&pd->pd_logo_tc); 11319 retain = 0; 11320 pd->pd_state = PORT_DEVICE_INVALID; 11321 } 11322 11323 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11324 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11325 tolerance, retain); 11326 11327 pd->pd_aux_flags |= PD_LOGGED_OUT; 11328 mutex_exit(&pd->pd_mutex); 11329 11330 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, 11331 KM_SLEEP, pd); 11332 if (cmd == NULL) { 11333 return; 11334 } 11335 11336 fp_els_acc_init(port, cmd, buf, job); 11337 11338 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11339 if (rval != FC_SUCCESS) { 11340 fp_free_pkt(cmd); 11341 return; 11342 } 11343 11344 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11345 11346 if (retain) { 11347 job_request_t *job; 11348 fctl_ns_req_t *ns_cmd; 11349 11350 /* 11351 * when get LOGO, first try to get PID from nameserver 11352 * if failed, then we do not need 11353 * send PLOGI to that remote port 11354 */ 11355 job = fctl_alloc_job( 11356 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP); 11357 11358 if (job != NULL) { 11359 ns_cmd = fctl_alloc_ns_cmd( 11360 sizeof (ns_req_gid_pn_t), 11361 sizeof (ns_resp_gid_pn_t), 11362 sizeof (ns_resp_gid_pn_t), 11363 0, KM_SLEEP); 11364 if (ns_cmd != NULL) { 11365 int ret; 11366 job->job_result = FC_SUCCESS; 11367 ns_cmd->ns_cmd_code = NS_GID_PN; 11368 ((ns_req_gid_pn_t *) 11369 (ns_cmd->ns_cmd_buf))->pwwn = 11370 pd->pd_port_name; 11371 ret = fp_ns_query( 11372 port, ns_cmd, job, 1, KM_SLEEP); 11373 if ((ret != FC_SUCCESS) || 11374 (job->job_result != FC_SUCCESS)) { 11375 fctl_free_ns_cmd(ns_cmd); 11376 fctl_dealloc_job(job); 11377 FP_TRACE(FP_NHEAD2(9, 0), 11378 "NS query failed,", 11379 " delete pd"); 11380 goto delete_pd; 11381 } 11382 fctl_free_ns_cmd(ns_cmd); 11383 } 11384 fctl_dealloc_job(job); 11385 } 11386 fp_unregister_login(pd); 11387 fctl_copy_portmap(listptr, pd); 11388 } else { 11389 uint32_t d_id; 11390 char ww_name[17]; 11391 11392 delete_pd: 11393 mutex_enter(&pd->pd_mutex); 11394 d_id = pd->pd_port_id.port_id; 11395 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11396 mutex_exit(&pd->pd_mutex); 11397 11398 FP_TRACE(FP_NHEAD2(9, 0), 11399 "N_x Port with D_ID=%x, PWWN=%s logged out" 11400 " %d times in %d us; Giving up", d_id, ww_name, 11401 FC_LOGO_TOLERANCE_LIMIT, 11402 FC_LOGO_TOLERANCE_TIME_LIMIT); 11403 11404 fp_fillout_old_map(listptr, pd, 0); 11405 listptr->map_type = PORT_DEVICE_OLD; 11406 } 11407 11408 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11409 } 11410 } 11411 11412 11413 /* 11414 * Perform general purpose preparation of a response to an unsolicited request 11415 */ 11416 static void 11417 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf, 11418 uchar_t r_ctl, uchar_t type) 11419 { 11420 pkt->pkt_cmd_fhdr.r_ctl = r_ctl; 11421 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id; 11422 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id; 11423 pkt->pkt_cmd_fhdr.type = type; 11424 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT; 11425 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id; 11426 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl; 11427 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt; 11428 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id; 11429 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id; 11430 pkt->pkt_cmd_fhdr.ro = 0; 11431 pkt->pkt_cmd_fhdr.rsvd = 0; 11432 pkt->pkt_comp = fp_unsol_intr; 11433 pkt->pkt_timeout = FP_ELS_TIMEOUT; 11434 } 11435 11436 /* 11437 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the 11438 * early development days of public loop soc+ firmware, numerous problems 11439 * were encountered (the details are undocumented and history now) which 11440 * led to the birth of this function. 11441 * 11442 * If a pre-allocated unsolicited response packet is free, send out an 11443 * immediate response, otherwise submit the request to the port thread 11444 * to do the deferred processing. 11445 */ 11446 static void 11447 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf) 11448 { 11449 int sent; 11450 int f_port; 11451 int do_acc; 11452 fp_cmd_t *cmd; 11453 la_els_logi_t *payload; 11454 fc_remote_port_t *pd; 11455 char dww_name[17]; 11456 11457 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11458 11459 cmd = port->fp_els_resp_pkt; 11460 11461 mutex_enter(&port->fp_mutex); 11462 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11463 mutex_exit(&port->fp_mutex); 11464 11465 switch (buf->ub_buffer[0]) { 11466 case LA_ELS_PLOGI: { 11467 int small; 11468 11469 payload = (la_els_logi_t *)buf->ub_buffer; 11470 11471 f_port = FP_IS_F_PORT(payload-> 11472 common_service.cmn_features) ? 1 : 0; 11473 11474 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 11475 &payload->nport_ww_name); 11476 pd = fctl_get_remote_port_by_pwwn(port, 11477 &payload->nport_ww_name); 11478 if (pd) { 11479 mutex_enter(&pd->pd_mutex); 11480 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11481 /* 11482 * Most likely this means a cross login is in 11483 * progress or a device about to be yanked out. 11484 * Only accept the plogi if my wwn is smaller. 11485 */ 11486 if (pd->pd_type == PORT_DEVICE_OLD) { 11487 sent = 1; 11488 } 11489 /* 11490 * Stop plogi request (if any) 11491 * attempt from local side to speedup 11492 * the discovery progress. 11493 * Mark the pd as PD_PLOGI_RECEPIENT. 11494 */ 11495 if (f_port == 0 && small < 0) { 11496 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11497 } 11498 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11499 11500 mutex_exit(&pd->pd_mutex); 11501 11502 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: " 11503 "Unsol PLOGI received. PD still exists in the " 11504 "PWWN list. pd=%p PWWN=%s, sent=%x", 11505 pd, dww_name, sent); 11506 11507 if (f_port == 0 && small < 0) { 11508 FP_TRACE(FP_NHEAD1(3, 0), 11509 "fp_i_handle_unsol_els: Mark the pd" 11510 " as plogi recipient, pd=%p, PWWN=%s" 11511 ", sent=%x", 11512 pd, dww_name, sent); 11513 } 11514 } else { 11515 sent = 0; 11516 } 11517 11518 /* 11519 * To avoid Login collisions, accept only if my WWN 11520 * is smaller than the requester (A curious side note 11521 * would be that this rule may not satisfy the PLOGIs 11522 * initiated by the switch from not-so-well known 11523 * ports such as 0xFFFC41) 11524 */ 11525 if ((f_port == 0 && small < 0) || 11526 (((small > 0 && do_acc) || 11527 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11528 if (fp_is_class_supported(port->fp_cos, 11529 buf->ub_class) == FC_FAILURE) { 11530 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11531 cmd->cmd_pkt.pkt_cmdlen = 11532 sizeof (la_els_rjt_t); 11533 cmd->cmd_pkt.pkt_rsplen = 0; 11534 fp_els_rjt_init(port, cmd, buf, 11535 FC_ACTION_NON_RETRYABLE, 11536 FC_REASON_CLASS_NOT_SUPP, NULL); 11537 FP_TRACE(FP_NHEAD1(3, 0), 11538 "fp_i_handle_unsol_els: " 11539 "Unsupported class. " 11540 "Rejecting PLOGI"); 11541 11542 } else { 11543 mutex_enter(&port->fp_mutex); 11544 port->fp_els_resp_pkt_busy = 0; 11545 mutex_exit(&port->fp_mutex); 11546 return; 11547 } 11548 } else { 11549 cmd->cmd_pkt.pkt_cmdlen = 11550 sizeof (la_els_logi_t); 11551 cmd->cmd_pkt.pkt_rsplen = 0; 11552 11553 /* 11554 * Sometime later, we should validate 11555 * the service parameters instead of 11556 * just accepting it. 11557 */ 11558 fp_login_acc_init(port, cmd, buf, NULL, 11559 KM_NOSLEEP); 11560 FP_TRACE(FP_NHEAD1(3, 0), 11561 "fp_i_handle_unsol_els: Accepting PLOGI," 11562 " f_port=%d, small=%d, do_acc=%d," 11563 " sent=%d.", f_port, small, do_acc, 11564 sent); 11565 /* 11566 * If fp_port_id is zero and topology is 11567 * Point-to-Point, get the local port id from 11568 * the d_id in the PLOGI request. 11569 * If the outgoing FLOGI hasn't been accepted, 11570 * the topology will be unknown here. But it's 11571 * still safe to save the d_id to fp_port_id, 11572 * just because it will be overwritten later 11573 * if the topology is not Point-to-Point. 11574 */ 11575 mutex_enter(&port->fp_mutex); 11576 if ((port->fp_port_id.port_id == 0) && 11577 (port->fp_topology == FC_TOP_PT_PT || 11578 port->fp_topology == FC_TOP_UNKNOWN)) { 11579 port->fp_port_id.port_id = 11580 buf->ub_frame.d_id; 11581 } 11582 mutex_exit(&port->fp_mutex); 11583 } 11584 } else { 11585 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 11586 port->fp_options & FP_SEND_RJT) { 11587 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11588 cmd->cmd_pkt.pkt_rsplen = 0; 11589 fp_els_rjt_init(port, cmd, buf, 11590 FC_ACTION_NON_RETRYABLE, 11591 FC_REASON_LOGICAL_BSY, NULL); 11592 FP_TRACE(FP_NHEAD1(3, 0), 11593 "fp_i_handle_unsol_els: " 11594 "Rejecting PLOGI with Logical Busy." 11595 "Possible Login collision."); 11596 } else { 11597 mutex_enter(&port->fp_mutex); 11598 port->fp_els_resp_pkt_busy = 0; 11599 mutex_exit(&port->fp_mutex); 11600 return; 11601 } 11602 } 11603 break; 11604 } 11605 11606 case LA_ELS_FLOGI: 11607 if (fp_is_class_supported(port->fp_cos, 11608 buf->ub_class) == FC_FAILURE) { 11609 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11610 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11611 cmd->cmd_pkt.pkt_rsplen = 0; 11612 fp_els_rjt_init(port, cmd, buf, 11613 FC_ACTION_NON_RETRYABLE, 11614 FC_REASON_CLASS_NOT_SUPP, NULL); 11615 FP_TRACE(FP_NHEAD1(3, 0), 11616 "fp_i_handle_unsol_els: " 11617 "Unsupported Class. Rejecting FLOGI."); 11618 } else { 11619 mutex_enter(&port->fp_mutex); 11620 port->fp_els_resp_pkt_busy = 0; 11621 mutex_exit(&port->fp_mutex); 11622 return; 11623 } 11624 } else { 11625 mutex_enter(&port->fp_mutex); 11626 if (FC_PORT_STATE_MASK(port->fp_state) != 11627 FC_STATE_ONLINE || (port->fp_port_id.port_id && 11628 buf->ub_frame.s_id == port->fp_port_id.port_id)) { 11629 mutex_exit(&port->fp_mutex); 11630 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11631 cmd->cmd_pkt.pkt_cmdlen = 11632 sizeof (la_els_rjt_t); 11633 cmd->cmd_pkt.pkt_rsplen = 0; 11634 fp_els_rjt_init(port, cmd, buf, 11635 FC_ACTION_NON_RETRYABLE, 11636 FC_REASON_INVALID_LINK_CTRL, 11637 NULL); 11638 FP_TRACE(FP_NHEAD1(3, 0), 11639 "fp_i_handle_unsol_els: " 11640 "Invalid Link Ctrl. " 11641 "Rejecting FLOGI."); 11642 } else { 11643 mutex_enter(&port->fp_mutex); 11644 port->fp_els_resp_pkt_busy = 0; 11645 mutex_exit(&port->fp_mutex); 11646 return; 11647 } 11648 } else { 11649 mutex_exit(&port->fp_mutex); 11650 cmd->cmd_pkt.pkt_cmdlen = 11651 sizeof (la_els_logi_t); 11652 cmd->cmd_pkt.pkt_rsplen = 0; 11653 /* 11654 * Let's not aggressively validate the N_Port's 11655 * service parameters until PLOGI. Suffice it 11656 * to give a hint that we are an N_Port and we 11657 * are game to some serious stuff here. 11658 */ 11659 fp_login_acc_init(port, cmd, buf, 11660 NULL, KM_NOSLEEP); 11661 FP_TRACE(FP_NHEAD1(3, 0), 11662 "fp_i_handle_unsol_els: " 11663 "Accepting FLOGI."); 11664 } 11665 } 11666 break; 11667 11668 default: 11669 return; 11670 } 11671 11672 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) { 11673 mutex_enter(&port->fp_mutex); 11674 port->fp_els_resp_pkt_busy = 0; 11675 mutex_exit(&port->fp_mutex); 11676 } 11677 } 11678 11679 11680 /* 11681 * Handle unsolicited PLOGI request 11682 */ 11683 static void 11684 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 11685 job_request_t *job, int sleep) 11686 { 11687 int sent; 11688 int small; 11689 int f_port; 11690 int do_acc; 11691 fp_cmd_t *cmd; 11692 la_wwn_t *swwn; 11693 la_wwn_t *dwwn; 11694 la_els_logi_t *payload; 11695 fc_remote_port_t *pd; 11696 char dww_name[17]; 11697 11698 payload = (la_els_logi_t *)buf->ub_buffer; 11699 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0; 11700 11701 mutex_enter(&port->fp_mutex); 11702 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11703 mutex_exit(&port->fp_mutex); 11704 11705 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x," 11706 "type=%x, f_ctl=%x" 11707 " seq_id=%x, ox_id=%x, rx_id=%x" 11708 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 11709 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 11710 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 11711 11712 swwn = &port->fp_service_params.nport_ww_name; 11713 dwwn = &payload->nport_ww_name; 11714 small = fctl_wwn_cmp(swwn, dwwn); 11715 pd = fctl_get_remote_port_by_pwwn(port, dwwn); 11716 if (pd) { 11717 mutex_enter(&pd->pd_mutex); 11718 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11719 /* 11720 * Most likely this means a cross login is in 11721 * progress or a device about to be yanked out. 11722 * Only accept the plogi if my wwn is smaller. 11723 */ 11724 11725 if (pd->pd_type == PORT_DEVICE_OLD) { 11726 sent = 1; 11727 } 11728 /* 11729 * Stop plogi request (if any) 11730 * attempt from local side to speedup 11731 * the discovery progress. 11732 * Mark the pd as PD_PLOGI_RECEPIENT. 11733 */ 11734 if (f_port == 0 && small < 0) { 11735 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11736 } 11737 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11738 11739 mutex_exit(&pd->pd_mutex); 11740 11741 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI" 11742 " received. PD still exists in the PWWN list. pd=%p " 11743 "PWWN=%s, sent=%x", pd, dww_name, sent); 11744 11745 if (f_port == 0 && small < 0) { 11746 FP_TRACE(FP_NHEAD1(3, 0), 11747 "fp_handle_unsol_plogi: Mark the pd" 11748 " as plogi recipient, pd=%p, PWWN=%s" 11749 ", sent=%x", 11750 pd, dww_name, sent); 11751 } 11752 } else { 11753 sent = 0; 11754 } 11755 11756 /* 11757 * Avoid Login collisions by accepting only if my WWN is smaller. 11758 * 11759 * A side note: There is no need to start a PLOGI from this end in 11760 * this context if login isn't going to be accepted for the 11761 * above reason as either a LIP (in private loop), RSCN (in 11762 * fabric topology), or an FLOGI (in point to point - Huh ? 11763 * check FC-PH) would normally drive the PLOGI from this end. 11764 * At this point of time there is no need for an inbound PLOGI 11765 * to kick an outbound PLOGI when it is going to be rejected 11766 * for the reason of WWN being smaller. However it isn't hard 11767 * to do that either (when such a need arises, start a timer 11768 * for a duration that extends beyond a normal device discovery 11769 * time and check if an outbound PLOGI did go before that, if 11770 * none fire one) 11771 * 11772 * Unfortunately, as it turned out, during booting, it is possible 11773 * to miss another initiator in the same loop as port driver 11774 * instances are serially attached. While preserving the above 11775 * comments for belly laughs, please kick an outbound PLOGI in 11776 * a non-switch environment (which is a pt pt between N_Ports or 11777 * a private loop) 11778 * 11779 * While preserving the above comments for amusement, send an 11780 * ACC if the PLOGI is going to be rejected for WWN being smaller 11781 * when no discovery is in progress at this end. Turn around 11782 * and make the port device as the PLOGI initiator, so that 11783 * during subsequent link/loop initialization, this end drives 11784 * the PLOGI (In fact both ends do in this particular case, but 11785 * only one wins) 11786 * 11787 * Make sure the PLOGIs initiated by the switch from not-so-well-known 11788 * ports (such as 0xFFFC41) are accepted too. 11789 */ 11790 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) || 11791 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11792 if (fp_is_class_supported(port->fp_cos, 11793 buf->ub_class) == FC_FAILURE) { 11794 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11795 cmd = fp_alloc_pkt(port, 11796 sizeof (la_els_logi_t), 0, sleep, pd); 11797 if (cmd == NULL) { 11798 return; 11799 } 11800 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11801 cmd->cmd_pkt.pkt_rsplen = 0; 11802 fp_els_rjt_init(port, cmd, buf, 11803 FC_ACTION_NON_RETRYABLE, 11804 FC_REASON_CLASS_NOT_SUPP, job); 11805 FP_TRACE(FP_NHEAD1(3, 0), 11806 "fp_handle_unsol_plogi: " 11807 "Unsupported class. rejecting PLOGI"); 11808 } 11809 } else { 11810 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 11811 0, sleep, pd); 11812 if (cmd == NULL) { 11813 return; 11814 } 11815 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t); 11816 cmd->cmd_pkt.pkt_rsplen = 0; 11817 11818 /* 11819 * Sometime later, we should validate the service 11820 * parameters instead of just accepting it. 11821 */ 11822 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 11823 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 11824 "Accepting PLOGI, f_port=%d, small=%d, " 11825 "do_acc=%d, sent=%d.", f_port, small, do_acc, 11826 sent); 11827 11828 /* 11829 * If fp_port_id is zero and topology is 11830 * Point-to-Point, get the local port id from 11831 * the d_id in the PLOGI request. 11832 * If the outgoing FLOGI hasn't been accepted, 11833 * the topology will be unknown here. But it's 11834 * still safe to save the d_id to fp_port_id, 11835 * just because it will be overwritten later 11836 * if the topology is not Point-to-Point. 11837 */ 11838 mutex_enter(&port->fp_mutex); 11839 if ((port->fp_port_id.port_id == 0) && 11840 (port->fp_topology == FC_TOP_PT_PT || 11841 port->fp_topology == FC_TOP_UNKNOWN)) { 11842 port->fp_port_id.port_id = 11843 buf->ub_frame.d_id; 11844 } 11845 mutex_exit(&port->fp_mutex); 11846 } 11847 } else { 11848 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 11849 port->fp_options & FP_SEND_RJT) { 11850 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 11851 0, sleep, pd); 11852 if (cmd == NULL) { 11853 return; 11854 } 11855 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11856 cmd->cmd_pkt.pkt_rsplen = 0; 11857 /* 11858 * Send out Logical busy to indicate 11859 * the detection of PLOGI collision 11860 */ 11861 fp_els_rjt_init(port, cmd, buf, 11862 FC_ACTION_NON_RETRYABLE, 11863 FC_REASON_LOGICAL_BSY, job); 11864 11865 fc_wwn_to_str(dwwn, dww_name); 11866 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 11867 "Rejecting Unsol PLOGI with Logical Busy." 11868 "possible PLOGI collision. PWWN=%s, sent=%x", 11869 dww_name, sent); 11870 } else { 11871 return; 11872 } 11873 } 11874 11875 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11876 fp_free_pkt(cmd); 11877 } 11878 } 11879 11880 11881 /* 11882 * Handle mischievous turning over of our own FLOGI requests back to 11883 * us by the SOC+ microcode. In other words, look at the class of such 11884 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them 11885 * on the floor 11886 */ 11887 static void 11888 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 11889 job_request_t *job, int sleep) 11890 { 11891 uint32_t state; 11892 uint32_t s_id; 11893 fp_cmd_t *cmd; 11894 11895 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) { 11896 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11897 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11898 0, sleep, NULL); 11899 if (cmd == NULL) { 11900 return; 11901 } 11902 fp_els_rjt_init(port, cmd, buf, 11903 FC_ACTION_NON_RETRYABLE, 11904 FC_REASON_CLASS_NOT_SUPP, job); 11905 } else { 11906 return; 11907 } 11908 } else { 11909 11910 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:" 11911 " s_id=%x, d_id=%x, type=%x, f_ctl=%x" 11912 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x", 11913 buf->ub_frame.s_id, buf->ub_frame.d_id, 11914 buf->ub_frame.type, buf->ub_frame.f_ctl, 11915 buf->ub_frame.seq_id, buf->ub_frame.ox_id, 11916 buf->ub_frame.rx_id, buf->ub_frame.ro); 11917 11918 mutex_enter(&port->fp_mutex); 11919 state = FC_PORT_STATE_MASK(port->fp_state); 11920 s_id = port->fp_port_id.port_id; 11921 mutex_exit(&port->fp_mutex); 11922 11923 if (state != FC_STATE_ONLINE || 11924 (s_id && buf->ub_frame.s_id == s_id)) { 11925 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11926 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11927 0, sleep, NULL); 11928 if (cmd == NULL) { 11929 return; 11930 } 11931 fp_els_rjt_init(port, cmd, buf, 11932 FC_ACTION_NON_RETRYABLE, 11933 FC_REASON_INVALID_LINK_CTRL, job); 11934 FP_TRACE(FP_NHEAD1(3, 0), 11935 "fp_handle_unsol_flogi: " 11936 "Rejecting PLOGI. Invalid Link CTRL"); 11937 } else { 11938 return; 11939 } 11940 } else { 11941 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 11942 0, sleep, NULL); 11943 if (cmd == NULL) { 11944 return; 11945 } 11946 /* 11947 * Let's not aggressively validate the N_Port's 11948 * service parameters until PLOGI. Suffice it 11949 * to give a hint that we are an N_Port and we 11950 * are game to some serious stuff here. 11951 */ 11952 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 11953 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: " 11954 "Accepting PLOGI"); 11955 } 11956 } 11957 11958 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11959 fp_free_pkt(cmd); 11960 } 11961 } 11962 11963 11964 /* 11965 * Perform PLOGI accept 11966 */ 11967 static void 11968 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11969 job_request_t *job, int sleep) 11970 { 11971 fc_packet_t *pkt; 11972 fc_portmap_t *listptr; 11973 la_els_logi_t payload; 11974 11975 ASSERT(buf != NULL); 11976 11977 /* 11978 * If we are sending ACC to PLOGI and we haven't already 11979 * create port and node device handles, let's create them 11980 * here. 11981 */ 11982 if (buf->ub_buffer[0] == LA_ELS_PLOGI && 11983 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) { 11984 int small; 11985 int do_acc; 11986 fc_remote_port_t *pd; 11987 la_els_logi_t *req; 11988 11989 req = (la_els_logi_t *)buf->ub_buffer; 11990 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 11991 &req->nport_ww_name); 11992 11993 mutex_enter(&port->fp_mutex); 11994 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11995 mutex_exit(&port->fp_mutex); 11996 11997 pd = fctl_create_remote_port(port, &req->node_ww_name, 11998 &req->nport_ww_name, buf->ub_frame.s_id, 11999 PD_PLOGI_RECEPIENT, sleep); 12000 if (pd == NULL) { 12001 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: " 12002 "Couldn't create port device for d_id:0x%x", 12003 buf->ub_frame.s_id); 12004 12005 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 12006 "couldn't create port device d_id=%x", 12007 buf->ub_frame.s_id); 12008 } else { 12009 /* 12010 * usoc currently returns PLOGIs inline and 12011 * the maximum buffer size is 60 bytes or so. 12012 * So attempt not to look beyond what is in 12013 * the unsolicited buffer 12014 * 12015 * JNI also traverses this path sometimes 12016 */ 12017 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) { 12018 fp_register_login(NULL, pd, req, buf->ub_class); 12019 } else { 12020 mutex_enter(&pd->pd_mutex); 12021 if (pd->pd_login_count == 0) { 12022 pd->pd_login_count++; 12023 } 12024 pd->pd_state = PORT_DEVICE_LOGGED_IN; 12025 pd->pd_login_class = buf->ub_class; 12026 mutex_exit(&pd->pd_mutex); 12027 } 12028 12029 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep); 12030 if (listptr != NULL) { 12031 fctl_copy_portmap(listptr, pd); 12032 (void) fp_ulp_devc_cb(port, listptr, 12033 1, 1, sleep, 0); 12034 } 12035 12036 if (small > 0 && do_acc) { 12037 mutex_enter(&pd->pd_mutex); 12038 pd->pd_recepient = PD_PLOGI_INITIATOR; 12039 mutex_exit(&pd->pd_mutex); 12040 } 12041 } 12042 } 12043 12044 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 12045 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 12046 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12047 cmd->cmd_retry_count = 1; 12048 cmd->cmd_ulp_pkt = NULL; 12049 12050 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12051 cmd->cmd_job = job; 12052 12053 pkt = &cmd->cmd_pkt; 12054 12055 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 12056 12057 payload = port->fp_service_params; 12058 payload.ls_code.ls_code = LA_ELS_ACC; 12059 12060 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 12061 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12062 12063 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x " 12064 "bufsize:0x%x sizeof(la_els_logi):0x%x " 12065 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x " 12066 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id, 12067 buf->ub_bufsize, sizeof (la_els_logi_t), 12068 port->fp_service_params.nport_ww_name.w.naa_id, 12069 port->fp_service_params.nport_ww_name.w.nport_id, 12070 port->fp_service_params.nport_ww_name.w.wwn_hi, 12071 port->fp_service_params.nport_ww_name.w.wwn_lo, 12072 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id, 12073 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id, 12074 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi, 12075 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo, 12076 port->fp_statec_busy); 12077 } 12078 12079 12080 #define RSCN_EVENT_NAME_LEN 256 12081 12082 /* 12083 * Handle RSCNs 12084 */ 12085 static void 12086 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf, 12087 job_request_t *job, int sleep) 12088 { 12089 uint32_t mask; 12090 fp_cmd_t *cmd; 12091 uint32_t count; 12092 int listindex; 12093 int16_t len; 12094 fc_rscn_t *payload; 12095 fc_portmap_t *listptr; 12096 fctl_ns_req_t *ns_cmd; 12097 fc_affected_id_t *page; 12098 caddr_t nvname; 12099 nvlist_t *attr_list = NULL; 12100 12101 mutex_enter(&port->fp_mutex); 12102 if (!FC_IS_TOP_SWITCH(port->fp_topology)) { 12103 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12104 --port->fp_rscn_count; 12105 } 12106 mutex_exit(&port->fp_mutex); 12107 return; 12108 } 12109 mutex_exit(&port->fp_mutex); 12110 12111 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL); 12112 if (cmd != NULL) { 12113 fp_els_acc_init(port, cmd, buf, job); 12114 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12115 fp_free_pkt(cmd); 12116 } 12117 } 12118 12119 payload = (fc_rscn_t *)buf->ub_buffer; 12120 ASSERT(payload->rscn_code == LA_ELS_RSCN); 12121 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN); 12122 12123 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN; 12124 12125 if (len <= 0) { 12126 mutex_enter(&port->fp_mutex); 12127 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12128 --port->fp_rscn_count; 12129 } 12130 mutex_exit(&port->fp_mutex); 12131 12132 return; 12133 } 12134 12135 ASSERT((len & 0x3) == 0); /* Must be power of 4 */ 12136 count = (len >> 2) << 1; /* number of pages multiplied by 2 */ 12137 12138 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 12139 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t)); 12140 12141 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12142 12143 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t), 12144 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t), 12145 0, sleep); 12146 if (ns_cmd == NULL) { 12147 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12148 12149 mutex_enter(&port->fp_mutex); 12150 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12151 --port->fp_rscn_count; 12152 } 12153 mutex_exit(&port->fp_mutex); 12154 12155 return; 12156 } 12157 12158 ns_cmd->ns_cmd_code = NS_GPN_ID; 12159 12160 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x," 12161 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x" 12162 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 12163 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 12164 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 12165 12166 /* Only proceed if we can allocate nvname and the nvlist */ 12167 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL && 12168 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 12169 KM_NOSLEEP) == DDI_SUCCESS) { 12170 if (!(attr_list && nvlist_add_uint32(attr_list, "instance", 12171 port->fp_instance) == DDI_SUCCESS && 12172 nvlist_add_byte_array(attr_list, "port-wwn", 12173 port->fp_service_params.nport_ww_name.raw_wwn, 12174 sizeof (la_wwn_t)) == DDI_SUCCESS)) { 12175 nvlist_free(attr_list); 12176 attr_list = NULL; 12177 } 12178 } 12179 12180 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) { 12181 /* Add affected page to the event payload */ 12182 if (attr_list != NULL) { 12183 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN, 12184 "affected_page_%d", listindex); 12185 if (attr_list && nvlist_add_uint32(attr_list, nvname, 12186 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) { 12187 /* We don't want to send a partial event, so dump it */ 12188 nvlist_free(attr_list); 12189 attr_list = NULL; 12190 } 12191 } 12192 /* 12193 * Query the NS to get the Port WWN for this 12194 * affected D_ID. 12195 */ 12196 mask = 0; 12197 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) { 12198 case FC_RSCN_PORT_ADDRESS: 12199 fp_validate_rscn_page(port, page, job, ns_cmd, 12200 listptr, &listindex, sleep); 12201 12202 if (listindex == 0) { 12203 /* 12204 * We essentially did not process this RSCN. So, 12205 * ULPs are not going to be called and so we 12206 * decrement the rscn_count 12207 */ 12208 mutex_enter(&port->fp_mutex); 12209 if (--port->fp_rscn_count == 12210 FC_INVALID_RSCN_COUNT) { 12211 --port->fp_rscn_count; 12212 } 12213 mutex_exit(&port->fp_mutex); 12214 } 12215 break; 12216 12217 case FC_RSCN_AREA_ADDRESS: 12218 mask = 0xFFFF00; 12219 /* FALLTHROUGH */ 12220 12221 case FC_RSCN_DOMAIN_ADDRESS: 12222 if (!mask) { 12223 mask = 0xFF0000; 12224 } 12225 fp_validate_area_domain(port, page->aff_d_id, mask, 12226 job, sleep); 12227 break; 12228 12229 case FC_RSCN_FABRIC_ADDRESS: 12230 /* 12231 * We need to discover all the devices on this 12232 * port. 12233 */ 12234 fp_validate_area_domain(port, 0, 0, job, sleep); 12235 break; 12236 12237 default: 12238 break; 12239 } 12240 } 12241 if (attr_list != NULL) { 12242 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, 12243 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list, 12244 NULL, DDI_SLEEP); 12245 nvlist_free(attr_list); 12246 } else { 12247 FP_TRACE(FP_NHEAD1(9, 0), 12248 "RSCN handled, but event not sent to userland"); 12249 } 12250 if (nvname != NULL) { 12251 kmem_free(nvname, RSCN_EVENT_NAME_LEN); 12252 } 12253 12254 if (ns_cmd) { 12255 fctl_free_ns_cmd(ns_cmd); 12256 } 12257 12258 if (listindex) { 12259 #ifdef DEBUG 12260 page = (fc_affected_id_t *)(buf->ub_buffer + 12261 sizeof (fc_rscn_t)); 12262 12263 if (listptr->map_did.port_id != page->aff_d_id) { 12264 FP_TRACE(FP_NHEAD1(9, 0), 12265 "PORT RSCN: processed=%x, reporting=%x", 12266 listptr->map_did.port_id, page->aff_d_id); 12267 } 12268 #endif 12269 12270 (void) fp_ulp_devc_cb(port, listptr, listindex, count, 12271 sleep, 0); 12272 } else { 12273 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12274 } 12275 } 12276 12277 12278 /* 12279 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held 12280 */ 12281 static void 12282 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12283 { 12284 int is_switch; 12285 int initiator; 12286 fc_local_port_t *port; 12287 12288 port = pd->pd_port; 12289 12290 /* This function has the following bunch of assumptions */ 12291 ASSERT(port != NULL); 12292 ASSERT(MUTEX_HELD(&port->fp_mutex)); 12293 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex)); 12294 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12295 12296 pd->pd_state = PORT_DEVICE_INVALID; 12297 pd->pd_type = PORT_DEVICE_OLD; 12298 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12299 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12300 12301 fctl_delist_did_table(port, pd); 12302 fctl_delist_pwwn_table(port, pd); 12303 12304 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x" 12305 " removed the PD=%p from DID and PWWN tables", 12306 port, pd->pd_port_id.port_id, pd); 12307 12308 if ((!flag) && port && initiator && is_switch) { 12309 (void) fctl_add_orphan_held(port, pd); 12310 } 12311 fctl_copy_portmap_held(map, pd); 12312 map->map_pd = pd; 12313 } 12314 12315 /* 12316 * Fill out old map for ULPs 12317 */ 12318 static void 12319 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12320 { 12321 int is_switch; 12322 int initiator; 12323 fc_local_port_t *port; 12324 12325 mutex_enter(&pd->pd_mutex); 12326 port = pd->pd_port; 12327 mutex_exit(&pd->pd_mutex); 12328 12329 mutex_enter(&port->fp_mutex); 12330 mutex_enter(&pd->pd_mutex); 12331 12332 pd->pd_state = PORT_DEVICE_INVALID; 12333 pd->pd_type = PORT_DEVICE_OLD; 12334 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12335 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12336 12337 fctl_delist_did_table(port, pd); 12338 fctl_delist_pwwn_table(port, pd); 12339 12340 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x" 12341 " removed the PD=%p from DID and PWWN tables", 12342 port, pd->pd_port_id.port_id, pd); 12343 12344 mutex_exit(&pd->pd_mutex); 12345 mutex_exit(&port->fp_mutex); 12346 12347 ASSERT(port != NULL); 12348 if ((!flag) && port && initiator && is_switch) { 12349 (void) fctl_add_orphan(port, pd, KM_NOSLEEP); 12350 } 12351 fctl_copy_portmap(map, pd); 12352 map->map_pd = pd; 12353 } 12354 12355 12356 /* 12357 * Fillout Changed Map for ULPs 12358 */ 12359 static void 12360 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd, 12361 uint32_t *new_did, la_wwn_t *new_pwwn) 12362 { 12363 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12364 12365 pd->pd_type = PORT_DEVICE_CHANGED; 12366 if (new_did) { 12367 pd->pd_port_id.port_id = *new_did; 12368 } 12369 if (new_pwwn) { 12370 pd->pd_port_name = *new_pwwn; 12371 } 12372 mutex_exit(&pd->pd_mutex); 12373 12374 fctl_copy_portmap(map, pd); 12375 12376 mutex_enter(&pd->pd_mutex); 12377 pd->pd_type = PORT_DEVICE_NOCHANGE; 12378 } 12379 12380 12381 /* 12382 * Fillout New Name Server map 12383 */ 12384 static void 12385 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle, 12386 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id) 12387 { 12388 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12389 12390 if (handle) { 12391 ddi_rep_get8(*handle, (uint8_t *)&port_map->map_pwwn, 12392 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn), 12393 DDI_DEV_AUTOINCR); 12394 ddi_rep_get8(*handle, (uint8_t *)&port_map->map_nwwn, 12395 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn), 12396 DDI_DEV_AUTOINCR); 12397 ddi_rep_get8(*handle, (uint8_t *)port_map->map_fc4_types, 12398 (uint8_t *)gan_resp->gan_fc4types, 12399 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR); 12400 } else { 12401 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn, 12402 sizeof (gan_resp->gan_pwwn)); 12403 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn, 12404 sizeof (gan_resp->gan_nwwn)); 12405 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types, 12406 sizeof (gan_resp->gan_fc4types)); 12407 } 12408 port_map->map_did.port_id = d_id; 12409 port_map->map_did.priv_lilp_posit = 0; 12410 port_map->map_hard_addr.hard_addr = 0; 12411 port_map->map_hard_addr.rsvd = 0; 12412 port_map->map_state = PORT_DEVICE_INVALID; 12413 port_map->map_type = PORT_DEVICE_NEW; 12414 port_map->map_flags = 0; 12415 port_map->map_pd = NULL; 12416 12417 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn); 12418 12419 ASSERT(port != NULL); 12420 } 12421 12422 12423 /* 12424 * Perform LINIT ELS 12425 */ 12426 static int 12427 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep, 12428 job_request_t *job) 12429 { 12430 int rval; 12431 uint32_t d_id; 12432 uint32_t s_id; 12433 uint32_t lfa; 12434 uchar_t class; 12435 uint32_t ret; 12436 fp_cmd_t *cmd; 12437 fc_porttype_t ptype; 12438 fc_packet_t *pkt; 12439 fc_linit_req_t payload; 12440 fc_remote_port_t *pd; 12441 12442 rval = 0; 12443 12444 ASSERT(job != NULL); 12445 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12446 12447 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 12448 if (pd == NULL) { 12449 fctl_ns_req_t *ns_cmd; 12450 12451 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 12452 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 12453 0, sleep); 12454 12455 if (ns_cmd == NULL) { 12456 return (FC_NOMEM); 12457 } 12458 job->job_result = FC_SUCCESS; 12459 ns_cmd->ns_cmd_code = NS_GID_PN; 12460 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 12461 12462 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12463 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12464 fctl_free_ns_cmd(ns_cmd); 12465 return (FC_FAILURE); 12466 } 12467 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id)); 12468 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 12469 12470 fctl_free_ns_cmd(ns_cmd); 12471 lfa = d_id & 0xFFFF00; 12472 12473 /* 12474 * Given this D_ID, get the port type to see if 12475 * we can do LINIT on the LFA 12476 */ 12477 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t), 12478 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t), 12479 0, sleep); 12480 12481 if (ns_cmd == NULL) { 12482 return (FC_NOMEM); 12483 } 12484 12485 job->job_result = FC_SUCCESS; 12486 ns_cmd->ns_cmd_code = NS_GPT_ID; 12487 12488 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id; 12489 ((ns_req_gpt_id_t *) 12490 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 12491 12492 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12493 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12494 fctl_free_ns_cmd(ns_cmd); 12495 return (FC_FAILURE); 12496 } 12497 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype)); 12498 12499 fctl_free_ns_cmd(ns_cmd); 12500 12501 switch (ptype.port_type) { 12502 case FC_NS_PORT_NL: 12503 case FC_NS_PORT_F_NL: 12504 case FC_NS_PORT_FL: 12505 break; 12506 12507 default: 12508 return (FC_FAILURE); 12509 } 12510 } else { 12511 mutex_enter(&pd->pd_mutex); 12512 ptype = pd->pd_porttype; 12513 12514 switch (pd->pd_porttype.port_type) { 12515 case FC_NS_PORT_NL: 12516 case FC_NS_PORT_F_NL: 12517 case FC_NS_PORT_FL: 12518 lfa = pd->pd_port_id.port_id & 0xFFFF00; 12519 break; 12520 12521 default: 12522 mutex_exit(&pd->pd_mutex); 12523 return (FC_FAILURE); 12524 } 12525 mutex_exit(&pd->pd_mutex); 12526 } 12527 12528 mutex_enter(&port->fp_mutex); 12529 s_id = port->fp_port_id.port_id; 12530 class = port->fp_ns_login_class; 12531 mutex_exit(&port->fp_mutex); 12532 12533 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t), 12534 sizeof (fc_linit_resp_t), sleep, pd); 12535 if (cmd == NULL) { 12536 return (FC_NOMEM); 12537 } 12538 12539 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12540 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12541 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12542 cmd->cmd_retry_count = fp_retry_count; 12543 cmd->cmd_ulp_pkt = NULL; 12544 12545 pkt = &cmd->cmd_pkt; 12546 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12547 12548 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job); 12549 12550 /* 12551 * How does LIP work by the way ? 12552 * If the L_Port receives three consecutive identical ordered 12553 * sets whose first two characters (fully decoded) are equal to 12554 * the values shown in Table 3 of FC-AL-2 then the L_Port shall 12555 * recognize a Loop Initialization Primitive sequence. The 12556 * character 3 determines the type of lip: 12557 * LIP(F7) Normal LIP 12558 * LIP(F8) Loop Failure LIP 12559 * 12560 * The possible combination for the 3rd and 4th bytes are: 12561 * F7, F7 Normal Lip - No valid AL_PA 12562 * F8, F8 Loop Failure - No valid AL_PA 12563 * F7, AL_PS Normal Lip - Valid source AL_PA 12564 * F8, AL_PS Loop Failure - Valid source AL_PA 12565 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS 12566 * And Normal Lip for all other loop members 12567 * 0xFF AL_PS Vendor specific reset of all loop members 12568 * 12569 * Now, it may not always be that we, at the source, may have an 12570 * AL_PS (AL_PA of source) for 4th character slot, so we decide 12571 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT 12572 * payload we are going to set: 12573 * lip_b3 = 0xF7; Normal LIP 12574 * lip_b4 = 0xF7; No valid source AL_PA 12575 */ 12576 payload.ls_code.ls_code = LA_ELS_LINIT; 12577 payload.ls_code.mbz = 0; 12578 payload.rsvd = 0; 12579 payload.func = 0; /* Let Fabric determine the best way */ 12580 payload.lip_b3 = 0xF7; /* Normal LIP */ 12581 payload.lip_b4 = 0xF7; /* No valid source AL_PA */ 12582 12583 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 12584 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12585 12586 job->job_counter = 1; 12587 12588 ret = fp_sendcmd(port, cmd, port->fp_fca_handle); 12589 if (ret == FC_SUCCESS) { 12590 fp_jobwait(job); 12591 rval = job->job_result; 12592 } else { 12593 rval = FC_FAILURE; 12594 fp_free_pkt(cmd); 12595 } 12596 12597 return (rval); 12598 } 12599 12600 12601 /* 12602 * Fill out the device handles with GAN response 12603 */ 12604 static void 12605 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 12606 ns_resp_gan_t *gan_resp) 12607 { 12608 fc_remote_node_t *node; 12609 fc_porttype_t type; 12610 fc_local_port_t *port; 12611 12612 ASSERT(pd != NULL); 12613 ASSERT(handle != NULL); 12614 12615 port = pd->pd_port; 12616 12617 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p," 12618 " port_id=%x, sym_len=%d fc4-type=%x", 12619 pd, gan_resp->gan_type_id.rsvd, 12620 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]); 12621 12622 mutex_enter(&pd->pd_mutex); 12623 12624 ddi_rep_get8(*handle, (uint8_t *)&type, 12625 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR); 12626 12627 pd->pd_porttype.port_type = type.port_type; 12628 pd->pd_porttype.rsvd = 0; 12629 12630 pd->pd_spn_len = gan_resp->gan_spnlen; 12631 if (pd->pd_spn_len) { 12632 ddi_rep_get8(*handle, (uint8_t *)pd->pd_spn, 12633 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len, 12634 DDI_DEV_AUTOINCR); 12635 } 12636 12637 ddi_rep_get8(*handle, (uint8_t *)pd->pd_ip_addr, 12638 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr), 12639 DDI_DEV_AUTOINCR); 12640 ddi_rep_get8(*handle, (uint8_t *)&pd->pd_cos, 12641 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos), 12642 DDI_DEV_AUTOINCR); 12643 ddi_rep_get8(*handle, (uint8_t *)pd->pd_fc4types, 12644 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types), 12645 DDI_DEV_AUTOINCR); 12646 12647 node = pd->pd_remote_nodep; 12648 mutex_exit(&pd->pd_mutex); 12649 12650 mutex_enter(&node->fd_mutex); 12651 12652 ddi_rep_get8(*handle, (uint8_t *)node->fd_ipa, 12653 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa), 12654 DDI_DEV_AUTOINCR); 12655 12656 node->fd_snn_len = gan_resp->gan_snnlen; 12657 if (node->fd_snn_len) { 12658 ddi_rep_get8(*handle, (uint8_t *)node->fd_snn, 12659 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len, 12660 DDI_DEV_AUTOINCR); 12661 } 12662 12663 mutex_exit(&node->fd_mutex); 12664 } 12665 12666 12667 /* 12668 * Handles all NS Queries (also means that this function 12669 * doesn't handle NS object registration) 12670 */ 12671 static int 12672 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job, 12673 int polled, int sleep) 12674 { 12675 int rval; 12676 fp_cmd_t *cmd; 12677 12678 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12679 12680 if (ns_cmd->ns_cmd_size == 0) { 12681 return (FC_FAILURE); 12682 } 12683 12684 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 12685 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) + 12686 ns_cmd->ns_resp_size, sleep, NULL); 12687 if (cmd == NULL) { 12688 return (FC_NOMEM); 12689 } 12690 12691 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf, 12692 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job); 12693 12694 if (polled) { 12695 job->job_counter = 1; 12696 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12697 } 12698 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 12699 if (rval != FC_SUCCESS) { 12700 job->job_result = rval; 12701 fp_iodone(cmd); 12702 if (polled == 0) { 12703 /* 12704 * Return FC_SUCCESS to indicate that 12705 * fp_iodone is performed already. 12706 */ 12707 rval = FC_SUCCESS; 12708 } 12709 } 12710 12711 if (polled) { 12712 fp_jobwait(job); 12713 rval = job->job_result; 12714 } 12715 12716 return (rval); 12717 } 12718 12719 12720 /* 12721 * Initialize Common Transport request 12722 */ 12723 static void 12724 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd, 12725 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len, 12726 uint16_t resp_len, job_request_t *job) 12727 { 12728 uint32_t s_id; 12729 uchar_t class; 12730 fc_packet_t *pkt; 12731 fc_ct_header_t ct; 12732 12733 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12734 12735 mutex_enter(&port->fp_mutex); 12736 s_id = port->fp_port_id.port_id; 12737 class = port->fp_ns_login_class; 12738 mutex_exit(&port->fp_mutex); 12739 12740 cmd->cmd_job = job; 12741 cmd->cmd_private = ns_cmd; 12742 pkt = &cmd->cmd_pkt; 12743 12744 ct.ct_rev = CT_REV; 12745 ct.ct_inid = 0; 12746 ct.ct_fcstype = FCSTYPE_DIRECTORY; 12747 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER; 12748 ct.ct_options = 0; 12749 ct.ct_reserved1 = 0; 12750 ct.ct_cmdrsp = cmd_code; 12751 ct.ct_aiusize = resp_len >> 2; 12752 ct.ct_reserved2 = 0; 12753 ct.ct_reason = 0; 12754 ct.ct_expln = 0; 12755 ct.ct_vendor = 0; 12756 12757 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ct, (uint8_t *)pkt->pkt_cmd, 12758 sizeof (ct), DDI_DEV_AUTOINCR); 12759 12760 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 12761 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC; 12762 pkt->pkt_cmd_fhdr.s_id = s_id; 12763 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 12764 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | 12765 F_CTL_FIRST_SEQ | F_CTL_END_SEQ; 12766 pkt->pkt_cmd_fhdr.seq_id = 0; 12767 pkt->pkt_cmd_fhdr.df_ctl = 0; 12768 pkt->pkt_cmd_fhdr.seq_cnt = 0; 12769 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 12770 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 12771 pkt->pkt_cmd_fhdr.ro = 0; 12772 pkt->pkt_cmd_fhdr.rsvd = 0; 12773 12774 pkt->pkt_comp = fp_ns_intr; 12775 pkt->pkt_ulp_private = (opaque_t)cmd; 12776 pkt->pkt_timeout = FP_NS_TIMEOUT; 12777 12778 if (cmd_buf) { 12779 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)cmd_buf, 12780 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 12781 cmd_len, DDI_DEV_AUTOINCR); 12782 } 12783 12784 cmd->cmd_transport = port->fp_fca_tran->fca_transport; 12785 12786 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12787 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12788 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 12789 cmd->cmd_retry_count = fp_retry_count; 12790 cmd->cmd_ulp_pkt = NULL; 12791 } 12792 12793 12794 /* 12795 * Name Server request interrupt routine 12796 */ 12797 static void 12798 fp_ns_intr(fc_packet_t *pkt) 12799 { 12800 fp_cmd_t *cmd; 12801 fc_local_port_t *port; 12802 fc_ct_header_t resp_hdr; 12803 fc_ct_header_t cmd_hdr; 12804 fctl_ns_req_t *ns_cmd; 12805 12806 cmd = pkt->pkt_ulp_private; 12807 port = cmd->cmd_port; 12808 12809 ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr, 12810 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR); 12811 12812 ns_cmd = (fctl_ns_req_t *) 12813 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private); 12814 12815 if (!FP_IS_PKT_ERROR(pkt)) { 12816 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp_hdr, 12817 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr), 12818 DDI_DEV_AUTOINCR); 12819 12820 /* 12821 * On x86 architectures, make sure the resp_hdr is big endian. 12822 * This macro is a NOP on sparc architectures mainly because 12823 * we don't want to end up wasting time since the end result 12824 * is going to be the same. 12825 */ 12826 MAKE_BE_32(&resp_hdr); 12827 12828 if (ns_cmd) { 12829 /* 12830 * Always copy out the response CT_HDR 12831 */ 12832 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr, 12833 sizeof (resp_hdr)); 12834 } 12835 12836 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) { 12837 pkt->pkt_state = FC_PKT_FS_RJT; 12838 pkt->pkt_reason = resp_hdr.ct_reason; 12839 pkt->pkt_expln = resp_hdr.ct_expln; 12840 } 12841 } 12842 12843 if (FP_IS_PKT_ERROR(pkt)) { 12844 if (ns_cmd) { 12845 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 12846 ASSERT(ns_cmd->ns_pd != NULL); 12847 12848 /* Mark it OLD if not already done */ 12849 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 12850 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD; 12851 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 12852 } 12853 12854 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 12855 fctl_free_ns_cmd(ns_cmd); 12856 ((fp_cmd_t *) 12857 (pkt->pkt_ulp_private))->cmd_private = NULL; 12858 } 12859 12860 } 12861 12862 FP_TRACE(FP_NHEAD1(4, 0), "NS failure; pkt state=%x reason=%x", 12863 pkt->pkt_state, pkt->pkt_reason); 12864 12865 (void) fp_common_intr(pkt, 1); 12866 12867 return; 12868 } 12869 12870 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) { 12871 uint32_t d_id; 12872 fc_local_port_t *port; 12873 fp_cmd_t *cmd; 12874 12875 d_id = pkt->pkt_cmd_fhdr.d_id; 12876 cmd = pkt->pkt_ulp_private; 12877 port = cmd->cmd_port; 12878 FP_TRACE(FP_NHEAD2(9, 0), 12879 "Bogus NS response received for D_ID=%x", d_id); 12880 } 12881 12882 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) { 12883 fp_gan_handler(pkt, ns_cmd); 12884 return; 12885 } 12886 12887 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID && 12888 cmd_hdr.ct_cmdrsp <= NS_GID_PT) { 12889 if (ns_cmd) { 12890 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) { 12891 fp_ns_query_handler(pkt, ns_cmd); 12892 return; 12893 } 12894 } 12895 } 12896 12897 fp_iodone(pkt->pkt_ulp_private); 12898 } 12899 12900 12901 /* 12902 * Process NS_GAN response 12903 */ 12904 static void 12905 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 12906 { 12907 int my_did; 12908 fc_portid_t d_id; 12909 fp_cmd_t *cmd; 12910 fc_local_port_t *port; 12911 fc_remote_port_t *pd; 12912 ns_req_gan_t gan_req; 12913 ns_resp_gan_t *gan_resp; 12914 12915 ASSERT(ns_cmd != NULL); 12916 12917 cmd = pkt->pkt_ulp_private; 12918 port = cmd->cmd_port; 12919 12920 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t)); 12921 12922 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&d_id, 12923 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR); 12924 12925 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id); 12926 12927 /* 12928 * In this case the priv_lilp_posit field in reality 12929 * is actually represents the relative position on a private loop. 12930 * So zero it while dealing with Port Identifiers. 12931 */ 12932 d_id.priv_lilp_posit = 0; 12933 pd = fctl_get_remote_port_by_did(port, d_id.port_id); 12934 if (ns_cmd->ns_gan_sid == d_id.port_id) { 12935 /* 12936 * We've come a full circle; time to get out. 12937 */ 12938 fp_iodone(cmd); 12939 return; 12940 } 12941 12942 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) { 12943 ns_cmd->ns_gan_sid = d_id.port_id; 12944 } 12945 12946 mutex_enter(&port->fp_mutex); 12947 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0; 12948 mutex_exit(&port->fp_mutex); 12949 12950 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, d_id=%x", port, 12951 d_id.port_id); 12952 12953 if (my_did == 0) { 12954 la_wwn_t pwwn; 12955 la_wwn_t nwwn; 12956 12957 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; " 12958 "port=%p, d_id=%x, type_id=%x, " 12959 "pwwn=%x %x %x %x %x %x %x %x, " 12960 "nwwn=%x %x %x %x %x %x %x %x", 12961 port, d_id.port_id, gan_resp->gan_type_id, 12962 12963 gan_resp->gan_pwwn.raw_wwn[0], 12964 gan_resp->gan_pwwn.raw_wwn[1], 12965 gan_resp->gan_pwwn.raw_wwn[2], 12966 gan_resp->gan_pwwn.raw_wwn[3], 12967 gan_resp->gan_pwwn.raw_wwn[4], 12968 gan_resp->gan_pwwn.raw_wwn[5], 12969 gan_resp->gan_pwwn.raw_wwn[6], 12970 gan_resp->gan_pwwn.raw_wwn[7], 12971 12972 gan_resp->gan_nwwn.raw_wwn[0], 12973 gan_resp->gan_nwwn.raw_wwn[1], 12974 gan_resp->gan_nwwn.raw_wwn[2], 12975 gan_resp->gan_nwwn.raw_wwn[3], 12976 gan_resp->gan_nwwn.raw_wwn[4], 12977 gan_resp->gan_nwwn.raw_wwn[5], 12978 gan_resp->gan_nwwn.raw_wwn[6], 12979 gan_resp->gan_nwwn.raw_wwn[7]); 12980 12981 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn, 12982 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn), 12983 DDI_DEV_AUTOINCR); 12984 12985 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn, 12986 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn), 12987 DDI_DEV_AUTOINCR); 12988 12989 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) { 12990 pd = fctl_create_remote_port(port, &nwwn, &pwwn, 12991 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); 12992 } 12993 if (pd != NULL) { 12994 fp_stuff_device_with_gan(&pkt->pkt_resp_acc, 12995 pd, gan_resp); 12996 } 12997 12998 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) { 12999 *((int *)ns_cmd->ns_data_buf) += 1; 13000 } 13001 13002 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) { 13003 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0); 13004 13005 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) { 13006 fc_port_dev_t *userbuf; 13007 13008 userbuf = ((fc_port_dev_t *) 13009 ns_cmd->ns_data_buf) + 13010 ns_cmd->ns_gan_index++; 13011 13012 userbuf->dev_did = d_id; 13013 13014 ddi_rep_get8(pkt->pkt_resp_acc, 13015 (uint8_t *)userbuf->dev_type, 13016 (uint8_t *)gan_resp->gan_fc4types, 13017 sizeof (userbuf->dev_type), 13018 DDI_DEV_AUTOINCR); 13019 13020 userbuf->dev_nwwn = nwwn; 13021 userbuf->dev_pwwn = pwwn; 13022 13023 if (pd != NULL) { 13024 mutex_enter(&pd->pd_mutex); 13025 userbuf->dev_state = pd->pd_state; 13026 userbuf->dev_hard_addr = 13027 pd->pd_hard_addr; 13028 mutex_exit(&pd->pd_mutex); 13029 } else { 13030 userbuf->dev_state = 13031 PORT_DEVICE_INVALID; 13032 } 13033 } else if (ns_cmd->ns_flags & 13034 FCTL_NS_BUF_IS_FC_PORTMAP) { 13035 fc_portmap_t *map; 13036 13037 map = ((fc_portmap_t *) 13038 ns_cmd->ns_data_buf) + 13039 ns_cmd->ns_gan_index++; 13040 13041 /* 13042 * First fill it like any new map 13043 * and update the port device info 13044 * below. 13045 */ 13046 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc, 13047 map, gan_resp, d_id.port_id); 13048 if (pd != NULL) { 13049 fctl_copy_portmap(map, pd); 13050 } else { 13051 map->map_state = PORT_DEVICE_INVALID; 13052 map->map_type = PORT_DEVICE_NOCHANGE; 13053 } 13054 } else { 13055 caddr_t dst_ptr; 13056 13057 dst_ptr = ns_cmd->ns_data_buf + 13058 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++; 13059 13060 ddi_rep_get8(pkt->pkt_resp_acc, 13061 (uint8_t *)dst_ptr, (uint8_t *)gan_resp, 13062 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR); 13063 } 13064 } else { 13065 ns_cmd->ns_gan_index++; 13066 } 13067 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) { 13068 fp_iodone(cmd); 13069 return; 13070 } 13071 } 13072 13073 gan_req.pid = d_id; 13074 13075 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&gan_req, 13076 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13077 sizeof (gan_req), DDI_DEV_AUTOINCR); 13078 13079 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) { 13080 pkt->pkt_state = FC_PKT_TRAN_ERROR; 13081 fp_iodone(cmd); 13082 } 13083 } 13084 13085 13086 /* 13087 * Handle NS Query interrupt 13088 */ 13089 static void 13090 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13091 { 13092 fp_cmd_t *cmd; 13093 fc_local_port_t *port; 13094 caddr_t src_ptr; 13095 uint32_t xfer_len; 13096 13097 cmd = pkt->pkt_ulp_private; 13098 port = cmd->cmd_port; 13099 13100 xfer_len = ns_cmd->ns_resp_size; 13101 13102 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x", 13103 ns_cmd->ns_cmd_code, xfer_len); 13104 13105 if (ns_cmd->ns_cmd_code == NS_GPN_ID) { 13106 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13107 13108 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x", 13109 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]); 13110 } 13111 13112 if (xfer_len <= ns_cmd->ns_data_len) { 13113 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13114 ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)ns_cmd->ns_data_buf, 13115 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR); 13116 } 13117 13118 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13119 ASSERT(ns_cmd->ns_pd != NULL); 13120 13121 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13122 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) { 13123 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE; 13124 } 13125 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13126 } 13127 13128 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13129 fctl_free_ns_cmd(ns_cmd); 13130 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL; 13131 } 13132 fp_iodone(cmd); 13133 } 13134 13135 13136 /* 13137 * Handle unsolicited ADISC ELS request 13138 */ 13139 static void 13140 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf, 13141 fc_remote_port_t *pd, job_request_t *job) 13142 { 13143 int rval; 13144 fp_cmd_t *cmd; 13145 13146 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p", 13147 port, pd->pd_port_id.port_id, pd->pd_state, pd); 13148 mutex_enter(&pd->pd_mutex); 13149 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 13150 mutex_exit(&pd->pd_mutex); 13151 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 13152 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 13153 0, KM_SLEEP, pd); 13154 if (cmd != NULL) { 13155 fp_els_rjt_init(port, cmd, buf, 13156 FC_ACTION_NON_RETRYABLE, 13157 FC_REASON_INVALID_LINK_CTRL, job); 13158 13159 if (fp_sendcmd(port, cmd, 13160 port->fp_fca_handle) != FC_SUCCESS) { 13161 fp_free_pkt(cmd); 13162 } 13163 } 13164 } 13165 } else { 13166 mutex_exit(&pd->pd_mutex); 13167 /* 13168 * Yes, yes, we don't have a hard address. But we 13169 * we should still respond. Huh ? Visit 21.19.2 13170 * of FC-PH-2 which essentially says that if an 13171 * NL_Port doesn't have a hard address, or if a port 13172 * does not have FC-AL capability, it shall report 13173 * zeroes in this field. 13174 */ 13175 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 13176 0, KM_SLEEP, pd); 13177 if (cmd == NULL) { 13178 return; 13179 } 13180 fp_adisc_acc_init(port, cmd, buf, job); 13181 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13182 if (rval != FC_SUCCESS) { 13183 fp_free_pkt(cmd); 13184 } 13185 } 13186 } 13187 13188 13189 /* 13190 * Initialize ADISC response. 13191 */ 13192 static void 13193 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 13194 job_request_t *job) 13195 { 13196 fc_packet_t *pkt; 13197 la_els_adisc_t payload; 13198 13199 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 13200 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 13201 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 13202 cmd->cmd_retry_count = 1; 13203 cmd->cmd_ulp_pkt = NULL; 13204 13205 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 13206 cmd->cmd_job = job; 13207 13208 pkt = &cmd->cmd_pkt; 13209 13210 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 13211 13212 payload.ls_code.ls_code = LA_ELS_ACC; 13213 payload.ls_code.mbz = 0; 13214 13215 mutex_enter(&port->fp_mutex); 13216 payload.nport_id = port->fp_port_id; 13217 payload.hard_addr = port->fp_hard_addr; 13218 mutex_exit(&port->fp_mutex); 13219 13220 payload.port_wwn = port->fp_service_params.nport_ww_name; 13221 payload.node_wwn = port->fp_service_params.node_ww_name; 13222 13223 ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload, 13224 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 13225 } 13226 13227 13228 /* 13229 * Hold and Install the requested ULP drivers 13230 */ 13231 static void 13232 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port) 13233 { 13234 int len; 13235 int count; 13236 int data_len; 13237 major_t ulp_major; 13238 caddr_t ulp_name; 13239 caddr_t data_ptr; 13240 caddr_t data_buf; 13241 13242 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13243 13244 data_buf = NULL; 13245 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 13246 DDI_PROP_DONTPASS, "load-ulp-list", 13247 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) { 13248 return; 13249 } 13250 13251 len = strlen(data_buf); 13252 port->fp_ulp_nload = fctl_atoi(data_buf, 10); 13253 13254 data_ptr = data_buf + len + 1; 13255 for (count = 0; count < port->fp_ulp_nload; count++) { 13256 len = strlen(data_ptr) + 1; 13257 ulp_name = kmem_zalloc(len, KM_SLEEP); 13258 bcopy(data_ptr, ulp_name, len); 13259 13260 ulp_major = ddi_name_to_major(ulp_name); 13261 13262 if (ulp_major != (major_t)-1) { 13263 if (modload("drv", ulp_name) < 0) { 13264 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 13265 0, NULL, "failed to load %s", 13266 ulp_name); 13267 } 13268 } else { 13269 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 13270 "%s isn't a valid driver", ulp_name); 13271 } 13272 13273 kmem_free(ulp_name, len); 13274 data_ptr += len; /* Skip to next field */ 13275 } 13276 13277 /* 13278 * Free the memory allocated by DDI 13279 */ 13280 if (data_buf != NULL) { 13281 kmem_free(data_buf, data_len); 13282 } 13283 } 13284 13285 13286 /* 13287 * Perform LOGO operation 13288 */ 13289 static int 13290 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job) 13291 { 13292 int rval; 13293 fp_cmd_t *cmd; 13294 13295 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13296 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 13297 13298 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 13299 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 13300 13301 mutex_enter(&port->fp_mutex); 13302 mutex_enter(&pd->pd_mutex); 13303 13304 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN); 13305 ASSERT(pd->pd_login_count == 1); 13306 13307 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 13308 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13309 cmd->cmd_flags = 0; 13310 cmd->cmd_retry_count = 1; 13311 cmd->cmd_ulp_pkt = NULL; 13312 13313 fp_logo_init(pd, cmd, job); 13314 13315 mutex_exit(&pd->pd_mutex); 13316 mutex_exit(&port->fp_mutex); 13317 13318 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13319 if (rval != FC_SUCCESS) { 13320 fp_iodone(cmd); 13321 } 13322 13323 return (rval); 13324 } 13325 13326 13327 /* 13328 * Perform Port attach callbacks to registered ULPs 13329 */ 13330 static void 13331 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd) 13332 { 13333 fp_soft_attach_t *att; 13334 13335 att = kmem_zalloc(sizeof (*att), KM_SLEEP); 13336 att->att_cmd = cmd; 13337 att->att_port = port; 13338 13339 /* 13340 * We need to remember whether or not fctl_busy_port 13341 * succeeded so we know whether or not to call 13342 * fctl_idle_port when the task is complete. 13343 */ 13344 13345 if (fctl_busy_port(port) == 0) { 13346 att->att_need_pm_idle = B_TRUE; 13347 } else { 13348 att->att_need_pm_idle = B_FALSE; 13349 } 13350 13351 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach, 13352 att, KM_SLEEP); 13353 } 13354 13355 13356 /* 13357 * Forward state change notifications on to interested ULPs. 13358 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the 13359 * real work. 13360 */ 13361 static int 13362 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep) 13363 { 13364 fc_port_clist_t *clist; 13365 13366 clist = kmem_zalloc(sizeof (*clist), sleep); 13367 if (clist == NULL) { 13368 return (FC_NOMEM); 13369 } 13370 13371 clist->clist_state = statec; 13372 13373 mutex_enter(&port->fp_mutex); 13374 clist->clist_flags = port->fp_topology; 13375 mutex_exit(&port->fp_mutex); 13376 13377 clist->clist_port = (opaque_t)port; 13378 clist->clist_len = 0; 13379 clist->clist_size = 0; 13380 clist->clist_map = NULL; 13381 13382 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 13383 clist, KM_SLEEP); 13384 13385 return (FC_SUCCESS); 13386 } 13387 13388 13389 /* 13390 * Get name server map 13391 */ 13392 static int 13393 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map, 13394 uint32_t *len, uint32_t sid) 13395 { 13396 int ret; 13397 fctl_ns_req_t *ns_cmd; 13398 13399 /* 13400 * Don't let the allocator do anything for response; 13401 * we have have buffer ready to fillout. 13402 */ 13403 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13404 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP | 13405 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP); 13406 13407 ns_cmd->ns_data_len = sizeof (**map) * (*len); 13408 ns_cmd->ns_data_buf = (caddr_t)*map; 13409 13410 ASSERT(ns_cmd != NULL); 13411 13412 ns_cmd->ns_gan_index = 0; 13413 ns_cmd->ns_gan_sid = sid; 13414 ns_cmd->ns_cmd_code = NS_GA_NXT; 13415 ns_cmd->ns_gan_max = *len; 13416 13417 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13418 13419 if (ns_cmd->ns_gan_index != *len) { 13420 *len = ns_cmd->ns_gan_index; 13421 } 13422 ns_cmd->ns_data_len = 0; 13423 ns_cmd->ns_data_buf = NULL; 13424 fctl_free_ns_cmd(ns_cmd); 13425 13426 return (ret); 13427 } 13428 13429 13430 /* 13431 * Create a remote port in Fabric topology by using NS services 13432 */ 13433 static fc_remote_port_t * 13434 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep) 13435 { 13436 int rval; 13437 job_request_t *job; 13438 fctl_ns_req_t *ns_cmd; 13439 fc_remote_port_t *pd; 13440 13441 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13442 13443 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x", 13444 port, d_id); 13445 13446 #ifdef DEBUG 13447 mutex_enter(&port->fp_mutex); 13448 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 13449 mutex_exit(&port->fp_mutex); 13450 #endif 13451 13452 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep); 13453 if (job == NULL) { 13454 return (NULL); 13455 } 13456 13457 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13458 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE | 13459 FCTL_NS_NO_DATA_BUF), sleep); 13460 if (ns_cmd == NULL) { 13461 return (NULL); 13462 } 13463 13464 job->job_result = FC_SUCCESS; 13465 ns_cmd->ns_gan_max = 1; 13466 ns_cmd->ns_cmd_code = NS_GA_NXT; 13467 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 13468 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 13469 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 13470 13471 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 13472 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13473 fctl_free_ns_cmd(ns_cmd); 13474 13475 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) { 13476 fctl_dealloc_job(job); 13477 return (NULL); 13478 } 13479 fctl_dealloc_job(job); 13480 13481 pd = fctl_get_remote_port_by_did(port, d_id); 13482 13483 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p", 13484 port, d_id, pd); 13485 13486 return (pd); 13487 } 13488 13489 13490 /* 13491 * Check for the permissions on an ioctl command. If it is required to have an 13492 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If 13493 * the ioctl command isn't in one of the list built, shut the door on that too. 13494 * 13495 * Certain ioctls perform hardware accesses in FCA drivers, and it needs 13496 * to be made sure that users open the port for an exclusive access while 13497 * performing those operations. 13498 * 13499 * This can prevent a casual user from inflicting damage on the port by 13500 * sending these ioctls from multiple processes/threads (there is no good 13501 * reason why one would need to do that) without actually realizing how 13502 * expensive such commands could turn out to be. 13503 * 13504 * It is also important to note that, even with an exclusive access, 13505 * multiple threads can share the same file descriptor and fire down 13506 * commands in parallel. To prevent that the driver needs to make sure 13507 * that such commands aren't in progress already. This is taken care of 13508 * in the FP_EXCL_BUSY bit of fp_flag. 13509 */ 13510 static int 13511 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd) 13512 { 13513 int ret = FC_FAILURE; 13514 int count; 13515 13516 for (count = 0; 13517 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]); 13518 count++) { 13519 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) { 13520 if (fp_perm_list[count].fp_open_flag & open_flag) { 13521 ret = FC_SUCCESS; 13522 } 13523 break; 13524 } 13525 } 13526 13527 return (ret); 13528 } 13529 13530 13531 /* 13532 * Bind Port driver's unsolicited, state change callbacks 13533 */ 13534 static int 13535 fp_bind_callbacks(fc_local_port_t *port) 13536 { 13537 fc_fca_bind_info_t bind_info = {0}; 13538 fc_fca_port_info_t *port_info; 13539 int rval = DDI_SUCCESS; 13540 uint16_t class; 13541 int node_namelen, port_namelen; 13542 char *nname = NULL, *pname = NULL; 13543 13544 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13545 13546 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13547 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13548 "node-name", &nname) != DDI_PROP_SUCCESS) { 13549 FP_TRACE(FP_NHEAD1(1, 0), 13550 "fp_bind_callback fail to get node-name"); 13551 } 13552 if (nname) { 13553 fc_str_to_wwn(nname, &(bind_info.port_nwwn)); 13554 } 13555 13556 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13557 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13558 "port-name", &pname) != DDI_PROP_SUCCESS) { 13559 FP_TRACE(FP_NHEAD1(1, 0), 13560 "fp_bind_callback fail to get port-name"); 13561 } 13562 if (pname) { 13563 fc_str_to_wwn(pname, &(bind_info.port_pwwn)); 13564 } 13565 13566 if (port->fp_npiv_type == FC_NPIV_PORT) { 13567 bind_info.port_npiv = 1; 13568 } 13569 13570 /* 13571 * fca_bind_port returns the FCA driver's handle for the local 13572 * port instance. If the port number isn't supported it returns NULL. 13573 * It also sets up callback in the FCA for various 13574 * things like state change, ELS etc.. 13575 */ 13576 bind_info.port_statec_cb = fp_statec_cb; 13577 bind_info.port_unsol_cb = fp_unsol_cb; 13578 bind_info.port_num = port->fp_port_num; 13579 bind_info.port_handle = (opaque_t)port; 13580 13581 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP); 13582 13583 /* 13584 * Hold the port driver mutex as the callbacks are bound until the 13585 * service parameters are properly filled in (in order to be able to 13586 * properly respond to unsolicited ELS requests) 13587 */ 13588 mutex_enter(&port->fp_mutex); 13589 13590 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port( 13591 port->fp_fca_dip, port_info, &bind_info); 13592 13593 if (port->fp_fca_handle == NULL) { 13594 rval = DDI_FAILURE; 13595 goto exit; 13596 } 13597 13598 port->fp_bind_state = port->fp_state = port_info->pi_port_state; 13599 port->fp_service_params = port_info->pi_login_params; 13600 port->fp_hard_addr = port_info->pi_hard_addr; 13601 13602 /* Copy from the FCA structure to the FP structure */ 13603 port->fp_hba_port_attrs = port_info->pi_attrs; 13604 13605 if (port_info->pi_rnid_params.status == FC_SUCCESS) { 13606 port->fp_rnid_init = 1; 13607 bcopy(&port_info->pi_rnid_params.params, 13608 &port->fp_rnid_params, 13609 sizeof (port->fp_rnid_params)); 13610 } else { 13611 port->fp_rnid_init = 0; 13612 } 13613 13614 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name); 13615 if (node_namelen) { 13616 bcopy(&port_info->pi_attrs.sym_node_name, 13617 &port->fp_sym_node_name, 13618 node_namelen); 13619 port->fp_sym_node_namelen = node_namelen; 13620 } 13621 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name); 13622 if (port_namelen) { 13623 bcopy(&port_info->pi_attrs.sym_port_name, 13624 &port->fp_sym_port_name, 13625 port_namelen); 13626 port->fp_sym_port_namelen = port_namelen; 13627 } 13628 13629 /* zero out the normally unused fields right away */ 13630 port->fp_service_params.ls_code.mbz = 0; 13631 port->fp_service_params.ls_code.ls_code = 0; 13632 bzero(&port->fp_service_params.reserved, 13633 sizeof (port->fp_service_params.reserved)); 13634 13635 class = port_info->pi_login_params.class_1.class_opt; 13636 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0; 13637 13638 class = port_info->pi_login_params.class_2.class_opt; 13639 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0; 13640 13641 class = port_info->pi_login_params.class_3.class_opt; 13642 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0; 13643 13644 exit: 13645 if (nname) { 13646 ddi_prop_free(nname); 13647 } 13648 if (pname) { 13649 ddi_prop_free(pname); 13650 } 13651 mutex_exit(&port->fp_mutex); 13652 kmem_free(port_info, sizeof (*port_info)); 13653 13654 return (rval); 13655 } 13656 13657 13658 /* 13659 * Retrieve FCA capabilities 13660 */ 13661 static void 13662 fp_retrieve_caps(fc_local_port_t *port) 13663 { 13664 int rval; 13665 int ub_count; 13666 fc_fcp_dma_t fcp_dma; 13667 fc_reset_action_t action; 13668 fc_dma_behavior_t dma_behavior; 13669 13670 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13671 13672 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13673 FC_CAP_UNSOL_BUF, &ub_count); 13674 13675 switch (rval) { 13676 case FC_CAP_FOUND: 13677 case FC_CAP_SETTABLE: 13678 switch (ub_count) { 13679 case 0: 13680 break; 13681 13682 case -1: 13683 ub_count = fp_unsol_buf_count; 13684 break; 13685 13686 default: 13687 /* 1/4th of total buffers is my share */ 13688 ub_count = 13689 (ub_count / port->fp_fca_tran->fca_numports) >> 2; 13690 break; 13691 } 13692 break; 13693 13694 default: 13695 ub_count = 0; 13696 break; 13697 } 13698 13699 mutex_enter(&port->fp_mutex); 13700 port->fp_ub_count = ub_count; 13701 mutex_exit(&port->fp_mutex); 13702 13703 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13704 FC_CAP_POST_RESET_BEHAVIOR, &action); 13705 13706 switch (rval) { 13707 case FC_CAP_FOUND: 13708 case FC_CAP_SETTABLE: 13709 switch (action) { 13710 case FC_RESET_RETURN_NONE: 13711 case FC_RESET_RETURN_ALL: 13712 case FC_RESET_RETURN_OUTSTANDING: 13713 break; 13714 13715 default: 13716 action = FC_RESET_RETURN_NONE; 13717 break; 13718 } 13719 break; 13720 13721 default: 13722 action = FC_RESET_RETURN_NONE; 13723 break; 13724 } 13725 mutex_enter(&port->fp_mutex); 13726 port->fp_reset_action = action; 13727 mutex_exit(&port->fp_mutex); 13728 13729 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13730 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior); 13731 13732 switch (rval) { 13733 case FC_CAP_FOUND: 13734 switch (dma_behavior) { 13735 case FC_ALLOW_STREAMING: 13736 /* FALLTHROUGH */ 13737 case FC_NO_STREAMING: 13738 break; 13739 13740 default: 13741 /* 13742 * If capability was found and the value 13743 * was incorrect assume the worst 13744 */ 13745 dma_behavior = FC_NO_STREAMING; 13746 break; 13747 } 13748 break; 13749 13750 default: 13751 /* 13752 * If capability was not defined - allow streaming; existing 13753 * FCAs should not be affected. 13754 */ 13755 dma_behavior = FC_ALLOW_STREAMING; 13756 break; 13757 } 13758 mutex_enter(&port->fp_mutex); 13759 port->fp_dma_behavior = dma_behavior; 13760 mutex_exit(&port->fp_mutex); 13761 13762 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13763 FC_CAP_FCP_DMA, &fcp_dma); 13764 13765 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE && 13766 fcp_dma != FC_DVMA_SPACE)) { 13767 fcp_dma = FC_DVMA_SPACE; 13768 } 13769 13770 mutex_enter(&port->fp_mutex); 13771 port->fp_fcp_dma = fcp_dma; 13772 mutex_exit(&port->fp_mutex); 13773 } 13774 13775 13776 /* 13777 * Handle Domain, Area changes in the Fabric. 13778 */ 13779 static void 13780 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask, 13781 job_request_t *job, int sleep) 13782 { 13783 #ifdef DEBUG 13784 uint32_t dcnt; 13785 #endif 13786 int rval; 13787 int send; 13788 int index; 13789 int listindex; 13790 int login; 13791 int job_flags; 13792 char ww_name[17]; 13793 uint32_t d_id; 13794 uint32_t count; 13795 fctl_ns_req_t *ns_cmd; 13796 fc_portmap_t *list; 13797 fc_orphan_t *orp; 13798 fc_orphan_t *norp; 13799 fc_orphan_t *prev; 13800 fc_remote_port_t *pd; 13801 fc_remote_port_t *npd; 13802 struct pwwn_hash *head; 13803 13804 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 13805 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 13806 0, sleep); 13807 if (ns_cmd == NULL) { 13808 mutex_enter(&port->fp_mutex); 13809 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 13810 --port->fp_rscn_count; 13811 } 13812 mutex_exit(&port->fp_mutex); 13813 13814 return; 13815 } 13816 ns_cmd->ns_cmd_code = NS_GID_PN; 13817 13818 /* 13819 * We need to get a new count of devices from the 13820 * name server, which will also create any new devices 13821 * as needed. 13822 */ 13823 13824 (void) fp_ns_get_devcount(port, job, 1, sleep); 13825 13826 FP_TRACE(FP_NHEAD1(3, 0), 13827 "fp_validate_area_domain: get_devcount found %d devices", 13828 port->fp_total_devices); 13829 13830 mutex_enter(&port->fp_mutex); 13831 13832 for (count = index = 0; index < pwwn_table_size; index++) { 13833 head = &port->fp_pwwn_table[index]; 13834 pd = head->pwwn_head; 13835 while (pd != NULL) { 13836 mutex_enter(&pd->pd_mutex); 13837 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 13838 if ((pd->pd_port_id.port_id & mask) == id && 13839 pd->pd_recepient == PD_PLOGI_INITIATOR) { 13840 count++; 13841 pd->pd_type = PORT_DEVICE_OLD; 13842 pd->pd_flags = PD_ELS_MARK; 13843 } 13844 } 13845 mutex_exit(&pd->pd_mutex); 13846 pd = pd->pd_wwn_hnext; 13847 } 13848 } 13849 13850 #ifdef DEBUG 13851 dcnt = count; 13852 #endif /* DEBUG */ 13853 13854 /* 13855 * Since port->fp_orphan_count is declared an 'int' it is 13856 * theoretically possible that the count could go negative. 13857 * 13858 * This would be bad and if that happens we really do want 13859 * to know. 13860 */ 13861 13862 ASSERT(port->fp_orphan_count >= 0); 13863 13864 count += port->fp_orphan_count; 13865 13866 /* 13867 * We add the port->fp_total_devices value to the count 13868 * in the case where our port is newly attached. This is 13869 * because we haven't done any discovery and we don't have 13870 * any orphans in the port's orphan list. If we do not do 13871 * this addition to count then we won't alloc enough kmem 13872 * to do discovery with. 13873 */ 13874 13875 if (count == 0) { 13876 count += port->fp_total_devices; 13877 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: " 13878 "0x%x orphans found, using 0x%x", 13879 port->fp_orphan_count, count); 13880 } 13881 13882 mutex_exit(&port->fp_mutex); 13883 13884 /* 13885 * Allocate the change list 13886 */ 13887 13888 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 13889 if (list == NULL) { 13890 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 13891 " Not enough memory to service RSCNs" 13892 " for %d ports, continuing...", count); 13893 13894 fctl_free_ns_cmd(ns_cmd); 13895 13896 mutex_enter(&port->fp_mutex); 13897 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 13898 --port->fp_rscn_count; 13899 } 13900 mutex_exit(&port->fp_mutex); 13901 13902 return; 13903 } 13904 13905 /* 13906 * Attempt to validate or invalidate the devices that were 13907 * already in the pwwn hash table. 13908 */ 13909 13910 mutex_enter(&port->fp_mutex); 13911 for (listindex = 0, index = 0; index < pwwn_table_size; index++) { 13912 head = &port->fp_pwwn_table[index]; 13913 npd = head->pwwn_head; 13914 13915 while ((pd = npd) != NULL) { 13916 npd = pd->pd_wwn_hnext; 13917 13918 mutex_enter(&pd->pd_mutex); 13919 if ((pd->pd_port_id.port_id & mask) == id && 13920 pd->pd_flags == PD_ELS_MARK) { 13921 la_wwn_t *pwwn; 13922 13923 job->job_result = FC_SUCCESS; 13924 13925 ((ns_req_gid_pn_t *) 13926 (ns_cmd->ns_cmd_buf))->pwwn = 13927 pd->pd_port_name; 13928 13929 pwwn = &pd->pd_port_name; 13930 d_id = pd->pd_port_id.port_id; 13931 13932 mutex_exit(&pd->pd_mutex); 13933 mutex_exit(&port->fp_mutex); 13934 13935 rval = fp_ns_query(port, ns_cmd, job, 1, 13936 sleep); 13937 if (rval != FC_SUCCESS) { 13938 fc_wwn_to_str(pwwn, ww_name); 13939 13940 FP_TRACE(FP_NHEAD1(3, 0), 13941 "AREA RSCN: PD disappeared; " 13942 "d_id=%x, PWWN=%s", d_id, ww_name); 13943 13944 FP_TRACE(FP_NHEAD2(9, 0), 13945 "N_x Port with D_ID=%x," 13946 " PWWN=%s disappeared from fabric", 13947 d_id, ww_name); 13948 13949 fp_fillout_old_map(list + listindex++, 13950 pd, 1); 13951 } else { 13952 fctl_copy_portmap(list + listindex++, 13953 pd); 13954 13955 mutex_enter(&pd->pd_mutex); 13956 pd->pd_flags = PD_ELS_IN_PROGRESS; 13957 mutex_exit(&pd->pd_mutex); 13958 } 13959 13960 mutex_enter(&port->fp_mutex); 13961 } else { 13962 mutex_exit(&pd->pd_mutex); 13963 } 13964 } 13965 } 13966 13967 mutex_exit(&port->fp_mutex); 13968 13969 ASSERT(listindex == dcnt); 13970 13971 job->job_counter = listindex; 13972 job_flags = job->job_flags; 13973 job->job_flags |= JOB_TYPE_FP_ASYNC; 13974 13975 /* 13976 * Login (if we were the initiator) or validate devices in the 13977 * port map. 13978 */ 13979 13980 for (index = 0; index < listindex; index++) { 13981 pd = list[index].map_pd; 13982 13983 mutex_enter(&pd->pd_mutex); 13984 ASSERT((pd->pd_port_id.port_id & mask) == id); 13985 13986 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 13987 ASSERT(pd->pd_type == PORT_DEVICE_OLD); 13988 mutex_exit(&pd->pd_mutex); 13989 fp_jobdone(job); 13990 continue; 13991 } 13992 13993 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0; 13994 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 13995 d_id = pd->pd_port_id.port_id; 13996 mutex_exit(&pd->pd_mutex); 13997 13998 if ((d_id & mask) == id && send) { 13999 if (login) { 14000 FP_TRACE(FP_NHEAD1(6, 0), 14001 "RSCN and PLOGI request;" 14002 " pd=%p, job=%p d_id=%x, index=%d", pd, 14003 job, d_id, index); 14004 14005 rval = fp_port_login(port, d_id, job, 14006 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL); 14007 if (rval != FC_SUCCESS) { 14008 mutex_enter(&pd->pd_mutex); 14009 pd->pd_flags = PD_IDLE; 14010 mutex_exit(&pd->pd_mutex); 14011 14012 job->job_result = rval; 14013 fp_jobdone(job); 14014 } 14015 14016 FP_TRACE(FP_NHEAD2(4, 0), 14017 "PLOGI succeeded:no skip(1) for " 14018 "D_ID %x", d_id); 14019 list[index].map_flags |= 14020 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14021 } else { 14022 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;" 14023 " pd=%p, job=%p d_id=%x, index=%d", pd, 14024 job, d_id, index); 14025 14026 rval = fp_ns_validate_device(port, pd, job, 14027 0, sleep); 14028 if (rval != FC_SUCCESS) { 14029 fp_jobdone(job); 14030 } 14031 mutex_enter(&pd->pd_mutex); 14032 pd->pd_flags = PD_IDLE; 14033 mutex_exit(&pd->pd_mutex); 14034 } 14035 } else { 14036 FP_TRACE(FP_NHEAD1(6, 0), 14037 "RSCN and NO request sent; pd=%p," 14038 " d_id=%x, index=%d", pd, d_id, index); 14039 14040 mutex_enter(&pd->pd_mutex); 14041 pd->pd_flags = PD_IDLE; 14042 mutex_exit(&pd->pd_mutex); 14043 14044 fp_jobdone(job); 14045 } 14046 } 14047 14048 if (listindex) { 14049 fctl_jobwait(job); 14050 } 14051 job->job_flags = job_flags; 14052 14053 /* 14054 * Orphan list validation. 14055 */ 14056 mutex_enter(&port->fp_mutex); 14057 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count && 14058 orp != NULL; orp = norp) { 14059 norp = orp->orp_next; 14060 mutex_exit(&port->fp_mutex); 14061 14062 job->job_counter = 1; 14063 job->job_result = FC_SUCCESS; 14064 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 14065 14066 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn; 14067 14068 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14069 ((ns_resp_gid_pn_t *) 14070 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14071 14072 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 14073 if (rval == FC_SUCCESS) { 14074 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 14075 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 14076 if (pd != NULL) { 14077 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 14078 14079 FP_TRACE(FP_NHEAD1(6, 0), 14080 "RSCN and ORPHAN list " 14081 "success; d_id=%x, PWWN=%s", d_id, ww_name); 14082 14083 FP_TRACE(FP_NHEAD2(6, 0), 14084 "N_x Port with D_ID=%x, PWWN=%s reappeared" 14085 " in fabric", d_id, ww_name); 14086 14087 mutex_enter(&port->fp_mutex); 14088 if (prev) { 14089 prev->orp_next = orp->orp_next; 14090 } else { 14091 ASSERT(orp == port->fp_orphan_list); 14092 port->fp_orphan_list = orp->orp_next; 14093 } 14094 port->fp_orphan_count--; 14095 mutex_exit(&port->fp_mutex); 14096 14097 kmem_free(orp, sizeof (*orp)); 14098 fctl_copy_portmap(list + listindex++, pd); 14099 } else { 14100 prev = orp; 14101 } 14102 } else { 14103 prev = orp; 14104 } 14105 mutex_enter(&port->fp_mutex); 14106 } 14107 mutex_exit(&port->fp_mutex); 14108 14109 /* 14110 * One more pass through the list to delist old devices from 14111 * the d_id and pwwn tables and possibly add to the orphan list. 14112 */ 14113 14114 for (index = 0; index < listindex; index++) { 14115 pd = list[index].map_pd; 14116 ASSERT(pd != NULL); 14117 14118 /* 14119 * Update PLOGI results; For NS validation 14120 * of orphan list, it is redundant 14121 * 14122 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if 14123 * appropriate as fctl_copy_portmap() will clear map_flags. 14124 */ 14125 if (list[index].map_flags & 14126 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) { 14127 fctl_copy_portmap(list + index, pd); 14128 list[index].map_flags |= 14129 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14130 } else { 14131 fctl_copy_portmap(list + index, pd); 14132 } 14133 14134 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14135 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x", 14136 pd, pd->pd_port_id.port_id, 14137 pd->pd_port_name.raw_wwn[0], 14138 pd->pd_port_name.raw_wwn[1], 14139 pd->pd_port_name.raw_wwn[2], 14140 pd->pd_port_name.raw_wwn[3], 14141 pd->pd_port_name.raw_wwn[4], 14142 pd->pd_port_name.raw_wwn[5], 14143 pd->pd_port_name.raw_wwn[6], 14144 pd->pd_port_name.raw_wwn[7]); 14145 14146 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14147 "results continued, pd=%p type=%x, flags=%x, state=%x", 14148 pd, pd->pd_type, pd->pd_flags, pd->pd_state); 14149 14150 mutex_enter(&pd->pd_mutex); 14151 if (pd->pd_type == PORT_DEVICE_OLD) { 14152 int initiator; 14153 14154 pd->pd_flags = PD_IDLE; 14155 initiator = (pd->pd_recepient == 14156 PD_PLOGI_INITIATOR) ? 1 : 0; 14157 14158 mutex_exit(&pd->pd_mutex); 14159 14160 mutex_enter(&port->fp_mutex); 14161 mutex_enter(&pd->pd_mutex); 14162 14163 pd->pd_state = PORT_DEVICE_INVALID; 14164 fctl_delist_did_table(port, pd); 14165 fctl_delist_pwwn_table(port, pd); 14166 14167 mutex_exit(&pd->pd_mutex); 14168 mutex_exit(&port->fp_mutex); 14169 14170 if (initiator) { 14171 (void) fctl_add_orphan(port, pd, sleep); 14172 } 14173 list[index].map_pd = pd; 14174 } else { 14175 ASSERT(pd->pd_flags == PD_IDLE); 14176 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 14177 /* 14178 * Reset LOGO tolerance to zero 14179 */ 14180 fctl_tc_reset(&pd->pd_logo_tc); 14181 } 14182 mutex_exit(&pd->pd_mutex); 14183 } 14184 } 14185 14186 if (ns_cmd) { 14187 fctl_free_ns_cmd(ns_cmd); 14188 } 14189 if (listindex) { 14190 (void) fp_ulp_devc_cb(port, list, listindex, count, 14191 sleep, 0); 14192 } else { 14193 kmem_free(list, sizeof (*list) * count); 14194 14195 mutex_enter(&port->fp_mutex); 14196 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14197 --port->fp_rscn_count; 14198 } 14199 mutex_exit(&port->fp_mutex); 14200 } 14201 } 14202 14203 14204 /* 14205 * Work hard to make sense out of an RSCN page. 14206 */ 14207 static void 14208 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page, 14209 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr, 14210 int *listindex, int sleep) 14211 { 14212 int rval; 14213 char ww_name[17]; 14214 la_wwn_t *pwwn; 14215 fc_remote_port_t *pwwn_pd; 14216 fc_remote_port_t *did_pd; 14217 14218 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id); 14219 14220 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; " 14221 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id, 14222 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg); 14223 14224 if (did_pd != NULL) { 14225 mutex_enter(&did_pd->pd_mutex); 14226 if (did_pd->pd_flags != PD_IDLE) { 14227 mutex_exit(&did_pd->pd_mutex); 14228 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: " 14229 "PD is BUSY; port=%p, d_id=%x, pd=%p", 14230 port, page->aff_d_id, did_pd); 14231 return; 14232 } 14233 did_pd->pd_flags = PD_ELS_IN_PROGRESS; 14234 mutex_exit(&did_pd->pd_mutex); 14235 } 14236 14237 job->job_counter = 1; 14238 14239 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn; 14240 14241 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id; 14242 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0; 14243 14244 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t)); 14245 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 14246 14247 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x," 14248 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x", 14249 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid, 14250 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason, 14251 ns_cmd->ns_resp_hdr.ct_expln); 14252 14253 job->job_counter = 1; 14254 14255 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) { 14256 /* 14257 * What this means is that the D_ID 14258 * disappeared from the Fabric. 14259 */ 14260 if (did_pd == NULL) { 14261 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;" 14262 " NULL PD disappeared, rval=%x", rval); 14263 return; 14264 } 14265 14266 fc_wwn_to_str(&did_pd->pd_port_name, ww_name); 14267 14268 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14269 (uint32_t)(uintptr_t)job->job_cb_arg; 14270 14271 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14272 14273 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; " 14274 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name); 14275 14276 FP_TRACE(FP_NHEAD2(9, 0), 14277 "GPN_ID for D_ID=%x failed", page->aff_d_id); 14278 14279 FP_TRACE(FP_NHEAD2(9, 0), 14280 "N_x Port with D_ID=%x, PWWN=%s disappeared from" 14281 " fabric", page->aff_d_id, ww_name); 14282 14283 mutex_enter(&did_pd->pd_mutex); 14284 did_pd->pd_flags = PD_IDLE; 14285 mutex_exit(&did_pd->pd_mutex); 14286 14287 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; " 14288 "PD disappeared, pd=%p", page->aff_d_id, did_pd); 14289 14290 return; 14291 } 14292 14293 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn); 14294 14295 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) { 14296 /* 14297 * There is no change. Do PLOGI again and add it to 14298 * ULP portmap baggage and return. Note: When RSCNs 14299 * arrive with per page states, the need for PLOGI 14300 * can be determined correctly. 14301 */ 14302 mutex_enter(&pwwn_pd->pd_mutex); 14303 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE; 14304 mutex_exit(&pwwn_pd->pd_mutex); 14305 14306 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14307 (uint32_t)(uintptr_t)job->job_cb_arg; 14308 14309 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14310 14311 mutex_enter(&pwwn_pd->pd_mutex); 14312 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14313 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14314 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14315 mutex_exit(&pwwn_pd->pd_mutex); 14316 14317 rval = fp_port_login(port, page->aff_d_id, job, 14318 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14319 if (rval == FC_SUCCESS) { 14320 fp_jobwait(job); 14321 rval = job->job_result; 14322 14323 /* 14324 * Reset LOGO tolerance to zero 14325 * Also we are the PLOGI initiator now. 14326 */ 14327 mutex_enter(&pwwn_pd->pd_mutex); 14328 fctl_tc_reset(&pwwn_pd->pd_logo_tc); 14329 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR; 14330 mutex_exit(&pwwn_pd->pd_mutex); 14331 } 14332 14333 if (rval == FC_SUCCESS) { 14334 struct fc_portmap *map = 14335 listptr + *listindex - 1; 14336 14337 FP_TRACE(FP_NHEAD2(4, 0), 14338 "PLOGI succeeded: no skip(2)" 14339 " for D_ID %x", page->aff_d_id); 14340 map->map_flags |= 14341 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14342 } else { 14343 FP_TRACE(FP_NHEAD2(9, rval), 14344 "PLOGI to D_ID=%x failed", page->aff_d_id); 14345 14346 FP_TRACE(FP_NHEAD2(9, 0), 14347 "N_x Port with D_ID=%x, PWWN=%s" 14348 " disappeared from fabric", 14349 page->aff_d_id, ww_name); 14350 14351 fp_fillout_old_map(listptr + 14352 *listindex - 1, pwwn_pd, 0); 14353 } 14354 } else { 14355 mutex_exit(&pwwn_pd->pd_mutex); 14356 } 14357 14358 mutex_enter(&did_pd->pd_mutex); 14359 did_pd->pd_flags = PD_IDLE; 14360 mutex_exit(&did_pd->pd_mutex); 14361 14362 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14363 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval, 14364 job->job_result, pwwn_pd); 14365 14366 return; 14367 } 14368 14369 if (did_pd == NULL && pwwn_pd == NULL) { 14370 14371 fc_orphan_t *orp = NULL; 14372 fc_orphan_t *norp = NULL; 14373 fc_orphan_t *prev = NULL; 14374 14375 /* 14376 * Hunt down the orphan list before giving up. 14377 */ 14378 14379 mutex_enter(&port->fp_mutex); 14380 if (port->fp_orphan_count) { 14381 14382 for (orp = port->fp_orphan_list; orp; orp = norp) { 14383 norp = orp->orp_next; 14384 14385 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) { 14386 prev = orp; 14387 continue; 14388 } 14389 14390 if (prev) { 14391 prev->orp_next = orp->orp_next; 14392 } else { 14393 ASSERT(orp == 14394 port->fp_orphan_list); 14395 port->fp_orphan_list = 14396 orp->orp_next; 14397 } 14398 port->fp_orphan_count--; 14399 break; 14400 } 14401 } 14402 14403 mutex_exit(&port->fp_mutex); 14404 pwwn_pd = fp_create_remote_port_by_ns(port, 14405 page->aff_d_id, sleep); 14406 14407 if (pwwn_pd != NULL) { 14408 14409 if (orp) { 14410 fc_wwn_to_str(&orp->orp_pwwn, 14411 ww_name); 14412 14413 FP_TRACE(FP_NHEAD2(9, 0), 14414 "N_x Port with D_ID=%x," 14415 " PWWN=%s reappeared in fabric", 14416 page->aff_d_id, ww_name); 14417 14418 kmem_free(orp, sizeof (*orp)); 14419 } 14420 14421 (listptr + *listindex)-> 14422 map_rscn_info.ulp_rscn_count = 14423 (uint32_t)(uintptr_t)job->job_cb_arg; 14424 14425 fctl_copy_portmap(listptr + 14426 (*listindex)++, pwwn_pd); 14427 } 14428 14429 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14430 "Case TWO", page->aff_d_id); 14431 14432 return; 14433 } 14434 14435 if (pwwn_pd != NULL && did_pd == NULL) { 14436 uint32_t old_d_id; 14437 uint32_t d_id = page->aff_d_id; 14438 14439 /* 14440 * What this means is there is a new D_ID for this 14441 * Port WWN. Take out the port device off D_ID 14442 * list and put it back with a new D_ID. Perform 14443 * PLOGI if already logged in. 14444 */ 14445 mutex_enter(&port->fp_mutex); 14446 mutex_enter(&pwwn_pd->pd_mutex); 14447 14448 old_d_id = pwwn_pd->pd_port_id.port_id; 14449 14450 fctl_delist_did_table(port, pwwn_pd); 14451 14452 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14453 (uint32_t)(uintptr_t)job->job_cb_arg; 14454 14455 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd, 14456 &d_id, NULL); 14457 fctl_enlist_did_table(port, pwwn_pd); 14458 14459 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;" 14460 " Case THREE, pd=%p," 14461 " state=%x", pwwn_pd, pwwn_pd->pd_state); 14462 14463 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14464 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14465 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14466 14467 mutex_exit(&pwwn_pd->pd_mutex); 14468 mutex_exit(&port->fp_mutex); 14469 14470 FP_TRACE(FP_NHEAD2(9, 0), 14471 "N_x Port with D_ID=%x, PWWN=%s has a new" 14472 " D_ID=%x now", old_d_id, ww_name, d_id); 14473 14474 rval = fp_port_login(port, page->aff_d_id, job, 14475 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14476 if (rval == FC_SUCCESS) { 14477 fp_jobwait(job); 14478 rval = job->job_result; 14479 } 14480 14481 if (rval != FC_SUCCESS) { 14482 fp_fillout_old_map(listptr + 14483 *listindex - 1, pwwn_pd, 0); 14484 } 14485 } else { 14486 mutex_exit(&pwwn_pd->pd_mutex); 14487 mutex_exit(&port->fp_mutex); 14488 } 14489 14490 return; 14491 } 14492 14493 if (pwwn_pd == NULL && did_pd != NULL) { 14494 fc_portmap_t *ptr; 14495 uint32_t len = 1; 14496 char old_ww_name[17]; 14497 14498 mutex_enter(&did_pd->pd_mutex); 14499 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name); 14500 mutex_exit(&did_pd->pd_mutex); 14501 14502 fc_wwn_to_str(pwwn, ww_name); 14503 14504 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14505 (uint32_t)(uintptr_t)job->job_cb_arg; 14506 14507 /* 14508 * What this means is that there is a new Port WWN for 14509 * this D_ID; Mark the Port device as old and provide 14510 * the new PWWN and D_ID combination as new. 14511 */ 14512 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14513 14514 FP_TRACE(FP_NHEAD2(9, 0), 14515 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now", 14516 page->aff_d_id, old_ww_name, ww_name); 14517 14518 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14519 (uint32_t)(uintptr_t)job->job_cb_arg; 14520 14521 ptr = listptr + (*listindex)++; 14522 14523 job->job_counter = 1; 14524 14525 if (fp_ns_getmap(port, job, &ptr, &len, 14526 page->aff_d_id - 1) != FC_SUCCESS) { 14527 (*listindex)--; 14528 } 14529 14530 mutex_enter(&did_pd->pd_mutex); 14531 did_pd->pd_flags = PD_IDLE; 14532 mutex_exit(&did_pd->pd_mutex); 14533 14534 return; 14535 } 14536 14537 /* 14538 * A weird case of Port WWN and D_ID existence but not matching up 14539 * between them. Trust your instincts - Take the port device handle 14540 * off Port WWN list, fix it with new Port WWN and put it back, In 14541 * the mean time mark the port device corresponding to the old port 14542 * WWN as OLD. 14543 */ 14544 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p," 14545 " did_pd=%p", pwwn_pd, did_pd); 14546 14547 mutex_enter(&port->fp_mutex); 14548 mutex_enter(&pwwn_pd->pd_mutex); 14549 14550 pwwn_pd->pd_type = PORT_DEVICE_OLD; 14551 pwwn_pd->pd_state = PORT_DEVICE_INVALID; 14552 fctl_delist_did_table(port, pwwn_pd); 14553 fctl_delist_pwwn_table(port, pwwn_pd); 14554 14555 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14556 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x", 14557 pwwn_pd->pd_port_id.port_id, 14558 14559 pwwn_pd->pd_port_name.raw_wwn[0], 14560 pwwn_pd->pd_port_name.raw_wwn[1], 14561 pwwn_pd->pd_port_name.raw_wwn[2], 14562 pwwn_pd->pd_port_name.raw_wwn[3], 14563 pwwn_pd->pd_port_name.raw_wwn[4], 14564 pwwn_pd->pd_port_name.raw_wwn[5], 14565 pwwn_pd->pd_port_name.raw_wwn[6], 14566 pwwn_pd->pd_port_name.raw_wwn[7]); 14567 14568 mutex_exit(&pwwn_pd->pd_mutex); 14569 mutex_exit(&port->fp_mutex); 14570 14571 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14572 (uint32_t)(uintptr_t)job->job_cb_arg; 14573 14574 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14575 14576 mutex_enter(&port->fp_mutex); 14577 mutex_enter(&did_pd->pd_mutex); 14578 14579 fctl_delist_pwwn_table(port, did_pd); 14580 14581 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14582 (uint32_t)(uintptr_t)job->job_cb_arg; 14583 14584 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn); 14585 fctl_enlist_pwwn_table(port, did_pd); 14586 14587 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14588 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x", 14589 did_pd->pd_port_id.port_id, did_pd->pd_state, 14590 14591 did_pd->pd_port_name.raw_wwn[0], 14592 did_pd->pd_port_name.raw_wwn[1], 14593 did_pd->pd_port_name.raw_wwn[2], 14594 did_pd->pd_port_name.raw_wwn[3], 14595 did_pd->pd_port_name.raw_wwn[4], 14596 did_pd->pd_port_name.raw_wwn[5], 14597 did_pd->pd_port_name.raw_wwn[6], 14598 did_pd->pd_port_name.raw_wwn[7]); 14599 14600 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14601 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14602 mutex_exit(&did_pd->pd_mutex); 14603 mutex_exit(&port->fp_mutex); 14604 14605 rval = fp_port_login(port, page->aff_d_id, job, 14606 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL); 14607 if (rval == FC_SUCCESS) { 14608 fp_jobwait(job); 14609 if (job->job_result != FC_SUCCESS) { 14610 fp_fillout_old_map(listptr + 14611 *listindex - 1, did_pd, 0); 14612 } 14613 } else { 14614 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0); 14615 } 14616 } else { 14617 mutex_exit(&did_pd->pd_mutex); 14618 mutex_exit(&port->fp_mutex); 14619 } 14620 14621 mutex_enter(&did_pd->pd_mutex); 14622 did_pd->pd_flags = PD_IDLE; 14623 mutex_exit(&did_pd->pd_mutex); 14624 } 14625 14626 14627 /* 14628 * Check with NS for the presence of this port WWN 14629 */ 14630 static int 14631 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd, 14632 job_request_t *job, int polled, int sleep) 14633 { 14634 la_wwn_t pwwn; 14635 uint32_t flags; 14636 fctl_ns_req_t *ns_cmd; 14637 14638 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST); 14639 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14640 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14641 flags, sleep); 14642 if (ns_cmd == NULL) { 14643 return (FC_NOMEM); 14644 } 14645 14646 mutex_enter(&pd->pd_mutex); 14647 pwwn = pd->pd_port_name; 14648 mutex_exit(&pd->pd_mutex); 14649 14650 ns_cmd->ns_cmd_code = NS_GID_PN; 14651 ns_cmd->ns_pd = pd; 14652 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn; 14653 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14654 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14655 14656 return (fp_ns_query(port, ns_cmd, job, polled, sleep)); 14657 } 14658 14659 14660 /* 14661 * Sanity check the LILP map returned by FCA 14662 */ 14663 static int 14664 fp_validate_lilp_map(fc_lilpmap_t *lilp_map) 14665 { 14666 int count; 14667 14668 if (lilp_map->lilp_length == 0) { 14669 return (FC_FAILURE); 14670 } 14671 14672 for (count = 0; count < lilp_map->lilp_length; count++) { 14673 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) != 14674 FC_SUCCESS) { 14675 return (FC_FAILURE); 14676 } 14677 } 14678 14679 return (FC_SUCCESS); 14680 } 14681 14682 14683 /* 14684 * Sanity check if the AL_PA is a valid address 14685 */ 14686 static int 14687 fp_is_valid_alpa(uchar_t al_pa) 14688 { 14689 int count; 14690 14691 for (count = 0; count < sizeof (fp_valid_alpas); count++) { 14692 if (al_pa == fp_valid_alpas[count] || al_pa == 0) { 14693 return (FC_SUCCESS); 14694 } 14695 } 14696 14697 return (FC_FAILURE); 14698 } 14699 14700 14701 /* 14702 * Post unsolicited callbacks to ULPs 14703 */ 14704 static void 14705 fp_ulp_unsol_cb(void *arg) 14706 { 14707 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg; 14708 14709 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf, 14710 ub_spec->buf->ub_frame.type); 14711 kmem_free(ub_spec, sizeof (*ub_spec)); 14712 } 14713 14714 14715 /* 14716 * Perform message reporting in a consistent manner. Unless there is 14717 * a strong reason NOT to use this function (which is very very rare) 14718 * all message reporting should go through this. 14719 */ 14720 static void 14721 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno, 14722 fc_packet_t *pkt, const char *fmt, ...) 14723 { 14724 caddr_t buf; 14725 va_list ap; 14726 14727 switch (level) { 14728 case CE_NOTE: 14729 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) { 14730 return; 14731 } 14732 break; 14733 14734 case CE_WARN: 14735 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) { 14736 return; 14737 } 14738 break; 14739 } 14740 14741 buf = kmem_zalloc(256, KM_NOSLEEP); 14742 if (buf == NULL) { 14743 return; 14744 } 14745 14746 (void) sprintf(buf, "fp(%d): ", port->fp_instance); 14747 14748 va_start(ap, fmt); 14749 (void) vsprintf(buf + strlen(buf), fmt, ap); 14750 va_end(ap); 14751 14752 if (fc_errno) { 14753 char *errmsg; 14754 14755 (void) fc_ulp_error(fc_errno, &errmsg); 14756 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg); 14757 } else { 14758 if (pkt) { 14759 caddr_t state, reason, action, expln; 14760 14761 (void) fc_ulp_pkt_error(pkt, &state, &reason, 14762 &action, &expln); 14763 14764 (void) sprintf(buf + strlen(buf), 14765 " state=%s, reason=%s", state, reason); 14766 14767 if (pkt->pkt_resp_resid) { 14768 (void) sprintf(buf + strlen(buf), 14769 " resp resid=%x\n", pkt->pkt_resp_resid); 14770 } 14771 } 14772 } 14773 14774 switch (dest) { 14775 case FP_CONSOLE_ONLY: 14776 cmn_err(level, "^%s", buf); 14777 break; 14778 14779 case FP_LOG_ONLY: 14780 cmn_err(level, "!%s", buf); 14781 break; 14782 14783 default: 14784 cmn_err(level, "%s", buf); 14785 break; 14786 } 14787 14788 kmem_free(buf, 256); 14789 } 14790 14791 static int 14792 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 14793 { 14794 int ret; 14795 uint32_t d_id; 14796 la_wwn_t pwwn; 14797 fc_remote_port_t *pd = NULL; 14798 fc_remote_port_t *held_pd = NULL; 14799 fctl_ns_req_t *ns_cmd; 14800 fc_portmap_t *changelist; 14801 14802 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 14803 14804 mutex_enter(&port->fp_mutex); 14805 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 14806 mutex_exit(&port->fp_mutex); 14807 job->job_counter = 1; 14808 14809 job->job_result = FC_SUCCESS; 14810 14811 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14812 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14813 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 14814 14815 ASSERT(ns_cmd != NULL); 14816 14817 ns_cmd->ns_cmd_code = NS_GID_PN; 14818 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn; 14819 14820 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 14821 14822 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 14823 if (ret != FC_SUCCESS) { 14824 fcio->fcio_errno = ret; 14825 } else { 14826 fcio->fcio_errno = job->job_result; 14827 } 14828 fctl_free_ns_cmd(ns_cmd); 14829 return (EIO); 14830 } 14831 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 14832 fctl_free_ns_cmd(ns_cmd); 14833 } else { 14834 mutex_exit(&port->fp_mutex); 14835 14836 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 14837 if (held_pd == NULL) { 14838 fcio->fcio_errno = FC_BADWWN; 14839 return (EIO); 14840 } 14841 pd = held_pd; 14842 14843 mutex_enter(&pd->pd_mutex); 14844 d_id = pd->pd_port_id.port_id; 14845 mutex_exit(&pd->pd_mutex); 14846 } 14847 14848 job->job_counter = 1; 14849 14850 pd = fctl_get_remote_port_by_did(port, d_id); 14851 14852 if (pd) { 14853 mutex_enter(&pd->pd_mutex); 14854 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 14855 pd->pd_login_count++; 14856 mutex_exit(&pd->pd_mutex); 14857 14858 fcio->fcio_errno = FC_SUCCESS; 14859 if (held_pd) { 14860 fctl_release_remote_port(held_pd); 14861 } 14862 14863 return (0); 14864 } 14865 mutex_exit(&pd->pd_mutex); 14866 } else { 14867 mutex_enter(&port->fp_mutex); 14868 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 14869 mutex_exit(&port->fp_mutex); 14870 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 14871 if (pd == NULL) { 14872 fcio->fcio_errno = FC_FAILURE; 14873 if (held_pd) { 14874 fctl_release_remote_port(held_pd); 14875 } 14876 return (EIO); 14877 } 14878 } else { 14879 mutex_exit(&port->fp_mutex); 14880 } 14881 } 14882 14883 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 14884 job->job_counter = 1; 14885 14886 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN, 14887 KM_SLEEP, pd, NULL); 14888 14889 if (ret != FC_SUCCESS) { 14890 fcio->fcio_errno = ret; 14891 if (held_pd) { 14892 fctl_release_remote_port(held_pd); 14893 } 14894 return (EIO); 14895 } 14896 fp_jobwait(job); 14897 14898 fcio->fcio_errno = job->job_result; 14899 14900 if (held_pd) { 14901 fctl_release_remote_port(held_pd); 14902 } 14903 14904 if (job->job_result != FC_SUCCESS) { 14905 return (EIO); 14906 } 14907 14908 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 14909 if (pd == NULL) { 14910 fcio->fcio_errno = FC_BADDEV; 14911 return (ENODEV); 14912 } 14913 14914 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 14915 14916 fctl_copy_portmap(changelist, pd); 14917 changelist->map_type = PORT_DEVICE_USER_LOGIN; 14918 14919 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 14920 14921 mutex_enter(&pd->pd_mutex); 14922 pd->pd_type = PORT_DEVICE_NOCHANGE; 14923 mutex_exit(&pd->pd_mutex); 14924 14925 fctl_release_remote_port(pd); 14926 14927 return (0); 14928 } 14929 14930 14931 static int 14932 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 14933 { 14934 la_wwn_t pwwn; 14935 fp_cmd_t *cmd; 14936 fc_portmap_t *changelist; 14937 fc_remote_port_t *pd; 14938 14939 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 14940 14941 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 14942 if (pd == NULL) { 14943 fcio->fcio_errno = FC_BADWWN; 14944 return (ENXIO); 14945 } 14946 14947 mutex_enter(&pd->pd_mutex); 14948 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 14949 fcio->fcio_errno = FC_LOGINREQ; 14950 mutex_exit(&pd->pd_mutex); 14951 14952 fctl_release_remote_port(pd); 14953 14954 return (EINVAL); 14955 } 14956 14957 ASSERT(pd->pd_login_count >= 1); 14958 14959 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 14960 fcio->fcio_errno = FC_FAILURE; 14961 mutex_exit(&pd->pd_mutex); 14962 14963 fctl_release_remote_port(pd); 14964 14965 return (EBUSY); 14966 } 14967 14968 if (pd->pd_login_count > 1) { 14969 pd->pd_login_count--; 14970 fcio->fcio_errno = FC_SUCCESS; 14971 mutex_exit(&pd->pd_mutex); 14972 14973 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 14974 14975 fctl_copy_portmap(changelist, pd); 14976 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 14977 14978 fctl_release_remote_port(pd); 14979 14980 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 14981 14982 return (0); 14983 } 14984 14985 pd->pd_flags = PD_ELS_IN_PROGRESS; 14986 mutex_exit(&pd->pd_mutex); 14987 14988 job->job_counter = 1; 14989 14990 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 14991 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 14992 if (cmd == NULL) { 14993 fcio->fcio_errno = FC_NOMEM; 14994 fctl_release_remote_port(pd); 14995 14996 mutex_enter(&pd->pd_mutex); 14997 pd->pd_flags = PD_IDLE; 14998 mutex_exit(&pd->pd_mutex); 14999 15000 return (ENOMEM); 15001 } 15002 15003 mutex_enter(&port->fp_mutex); 15004 mutex_enter(&pd->pd_mutex); 15005 15006 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 15007 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 15008 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 15009 cmd->cmd_retry_count = 1; 15010 cmd->cmd_ulp_pkt = NULL; 15011 15012 fp_logo_init(pd, cmd, job); 15013 15014 mutex_exit(&pd->pd_mutex); 15015 mutex_exit(&port->fp_mutex); 15016 15017 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 15018 mutex_enter(&pd->pd_mutex); 15019 pd->pd_flags = PD_IDLE; 15020 mutex_exit(&pd->pd_mutex); 15021 15022 fp_free_pkt(cmd); 15023 fctl_release_remote_port(pd); 15024 15025 return (EIO); 15026 } 15027 15028 fp_jobwait(job); 15029 15030 fcio->fcio_errno = job->job_result; 15031 if (job->job_result != FC_SUCCESS) { 15032 mutex_enter(&pd->pd_mutex); 15033 pd->pd_flags = PD_IDLE; 15034 mutex_exit(&pd->pd_mutex); 15035 15036 fctl_release_remote_port(pd); 15037 15038 return (EIO); 15039 } 15040 15041 ASSERT(pd != NULL); 15042 15043 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15044 15045 fctl_copy_portmap(changelist, pd); 15046 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15047 changelist->map_state = PORT_DEVICE_INVALID; 15048 15049 mutex_enter(&port->fp_mutex); 15050 mutex_enter(&pd->pd_mutex); 15051 15052 fctl_delist_did_table(port, pd); 15053 fctl_delist_pwwn_table(port, pd); 15054 pd->pd_flags = PD_IDLE; 15055 15056 mutex_exit(&pd->pd_mutex); 15057 mutex_exit(&port->fp_mutex); 15058 15059 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15060 15061 fctl_release_remote_port(pd); 15062 15063 return (0); 15064 } 15065 15066 15067 15068 /* 15069 * Send a syslog event for adapter port level events. 15070 */ 15071 static void 15072 fp_log_port_event(fc_local_port_t *port, char *subclass) 15073 { 15074 nvlist_t *attr_list; 15075 15076 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15077 KM_SLEEP) != DDI_SUCCESS) { 15078 goto alloc_failed; 15079 } 15080 15081 if (nvlist_add_uint32(attr_list, "instance", 15082 port->fp_instance) != DDI_SUCCESS) { 15083 goto error; 15084 } 15085 15086 if (nvlist_add_byte_array(attr_list, "port-wwn", 15087 port->fp_service_params.nport_ww_name.raw_wwn, 15088 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15089 goto error; 15090 } 15091 15092 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15093 subclass, attr_list, NULL, DDI_SLEEP); 15094 15095 nvlist_free(attr_list); 15096 return; 15097 15098 error: 15099 nvlist_free(attr_list); 15100 alloc_failed: 15101 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15102 } 15103 15104 15105 static void 15106 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn, 15107 uint32_t port_id) 15108 { 15109 nvlist_t *attr_list; 15110 15111 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15112 KM_SLEEP) != DDI_SUCCESS) { 15113 goto alloc_failed; 15114 } 15115 15116 if (nvlist_add_uint32(attr_list, "instance", 15117 port->fp_instance) != DDI_SUCCESS) { 15118 goto error; 15119 } 15120 15121 if (nvlist_add_byte_array(attr_list, "port-wwn", 15122 port->fp_service_params.nport_ww_name.raw_wwn, 15123 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15124 goto error; 15125 } 15126 15127 if (nvlist_add_byte_array(attr_list, "target-port-wwn", 15128 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) { 15129 goto error; 15130 } 15131 15132 if (nvlist_add_uint32(attr_list, "target-port-id", 15133 port_id) != DDI_SUCCESS) { 15134 goto error; 15135 } 15136 15137 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15138 subclass, attr_list, NULL, DDI_SLEEP); 15139 15140 nvlist_free(attr_list); 15141 return; 15142 15143 error: 15144 nvlist_free(attr_list); 15145 alloc_failed: 15146 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15147 } 15148 15149 static uint32_t 15150 fp_map_remote_port_state(uint32_t rm_state) 15151 { 15152 switch (rm_state) { 15153 case PORT_DEVICE_LOGGED_IN: 15154 return (FC_HBA_PORTSTATE_ONLINE); 15155 case PORT_DEVICE_VALID: 15156 case PORT_DEVICE_INVALID: 15157 default: 15158 return (FC_HBA_PORTSTATE_UNKNOWN); 15159 } 15160 } 15161