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 2009 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 ddi_quiesce_not_needed /* quiesce */ 96 }; 97 98 #define FP_VERSION "20091123-1.101" 99 #define FP_NAME_VERSION "SunFC Port v" FP_VERSION 100 101 char *fp_version = FP_NAME_VERSION; 102 103 static struct modldrv modldrv = { 104 &mod_driverops, /* Type of Module */ 105 FP_NAME_VERSION, /* Name/Version of fp */ 106 &fp_ops /* driver ops */ 107 }; 108 109 static struct modlinkage modlinkage = { 110 MODREV_1, /* Rev of the loadable modules system */ 111 &modldrv, /* NULL terminated list of */ 112 NULL /* Linkage structures */ 113 }; 114 115 116 117 static uint16_t ns_reg_cmds[] = { 118 NS_RPN_ID, 119 NS_RNN_ID, 120 NS_RCS_ID, 121 NS_RFT_ID, 122 NS_RPT_ID, 123 NS_RSPN_ID, 124 NS_RSNN_NN 125 }; 126 127 struct fp_xlat { 128 uchar_t xlat_state; 129 int xlat_rval; 130 } fp_xlat [] = { 131 { FC_PKT_SUCCESS, FC_SUCCESS }, 132 { FC_PKT_REMOTE_STOP, FC_FAILURE }, 133 { FC_PKT_LOCAL_RJT, FC_FAILURE }, 134 { FC_PKT_NPORT_RJT, FC_ELS_PREJECT }, 135 { FC_PKT_FABRIC_RJT, FC_ELS_FREJECT }, 136 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY }, 137 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY }, 138 { FC_PKT_NPORT_BSY, FC_PBUSY }, 139 { FC_PKT_FABRIC_BSY, FC_FBUSY }, 140 { FC_PKT_LS_RJT, FC_FAILURE }, 141 { FC_PKT_BA_RJT, FC_FAILURE }, 142 { FC_PKT_TIMEOUT, FC_FAILURE }, 143 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR }, 144 { FC_PKT_FAILURE, FC_FAILURE }, 145 { FC_PKT_PORT_OFFLINE, FC_OFFLINE } 146 }; 147 148 static uchar_t fp_valid_alpas[] = { 149 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 150 0x1D, 0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 151 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 152 0x36, 0x39, 0x3A, 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 153 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 154 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, 155 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, 0x73, 156 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, 0x81, 0x82, 157 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D, 0x9E, 158 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC, 159 0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 160 0xBA, 0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 161 0xCC, 0xCD, 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 162 0xD9, 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF 163 }; 164 165 static struct fp_perms { 166 uint16_t fp_ioctl_cmd; 167 uchar_t fp_open_flag; 168 } fp_perm_list [] = { 169 { FCIO_GET_NUM_DEVS, FP_OPEN }, 170 { FCIO_GET_DEV_LIST, FP_OPEN }, 171 { FCIO_GET_SYM_PNAME, FP_OPEN }, 172 { FCIO_GET_SYM_NNAME, FP_OPEN }, 173 { FCIO_SET_SYM_PNAME, FP_EXCL }, 174 { FCIO_SET_SYM_NNAME, FP_EXCL }, 175 { FCIO_GET_LOGI_PARAMS, FP_OPEN }, 176 { FCIO_DEV_LOGIN, FP_EXCL }, 177 { FCIO_DEV_LOGOUT, FP_EXCL }, 178 { FCIO_GET_STATE, FP_OPEN }, 179 { FCIO_DEV_REMOVE, FP_EXCL }, 180 { FCIO_GET_FCODE_REV, FP_OPEN }, 181 { FCIO_GET_FW_REV, FP_OPEN }, 182 { FCIO_GET_DUMP_SIZE, FP_OPEN }, 183 { FCIO_FORCE_DUMP, FP_EXCL }, 184 { FCIO_GET_DUMP, FP_OPEN }, 185 { FCIO_GET_TOPOLOGY, FP_OPEN }, 186 { FCIO_RESET_LINK, FP_EXCL }, 187 { FCIO_RESET_HARD, FP_EXCL }, 188 { FCIO_RESET_HARD_CORE, FP_EXCL }, 189 { FCIO_DIAG, FP_OPEN }, 190 { FCIO_NS, FP_EXCL }, 191 { FCIO_DOWNLOAD_FW, FP_EXCL }, 192 { FCIO_DOWNLOAD_FCODE, FP_EXCL }, 193 { FCIO_LINK_STATUS, FP_OPEN }, 194 { FCIO_GET_HOST_PARAMS, FP_OPEN }, 195 { FCIO_GET_NODE_ID, FP_OPEN }, 196 { FCIO_SET_NODE_ID, FP_EXCL }, 197 { FCIO_SEND_NODE_ID, FP_OPEN }, 198 { FCIO_GET_ADAPTER_ATTRIBUTES, FP_OPEN }, 199 { FCIO_GET_OTHER_ADAPTER_PORTS, FP_OPEN }, 200 { FCIO_GET_ADAPTER_PORT_ATTRIBUTES, FP_OPEN }, 201 { FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, FP_OPEN }, 202 { FCIO_GET_PORT_ATTRIBUTES, FP_OPEN }, 203 { FCIO_GET_ADAPTER_PORT_STATS, FP_OPEN }, 204 { FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES, FP_OPEN }, 205 { FCIO_GET_NPIV_PORT_LIST, FP_OPEN }, 206 { FCIO_DELETE_NPIV_PORT, FP_OPEN }, 207 { FCIO_GET_NPIV_ATTRIBUTES, FP_OPEN }, 208 { FCIO_CREATE_NPIV_PORT, FP_OPEN }, 209 { FCIO_NPIV_GET_ADAPTER_ATTRIBUTES, FP_OPEN } 210 }; 211 212 static char *fp_pm_comps[] = { 213 "NAME=FC Port", 214 "0=Port Down", 215 "1=Port Up" 216 }; 217 218 219 #ifdef _LITTLE_ENDIAN 220 #define MAKE_BE_32(x) { \ 221 uint32_t *ptr1, i; \ 222 ptr1 = (uint32_t *)(x); \ 223 for (i = 0; i < sizeof (*(x)) / sizeof (uint32_t); i++) { \ 224 *ptr1 = BE_32(*ptr1); \ 225 ptr1++; \ 226 } \ 227 } 228 #else 229 #define MAKE_BE_32(x) 230 #endif 231 232 static uchar_t fp_verbosity = (FP_WARNING_MESSAGES | FP_FATAL_MESSAGES); 233 static uint32_t fp_options = 0; 234 235 static int fp_cmd_wait_cnt = FP_CMDWAIT_DELAY; 236 static int fp_retry_delay = FP_RETRY_DELAY; /* retry after this delay */ 237 static int fp_retry_count = FP_RETRY_COUNT; /* number of retries */ 238 unsigned int fp_offline_ticker; /* seconds */ 239 240 /* 241 * Driver global variable to anchor the list of soft state structs for 242 * all fp driver instances. Used with the Solaris DDI soft state functions. 243 */ 244 static void *fp_driver_softstate; 245 246 static clock_t fp_retry_ticks; 247 static clock_t fp_offline_ticks; 248 249 static int fp_retry_ticker; 250 static uint32_t fp_unsol_buf_count = FP_UNSOL_BUF_COUNT; 251 static uint32_t fp_unsol_buf_size = FP_UNSOL_BUF_SIZE; 252 253 static int fp_log_size = FP_LOG_SIZE; 254 static int fp_trace = FP_TRACE_DEFAULT; 255 static fc_trace_logq_t *fp_logq = NULL; 256 257 int fp_get_adapter_paths(char *pathList, int count); 258 static void fp_log_port_event(fc_local_port_t *port, char *subclass); 259 static void fp_log_target_event(fc_local_port_t *port, char *subclass, 260 la_wwn_t tgt_pwwn, uint32_t port_id); 261 static uint32_t fp_map_remote_port_state(uint32_t rm_state); 262 static void fp_init_symbolic_names(fc_local_port_t *port); 263 264 265 /* 266 * Perform global initialization 267 */ 268 int 269 _init(void) 270 { 271 int ret; 272 273 if ((ret = ddi_soft_state_init(&fp_driver_softstate, 274 sizeof (struct fc_local_port), 8)) != 0) { 275 return (ret); 276 } 277 278 if ((ret = scsi_hba_init(&modlinkage)) != 0) { 279 ddi_soft_state_fini(&fp_driver_softstate); 280 return (ret); 281 } 282 283 fp_logq = fc_trace_alloc_logq(fp_log_size); 284 285 if ((ret = mod_install(&modlinkage)) != 0) { 286 fc_trace_free_logq(fp_logq); 287 ddi_soft_state_fini(&fp_driver_softstate); 288 scsi_hba_fini(&modlinkage); 289 } 290 291 return (ret); 292 } 293 294 295 /* 296 * Prepare for driver unload 297 */ 298 int 299 _fini(void) 300 { 301 int ret; 302 303 if ((ret = mod_remove(&modlinkage)) == 0) { 304 fc_trace_free_logq(fp_logq); 305 ddi_soft_state_fini(&fp_driver_softstate); 306 scsi_hba_fini(&modlinkage); 307 } 308 309 return (ret); 310 } 311 312 313 /* 314 * Request mod_info() to handle all cases 315 */ 316 int 317 _info(struct modinfo *modinfo) 318 { 319 return (mod_info(&modlinkage, modinfo)); 320 } 321 322 323 /* 324 * fp_attach: 325 * 326 * The respective cmd handlers take care of performing 327 * ULP related invocations 328 */ 329 static int 330 fp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 331 { 332 int rval; 333 334 /* 335 * We check the value of fp_offline_ticker at this 336 * point. The variable is global for the driver and 337 * not specific to an instance. 338 * 339 * If there is no user-defined value found in /etc/system 340 * or fp.conf, then we use 90 seconds (FP_OFFLINE_TICKER). 341 * The minimum setting for this offline timeout according 342 * to the FC-FS2 standard (Fibre Channel Framing and 343 * Signalling-2, see www.t11.org) is R_T_TOV == 100msec. 344 * 345 * We do not recommend setting the value to less than 10 346 * seconds (RA_TOV) or more than 90 seconds. If this 347 * variable is greater than 90 seconds then drivers above 348 * fp (fcp, sd, scsi_vhci, vxdmp et al) might complain. 349 */ 350 351 fp_offline_ticker = ddi_prop_get_int(DDI_DEV_T_ANY, 352 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fp_offline_ticker", 353 FP_OFFLINE_TICKER); 354 355 if ((fp_offline_ticker < 10) || 356 (fp_offline_ticker > 90)) { 357 cmn_err(CE_WARN, "Setting fp_offline_ticker to " 358 "%d second(s). This is outside the " 359 "recommended range of 10..90 seconds", 360 fp_offline_ticker); 361 } 362 363 /* 364 * Tick every second when there are commands to retry. 365 * It should tick at the least granular value of pkt_timeout 366 * (which is one second) 367 */ 368 fp_retry_ticker = 1; 369 370 fp_retry_ticks = drv_usectohz(fp_retry_ticker * 1000 * 1000); 371 fp_offline_ticks = drv_usectohz(fp_offline_ticker * 1000 * 1000); 372 373 switch (cmd) { 374 case DDI_ATTACH: 375 rval = fp_attach_handler(dip); 376 break; 377 378 case DDI_RESUME: 379 rval = fp_resume_handler(dip); 380 break; 381 382 default: 383 rval = DDI_FAILURE; 384 break; 385 } 386 return (rval); 387 } 388 389 390 /* 391 * fp_detach: 392 * 393 * If a ULP fails to handle cmd request converse of 394 * cmd is invoked for ULPs that previously succeeded 395 * cmd request. 396 */ 397 static int 398 fp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 399 { 400 int rval = DDI_FAILURE; 401 fc_local_port_t *port; 402 fc_attach_cmd_t converse; 403 uint8_t cnt; 404 405 if ((port = ddi_get_soft_state(fp_driver_softstate, 406 ddi_get_instance(dip))) == NULL) { 407 return (DDI_FAILURE); 408 } 409 410 mutex_enter(&port->fp_mutex); 411 412 if (port->fp_ulp_attach) { 413 mutex_exit(&port->fp_mutex); 414 return (DDI_FAILURE); 415 } 416 417 switch (cmd) { 418 case DDI_DETACH: 419 if (port->fp_task != FP_TASK_IDLE) { 420 mutex_exit(&port->fp_mutex); 421 return (DDI_FAILURE); 422 } 423 424 /* Let's attempt to quit the job handler gracefully */ 425 port->fp_soft_state |= FP_DETACH_INPROGRESS; 426 427 mutex_exit(&port->fp_mutex); 428 converse = FC_CMD_ATTACH; 429 if (fctl_detach_ulps(port, FC_CMD_DETACH, 430 &modlinkage) != FC_SUCCESS) { 431 mutex_enter(&port->fp_mutex); 432 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 433 mutex_exit(&port->fp_mutex); 434 rval = DDI_FAILURE; 435 break; 436 } 437 438 mutex_enter(&port->fp_mutex); 439 for (cnt = 0; (port->fp_job_head) && (cnt < fp_cmd_wait_cnt); 440 cnt++) { 441 mutex_exit(&port->fp_mutex); 442 delay(drv_usectohz(1000000)); 443 mutex_enter(&port->fp_mutex); 444 } 445 446 if (port->fp_job_head) { 447 mutex_exit(&port->fp_mutex); 448 rval = DDI_FAILURE; 449 break; 450 } 451 mutex_exit(&port->fp_mutex); 452 453 rval = fp_detach_handler(port); 454 break; 455 456 case DDI_SUSPEND: 457 mutex_exit(&port->fp_mutex); 458 converse = FC_CMD_RESUME; 459 if (fctl_detach_ulps(port, FC_CMD_SUSPEND, 460 &modlinkage) != FC_SUCCESS) { 461 rval = DDI_FAILURE; 462 break; 463 } 464 if ((rval = fp_suspend_handler(port)) != DDI_SUCCESS) { 465 (void) callb_generic_cpr(&port->fp_cpr_info, 466 CB_CODE_CPR_RESUME); 467 } 468 break; 469 470 default: 471 mutex_exit(&port->fp_mutex); 472 break; 473 } 474 475 /* 476 * Use softint to perform reattach. Mark fp_ulp_attach so we 477 * don't attempt to do this repeatedly on behalf of some persistent 478 * caller. 479 */ 480 if (rval != DDI_SUCCESS) { 481 mutex_enter(&port->fp_mutex); 482 port->fp_ulp_attach = 1; 483 484 /* 485 * If the port is in the low power mode then there is 486 * possibility that fca too could be in low power mode. 487 * Try to raise the power before calling attach ulps. 488 */ 489 490 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 491 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 492 mutex_exit(&port->fp_mutex); 493 (void) pm_raise_power(port->fp_port_dip, 494 FP_PM_COMPONENT, FP_PM_PORT_UP); 495 } else { 496 mutex_exit(&port->fp_mutex); 497 } 498 499 500 fp_attach_ulps(port, converse); 501 502 mutex_enter(&port->fp_mutex); 503 while (port->fp_ulp_attach) { 504 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 505 } 506 507 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 508 509 /* 510 * Mark state as detach failed so asynchronous ULP attach 511 * events (downstream, not the ones we're initiating with 512 * the call to fp_attach_ulps) are not honored. We're 513 * really still in pending detach. 514 */ 515 port->fp_soft_state |= FP_DETACH_FAILED; 516 517 mutex_exit(&port->fp_mutex); 518 } 519 520 return (rval); 521 } 522 523 524 /* 525 * fp_getinfo: 526 * Given the device number, return either the 527 * dev_info_t pointer or the instance number. 528 */ 529 530 /* ARGSUSED */ 531 static int 532 fp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 533 { 534 int rval; 535 minor_t instance; 536 fc_local_port_t *port; 537 538 rval = DDI_SUCCESS; 539 instance = getminor((dev_t)arg); 540 541 switch (cmd) { 542 case DDI_INFO_DEVT2DEVINFO: 543 if ((port = ddi_get_soft_state(fp_driver_softstate, 544 instance)) == NULL) { 545 rval = DDI_FAILURE; 546 break; 547 } 548 *result = (void *)port->fp_port_dip; 549 break; 550 551 case DDI_INFO_DEVT2INSTANCE: 552 *result = (void *)(uintptr_t)instance; 553 break; 554 555 default: 556 rval = DDI_FAILURE; 557 break; 558 } 559 560 return (rval); 561 } 562 563 564 /* 565 * Entry point for power up and power down request from kernel 566 */ 567 static int 568 fp_power(dev_info_t *dip, int comp, int level) 569 { 570 int rval = DDI_FAILURE; 571 fc_local_port_t *port; 572 573 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 574 if (port == NULL || comp != FP_PM_COMPONENT) { 575 return (rval); 576 } 577 578 switch (level) { 579 case FP_PM_PORT_UP: 580 rval = DDI_SUCCESS; 581 582 /* 583 * If the port is DDI_SUSPENDed, let the DDI_RESUME 584 * code complete the rediscovery. 585 */ 586 mutex_enter(&port->fp_mutex); 587 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 588 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 589 port->fp_pm_level = FP_PM_PORT_UP; 590 mutex_exit(&port->fp_mutex); 591 fctl_attach_ulps(port, FC_CMD_POWER_UP, &modlinkage); 592 break; 593 } 594 595 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 596 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 597 598 port->fp_pm_level = FP_PM_PORT_UP; 599 rval = fp_power_up(port); 600 if (rval != DDI_SUCCESS) { 601 port->fp_pm_level = FP_PM_PORT_DOWN; 602 } 603 } else { 604 port->fp_pm_level = FP_PM_PORT_UP; 605 } 606 mutex_exit(&port->fp_mutex); 607 break; 608 609 case FP_PM_PORT_DOWN: 610 mutex_enter(&port->fp_mutex); 611 612 ASSERT(!(port->fp_soft_state & FP_SOFT_NO_PMCOMP)); 613 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 614 /* 615 * PM framework goofed up. We have don't 616 * have any PM components. Let's never go down. 617 */ 618 mutex_exit(&port->fp_mutex); 619 break; 620 621 } 622 623 if (port->fp_ulp_attach) { 624 /* We shouldn't let the power go down */ 625 mutex_exit(&port->fp_mutex); 626 break; 627 } 628 629 /* 630 * Not a whole lot to do if we are detaching 631 */ 632 if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 633 port->fp_pm_level = FP_PM_PORT_DOWN; 634 mutex_exit(&port->fp_mutex); 635 rval = DDI_SUCCESS; 636 break; 637 } 638 639 if (!port->fp_pm_busy && !port->fp_pm_busy_nocomp) { 640 port->fp_pm_level = FP_PM_PORT_DOWN; 641 642 rval = fp_power_down(port); 643 if (rval != DDI_SUCCESS) { 644 port->fp_pm_level = FP_PM_PORT_UP; 645 ASSERT(!(port->fp_soft_state & 646 FP_SOFT_POWER_DOWN)); 647 } else { 648 ASSERT(port->fp_soft_state & 649 FP_SOFT_POWER_DOWN); 650 } 651 } 652 mutex_exit(&port->fp_mutex); 653 break; 654 655 default: 656 break; 657 } 658 659 return (rval); 660 } 661 662 663 /* 664 * Open FC port devctl node 665 */ 666 static int 667 fp_open(dev_t *devp, int flag, int otype, cred_t *credp) 668 { 669 int instance; 670 fc_local_port_t *port; 671 672 if (otype != OTYP_CHR) { 673 return (EINVAL); 674 } 675 676 /* 677 * This is not a toy to play with. Allow only powerful 678 * users (hopefully knowledgeable) to access the port 679 * (A hacker potentially could download a sick binary 680 * file into FCA) 681 */ 682 if (drv_priv(credp)) { 683 return (EPERM); 684 } 685 686 instance = (int)getminor(*devp); 687 688 port = ddi_get_soft_state(fp_driver_softstate, instance); 689 if (port == NULL) { 690 return (ENXIO); 691 } 692 693 mutex_enter(&port->fp_mutex); 694 if (port->fp_flag & FP_EXCL) { 695 /* 696 * It is already open for exclusive access. 697 * So shut the door on this caller. 698 */ 699 mutex_exit(&port->fp_mutex); 700 return (EBUSY); 701 } 702 703 if (flag & FEXCL) { 704 if (port->fp_flag & FP_OPEN) { 705 /* 706 * Exclusive operation not possible 707 * as it is already opened 708 */ 709 mutex_exit(&port->fp_mutex); 710 return (EBUSY); 711 } 712 port->fp_flag |= FP_EXCL; 713 } 714 port->fp_flag |= FP_OPEN; 715 mutex_exit(&port->fp_mutex); 716 717 return (0); 718 } 719 720 721 /* 722 * The driver close entry point is called on the last close() 723 * of a device. So it is perfectly alright to just clobber the 724 * open flag and reset it to idle (instead of having to reset 725 * each flag bits). For any confusion, check out close(9E). 726 */ 727 728 /* ARGSUSED */ 729 static int 730 fp_close(dev_t dev, int flag, int otype, cred_t *credp) 731 { 732 int instance; 733 fc_local_port_t *port; 734 735 if (otype != OTYP_CHR) { 736 return (EINVAL); 737 } 738 739 instance = (int)getminor(dev); 740 741 port = ddi_get_soft_state(fp_driver_softstate, instance); 742 if (port == NULL) { 743 return (ENXIO); 744 } 745 746 mutex_enter(&port->fp_mutex); 747 if ((port->fp_flag & FP_OPEN) == 0) { 748 mutex_exit(&port->fp_mutex); 749 return (ENODEV); 750 } 751 port->fp_flag = FP_IDLE; 752 mutex_exit(&port->fp_mutex); 753 754 return (0); 755 } 756 757 /* 758 * Handle IOCTL requests 759 */ 760 761 /* ARGSUSED */ 762 static int 763 fp_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval) 764 { 765 int instance; 766 int ret = 0; 767 fcio_t fcio; 768 fc_local_port_t *port; 769 770 instance = (int)getminor(dev); 771 772 port = ddi_get_soft_state(fp_driver_softstate, instance); 773 if (port == NULL) { 774 return (ENXIO); 775 } 776 777 mutex_enter(&port->fp_mutex); 778 if ((port->fp_flag & FP_OPEN) == 0) { 779 mutex_exit(&port->fp_mutex); 780 return (ENXIO); 781 } 782 783 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 784 mutex_exit(&port->fp_mutex); 785 return (ENXIO); 786 } 787 788 mutex_exit(&port->fp_mutex); 789 790 /* this will raise power if necessary */ 791 ret = fctl_busy_port(port); 792 if (ret != 0) { 793 return (ret); 794 } 795 796 ASSERT(port->fp_pm_level == FP_PM_PORT_UP); 797 798 799 switch (cmd) { 800 case FCIO_CMD: { 801 #ifdef _MULTI_DATAMODEL 802 switch (ddi_model_convert_from(mode & FMODELS)) { 803 case DDI_MODEL_ILP32: { 804 struct fcio32 fcio32; 805 806 if (ddi_copyin((void *)data, (void *)&fcio32, 807 sizeof (struct fcio32), mode)) { 808 ret = EFAULT; 809 break; 810 } 811 fcio.fcio_xfer = fcio32.fcio_xfer; 812 fcio.fcio_cmd = fcio32.fcio_cmd; 813 fcio.fcio_flags = fcio32.fcio_flags; 814 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags; 815 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen; 816 fcio.fcio_ibuf = 817 (caddr_t)(uintptr_t)fcio32.fcio_ibuf; 818 fcio.fcio_olen = (size_t)fcio32.fcio_olen; 819 fcio.fcio_obuf = 820 (caddr_t)(uintptr_t)fcio32.fcio_obuf; 821 fcio.fcio_alen = (size_t)fcio32.fcio_alen; 822 fcio.fcio_abuf = 823 (caddr_t)(uintptr_t)fcio32.fcio_abuf; 824 fcio.fcio_errno = fcio32.fcio_errno; 825 break; 826 } 827 828 case DDI_MODEL_NONE: 829 if (ddi_copyin((void *)data, (void *)&fcio, 830 sizeof (fcio_t), mode)) { 831 ret = EFAULT; 832 } 833 break; 834 } 835 #else /* _MULTI_DATAMODEL */ 836 if (ddi_copyin((void *)data, (void *)&fcio, 837 sizeof (fcio_t), mode)) { 838 ret = EFAULT; 839 break; 840 } 841 #endif /* _MULTI_DATAMODEL */ 842 if (!ret) { 843 ret = fp_fciocmd(port, data, mode, &fcio); 844 } 845 break; 846 } 847 848 default: 849 ret = fctl_ulp_port_ioctl(port, dev, cmd, data, 850 mode, credp, rval); 851 } 852 853 fctl_idle_port(port); 854 855 return (ret); 856 } 857 858 859 /* 860 * Init Symbolic Port Name and Node Name 861 * LV will try to get symbolic names from FCA driver 862 * and register these to name server, 863 * if LV fails to get these, 864 * LV will register its default symbolic names to name server. 865 * The Default symbolic node name format is : 866 * <hostname>:<hba driver name>(instance) 867 * The Default symbolic port name format is : 868 * <fp path name> 869 */ 870 static void 871 fp_init_symbolic_names(fc_local_port_t *port) 872 { 873 const char *vendorname = ddi_driver_name(port->fp_fca_dip); 874 char *sym_name; 875 char fcaname[50] = {0}; 876 int hostnlen, fcanlen; 877 878 if (port->fp_sym_node_namelen == 0) { 879 hostnlen = strlen(utsname.nodename); 880 (void) snprintf(fcaname, sizeof (fcaname), 881 "%s%d", vendorname, ddi_get_instance(port->fp_fca_dip)); 882 fcanlen = strlen(fcaname); 883 884 sym_name = kmem_zalloc(hostnlen + fcanlen + 2, KM_SLEEP); 885 (void) sprintf(sym_name, "%s:%s", utsname.nodename, fcaname); 886 port->fp_sym_node_namelen = strlen(sym_name); 887 if (port->fp_sym_node_namelen >= FCHBA_SYMB_NAME_LEN) { 888 port->fp_sym_node_namelen = FCHBA_SYMB_NAME_LEN; 889 } 890 (void) strncpy(port->fp_sym_node_name, sym_name, 891 port->fp_sym_node_namelen); 892 kmem_free(sym_name, hostnlen + fcanlen + 2); 893 } 894 895 if (port->fp_sym_port_namelen == 0) { 896 char *pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 897 898 (void) ddi_pathname(port->fp_port_dip, pathname); 899 port->fp_sym_port_namelen = strlen(pathname); 900 if (port->fp_sym_port_namelen >= FCHBA_SYMB_NAME_LEN) { 901 port->fp_sym_port_namelen = FCHBA_SYMB_NAME_LEN; 902 } 903 (void) strncpy(port->fp_sym_port_name, pathname, 904 port->fp_sym_port_namelen); 905 kmem_free(pathname, MAXPATHLEN); 906 } 907 } 908 909 910 /* 911 * Perform port attach 912 */ 913 static int 914 fp_attach_handler(dev_info_t *dip) 915 { 916 int rval; 917 int instance; 918 int port_num; 919 int port_len; 920 char name[30]; 921 char i_pwwn[17]; 922 fp_cmd_t *pkt; 923 uint32_t ub_count; 924 fc_local_port_t *port; 925 job_request_t *job; 926 fc_local_port_t *phyport = NULL; 927 int portpro1; 928 char pwwn[17], nwwn[17]; 929 930 instance = ddi_get_instance(dip); 931 port_len = sizeof (port_num); 932 rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 933 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 934 (caddr_t)&port_num, &port_len); 935 if (rval != DDI_SUCCESS) { 936 cmn_err(CE_WARN, "fp(%d): No port property in devinfo", 937 instance); 938 return (DDI_FAILURE); 939 } 940 941 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 942 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 943 cmn_err(CE_WARN, "fp(%d): failed to create devctl minor node", 944 instance); 945 return (DDI_FAILURE); 946 } 947 948 if (ddi_create_minor_node(dip, "fc", S_IFCHR, instance, 949 DDI_NT_FC_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 950 cmn_err(CE_WARN, "fp(%d): failed to create fc attachment" 951 " point minor node", instance); 952 ddi_remove_minor_node(dip, NULL); 953 return (DDI_FAILURE); 954 } 955 956 if (ddi_soft_state_zalloc(fp_driver_softstate, instance) 957 != DDI_SUCCESS) { 958 cmn_err(CE_WARN, "fp(%d): failed to alloc soft state", 959 instance); 960 ddi_remove_minor_node(dip, NULL); 961 return (DDI_FAILURE); 962 } 963 port = ddi_get_soft_state(fp_driver_softstate, instance); 964 965 (void) sprintf(port->fp_ibuf, "fp(%d)", instance); 966 967 port->fp_instance = instance; 968 port->fp_ulp_attach = 1; 969 port->fp_port_num = port_num; 970 port->fp_verbose = fp_verbosity; 971 port->fp_options = fp_options; 972 973 port->fp_fca_dip = ddi_get_parent(dip); 974 port->fp_port_dip = dip; 975 port->fp_fca_tran = (fc_fca_tran_t *) 976 ddi_get_driver_private(port->fp_fca_dip); 977 978 port->fp_task = port->fp_last_task = FP_TASK_IDLE; 979 980 /* 981 * Init the starting value of fp_rscn_count. Note that if 982 * FC_INVALID_RSCN_COUNT is 0 (which is what it currently is), the 983 * actual # of RSCNs will be (fp_rscn_count - 1) 984 */ 985 port->fp_rscn_count = FC_INVALID_RSCN_COUNT + 1; 986 987 mutex_init(&port->fp_mutex, NULL, MUTEX_DRIVER, NULL); 988 cv_init(&port->fp_cv, NULL, CV_DRIVER, NULL); 989 cv_init(&port->fp_attach_cv, NULL, CV_DRIVER, NULL); 990 991 (void) sprintf(name, "fp%d_cache", instance); 992 993 if ((portpro1 = ddi_prop_get_int(DDI_DEV_T_ANY, 994 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 995 "phyport-instance", -1)) != -1) { 996 phyport = ddi_get_soft_state(fp_driver_softstate, portpro1); 997 fc_wwn_to_str(&phyport->fp_service_params.nport_ww_name, pwwn); 998 fc_wwn_to_str(&phyport->fp_service_params.node_ww_name, nwwn); 999 port->fp_npiv_type = FC_NPIV_PORT; 1000 } 1001 1002 /* 1003 * Allocate the pool of fc_packet_t structs to be used with 1004 * this fp instance. 1005 */ 1006 port->fp_pkt_cache = kmem_cache_create(name, 1007 (port->fp_fca_tran->fca_pkt_size) + sizeof (fp_cmd_t), 8, 1008 fp_cache_constructor, fp_cache_destructor, NULL, (void *)port, 1009 NULL, 0); 1010 port->fp_out_fpcmds = 0; 1011 if (port->fp_pkt_cache == NULL) { 1012 goto cache_alloc_failed; 1013 } 1014 1015 1016 /* 1017 * Allocate the d_id and pwwn hash tables for all remote ports 1018 * connected to this local port. 1019 */ 1020 port->fp_did_table = kmem_zalloc(did_table_size * 1021 sizeof (struct d_id_hash), KM_SLEEP); 1022 1023 port->fp_pwwn_table = kmem_zalloc(pwwn_table_size * 1024 sizeof (struct pwwn_hash), KM_SLEEP); 1025 1026 port->fp_taskq = taskq_create("fp_ulp_callback", 1, 1027 MINCLSYSPRI, 1, 16, 0); 1028 1029 /* Indicate that don't have the pm components yet */ 1030 port->fp_soft_state |= FP_SOFT_NO_PMCOMP; 1031 1032 /* 1033 * Bind the callbacks with the FCA driver. This will open the gate 1034 * for asynchronous callbacks, so after this call the fp_mutex 1035 * must be held when updating the fc_local_port_t struct. 1036 * 1037 * This is done _before_ setting up the job thread so we can avoid 1038 * cleaning up after the thread_create() in the error path. This 1039 * also means fp will be operating with fp_els_resp_pkt set to NULL. 1040 */ 1041 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1042 goto bind_callbacks_failed; 1043 } 1044 1045 if (phyport) { 1046 mutex_enter(&phyport->fp_mutex); 1047 if (phyport->fp_port_next) { 1048 phyport->fp_port_next->fp_port_prev = port; 1049 port->fp_port_next = phyport->fp_port_next; 1050 phyport->fp_port_next = port; 1051 port->fp_port_prev = phyport; 1052 } else { 1053 phyport->fp_port_next = port; 1054 phyport->fp_port_prev = port; 1055 port->fp_port_next = phyport; 1056 port->fp_port_prev = phyport; 1057 } 1058 mutex_exit(&phyport->fp_mutex); 1059 } 1060 1061 /* 1062 * Init Symbolic Names 1063 */ 1064 fp_init_symbolic_names(port); 1065 1066 pkt = fp_alloc_pkt(port, sizeof (la_els_logi_t), sizeof (la_els_logi_t), 1067 KM_SLEEP, NULL); 1068 1069 if (pkt == NULL) { 1070 cmn_err(CE_WARN, "fp(%d): failed to allocate ELS packet", 1071 instance); 1072 goto alloc_els_packet_failed; 1073 } 1074 1075 (void) thread_create(NULL, 0, fp_job_handler, port, 0, &p0, TS_RUN, 1076 v.v_maxsyspri - 2); 1077 1078 fc_wwn_to_str(&port->fp_service_params.nport_ww_name, i_pwwn); 1079 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-port", 1080 i_pwwn) != DDI_PROP_SUCCESS) { 1081 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1082 "fp(%d): Updating 'initiator-port' property" 1083 " on fp dev_info node failed", instance); 1084 } 1085 1086 fc_wwn_to_str(&port->fp_service_params.node_ww_name, i_pwwn); 1087 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "initiator-node", 1088 i_pwwn) != DDI_PROP_SUCCESS) { 1089 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 1090 "fp(%d): Updating 'initiator-node' property" 1091 " on fp dev_info node failed", instance); 1092 } 1093 1094 mutex_enter(&port->fp_mutex); 1095 port->fp_els_resp_pkt = pkt; 1096 mutex_exit(&port->fp_mutex); 1097 1098 /* 1099 * Determine the count of unsolicited buffers this FCA can support 1100 */ 1101 fp_retrieve_caps(port); 1102 1103 /* 1104 * Allocate unsolicited buffer tokens 1105 */ 1106 if (port->fp_ub_count) { 1107 ub_count = port->fp_ub_count; 1108 port->fp_ub_tokens = kmem_zalloc(ub_count * 1109 sizeof (*port->fp_ub_tokens), KM_SLEEP); 1110 /* 1111 * Do not fail the attach if unsolicited buffer allocation 1112 * fails; Just try to get along with whatever the FCA can do. 1113 */ 1114 if (fc_ulp_uballoc(port, &ub_count, fp_unsol_buf_size, 1115 FC_TYPE_EXTENDED_LS, port->fp_ub_tokens) != 1116 FC_SUCCESS || ub_count != port->fp_ub_count) { 1117 cmn_err(CE_WARN, "fp(%d): failed to allocate " 1118 " Unsolicited buffers. proceeding with attach...", 1119 instance); 1120 kmem_free(port->fp_ub_tokens, 1121 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1122 port->fp_ub_tokens = NULL; 1123 } 1124 } 1125 1126 fp_load_ulp_modules(dip, port); 1127 1128 /* 1129 * Enable DDI_SUSPEND and DDI_RESUME for this instance. 1130 */ 1131 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 1132 "pm-hardware-state", "needs-suspend-resume", 1133 strlen("needs-suspend-resume") + 1); 1134 1135 /* 1136 * fctl maintains a list of all port handles, so 1137 * help fctl add this one to its list now. 1138 */ 1139 mutex_enter(&port->fp_mutex); 1140 fctl_add_port(port); 1141 1142 /* 1143 * If a state change is already in progress, set the bind state t 1144 * OFFLINE as well, so further state change callbacks into ULPs 1145 * will pass the appropriate states 1146 */ 1147 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE || 1148 port->fp_statec_busy) { 1149 port->fp_bind_state = FC_STATE_OFFLINE; 1150 mutex_exit(&port->fp_mutex); 1151 1152 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 1153 } else { 1154 /* 1155 * Without dropping the mutex, ensure that the port 1156 * startup happens ahead of state change callback 1157 * processing 1158 */ 1159 ASSERT(port->fp_job_tail == NULL && port->fp_job_head == NULL); 1160 1161 port->fp_last_task = port->fp_task; 1162 port->fp_task = FP_TASK_PORT_STARTUP; 1163 1164 job = fctl_alloc_job(JOB_PORT_STARTUP, JOB_TYPE_FCTL_ASYNC, 1165 fp_startup_done, (opaque_t)port, KM_SLEEP); 1166 1167 port->fp_job_head = port->fp_job_tail = job; 1168 1169 cv_signal(&port->fp_cv); 1170 1171 mutex_exit(&port->fp_mutex); 1172 } 1173 1174 mutex_enter(&port->fp_mutex); 1175 while (port->fp_ulp_attach) { 1176 cv_wait(&port->fp_attach_cv, &port->fp_mutex); 1177 } 1178 mutex_exit(&port->fp_mutex); 1179 1180 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1181 "pm-components", fp_pm_comps, 1182 sizeof (fp_pm_comps) / sizeof (fp_pm_comps[0])) != 1183 DDI_PROP_SUCCESS) { 1184 FP_TRACE(FP_NHEAD2(9, 0), "Failed to create PM" 1185 " components property, PM disabled on this port."); 1186 mutex_enter(&port->fp_mutex); 1187 port->fp_pm_level = FP_PM_PORT_UP; 1188 mutex_exit(&port->fp_mutex); 1189 } else { 1190 if (pm_raise_power(dip, FP_PM_COMPONENT, 1191 FP_PM_PORT_UP) != DDI_SUCCESS) { 1192 FP_TRACE(FP_NHEAD2(9, 0), "Failed to raise" 1193 " power level"); 1194 mutex_enter(&port->fp_mutex); 1195 port->fp_pm_level = FP_PM_PORT_UP; 1196 mutex_exit(&port->fp_mutex); 1197 } 1198 1199 /* 1200 * Don't unset the FP_SOFT_NO_PMCOMP flag until after 1201 * the call to pm_raise_power. The PM framework can't 1202 * handle multiple threads calling into it during attach. 1203 */ 1204 1205 mutex_enter(&port->fp_mutex); 1206 port->fp_soft_state &= ~FP_SOFT_NO_PMCOMP; 1207 mutex_exit(&port->fp_mutex); 1208 } 1209 1210 ddi_report_dev(dip); 1211 1212 fp_log_port_event(port, ESC_SUNFC_PORT_ATTACH); 1213 1214 return (DDI_SUCCESS); 1215 1216 /* 1217 * Unwind any/all preceeding allocations in the event of an error. 1218 */ 1219 1220 alloc_els_packet_failed: 1221 1222 if (port->fp_fca_handle != NULL) { 1223 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1224 port->fp_fca_handle = NULL; 1225 } 1226 1227 if (port->fp_ub_tokens != NULL) { 1228 (void) fc_ulp_ubfree(port, port->fp_ub_count, 1229 port->fp_ub_tokens); 1230 kmem_free(port->fp_ub_tokens, 1231 port->fp_ub_count * sizeof (*port->fp_ub_tokens)); 1232 port->fp_ub_tokens = NULL; 1233 } 1234 1235 if (port->fp_els_resp_pkt != NULL) { 1236 fp_free_pkt(port->fp_els_resp_pkt); 1237 port->fp_els_resp_pkt = NULL; 1238 } 1239 1240 bind_callbacks_failed: 1241 1242 if (port->fp_taskq != NULL) { 1243 taskq_destroy(port->fp_taskq); 1244 } 1245 1246 if (port->fp_pwwn_table != NULL) { 1247 kmem_free(port->fp_pwwn_table, 1248 pwwn_table_size * sizeof (struct pwwn_hash)); 1249 port->fp_pwwn_table = NULL; 1250 } 1251 1252 if (port->fp_did_table != NULL) { 1253 kmem_free(port->fp_did_table, 1254 did_table_size * sizeof (struct d_id_hash)); 1255 port->fp_did_table = NULL; 1256 } 1257 1258 if (port->fp_pkt_cache != NULL) { 1259 kmem_cache_destroy(port->fp_pkt_cache); 1260 port->fp_pkt_cache = NULL; 1261 } 1262 1263 cache_alloc_failed: 1264 1265 cv_destroy(&port->fp_attach_cv); 1266 cv_destroy(&port->fp_cv); 1267 mutex_destroy(&port->fp_mutex); 1268 ddi_remove_minor_node(port->fp_port_dip, NULL); 1269 ddi_soft_state_free(fp_driver_softstate, instance); 1270 ddi_prop_remove_all(dip); 1271 1272 return (DDI_FAILURE); 1273 } 1274 1275 1276 /* 1277 * Handle DDI_RESUME request 1278 */ 1279 static int 1280 fp_resume_handler(dev_info_t *dip) 1281 { 1282 int rval; 1283 fc_local_port_t *port; 1284 1285 port = ddi_get_soft_state(fp_driver_softstate, ddi_get_instance(dip)); 1286 1287 ASSERT(port != NULL); 1288 1289 #ifdef DEBUG 1290 mutex_enter(&port->fp_mutex); 1291 ASSERT(port->fp_soft_state & FP_SOFT_SUSPEND); 1292 mutex_exit(&port->fp_mutex); 1293 #endif 1294 1295 /* 1296 * If the port was power suspended, raise the power level 1297 */ 1298 mutex_enter(&port->fp_mutex); 1299 if ((port->fp_soft_state & FP_SOFT_POWER_DOWN) && 1300 (!(port->fp_soft_state & FP_SOFT_NO_PMCOMP))) { 1301 ASSERT(port->fp_pm_level == FP_PM_PORT_DOWN); 1302 1303 mutex_exit(&port->fp_mutex); 1304 if (pm_raise_power(dip, FP_PM_COMPONENT, 1305 FP_PM_PORT_UP) != DDI_SUCCESS) { 1306 FP_TRACE(FP_NHEAD2(9, 0), 1307 "Failed to raise the power level"); 1308 return (DDI_FAILURE); 1309 } 1310 mutex_enter(&port->fp_mutex); 1311 } 1312 port->fp_soft_state &= ~FP_SOFT_SUSPEND; 1313 mutex_exit(&port->fp_mutex); 1314 1315 /* 1316 * All the discovery is initiated and handled by per-port thread. 1317 * Further all the discovery is done in handled in callback mode 1318 * (not polled mode); In a specific case such as this, the discovery 1319 * is required to happen in polled mode. The easiest way out is 1320 * to bail out port thread and get started. Come back and fix this 1321 * to do on demand discovery initiated by ULPs. ULPs such as FCP 1322 * will do on-demand discovery during pre-power-up busctl handling 1323 * which will only be possible when SCSA provides a new HBA vector 1324 * for sending down the PM busctl requests. 1325 */ 1326 (void) callb_generic_cpr(&port->fp_cpr_info, CB_CODE_CPR_RESUME); 1327 1328 rval = fp_resume_all(port, FC_CMD_RESUME); 1329 if (rval != DDI_SUCCESS) { 1330 mutex_enter(&port->fp_mutex); 1331 port->fp_soft_state |= FP_SOFT_SUSPEND; 1332 mutex_exit(&port->fp_mutex); 1333 (void) callb_generic_cpr(&port->fp_cpr_info, 1334 CB_CODE_CPR_CHKPT); 1335 } 1336 1337 return (rval); 1338 } 1339 1340 /* 1341 * Perform FC Port power on initialization 1342 */ 1343 static int 1344 fp_power_up(fc_local_port_t *port) 1345 { 1346 int rval; 1347 1348 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1349 1350 ASSERT((port->fp_soft_state & FP_SOFT_SUSPEND) == 0); 1351 ASSERT(port->fp_soft_state & FP_SOFT_POWER_DOWN); 1352 1353 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1354 1355 mutex_exit(&port->fp_mutex); 1356 1357 rval = fp_resume_all(port, FC_CMD_POWER_UP); 1358 if (rval != DDI_SUCCESS) { 1359 mutex_enter(&port->fp_mutex); 1360 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1361 } else { 1362 mutex_enter(&port->fp_mutex); 1363 } 1364 1365 return (rval); 1366 } 1367 1368 1369 /* 1370 * It is important to note that the power may possibly be removed between 1371 * SUSPEND and the ensuing RESUME operation. In such a context the underlying 1372 * FC port hardware would have gone through an OFFLINE to ONLINE transition 1373 * (hardware state). In this case, the port driver may need to rediscover the 1374 * topology, perform LOGINs, register with the name server again and perform 1375 * any such port initialization procedures. To perform LOGINs, the driver could 1376 * use the port device handle to see if a LOGIN needs to be performed and use 1377 * the D_ID and WWN in it. The LOGINs may fail (if the hardware is reconfigured 1378 * or removed) which will be reflected in the map the ULPs will see. 1379 */ 1380 static int 1381 fp_resume_all(fc_local_port_t *port, fc_attach_cmd_t cmd) 1382 { 1383 1384 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1385 1386 if (fp_bind_callbacks(port) != DDI_SUCCESS) { 1387 return (DDI_FAILURE); 1388 } 1389 1390 mutex_enter(&port->fp_mutex); 1391 1392 /* 1393 * If there are commands queued for delayed retry, instead of 1394 * working the hard way to figure out which ones are good for 1395 * restart and which ones not (ELSs are definitely not good 1396 * as the port will have to go through a new spin of rediscovery 1397 * now), so just flush them out. 1398 */ 1399 if (port->fp_restore & FP_RESTORE_WAIT_TIMEOUT) { 1400 fp_cmd_t *cmd; 1401 1402 port->fp_restore &= ~FP_RESTORE_WAIT_TIMEOUT; 1403 1404 mutex_exit(&port->fp_mutex); 1405 while ((cmd = fp_deque_cmd(port)) != NULL) { 1406 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 1407 fp_iodone(cmd); 1408 } 1409 mutex_enter(&port->fp_mutex); 1410 } 1411 1412 if (FC_PORT_STATE_MASK(port->fp_bind_state) == FC_STATE_OFFLINE) { 1413 if ((port->fp_restore & FP_RESTORE_OFFLINE_TIMEOUT) || 1414 port->fp_dev_count) { 1415 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1416 port->fp_offline_tid = timeout(fp_offline_timeout, 1417 (caddr_t)port, fp_offline_ticks); 1418 } 1419 if (port->fp_job_head) { 1420 cv_signal(&port->fp_cv); 1421 } 1422 mutex_exit(&port->fp_mutex); 1423 fctl_attach_ulps(port, cmd, &modlinkage); 1424 } else { 1425 struct job_request *job; 1426 1427 /* 1428 * If an OFFLINE timer was running at the time of 1429 * suspending, there is no need to restart it as 1430 * the port is ONLINE now. 1431 */ 1432 port->fp_restore &= ~FP_RESTORE_OFFLINE_TIMEOUT; 1433 if (port->fp_statec_busy == 0) { 1434 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 1435 } 1436 port->fp_statec_busy++; 1437 mutex_exit(&port->fp_mutex); 1438 1439 job = fctl_alloc_job(JOB_PORT_ONLINE, 1440 JOB_CANCEL_ULP_NOTIFICATION, NULL, NULL, KM_SLEEP); 1441 fctl_enque_job(port, job); 1442 1443 fctl_jobwait(job); 1444 fctl_remove_oldies(port); 1445 1446 fctl_attach_ulps(port, cmd, &modlinkage); 1447 fctl_dealloc_job(job); 1448 } 1449 1450 return (DDI_SUCCESS); 1451 } 1452 1453 1454 /* 1455 * At this time, there shouldn't be any I/O requests on this port. 1456 * But the unsolicited callbacks from the underlying FCA port need 1457 * to be handled very carefully. The steps followed to handle the 1458 * DDI_DETACH are: 1459 * + Grab the port driver mutex, check if the unsolicited 1460 * callback is currently under processing. If true, fail 1461 * the DDI_DETACH request by printing a message; If false 1462 * mark the DDI_DETACH as under progress, so that any 1463 * further unsolicited callbacks get bounced. 1464 * + Perform PRLO/LOGO if necessary, cleanup all the data 1465 * structures. 1466 * + Get the job_handler thread to gracefully exit. 1467 * + Unregister callbacks with the FCA port. 1468 * + Now that some peace is found, notify all the ULPs of 1469 * DDI_DETACH request (using ulp_port_detach entry point) 1470 * + Free all mutexes, semaphores, conditional variables. 1471 * + Free the soft state, return success. 1472 * 1473 * Important considerations: 1474 * Port driver de-registers state change and unsolicited 1475 * callbacks before taking up the task of notifying ULPs 1476 * and performing PRLO and LOGOs. 1477 * 1478 * A port may go offline at the time PRLO/LOGO is being 1479 * requested. It is expected of all FCA drivers to fail 1480 * such requests either immediately with a FC_OFFLINE 1481 * return code to fc_fca_transport() or return the packet 1482 * asynchronously with pkt state set to FC_PKT_PORT_OFFLINE 1483 */ 1484 static int 1485 fp_detach_handler(fc_local_port_t *port) 1486 { 1487 job_request_t *job; 1488 uint32_t delay_count; 1489 fc_orphan_t *orp, *tmporp; 1490 1491 /* 1492 * In a Fabric topology with many host ports connected to 1493 * a switch, another detaching instance of fp might have 1494 * triggered a LOGO (which is an unsolicited request to 1495 * this instance). So in order to be able to successfully 1496 * detach by taking care of such cases a delay of about 1497 * 30 seconds is introduced. 1498 */ 1499 delay_count = 0; 1500 mutex_enter(&port->fp_mutex); 1501 if (port->fp_out_fpcmds != 0) { 1502 /* 1503 * At this time we can only check fp internal commands, because 1504 * sd/ssd/scsi_vhci should have finsihed all their commands, 1505 * fcp/fcip/fcsm should have finished all their commands. 1506 * 1507 * It seems that all fp internal commands are asynchronous now. 1508 */ 1509 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1510 mutex_exit(&port->fp_mutex); 1511 1512 cmn_err(CE_WARN, "fp(%d): %d fp_cmd(s) is/are in progress" 1513 " Failing detach", port->fp_instance, port->fp_out_fpcmds); 1514 return (DDI_FAILURE); 1515 } 1516 1517 while ((port->fp_soft_state & 1518 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) && 1519 (delay_count < 30)) { 1520 mutex_exit(&port->fp_mutex); 1521 delay_count++; 1522 delay(drv_usectohz(1000000)); 1523 mutex_enter(&port->fp_mutex); 1524 } 1525 1526 if (port->fp_soft_state & 1527 (FP_SOFT_IN_STATEC_CB | FP_SOFT_IN_UNSOL_CB)) { 1528 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1529 mutex_exit(&port->fp_mutex); 1530 1531 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1532 " Failing detach", port->fp_instance); 1533 return (DDI_FAILURE); 1534 } 1535 1536 port->fp_soft_state |= FP_SOFT_IN_DETACH; 1537 port->fp_soft_state &= ~FP_DETACH_INPROGRESS; 1538 mutex_exit(&port->fp_mutex); 1539 1540 /* 1541 * If we're powered down, we need to raise power prior to submitting 1542 * the JOB_PORT_SHUTDOWN job. Otherwise, the job handler will never 1543 * process the shutdown job. 1544 */ 1545 if (fctl_busy_port(port) != 0) { 1546 cmn_err(CE_WARN, "fp(%d): fctl_busy_port failed", 1547 port->fp_instance); 1548 mutex_enter(&port->fp_mutex); 1549 port->fp_soft_state &= ~FP_SOFT_IN_DETACH; 1550 mutex_exit(&port->fp_mutex); 1551 return (DDI_FAILURE); 1552 } 1553 1554 /* 1555 * This will deallocate data structs and cause the "job" thread 1556 * to exit, in preparation for DDI_DETACH on the instance. 1557 * This can sleep for an arbitrary duration, since it waits for 1558 * commands over the wire, timeout(9F) callbacks, etc. 1559 * 1560 * CAUTION: There is still a race here, where the "job" thread 1561 * can still be executing code even tho the fctl_jobwait() call 1562 * below has returned to us. In theory the fp driver could even be 1563 * modunloaded even tho the job thread isn't done executing. 1564 * without creating the race condition. 1565 */ 1566 job = fctl_alloc_job(JOB_PORT_SHUTDOWN, 0, NULL, 1567 (opaque_t)port, KM_SLEEP); 1568 fctl_enque_job(port, job); 1569 fctl_jobwait(job); 1570 fctl_dealloc_job(job); 1571 1572 1573 (void) pm_lower_power(port->fp_port_dip, FP_PM_COMPONENT, 1574 FP_PM_PORT_DOWN); 1575 1576 if (port->fp_taskq) { 1577 taskq_destroy(port->fp_taskq); 1578 } 1579 1580 ddi_prop_remove_all(port->fp_port_dip); 1581 1582 ddi_remove_minor_node(port->fp_port_dip, NULL); 1583 1584 fctl_remove_port(port); 1585 1586 fp_free_pkt(port->fp_els_resp_pkt); 1587 1588 if (port->fp_ub_tokens) { 1589 if (fc_ulp_ubfree(port, port->fp_ub_count, 1590 port->fp_ub_tokens) != FC_SUCCESS) { 1591 cmn_err(CE_WARN, "fp(%d): couldn't free " 1592 " unsolicited buffers", port->fp_instance); 1593 } 1594 kmem_free(port->fp_ub_tokens, 1595 sizeof (*port->fp_ub_tokens) * port->fp_ub_count); 1596 port->fp_ub_tokens = NULL; 1597 } 1598 1599 if (port->fp_pkt_cache != NULL) { 1600 kmem_cache_destroy(port->fp_pkt_cache); 1601 } 1602 1603 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1604 1605 mutex_enter(&port->fp_mutex); 1606 if (port->fp_did_table) { 1607 kmem_free(port->fp_did_table, did_table_size * 1608 sizeof (struct d_id_hash)); 1609 } 1610 1611 if (port->fp_pwwn_table) { 1612 kmem_free(port->fp_pwwn_table, pwwn_table_size * 1613 sizeof (struct pwwn_hash)); 1614 } 1615 orp = port->fp_orphan_list; 1616 while (orp) { 1617 tmporp = orp; 1618 orp = orp->orp_next; 1619 kmem_free(tmporp, sizeof (*orp)); 1620 } 1621 1622 mutex_exit(&port->fp_mutex); 1623 1624 fp_log_port_event(port, ESC_SUNFC_PORT_DETACH); 1625 1626 mutex_destroy(&port->fp_mutex); 1627 cv_destroy(&port->fp_attach_cv); 1628 cv_destroy(&port->fp_cv); 1629 ddi_soft_state_free(fp_driver_softstate, port->fp_instance); 1630 1631 return (DDI_SUCCESS); 1632 } 1633 1634 1635 /* 1636 * Steps to perform DDI_SUSPEND operation on a FC port 1637 * 1638 * - If already suspended return DDI_FAILURE 1639 * - If already power-suspended return DDI_SUCCESS 1640 * - If an unsolicited callback or state change handling is in 1641 * in progress, throw a warning message, return DDI_FAILURE 1642 * - Cancel timeouts 1643 * - SUSPEND the job_handler thread (means do nothing as it is 1644 * taken care of by the CPR frame work) 1645 */ 1646 static int 1647 fp_suspend_handler(fc_local_port_t *port) 1648 { 1649 uint32_t delay_count; 1650 1651 mutex_enter(&port->fp_mutex); 1652 1653 /* 1654 * The following should never happen, but 1655 * let the driver be more defensive here 1656 */ 1657 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1658 mutex_exit(&port->fp_mutex); 1659 return (DDI_FAILURE); 1660 } 1661 1662 /* 1663 * If the port is already power suspended, there 1664 * is nothing else to do, So return DDI_SUCCESS, 1665 * but mark the SUSPEND bit in the soft state 1666 * before leaving. 1667 */ 1668 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1669 port->fp_soft_state |= FP_SOFT_SUSPEND; 1670 mutex_exit(&port->fp_mutex); 1671 return (DDI_SUCCESS); 1672 } 1673 1674 /* 1675 * Check if an unsolicited callback or state change handling is 1676 * in progress. If true, fail the suspend operation; also throw 1677 * a warning message notifying the failure. Note that Sun PCI 1678 * hotplug spec recommends messages in cases of failure (but 1679 * not flooding the console) 1680 * 1681 * Busy waiting for a short interval (500 millisecond ?) to see 1682 * if the callback processing completes may be another idea. Since 1683 * most of the callback processing involves a lot of work, it 1684 * is safe to just fail the SUSPEND operation. It is definitely 1685 * not bad to fail the SUSPEND operation if the driver is busy. 1686 */ 1687 delay_count = 0; 1688 while ((port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1689 FP_SOFT_IN_UNSOL_CB)) && (delay_count < 30)) { 1690 mutex_exit(&port->fp_mutex); 1691 delay_count++; 1692 delay(drv_usectohz(1000000)); 1693 mutex_enter(&port->fp_mutex); 1694 } 1695 1696 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 1697 FP_SOFT_IN_UNSOL_CB)) { 1698 mutex_exit(&port->fp_mutex); 1699 cmn_err(CE_WARN, "fp(%d): FCA callback in progress: " 1700 " Failing suspend", port->fp_instance); 1701 return (DDI_FAILURE); 1702 } 1703 1704 /* 1705 * Check of FC port thread is busy 1706 */ 1707 if (port->fp_job_head) { 1708 mutex_exit(&port->fp_mutex); 1709 FP_TRACE(FP_NHEAD2(9, 0), 1710 "FC port thread is busy: Failing suspend"); 1711 return (DDI_FAILURE); 1712 } 1713 port->fp_soft_state |= FP_SOFT_SUSPEND; 1714 1715 fp_suspend_all(port); 1716 mutex_exit(&port->fp_mutex); 1717 1718 return (DDI_SUCCESS); 1719 } 1720 1721 1722 /* 1723 * Prepare for graceful power down of a FC port 1724 */ 1725 static int 1726 fp_power_down(fc_local_port_t *port) 1727 { 1728 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1729 1730 /* 1731 * Power down request followed by a DDI_SUSPEND should 1732 * never happen; If it does return DDI_SUCCESS 1733 */ 1734 if (port->fp_soft_state & FP_SOFT_SUSPEND) { 1735 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1736 return (DDI_SUCCESS); 1737 } 1738 1739 /* 1740 * If the port is already power suspended, there 1741 * is nothing else to do, So return DDI_SUCCESS, 1742 */ 1743 if (port->fp_soft_state & FP_SOFT_POWER_DOWN) { 1744 return (DDI_SUCCESS); 1745 } 1746 1747 /* 1748 * Check if an unsolicited callback or state change handling 1749 * is in progress. If true, fail the PM suspend operation. 1750 * But don't print a message unless the verbosity of the 1751 * driver desires otherwise. 1752 */ 1753 if ((port->fp_soft_state & FP_SOFT_IN_STATEC_CB) || 1754 (port->fp_soft_state & FP_SOFT_IN_UNSOL_CB)) { 1755 FP_TRACE(FP_NHEAD2(9, 0), 1756 "Unsolicited callback in progress: Failing power down"); 1757 return (DDI_FAILURE); 1758 } 1759 1760 /* 1761 * Check of FC port thread is busy 1762 */ 1763 if (port->fp_job_head) { 1764 FP_TRACE(FP_NHEAD2(9, 0), 1765 "FC port thread is busy: Failing power down"); 1766 return (DDI_FAILURE); 1767 } 1768 port->fp_soft_state |= FP_SOFT_POWER_DOWN; 1769 1770 /* 1771 * check if the ULPs are ready for power down 1772 */ 1773 mutex_exit(&port->fp_mutex); 1774 if (fctl_detach_ulps(port, FC_CMD_POWER_DOWN, 1775 &modlinkage) != FC_SUCCESS) { 1776 mutex_enter(&port->fp_mutex); 1777 port->fp_soft_state &= ~FP_SOFT_POWER_DOWN; 1778 mutex_exit(&port->fp_mutex); 1779 1780 /* 1781 * Power back up the obedient ULPs that went down 1782 */ 1783 fp_attach_ulps(port, FC_CMD_POWER_UP); 1784 1785 FP_TRACE(FP_NHEAD2(9, 0), 1786 "ULP(s) busy, detach_ulps failed. Failing power down"); 1787 mutex_enter(&port->fp_mutex); 1788 return (DDI_FAILURE); 1789 } 1790 mutex_enter(&port->fp_mutex); 1791 1792 fp_suspend_all(port); 1793 1794 return (DDI_SUCCESS); 1795 } 1796 1797 1798 /* 1799 * Suspend the entire FC port 1800 */ 1801 static void 1802 fp_suspend_all(fc_local_port_t *port) 1803 { 1804 int index; 1805 struct pwwn_hash *head; 1806 fc_remote_port_t *pd; 1807 1808 ASSERT(MUTEX_HELD(&port->fp_mutex)); 1809 1810 if (port->fp_wait_tid != 0) { 1811 timeout_id_t tid; 1812 1813 tid = port->fp_wait_tid; 1814 port->fp_wait_tid = (timeout_id_t)NULL; 1815 mutex_exit(&port->fp_mutex); 1816 (void) untimeout(tid); 1817 mutex_enter(&port->fp_mutex); 1818 port->fp_restore |= FP_RESTORE_WAIT_TIMEOUT; 1819 } 1820 1821 if (port->fp_offline_tid) { 1822 timeout_id_t tid; 1823 1824 tid = port->fp_offline_tid; 1825 port->fp_offline_tid = (timeout_id_t)NULL; 1826 mutex_exit(&port->fp_mutex); 1827 (void) untimeout(tid); 1828 mutex_enter(&port->fp_mutex); 1829 port->fp_restore |= FP_RESTORE_OFFLINE_TIMEOUT; 1830 } 1831 mutex_exit(&port->fp_mutex); 1832 port->fp_fca_tran->fca_unbind_port(port->fp_fca_handle); 1833 mutex_enter(&port->fp_mutex); 1834 1835 /* 1836 * Mark all devices as OLD, and reset the LOGIN state as well 1837 * (this will force the ULPs to perform a LOGIN after calling 1838 * fc_portgetmap() during RESUME/PM_RESUME) 1839 */ 1840 for (index = 0; index < pwwn_table_size; index++) { 1841 head = &port->fp_pwwn_table[index]; 1842 pd = head->pwwn_head; 1843 while (pd != NULL) { 1844 mutex_enter(&pd->pd_mutex); 1845 fp_remote_port_offline(pd); 1846 fctl_delist_did_table(port, pd); 1847 pd->pd_state = PORT_DEVICE_VALID; 1848 pd->pd_login_count = 0; 1849 mutex_exit(&pd->pd_mutex); 1850 pd = pd->pd_wwn_hnext; 1851 } 1852 } 1853 } 1854 1855 1856 /* 1857 * fp_cache_constructor: Constructor function for kmem_cache_create(9F). 1858 * Performs intializations for fc_packet_t structs. 1859 * Returns 0 for success or -1 for failure. 1860 * 1861 * This function allocates DMA handles for both command and responses. 1862 * Most of the ELSs used have both command and responses so it is strongly 1863 * desired to move them to cache constructor routine. 1864 * 1865 * Context: Can sleep iff called with KM_SLEEP flag. 1866 */ 1867 static int 1868 fp_cache_constructor(void *buf, void *cdarg, int kmflags) 1869 { 1870 int (*cb) (caddr_t); 1871 fc_packet_t *pkt; 1872 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1873 fc_local_port_t *port = (fc_local_port_t *)cdarg; 1874 1875 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1876 1877 cmd->cmd_next = NULL; 1878 cmd->cmd_flags = 0; 1879 cmd->cmd_dflags = 0; 1880 cmd->cmd_job = NULL; 1881 cmd->cmd_port = port; 1882 pkt = &cmd->cmd_pkt; 1883 1884 if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 1885 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1886 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1887 &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 1888 return (-1); 1889 } 1890 1891 if (ddi_dma_alloc_handle(port->fp_fca_dip, 1892 port->fp_fca_tran->fca_dma_attr, cb, NULL, 1893 &pkt->pkt_resp_dma) != DDI_SUCCESS) { 1894 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1895 return (-1); 1896 } 1897 } else { 1898 pkt->pkt_cmd_dma = 0; 1899 pkt->pkt_resp_dma = 0; 1900 } 1901 1902 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL; 1903 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt = 1904 pkt->pkt_data_cookie_cnt = 0; 1905 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie = 1906 pkt->pkt_data_cookie = NULL; 1907 pkt->pkt_fca_private = (caddr_t)buf + sizeof (fp_cmd_t); 1908 1909 return (0); 1910 } 1911 1912 1913 /* 1914 * fp_cache_destructor: Destructor function for kmem_cache_create(). 1915 * Performs un-intializations for fc_packet_t structs. 1916 */ 1917 /* ARGSUSED */ 1918 static void 1919 fp_cache_destructor(void *buf, void *cdarg) 1920 { 1921 fp_cmd_t *cmd = (fp_cmd_t *)buf; 1922 fc_packet_t *pkt; 1923 1924 pkt = &cmd->cmd_pkt; 1925 if (pkt->pkt_cmd_dma) { 1926 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1927 } 1928 1929 if (pkt->pkt_resp_dma) { 1930 ddi_dma_free_handle(&pkt->pkt_resp_dma); 1931 } 1932 } 1933 1934 1935 /* 1936 * Packet allocation for ELS and any other port driver commands 1937 * 1938 * Some ELSs like FLOGI and PLOGI are critical for topology and 1939 * device discovery and a system's inability to allocate memory 1940 * or DVMA resources while performing some of these critical ELSs 1941 * cause a lot of problem. While memory allocation failures are 1942 * rare, DVMA resource failures are common as the applications 1943 * are becoming more and more powerful on huge servers. So it 1944 * is desirable to have a framework support to reserve a fragment 1945 * of DVMA. So until this is fixed the correct way, the suffering 1946 * is huge whenever a LIP happens at a time DVMA resources are 1947 * drained out completely - So an attempt needs to be made to 1948 * KM_SLEEP while requesting for these resources, hoping that 1949 * the requests won't hang forever. 1950 * 1951 * The fc_remote_port_t argument is stored into the pkt_pd field in the 1952 * fc_packet_t struct prior to the fc_ulp_init_packet() call. This 1953 * ensures that the pd_ref_count for the fc_remote_port_t is valid. 1954 * If there is no fc_remote_port_t associated with the fc_packet_t, then 1955 * fp_alloc_pkt() must be called with pd set to NULL. 1956 * 1957 * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen, 1958 * actually, it's a design fault. But there's no problem for physical 1959 * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei. 1960 * 1961 * For FCAs that don't support DMA, such as fcoei, we will use 1962 * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len. 1963 */ 1964 1965 static fp_cmd_t * 1966 fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags, 1967 fc_remote_port_t *pd) 1968 { 1969 int rval; 1970 ulong_t real_len; 1971 fp_cmd_t *cmd; 1972 fc_packet_t *pkt; 1973 int (*cb) (caddr_t); 1974 ddi_dma_cookie_t pkt_cookie; 1975 ddi_dma_cookie_t *cp; 1976 uint32_t cnt; 1977 1978 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 1979 1980 cb = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 1981 1982 cmd = (fp_cmd_t *)kmem_cache_alloc(port->fp_pkt_cache, kmflags); 1983 if (cmd == NULL) { 1984 return (cmd); 1985 } 1986 1987 cmd->cmd_ulp_pkt = NULL; 1988 cmd->cmd_flags = 0; 1989 pkt = &cmd->cmd_pkt; 1990 ASSERT(cmd->cmd_dflags == 0); 1991 1992 pkt->pkt_datalen = 0; 1993 pkt->pkt_data = NULL; 1994 pkt->pkt_state = 0; 1995 pkt->pkt_action = 0; 1996 pkt->pkt_reason = 0; 1997 pkt->pkt_expln = 0; 1998 pkt->pkt_cmd = NULL; 1999 pkt->pkt_resp = NULL; 2000 pkt->pkt_fctl_rsvd1 = NULL; 2001 pkt->pkt_fctl_rsvd2 = NULL; 2002 2003 /* 2004 * Init pkt_pd with the given pointer; this must be done _before_ 2005 * the call to fc_ulp_init_packet(). 2006 */ 2007 pkt->pkt_pd = pd; 2008 2009 /* Now call the FCA driver to init its private, per-packet fields */ 2010 if (fc_ulp_init_packet((opaque_t)port, pkt, kmflags) != FC_SUCCESS) { 2011 goto alloc_pkt_failed; 2012 } 2013 2014 if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2015 ASSERT(pkt->pkt_cmd_dma != NULL); 2016 2017 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len, 2018 port->fp_fca_tran->fca_acc_attr, DDI_DMA_CONSISTENT, 2019 cb, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len, 2020 &pkt->pkt_cmd_acc); 2021 2022 if (rval != DDI_SUCCESS) { 2023 goto alloc_pkt_failed; 2024 } 2025 cmd->cmd_dflags |= FP_CMD_VALID_DMA_MEM; 2026 2027 if (real_len < cmd_len) { 2028 goto alloc_pkt_failed; 2029 } 2030 2031 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 2032 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | 2033 DDI_DMA_CONSISTENT, cb, NULL, 2034 &pkt_cookie, &pkt->pkt_cmd_cookie_cnt); 2035 2036 if (rval != DDI_DMA_MAPPED) { 2037 goto alloc_pkt_failed; 2038 } 2039 2040 cmd->cmd_dflags |= FP_CMD_VALID_DMA_BIND; 2041 2042 if (pkt->pkt_cmd_cookie_cnt > 2043 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2044 goto alloc_pkt_failed; 2045 } 2046 2047 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2048 2049 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2050 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie), 2051 KM_NOSLEEP); 2052 2053 if (cp == NULL) { 2054 goto alloc_pkt_failed; 2055 } 2056 2057 *cp = pkt_cookie; 2058 cp++; 2059 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) { 2060 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie); 2061 *cp = pkt_cookie; 2062 } 2063 } else if (cmd_len != 0) { 2064 pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP); 2065 pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len; 2066 } 2067 2068 if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) { 2069 ASSERT(pkt->pkt_resp_dma != NULL); 2070 2071 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len, 2072 port->fp_fca_tran->fca_acc_attr, 2073 DDI_DMA_CONSISTENT, cb, NULL, 2074 (caddr_t *)&pkt->pkt_resp, &real_len, 2075 &pkt->pkt_resp_acc); 2076 2077 if (rval != DDI_SUCCESS) { 2078 goto alloc_pkt_failed; 2079 } 2080 cmd->cmd_dflags |= FP_RESP_VALID_DMA_MEM; 2081 2082 if (real_len < resp_len) { 2083 goto alloc_pkt_failed; 2084 } 2085 2086 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 2087 pkt->pkt_resp, real_len, DDI_DMA_READ | 2088 DDI_DMA_CONSISTENT, cb, NULL, 2089 &pkt_cookie, &pkt->pkt_resp_cookie_cnt); 2090 2091 if (rval != DDI_DMA_MAPPED) { 2092 goto alloc_pkt_failed; 2093 } 2094 2095 cmd->cmd_dflags |= FP_RESP_VALID_DMA_BIND; 2096 2097 if (pkt->pkt_resp_cookie_cnt > 2098 port->fp_fca_tran->fca_dma_attr->dma_attr_sgllen) { 2099 goto alloc_pkt_failed; 2100 } 2101 2102 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2103 2104 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2105 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie), 2106 KM_NOSLEEP); 2107 2108 if (cp == NULL) { 2109 goto alloc_pkt_failed; 2110 } 2111 2112 *cp = pkt_cookie; 2113 cp++; 2114 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) { 2115 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie); 2116 *cp = pkt_cookie; 2117 } 2118 } else if (resp_len != 0) { 2119 pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP); 2120 pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len; 2121 } 2122 2123 pkt->pkt_cmdlen = cmd_len; 2124 pkt->pkt_rsplen = resp_len; 2125 pkt->pkt_ulp_private = cmd; 2126 2127 return (cmd); 2128 2129 alloc_pkt_failed: 2130 2131 fp_free_dma(cmd); 2132 2133 if (pkt->pkt_cmd_cookie != NULL) { 2134 kmem_free(pkt->pkt_cmd_cookie, 2135 pkt->pkt_cmd_cookie_cnt * 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, 2141 pkt->pkt_resp_cookie_cnt * sizeof (ddi_dma_cookie_t)); 2142 pkt->pkt_resp_cookie = NULL; 2143 } 2144 2145 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2146 if (pkt->pkt_cmd) { 2147 kmem_free(pkt->pkt_cmd, cmd_len); 2148 } 2149 2150 if (pkt->pkt_resp) { 2151 kmem_free(pkt->pkt_resp, resp_len); 2152 } 2153 } 2154 2155 kmem_cache_free(port->fp_pkt_cache, cmd); 2156 2157 return (NULL); 2158 } 2159 2160 2161 /* 2162 * Free FC packet 2163 */ 2164 static void 2165 fp_free_pkt(fp_cmd_t *cmd) 2166 { 2167 fc_local_port_t *port; 2168 fc_packet_t *pkt; 2169 2170 ASSERT(!MUTEX_HELD(&cmd->cmd_port->fp_mutex)); 2171 2172 cmd->cmd_next = NULL; 2173 cmd->cmd_job = NULL; 2174 pkt = &cmd->cmd_pkt; 2175 pkt->pkt_ulp_private = 0; 2176 pkt->pkt_tran_flags = 0; 2177 pkt->pkt_tran_type = 0; 2178 port = cmd->cmd_port; 2179 2180 if (pkt->pkt_cmd_cookie != NULL) { 2181 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt * 2182 sizeof (ddi_dma_cookie_t)); 2183 pkt->pkt_cmd_cookie = NULL; 2184 } 2185 2186 if (pkt->pkt_resp_cookie != NULL) { 2187 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt * 2188 sizeof (ddi_dma_cookie_t)); 2189 pkt->pkt_resp_cookie = NULL; 2190 } 2191 2192 if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) { 2193 if (pkt->pkt_cmd) { 2194 kmem_free(pkt->pkt_cmd, 2195 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1); 2196 } 2197 2198 if (pkt->pkt_resp) { 2199 kmem_free(pkt->pkt_resp, 2200 (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2); 2201 } 2202 } 2203 2204 fp_free_dma(cmd); 2205 (void) fc_ulp_uninit_packet((opaque_t)port, pkt); 2206 kmem_cache_free(port->fp_pkt_cache, (void *)cmd); 2207 } 2208 2209 2210 /* 2211 * Release DVMA resources 2212 */ 2213 static void 2214 fp_free_dma(fp_cmd_t *cmd) 2215 { 2216 fc_packet_t *pkt = &cmd->cmd_pkt; 2217 2218 pkt->pkt_cmdlen = 0; 2219 pkt->pkt_rsplen = 0; 2220 pkt->pkt_tran_type = 0; 2221 pkt->pkt_tran_flags = 0; 2222 2223 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_BIND) { 2224 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 2225 } 2226 2227 if (cmd->cmd_dflags & FP_CMD_VALID_DMA_MEM) { 2228 if (pkt->pkt_cmd_acc) { 2229 ddi_dma_mem_free(&pkt->pkt_cmd_acc); 2230 } 2231 } 2232 2233 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_BIND) { 2234 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 2235 } 2236 2237 if (cmd->cmd_dflags & FP_RESP_VALID_DMA_MEM) { 2238 if (pkt->pkt_resp_acc) { 2239 ddi_dma_mem_free(&pkt->pkt_resp_acc); 2240 } 2241 } 2242 cmd->cmd_dflags = 0; 2243 } 2244 2245 2246 /* 2247 * Dedicated thread to perform various activities. One thread for 2248 * each fc_local_port_t (driver soft state) instance. 2249 * Note, this effectively works out to one thread for each local 2250 * port, but there are also some Solaris taskq threads in use on a per-local 2251 * port basis; these also need to be taken into consideration. 2252 */ 2253 static void 2254 fp_job_handler(fc_local_port_t *port) 2255 { 2256 int rval; 2257 uint32_t *d_id; 2258 fc_remote_port_t *pd; 2259 job_request_t *job; 2260 2261 #ifndef __lock_lint 2262 /* 2263 * Solaris-internal stuff for proper operation of kernel threads 2264 * with Solaris CPR. 2265 */ 2266 CALLB_CPR_INIT(&port->fp_cpr_info, &port->fp_mutex, 2267 callb_generic_cpr, "fp_job_handler"); 2268 #endif 2269 2270 2271 /* Loop forever waiting for work to do */ 2272 for (;;) { 2273 2274 mutex_enter(&port->fp_mutex); 2275 2276 /* 2277 * Sleep if no work to do right now, or if we want 2278 * to suspend or power-down. 2279 */ 2280 while (port->fp_job_head == NULL || 2281 (port->fp_soft_state & (FP_SOFT_POWER_DOWN | 2282 FP_SOFT_SUSPEND))) { 2283 CALLB_CPR_SAFE_BEGIN(&port->fp_cpr_info); 2284 cv_wait(&port->fp_cv, &port->fp_mutex); 2285 CALLB_CPR_SAFE_END(&port->fp_cpr_info, &port->fp_mutex); 2286 } 2287 2288 /* 2289 * OK, we've just been woken up, so retrieve the next entry 2290 * from the head of the job queue for this local port. 2291 */ 2292 job = fctl_deque_job(port); 2293 2294 /* 2295 * Handle all the fp driver's supported job codes here 2296 * in this big honkin' switch. 2297 */ 2298 switch (job->job_code) { 2299 case JOB_PORT_SHUTDOWN: 2300 /* 2301 * fp_port_shutdown() is only called from here. This 2302 * will prepare the local port instance (softstate) 2303 * for detaching. This cancels timeout callbacks, 2304 * executes LOGOs with remote ports, cleans up tables, 2305 * and deallocates data structs. 2306 */ 2307 fp_port_shutdown(port, job); 2308 2309 /* 2310 * This will exit the job thread. 2311 */ 2312 #ifndef __lock_lint 2313 CALLB_CPR_EXIT(&(port->fp_cpr_info)); 2314 #else 2315 mutex_exit(&port->fp_mutex); 2316 #endif 2317 fctl_jobdone(job); 2318 thread_exit(); 2319 2320 /* NOTREACHED */ 2321 2322 case JOB_ATTACH_ULP: { 2323 /* 2324 * This job is spawned in response to a ULP calling 2325 * fc_ulp_add(). 2326 */ 2327 2328 boolean_t do_attach_ulps = B_TRUE; 2329 2330 /* 2331 * If fp is detaching, we don't want to call 2332 * fp_startup_done as this asynchronous 2333 * notification may interfere with the re-attach. 2334 */ 2335 2336 if (port->fp_soft_state & (FP_DETACH_INPROGRESS | 2337 FP_SOFT_IN_DETACH | FP_DETACH_FAILED)) { 2338 do_attach_ulps = B_FALSE; 2339 } else { 2340 /* 2341 * We are going to force the transport 2342 * to attach to the ULPs, so set 2343 * fp_ulp_attach. This will keep any 2344 * potential detach from occurring until 2345 * we are done. 2346 */ 2347 port->fp_ulp_attach = 1; 2348 } 2349 2350 mutex_exit(&port->fp_mutex); 2351 2352 /* 2353 * NOTE: Since we just dropped the mutex, there is now 2354 * a race window where the fp_soft_state check above 2355 * could change here. This race is covered because an 2356 * additional check was added in the functions hidden 2357 * under fp_startup_done(). 2358 */ 2359 if (do_attach_ulps == B_TRUE) { 2360 /* 2361 * This goes thru a bit of a convoluted call 2362 * chain before spawning off a DDI taskq 2363 * request to perform the actual attach 2364 * operations. Blocking can occur at a number 2365 * of points. 2366 */ 2367 fp_startup_done((opaque_t)port, FC_PKT_SUCCESS); 2368 } 2369 job->job_result = FC_SUCCESS; 2370 fctl_jobdone(job); 2371 break; 2372 } 2373 2374 case JOB_ULP_NOTIFY: { 2375 /* 2376 * Pass state change notifications up to any/all 2377 * registered ULPs. 2378 */ 2379 uint32_t statec; 2380 2381 statec = job->job_ulp_listlen; 2382 if (statec == FC_STATE_RESET_REQUESTED) { 2383 port->fp_last_task = port->fp_task; 2384 port->fp_task = FP_TASK_OFFLINE; 2385 fp_port_offline(port, 0); 2386 port->fp_task = port->fp_last_task; 2387 port->fp_last_task = FP_TASK_IDLE; 2388 } 2389 2390 if (--port->fp_statec_busy == 0) { 2391 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2392 } 2393 2394 mutex_exit(&port->fp_mutex); 2395 2396 job->job_result = fp_ulp_notify(port, statec, KM_SLEEP); 2397 fctl_jobdone(job); 2398 break; 2399 } 2400 2401 case JOB_PLOGI_ONE: 2402 /* 2403 * Issue a PLOGI to a single remote port. Multiple 2404 * PLOGIs to different remote ports may occur in 2405 * parallel. 2406 * This can create the fc_remote_port_t if it does not 2407 * already exist. 2408 */ 2409 2410 mutex_exit(&port->fp_mutex); 2411 d_id = (uint32_t *)job->job_private; 2412 pd = fctl_get_remote_port_by_did(port, *d_id); 2413 2414 if (pd) { 2415 mutex_enter(&pd->pd_mutex); 2416 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 2417 pd->pd_login_count++; 2418 mutex_exit(&pd->pd_mutex); 2419 job->job_result = FC_SUCCESS; 2420 fctl_jobdone(job); 2421 break; 2422 } 2423 mutex_exit(&pd->pd_mutex); 2424 } else { 2425 mutex_enter(&port->fp_mutex); 2426 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2427 mutex_exit(&port->fp_mutex); 2428 pd = fp_create_remote_port_by_ns(port, 2429 *d_id, KM_SLEEP); 2430 if (pd == NULL) { 2431 job->job_result = FC_FAILURE; 2432 fctl_jobdone(job); 2433 break; 2434 } 2435 } else { 2436 mutex_exit(&port->fp_mutex); 2437 } 2438 } 2439 2440 job->job_flags |= JOB_TYPE_FP_ASYNC; 2441 job->job_counter = 1; 2442 2443 rval = fp_port_login(port, *d_id, job, 2444 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 2445 2446 if (rval != FC_SUCCESS) { 2447 job->job_result = rval; 2448 fctl_jobdone(job); 2449 } 2450 break; 2451 2452 case JOB_LOGO_ONE: { 2453 /* 2454 * Issue a PLOGO to a single remote port. Multiple 2455 * PLOGOs to different remote ports may occur in 2456 * parallel. 2457 */ 2458 fc_remote_port_t *pd; 2459 2460 #ifndef __lock_lint 2461 ASSERT(job->job_counter > 0); 2462 #endif 2463 2464 pd = (fc_remote_port_t *)job->job_ulp_pkts; 2465 2466 mutex_enter(&pd->pd_mutex); 2467 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 2468 mutex_exit(&pd->pd_mutex); 2469 job->job_result = FC_LOGINREQ; 2470 mutex_exit(&port->fp_mutex); 2471 fctl_jobdone(job); 2472 break; 2473 } 2474 if (pd->pd_login_count > 1) { 2475 pd->pd_login_count--; 2476 mutex_exit(&pd->pd_mutex); 2477 job->job_result = FC_SUCCESS; 2478 mutex_exit(&port->fp_mutex); 2479 fctl_jobdone(job); 2480 break; 2481 } 2482 mutex_exit(&pd->pd_mutex); 2483 mutex_exit(&port->fp_mutex); 2484 job->job_flags |= JOB_TYPE_FP_ASYNC; 2485 (void) fp_logout(port, pd, job); 2486 break; 2487 } 2488 2489 case JOB_FCIO_LOGIN: 2490 /* 2491 * PLOGI initiated at ioctl request. 2492 */ 2493 mutex_exit(&port->fp_mutex); 2494 job->job_result = 2495 fp_fcio_login(port, job->job_private, job); 2496 fctl_jobdone(job); 2497 break; 2498 2499 case JOB_FCIO_LOGOUT: 2500 /* 2501 * PLOGO initiated at ioctl request. 2502 */ 2503 mutex_exit(&port->fp_mutex); 2504 job->job_result = 2505 fp_fcio_logout(port, job->job_private, job); 2506 fctl_jobdone(job); 2507 break; 2508 2509 case JOB_PORT_GETMAP: 2510 case JOB_PORT_GETMAP_PLOGI_ALL: { 2511 port->fp_last_task = port->fp_task; 2512 port->fp_task = FP_TASK_GETMAP; 2513 2514 switch (port->fp_topology) { 2515 case FC_TOP_PRIVATE_LOOP: 2516 job->job_counter = 1; 2517 2518 fp_get_loopmap(port, job); 2519 mutex_exit(&port->fp_mutex); 2520 fp_jobwait(job); 2521 fctl_fillout_map(port, 2522 (fc_portmap_t **)job->job_private, 2523 (uint32_t *)job->job_arg, 1, 0, 0); 2524 fctl_jobdone(job); 2525 mutex_enter(&port->fp_mutex); 2526 break; 2527 2528 case FC_TOP_PUBLIC_LOOP: 2529 case FC_TOP_FABRIC: 2530 mutex_exit(&port->fp_mutex); 2531 job->job_counter = 1; 2532 2533 job->job_result = fp_ns_getmap(port, 2534 job, (fc_portmap_t **)job->job_private, 2535 (uint32_t *)job->job_arg, 2536 FCTL_GAN_START_ID); 2537 fctl_jobdone(job); 2538 mutex_enter(&port->fp_mutex); 2539 break; 2540 2541 case FC_TOP_PT_PT: 2542 mutex_exit(&port->fp_mutex); 2543 fctl_fillout_map(port, 2544 (fc_portmap_t **)job->job_private, 2545 (uint32_t *)job->job_arg, 1, 0, 0); 2546 fctl_jobdone(job); 2547 mutex_enter(&port->fp_mutex); 2548 break; 2549 2550 default: 2551 mutex_exit(&port->fp_mutex); 2552 fctl_jobdone(job); 2553 mutex_enter(&port->fp_mutex); 2554 break; 2555 } 2556 port->fp_task = port->fp_last_task; 2557 port->fp_last_task = FP_TASK_IDLE; 2558 mutex_exit(&port->fp_mutex); 2559 break; 2560 } 2561 2562 case JOB_PORT_OFFLINE: { 2563 fp_log_port_event(port, ESC_SUNFC_PORT_OFFLINE); 2564 2565 port->fp_last_task = port->fp_task; 2566 port->fp_task = FP_TASK_OFFLINE; 2567 2568 if (port->fp_statec_busy > 2) { 2569 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2570 fp_port_offline(port, 0); 2571 if (--port->fp_statec_busy == 0) { 2572 port->fp_soft_state &= 2573 ~FP_SOFT_IN_STATEC_CB; 2574 } 2575 } else { 2576 fp_port_offline(port, 1); 2577 } 2578 2579 port->fp_task = port->fp_last_task; 2580 port->fp_last_task = FP_TASK_IDLE; 2581 2582 mutex_exit(&port->fp_mutex); 2583 2584 fctl_jobdone(job); 2585 break; 2586 } 2587 2588 case JOB_PORT_STARTUP: { 2589 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2590 if (port->fp_statec_busy > 1) { 2591 mutex_exit(&port->fp_mutex); 2592 break; 2593 } 2594 mutex_exit(&port->fp_mutex); 2595 2596 FP_TRACE(FP_NHEAD2(9, rval), 2597 "Topology discovery failed"); 2598 break; 2599 } 2600 2601 /* 2602 * Attempt building device handles in case 2603 * of private Loop. 2604 */ 2605 if (port->fp_topology == FC_TOP_PRIVATE_LOOP) { 2606 job->job_counter = 1; 2607 2608 fp_get_loopmap(port, job); 2609 mutex_exit(&port->fp_mutex); 2610 fp_jobwait(job); 2611 mutex_enter(&port->fp_mutex); 2612 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 2613 ASSERT(port->fp_total_devices == 0); 2614 port->fp_total_devices = 2615 port->fp_dev_count; 2616 } 2617 } else if (FC_IS_TOP_SWITCH(port->fp_topology)) { 2618 /* 2619 * Hack to avoid state changes going up early 2620 */ 2621 port->fp_statec_busy++; 2622 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 2623 2624 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 2625 fp_fabric_online(port, job); 2626 job->job_flags &= ~JOB_CANCEL_ULP_NOTIFICATION; 2627 } 2628 mutex_exit(&port->fp_mutex); 2629 fctl_jobdone(job); 2630 break; 2631 } 2632 2633 case JOB_PORT_ONLINE: { 2634 char *newtop; 2635 char *oldtop; 2636 uint32_t old_top; 2637 2638 fp_log_port_event(port, ESC_SUNFC_PORT_ONLINE); 2639 2640 /* 2641 * Bail out early if there are a lot of 2642 * state changes in the pipeline 2643 */ 2644 if (port->fp_statec_busy > 1) { 2645 --port->fp_statec_busy; 2646 mutex_exit(&port->fp_mutex); 2647 fctl_jobdone(job); 2648 break; 2649 } 2650 2651 switch (old_top = port->fp_topology) { 2652 case FC_TOP_PRIVATE_LOOP: 2653 oldtop = "Private Loop"; 2654 break; 2655 2656 case FC_TOP_PUBLIC_LOOP: 2657 oldtop = "Public Loop"; 2658 break; 2659 2660 case FC_TOP_PT_PT: 2661 oldtop = "Point to Point"; 2662 break; 2663 2664 case FC_TOP_FABRIC: 2665 oldtop = "Fabric"; 2666 break; 2667 2668 default: 2669 oldtop = NULL; 2670 break; 2671 } 2672 2673 port->fp_last_task = port->fp_task; 2674 port->fp_task = FP_TASK_ONLINE; 2675 2676 if ((rval = fp_port_startup(port, job)) != FC_SUCCESS) { 2677 2678 port->fp_task = port->fp_last_task; 2679 port->fp_last_task = FP_TASK_IDLE; 2680 2681 if (port->fp_statec_busy > 1) { 2682 --port->fp_statec_busy; 2683 mutex_exit(&port->fp_mutex); 2684 break; 2685 } 2686 2687 port->fp_state = FC_STATE_OFFLINE; 2688 2689 FP_TRACE(FP_NHEAD2(9, rval), 2690 "Topology discovery failed"); 2691 2692 if (--port->fp_statec_busy == 0) { 2693 port->fp_soft_state &= 2694 ~FP_SOFT_IN_STATEC_CB; 2695 } 2696 2697 if (port->fp_offline_tid == NULL) { 2698 port->fp_offline_tid = 2699 timeout(fp_offline_timeout, 2700 (caddr_t)port, fp_offline_ticks); 2701 } 2702 2703 mutex_exit(&port->fp_mutex); 2704 break; 2705 } 2706 2707 switch (port->fp_topology) { 2708 case FC_TOP_PRIVATE_LOOP: 2709 newtop = "Private Loop"; 2710 break; 2711 2712 case FC_TOP_PUBLIC_LOOP: 2713 newtop = "Public Loop"; 2714 break; 2715 2716 case FC_TOP_PT_PT: 2717 newtop = "Point to Point"; 2718 break; 2719 2720 case FC_TOP_FABRIC: 2721 newtop = "Fabric"; 2722 break; 2723 2724 default: 2725 newtop = NULL; 2726 break; 2727 } 2728 2729 if (oldtop && newtop && strcmp(oldtop, newtop)) { 2730 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2731 "Change in FC Topology old = %s new = %s", 2732 oldtop, newtop); 2733 } 2734 2735 switch (port->fp_topology) { 2736 case FC_TOP_PRIVATE_LOOP: { 2737 int orphan = (old_top == FC_TOP_FABRIC || 2738 old_top == FC_TOP_PUBLIC_LOOP) ? 1 : 0; 2739 2740 mutex_exit(&port->fp_mutex); 2741 fp_loop_online(port, job, orphan); 2742 break; 2743 } 2744 2745 case FC_TOP_PUBLIC_LOOP: 2746 /* FALLTHROUGH */ 2747 case FC_TOP_FABRIC: 2748 fp_fabric_online(port, job); 2749 mutex_exit(&port->fp_mutex); 2750 break; 2751 2752 case FC_TOP_PT_PT: 2753 fp_p2p_online(port, job); 2754 mutex_exit(&port->fp_mutex); 2755 break; 2756 2757 default: 2758 if (--port->fp_statec_busy != 0) { 2759 /* 2760 * Watch curiously at what the next 2761 * state transition can do. 2762 */ 2763 mutex_exit(&port->fp_mutex); 2764 break; 2765 } 2766 2767 FP_TRACE(FP_NHEAD2(9, 0), 2768 "Topology Unknown, Offlining the port.."); 2769 2770 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 2771 port->fp_state = FC_STATE_OFFLINE; 2772 2773 if (port->fp_offline_tid == NULL) { 2774 port->fp_offline_tid = 2775 timeout(fp_offline_timeout, 2776 (caddr_t)port, fp_offline_ticks); 2777 } 2778 mutex_exit(&port->fp_mutex); 2779 break; 2780 } 2781 2782 mutex_enter(&port->fp_mutex); 2783 2784 port->fp_task = port->fp_last_task; 2785 port->fp_last_task = FP_TASK_IDLE; 2786 2787 mutex_exit(&port->fp_mutex); 2788 2789 fctl_jobdone(job); 2790 break; 2791 } 2792 2793 case JOB_PLOGI_GROUP: { 2794 mutex_exit(&port->fp_mutex); 2795 fp_plogi_group(port, job); 2796 break; 2797 } 2798 2799 case JOB_UNSOL_REQUEST: { 2800 mutex_exit(&port->fp_mutex); 2801 fp_handle_unsol_buf(port, 2802 (fc_unsol_buf_t *)job->job_private, job); 2803 fctl_dealloc_job(job); 2804 break; 2805 } 2806 2807 case JOB_NS_CMD: { 2808 fctl_ns_req_t *ns_cmd; 2809 2810 mutex_exit(&port->fp_mutex); 2811 2812 job->job_flags |= JOB_TYPE_FP_ASYNC; 2813 ns_cmd = (fctl_ns_req_t *)job->job_private; 2814 if (ns_cmd->ns_cmd_code < NS_GA_NXT || 2815 ns_cmd->ns_cmd_code > NS_DA_ID) { 2816 job->job_result = FC_BADCMD; 2817 fctl_jobdone(job); 2818 break; 2819 } 2820 2821 if (FC_IS_CMD_A_REG(ns_cmd->ns_cmd_code)) { 2822 if (ns_cmd->ns_pd != NULL) { 2823 job->job_result = FC_BADOBJECT; 2824 fctl_jobdone(job); 2825 break; 2826 } 2827 2828 job->job_counter = 1; 2829 2830 rval = fp_ns_reg(port, ns_cmd->ns_pd, 2831 ns_cmd->ns_cmd_code, job, 0, KM_SLEEP); 2832 2833 if (rval != FC_SUCCESS) { 2834 job->job_result = rval; 2835 fctl_jobdone(job); 2836 } 2837 break; 2838 } 2839 job->job_result = FC_SUCCESS; 2840 job->job_counter = 1; 2841 2842 rval = fp_ns_query(port, ns_cmd, job, 0, KM_SLEEP); 2843 if (rval != FC_SUCCESS) { 2844 fctl_jobdone(job); 2845 } 2846 break; 2847 } 2848 2849 case JOB_LINK_RESET: { 2850 la_wwn_t *pwwn; 2851 uint32_t topology; 2852 2853 pwwn = (la_wwn_t *)job->job_private; 2854 ASSERT(pwwn != NULL); 2855 2856 topology = port->fp_topology; 2857 mutex_exit(&port->fp_mutex); 2858 2859 if (fctl_is_wwn_zero(pwwn) == FC_SUCCESS || 2860 topology == FC_TOP_PRIVATE_LOOP) { 2861 job->job_flags |= JOB_TYPE_FP_ASYNC; 2862 rval = port->fp_fca_tran->fca_reset( 2863 port->fp_fca_handle, FC_FCA_LINK_RESET); 2864 job->job_result = rval; 2865 fp_jobdone(job); 2866 } else { 2867 ASSERT((job->job_flags & 2868 JOB_TYPE_FP_ASYNC) == 0); 2869 2870 if (FC_IS_TOP_SWITCH(topology)) { 2871 rval = fp_remote_lip(port, pwwn, 2872 KM_SLEEP, job); 2873 } else { 2874 rval = FC_FAILURE; 2875 } 2876 if (rval != FC_SUCCESS) { 2877 job->job_result = rval; 2878 } 2879 fctl_jobdone(job); 2880 } 2881 break; 2882 } 2883 2884 default: 2885 mutex_exit(&port->fp_mutex); 2886 job->job_result = FC_BADCMD; 2887 fctl_jobdone(job); 2888 break; 2889 } 2890 } 2891 /* NOTREACHED */ 2892 } 2893 2894 2895 /* 2896 * Perform FC port bring up initialization 2897 */ 2898 static int 2899 fp_port_startup(fc_local_port_t *port, job_request_t *job) 2900 { 2901 int rval; 2902 uint32_t state; 2903 uint32_t src_id; 2904 fc_lilpmap_t *lilp_map; 2905 2906 ASSERT(MUTEX_HELD(&port->fp_mutex)); 2907 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 2908 2909 FP_DTRACE(FP_NHEAD1(2, 0), "Entering fp_port_startup;" 2910 " port=%p, job=%p", port, job); 2911 2912 port->fp_topology = FC_TOP_UNKNOWN; 2913 port->fp_port_id.port_id = 0; 2914 state = FC_PORT_STATE_MASK(port->fp_state); 2915 2916 if (state == FC_STATE_OFFLINE) { 2917 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 2918 job->job_result = FC_OFFLINE; 2919 mutex_exit(&port->fp_mutex); 2920 fctl_jobdone(job); 2921 mutex_enter(&port->fp_mutex); 2922 return (FC_OFFLINE); 2923 } 2924 2925 if (state == FC_STATE_LOOP) { 2926 port->fp_port_type.port_type = FC_NS_PORT_NL; 2927 mutex_exit(&port->fp_mutex); 2928 2929 lilp_map = &port->fp_lilp_map; 2930 if ((rval = fp_get_lilpmap(port, lilp_map)) != FC_SUCCESS) { 2931 job->job_result = FC_FAILURE; 2932 fctl_jobdone(job); 2933 2934 FP_TRACE(FP_NHEAD1(9, rval), 2935 "LILP map Invalid or not present"); 2936 mutex_enter(&port->fp_mutex); 2937 return (FC_FAILURE); 2938 } 2939 2940 if (lilp_map->lilp_length == 0) { 2941 job->job_result = FC_NO_MAP; 2942 fctl_jobdone(job); 2943 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 2944 "LILP map length zero"); 2945 mutex_enter(&port->fp_mutex); 2946 return (FC_NO_MAP); 2947 } 2948 src_id = lilp_map->lilp_myalpa & 0xFF; 2949 } else { 2950 fc_remote_port_t *pd; 2951 fc_fca_pm_t pm; 2952 fc_fca_p2p_info_t p2p_info; 2953 int pd_recepient; 2954 2955 /* 2956 * Get P2P remote port info if possible 2957 */ 2958 bzero((caddr_t)&pm, sizeof (pm)); 2959 2960 pm.pm_cmd_flags = FC_FCA_PM_READ; 2961 pm.pm_cmd_code = FC_PORT_GET_P2P_INFO; 2962 pm.pm_data_len = sizeof (fc_fca_p2p_info_t); 2963 pm.pm_data_buf = (caddr_t)&p2p_info; 2964 2965 rval = port->fp_fca_tran->fca_port_manage( 2966 port->fp_fca_handle, &pm); 2967 2968 if (rval == FC_SUCCESS) { 2969 port->fp_port_id.port_id = p2p_info.fca_d_id; 2970 port->fp_port_type.port_type = FC_NS_PORT_N; 2971 port->fp_topology = FC_TOP_PT_PT; 2972 port->fp_total_devices = 1; 2973 pd_recepient = fctl_wwn_cmp( 2974 &port->fp_service_params.nport_ww_name, 2975 &p2p_info.pwwn) < 0 ? 2976 PD_PLOGI_RECEPIENT : PD_PLOGI_INITIATOR; 2977 mutex_exit(&port->fp_mutex); 2978 pd = fctl_create_remote_port(port, 2979 &p2p_info.nwwn, 2980 &p2p_info.pwwn, 2981 p2p_info.d_id, 2982 pd_recepient, KM_NOSLEEP); 2983 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup;" 2984 " P2P port=%p pd=%p fp %x pd %x", port, pd, 2985 port->fp_port_id.port_id, p2p_info.d_id); 2986 mutex_enter(&port->fp_mutex); 2987 return (FC_SUCCESS); 2988 } 2989 port->fp_port_type.port_type = FC_NS_PORT_N; 2990 mutex_exit(&port->fp_mutex); 2991 src_id = 0; 2992 } 2993 2994 job->job_counter = 1; 2995 job->job_result = FC_SUCCESS; 2996 2997 if ((rval = fp_fabric_login(port, src_id, job, FP_CMD_PLOGI_DONT_CARE, 2998 KM_SLEEP)) != FC_SUCCESS) { 2999 port->fp_port_type.port_type = FC_NS_PORT_UNKNOWN; 3000 job->job_result = FC_FAILURE; 3001 fctl_jobdone(job); 3002 3003 mutex_enter(&port->fp_mutex); 3004 if (port->fp_statec_busy <= 1) { 3005 mutex_exit(&port->fp_mutex); 3006 fp_printf(port, CE_NOTE, FP_LOG_ONLY, rval, NULL, 3007 "Couldn't transport FLOGI"); 3008 mutex_enter(&port->fp_mutex); 3009 } 3010 return (FC_FAILURE); 3011 } 3012 3013 fp_jobwait(job); 3014 3015 mutex_enter(&port->fp_mutex); 3016 if (job->job_result == FC_SUCCESS) { 3017 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3018 mutex_exit(&port->fp_mutex); 3019 fp_ns_init(port, job, KM_SLEEP); 3020 mutex_enter(&port->fp_mutex); 3021 } 3022 } else { 3023 if (state == FC_STATE_LOOP) { 3024 port->fp_topology = FC_TOP_PRIVATE_LOOP; 3025 port->fp_port_id.port_id = 3026 port->fp_lilp_map.lilp_myalpa & 0xFF; 3027 } 3028 } 3029 3030 FP_DTRACE(FP_NHEAD1(2, 0), "Exiting fp_port_startup; port=%p, job=%p", 3031 port, job); 3032 3033 return (FC_SUCCESS); 3034 } 3035 3036 3037 /* 3038 * Perform ULP invocations following FC port startup 3039 */ 3040 /* ARGSUSED */ 3041 static void 3042 fp_startup_done(opaque_t arg, uchar_t result) 3043 { 3044 fc_local_port_t *port = arg; 3045 3046 fp_attach_ulps(port, FC_CMD_ATTACH); 3047 3048 FP_DTRACE(FP_NHEAD1(2, 0), "fp_startup almost complete; port=%p", port); 3049 } 3050 3051 3052 /* 3053 * Perform ULP port attach 3054 */ 3055 static void 3056 fp_ulp_port_attach(void *arg) 3057 { 3058 fp_soft_attach_t *att = (fp_soft_attach_t *)arg; 3059 fc_local_port_t *port = att->att_port; 3060 3061 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3062 " ULPs begin; port=%p, cmd=%x", port, att->att_cmd); 3063 3064 fctl_attach_ulps(att->att_port, att->att_cmd, &modlinkage); 3065 3066 if (att->att_need_pm_idle == B_TRUE) { 3067 fctl_idle_port(port); 3068 } 3069 3070 FP_DTRACE(FP_NHEAD1(1, 0), "port attach of" 3071 " ULPs end; port=%p, cmd=%x", port, att->att_cmd); 3072 3073 mutex_enter(&att->att_port->fp_mutex); 3074 att->att_port->fp_ulp_attach = 0; 3075 3076 port->fp_task = port->fp_last_task; 3077 port->fp_last_task = FP_TASK_IDLE; 3078 3079 cv_signal(&att->att_port->fp_attach_cv); 3080 3081 mutex_exit(&att->att_port->fp_mutex); 3082 3083 kmem_free(att, sizeof (fp_soft_attach_t)); 3084 } 3085 3086 /* 3087 * Entry point to funnel all requests down to FCAs 3088 */ 3089 static int 3090 fp_sendcmd(fc_local_port_t *port, fp_cmd_t *cmd, opaque_t fca_handle) 3091 { 3092 int rval; 3093 3094 mutex_enter(&port->fp_mutex); 3095 if (port->fp_statec_busy > 1 || (cmd->cmd_ulp_pkt != NULL && 3096 (port->fp_statec_busy || FC_PORT_STATE_MASK(port->fp_state) == 3097 FC_STATE_OFFLINE))) { 3098 /* 3099 * This means there is more than one state change 3100 * at this point of time - Since they are processed 3101 * serially, any processing of the current one should 3102 * be failed, failed and move up in processing the next 3103 */ 3104 cmd->cmd_pkt.pkt_state = FC_PKT_ELS_IN_PROGRESS; 3105 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3106 if (cmd->cmd_job) { 3107 /* 3108 * A state change that is going to be invalidated 3109 * by another one already in the port driver's queue 3110 * need not go up to all ULPs. This will minimize 3111 * needless processing and ripples in ULP modules 3112 */ 3113 cmd->cmd_job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3114 } 3115 mutex_exit(&port->fp_mutex); 3116 return (FC_STATEC_BUSY); 3117 } 3118 3119 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3120 cmd->cmd_pkt.pkt_state = FC_PKT_PORT_OFFLINE; 3121 cmd->cmd_pkt.pkt_reason = FC_REASON_OFFLINE; 3122 mutex_exit(&port->fp_mutex); 3123 3124 return (FC_OFFLINE); 3125 } 3126 mutex_exit(&port->fp_mutex); 3127 3128 rval = cmd->cmd_transport(fca_handle, &cmd->cmd_pkt); 3129 if (rval != FC_SUCCESS) { 3130 if (rval == FC_TRAN_BUSY) { 3131 cmd->cmd_retry_interval = fp_retry_delay; 3132 rval = fp_retry_cmd(&cmd->cmd_pkt); 3133 if (rval == FC_FAILURE) { 3134 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_BSY; 3135 } 3136 } 3137 } else { 3138 mutex_enter(&port->fp_mutex); 3139 port->fp_out_fpcmds++; 3140 mutex_exit(&port->fp_mutex); 3141 } 3142 3143 return (rval); 3144 } 3145 3146 3147 /* 3148 * Each time a timeout kicks in, walk the wait queue, decrement the 3149 * the retry_interval, when the retry_interval becomes less than 3150 * or equal to zero, re-transport the command: If the re-transport 3151 * fails with BUSY, enqueue the command in the wait queue. 3152 * 3153 * In order to prevent looping forever because of commands enqueued 3154 * from within this function itself, save the current tail pointer 3155 * (in cur_tail) and exit the loop after serving this command. 3156 */ 3157 static void 3158 fp_resendcmd(void *port_handle) 3159 { 3160 int rval; 3161 fc_local_port_t *port; 3162 fp_cmd_t *cmd; 3163 fp_cmd_t *cur_tail; 3164 3165 port = port_handle; 3166 mutex_enter(&port->fp_mutex); 3167 cur_tail = port->fp_wait_tail; 3168 mutex_exit(&port->fp_mutex); 3169 3170 while ((cmd = fp_deque_cmd(port)) != NULL) { 3171 cmd->cmd_retry_interval -= fp_retry_ticker; 3172 /* Check if we are detaching */ 3173 if (port->fp_soft_state & 3174 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS)) { 3175 cmd->cmd_pkt.pkt_state = FC_PKT_TRAN_ERROR; 3176 cmd->cmd_pkt.pkt_reason = 0; 3177 fp_iodone(cmd); 3178 } else if (cmd->cmd_retry_interval <= 0) { 3179 rval = cmd->cmd_transport(port->fp_fca_handle, 3180 &cmd->cmd_pkt); 3181 3182 if (rval != FC_SUCCESS) { 3183 if (cmd->cmd_pkt.pkt_state == FC_PKT_TRAN_BSY) { 3184 if (--cmd->cmd_retry_count) { 3185 fp_enque_cmd(port, cmd); 3186 if (cmd == cur_tail) { 3187 break; 3188 } 3189 continue; 3190 } 3191 cmd->cmd_pkt.pkt_state = 3192 FC_PKT_TRAN_BSY; 3193 } else { 3194 cmd->cmd_pkt.pkt_state = 3195 FC_PKT_TRAN_ERROR; 3196 } 3197 cmd->cmd_pkt.pkt_reason = 0; 3198 fp_iodone(cmd); 3199 } else { 3200 mutex_enter(&port->fp_mutex); 3201 port->fp_out_fpcmds++; 3202 mutex_exit(&port->fp_mutex); 3203 } 3204 } else { 3205 fp_enque_cmd(port, cmd); 3206 } 3207 3208 if (cmd == cur_tail) { 3209 break; 3210 } 3211 } 3212 3213 mutex_enter(&port->fp_mutex); 3214 if (port->fp_wait_head) { 3215 timeout_id_t tid; 3216 3217 mutex_exit(&port->fp_mutex); 3218 tid = timeout(fp_resendcmd, (caddr_t)port, 3219 fp_retry_ticks); 3220 mutex_enter(&port->fp_mutex); 3221 port->fp_wait_tid = tid; 3222 } else { 3223 port->fp_wait_tid = NULL; 3224 } 3225 mutex_exit(&port->fp_mutex); 3226 } 3227 3228 3229 /* 3230 * Handle Local, Fabric, N_Port, Transport (whatever that means) BUSY here. 3231 * 3232 * Yes, as you can see below, cmd_retry_count is used here too. That means 3233 * the retries for BUSY are less if there were transport failures (transport 3234 * failure means fca_transport failure). The goal is not to exceed overall 3235 * retries set in the cmd_retry_count (whatever may be the reason for retry) 3236 * 3237 * Return Values: 3238 * FC_SUCCESS 3239 * FC_FAILURE 3240 */ 3241 static int 3242 fp_retry_cmd(fc_packet_t *pkt) 3243 { 3244 fp_cmd_t *cmd; 3245 3246 cmd = pkt->pkt_ulp_private; 3247 3248 if (--cmd->cmd_retry_count) { 3249 fp_enque_cmd(cmd->cmd_port, cmd); 3250 return (FC_SUCCESS); 3251 } else { 3252 return (FC_FAILURE); 3253 } 3254 } 3255 3256 3257 /* 3258 * Queue up FC packet for deferred retry 3259 */ 3260 static void 3261 fp_enque_cmd(fc_local_port_t *port, fp_cmd_t *cmd) 3262 { 3263 timeout_id_t tid; 3264 3265 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3266 3267 #ifdef DEBUG 3268 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, &cmd->cmd_pkt, 3269 "Retrying ELS for %x", cmd->cmd_pkt.pkt_cmd_fhdr.d_id); 3270 #endif 3271 3272 mutex_enter(&port->fp_mutex); 3273 if (port->fp_wait_tail) { 3274 port->fp_wait_tail->cmd_next = cmd; 3275 port->fp_wait_tail = cmd; 3276 } else { 3277 ASSERT(port->fp_wait_head == NULL); 3278 port->fp_wait_head = port->fp_wait_tail = cmd; 3279 if (port->fp_wait_tid == NULL) { 3280 mutex_exit(&port->fp_mutex); 3281 tid = timeout(fp_resendcmd, (caddr_t)port, 3282 fp_retry_ticks); 3283 mutex_enter(&port->fp_mutex); 3284 port->fp_wait_tid = tid; 3285 } 3286 } 3287 mutex_exit(&port->fp_mutex); 3288 } 3289 3290 3291 /* 3292 * Handle all RJT codes 3293 */ 3294 static int 3295 fp_handle_reject(fc_packet_t *pkt) 3296 { 3297 int rval = FC_FAILURE; 3298 uchar_t next_class; 3299 fp_cmd_t *cmd; 3300 fc_local_port_t *port; 3301 3302 cmd = pkt->pkt_ulp_private; 3303 port = cmd->cmd_port; 3304 3305 switch (pkt->pkt_state) { 3306 case FC_PKT_FABRIC_RJT: 3307 case FC_PKT_NPORT_RJT: 3308 if (pkt->pkt_reason == FC_REASON_CLASS_NOT_SUPP) { 3309 next_class = fp_get_nextclass(cmd->cmd_port, 3310 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 3311 3312 if (next_class == FC_TRAN_CLASS_INVALID) { 3313 return (rval); 3314 } 3315 pkt->pkt_tran_flags = FC_TRAN_INTR | next_class; 3316 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 3317 3318 rval = fp_sendcmd(cmd->cmd_port, cmd, 3319 cmd->cmd_port->fp_fca_handle); 3320 3321 if (rval != FC_SUCCESS) { 3322 pkt->pkt_state = FC_PKT_TRAN_ERROR; 3323 } 3324 } 3325 break; 3326 3327 case FC_PKT_LS_RJT: 3328 case FC_PKT_BA_RJT: 3329 if ((pkt->pkt_reason == FC_REASON_LOGICAL_ERROR) || 3330 (pkt->pkt_reason == FC_REASON_LOGICAL_BSY)) { 3331 cmd->cmd_retry_interval = fp_retry_delay; 3332 rval = fp_retry_cmd(pkt); 3333 } 3334 break; 3335 3336 case FC_PKT_FS_RJT: 3337 if ((pkt->pkt_reason == FC_REASON_FS_LOGICAL_BUSY) || 3338 ((pkt->pkt_reason == FC_REASON_FS_CMD_UNABLE) && 3339 (pkt->pkt_expln == 0x00))) { 3340 cmd->cmd_retry_interval = fp_retry_delay; 3341 rval = fp_retry_cmd(pkt); 3342 } 3343 break; 3344 3345 case FC_PKT_LOCAL_RJT: 3346 if (pkt->pkt_reason == FC_REASON_QFULL) { 3347 cmd->cmd_retry_interval = fp_retry_delay; 3348 rval = fp_retry_cmd(pkt); 3349 } 3350 break; 3351 3352 default: 3353 FP_TRACE(FP_NHEAD1(1, 0), 3354 "fp_handle_reject(): Invalid pkt_state"); 3355 break; 3356 } 3357 3358 return (rval); 3359 } 3360 3361 3362 /* 3363 * Return the next class of service supported by the FCA 3364 */ 3365 static uchar_t 3366 fp_get_nextclass(fc_local_port_t *port, uchar_t cur_class) 3367 { 3368 uchar_t next_class; 3369 3370 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3371 3372 switch (cur_class) { 3373 case FC_TRAN_CLASS_INVALID: 3374 if (port->fp_cos & FC_NS_CLASS1) { 3375 next_class = FC_TRAN_CLASS1; 3376 break; 3377 } 3378 /* FALLTHROUGH */ 3379 3380 case FC_TRAN_CLASS1: 3381 if (port->fp_cos & FC_NS_CLASS2) { 3382 next_class = FC_TRAN_CLASS2; 3383 break; 3384 } 3385 /* FALLTHROUGH */ 3386 3387 case FC_TRAN_CLASS2: 3388 if (port->fp_cos & FC_NS_CLASS3) { 3389 next_class = FC_TRAN_CLASS3; 3390 break; 3391 } 3392 /* FALLTHROUGH */ 3393 3394 case FC_TRAN_CLASS3: 3395 default: 3396 next_class = FC_TRAN_CLASS_INVALID; 3397 break; 3398 } 3399 3400 return (next_class); 3401 } 3402 3403 3404 /* 3405 * Determine if a class of service is supported by the FCA 3406 */ 3407 static int 3408 fp_is_class_supported(uint32_t cos, uchar_t tran_class) 3409 { 3410 int rval; 3411 3412 switch (tran_class) { 3413 case FC_TRAN_CLASS1: 3414 if (cos & FC_NS_CLASS1) { 3415 rval = FC_SUCCESS; 3416 } else { 3417 rval = FC_FAILURE; 3418 } 3419 break; 3420 3421 case FC_TRAN_CLASS2: 3422 if (cos & FC_NS_CLASS2) { 3423 rval = FC_SUCCESS; 3424 } else { 3425 rval = FC_FAILURE; 3426 } 3427 break; 3428 3429 case FC_TRAN_CLASS3: 3430 if (cos & FC_NS_CLASS3) { 3431 rval = FC_SUCCESS; 3432 } else { 3433 rval = FC_FAILURE; 3434 } 3435 break; 3436 3437 default: 3438 rval = FC_FAILURE; 3439 break; 3440 } 3441 3442 return (rval); 3443 } 3444 3445 3446 /* 3447 * Dequeue FC packet for retry 3448 */ 3449 static fp_cmd_t * 3450 fp_deque_cmd(fc_local_port_t *port) 3451 { 3452 fp_cmd_t *cmd; 3453 3454 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3455 3456 mutex_enter(&port->fp_mutex); 3457 3458 if (port->fp_wait_head == NULL) { 3459 /* 3460 * To avoid races, NULL the fp_wait_tid as 3461 * we are about to exit the timeout thread. 3462 */ 3463 port->fp_wait_tid = NULL; 3464 mutex_exit(&port->fp_mutex); 3465 return (NULL); 3466 } 3467 3468 cmd = port->fp_wait_head; 3469 port->fp_wait_head = cmd->cmd_next; 3470 cmd->cmd_next = NULL; 3471 3472 if (port->fp_wait_head == NULL) { 3473 port->fp_wait_tail = NULL; 3474 } 3475 mutex_exit(&port->fp_mutex); 3476 3477 return (cmd); 3478 } 3479 3480 3481 /* 3482 * Wait for job completion 3483 */ 3484 static void 3485 fp_jobwait(job_request_t *job) 3486 { 3487 sema_p(&job->job_port_sema); 3488 } 3489 3490 3491 /* 3492 * Convert FC packet state to FC errno 3493 */ 3494 int 3495 fp_state_to_rval(uchar_t state) 3496 { 3497 int count; 3498 3499 for (count = 0; count < sizeof (fp_xlat) / 3500 sizeof (fp_xlat[0]); count++) { 3501 if (fp_xlat[count].xlat_state == state) { 3502 return (fp_xlat[count].xlat_rval); 3503 } 3504 } 3505 3506 return (FC_FAILURE); 3507 } 3508 3509 3510 /* 3511 * For Synchronous I/O requests, the caller is 3512 * expected to do fctl_jobdone(if necessary) 3513 * 3514 * We want to preserve at least one failure in the 3515 * job_result if it happens. 3516 * 3517 */ 3518 static void 3519 fp_iodone(fp_cmd_t *cmd) 3520 { 3521 fc_packet_t *ulp_pkt = cmd->cmd_ulp_pkt; 3522 job_request_t *job = cmd->cmd_job; 3523 fc_remote_port_t *pd = cmd->cmd_pkt.pkt_pd; 3524 3525 ASSERT(job != NULL); 3526 ASSERT(cmd->cmd_port != NULL); 3527 ASSERT(&cmd->cmd_pkt != NULL); 3528 3529 mutex_enter(&job->job_mutex); 3530 if (job->job_result == FC_SUCCESS) { 3531 job->job_result = fp_state_to_rval(cmd->cmd_pkt.pkt_state); 3532 } 3533 mutex_exit(&job->job_mutex); 3534 3535 if (pd) { 3536 mutex_enter(&pd->pd_mutex); 3537 pd->pd_flags = PD_IDLE; 3538 mutex_exit(&pd->pd_mutex); 3539 } 3540 3541 if (ulp_pkt) { 3542 if (pd && cmd->cmd_flags & FP_CMD_DELDEV_ON_ERROR && 3543 FP_IS_PKT_ERROR(ulp_pkt)) { 3544 fc_local_port_t *port; 3545 fc_remote_node_t *node; 3546 3547 port = cmd->cmd_port; 3548 3549 mutex_enter(&pd->pd_mutex); 3550 pd->pd_state = PORT_DEVICE_INVALID; 3551 pd->pd_ref_count--; 3552 node = pd->pd_remote_nodep; 3553 mutex_exit(&pd->pd_mutex); 3554 3555 ASSERT(node != NULL); 3556 ASSERT(port != NULL); 3557 3558 if (fctl_destroy_remote_port(port, pd) == 0) { 3559 fctl_destroy_remote_node(node); 3560 } 3561 3562 ulp_pkt->pkt_pd = NULL; 3563 } 3564 3565 ulp_pkt->pkt_comp(ulp_pkt); 3566 } 3567 3568 fp_free_pkt(cmd); 3569 fp_jobdone(job); 3570 } 3571 3572 3573 /* 3574 * Job completion handler 3575 */ 3576 static void 3577 fp_jobdone(job_request_t *job) 3578 { 3579 mutex_enter(&job->job_mutex); 3580 ASSERT(job->job_counter > 0); 3581 3582 if (--job->job_counter != 0) { 3583 mutex_exit(&job->job_mutex); 3584 return; 3585 } 3586 3587 if (job->job_ulp_pkts) { 3588 ASSERT(job->job_ulp_listlen > 0); 3589 kmem_free(job->job_ulp_pkts, 3590 sizeof (fc_packet_t *) * job->job_ulp_listlen); 3591 } 3592 3593 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3594 mutex_exit(&job->job_mutex); 3595 fctl_jobdone(job); 3596 } else { 3597 mutex_exit(&job->job_mutex); 3598 sema_v(&job->job_port_sema); 3599 } 3600 } 3601 3602 3603 /* 3604 * Try to perform shutdown of a port during a detach. No return 3605 * value since the detach should not fail because the port shutdown 3606 * failed. 3607 */ 3608 static void 3609 fp_port_shutdown(fc_local_port_t *port, job_request_t *job) 3610 { 3611 int index; 3612 int count; 3613 int flags; 3614 fp_cmd_t *cmd; 3615 struct pwwn_hash *head; 3616 fc_remote_port_t *pd; 3617 3618 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3619 3620 job->job_result = FC_SUCCESS; 3621 3622 if (port->fp_taskq) { 3623 /* 3624 * We must release the mutex here to ensure that other 3625 * potential jobs can complete their processing. Many 3626 * also need this mutex. 3627 */ 3628 mutex_exit(&port->fp_mutex); 3629 taskq_wait(port->fp_taskq); 3630 mutex_enter(&port->fp_mutex); 3631 } 3632 3633 if (port->fp_offline_tid) { 3634 timeout_id_t tid; 3635 3636 tid = port->fp_offline_tid; 3637 port->fp_offline_tid = NULL; 3638 mutex_exit(&port->fp_mutex); 3639 (void) untimeout(tid); 3640 mutex_enter(&port->fp_mutex); 3641 } 3642 3643 if (port->fp_wait_tid) { 3644 timeout_id_t tid; 3645 3646 tid = port->fp_wait_tid; 3647 port->fp_wait_tid = NULL; 3648 mutex_exit(&port->fp_mutex); 3649 (void) untimeout(tid); 3650 } else { 3651 mutex_exit(&port->fp_mutex); 3652 } 3653 3654 /* 3655 * While we cancel the timeout, let's also return the 3656 * the outstanding requests back to the callers. 3657 */ 3658 while ((cmd = fp_deque_cmd(port)) != NULL) { 3659 ASSERT(cmd->cmd_job != NULL); 3660 cmd->cmd_job->job_result = FC_OFFLINE; 3661 fp_iodone(cmd); 3662 } 3663 3664 /* 3665 * Gracefully LOGO with all the devices logged in. 3666 */ 3667 mutex_enter(&port->fp_mutex); 3668 3669 for (count = index = 0; index < pwwn_table_size; index++) { 3670 head = &port->fp_pwwn_table[index]; 3671 pd = head->pwwn_head; 3672 while (pd != NULL) { 3673 mutex_enter(&pd->pd_mutex); 3674 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3675 count++; 3676 } 3677 mutex_exit(&pd->pd_mutex); 3678 pd = pd->pd_wwn_hnext; 3679 } 3680 } 3681 3682 if (job->job_flags & JOB_TYPE_FP_ASYNC) { 3683 flags = job->job_flags; 3684 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 3685 } else { 3686 flags = 0; 3687 } 3688 if (count) { 3689 job->job_counter = count; 3690 3691 for (index = 0; index < pwwn_table_size; index++) { 3692 head = &port->fp_pwwn_table[index]; 3693 pd = head->pwwn_head; 3694 while (pd != NULL) { 3695 mutex_enter(&pd->pd_mutex); 3696 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3697 ASSERT(pd->pd_login_count > 0); 3698 /* 3699 * Force the counter to ONE in order 3700 * for us to really send LOGO els. 3701 */ 3702 pd->pd_login_count = 1; 3703 mutex_exit(&pd->pd_mutex); 3704 mutex_exit(&port->fp_mutex); 3705 (void) fp_logout(port, pd, job); 3706 mutex_enter(&port->fp_mutex); 3707 } else { 3708 mutex_exit(&pd->pd_mutex); 3709 } 3710 pd = pd->pd_wwn_hnext; 3711 } 3712 } 3713 mutex_exit(&port->fp_mutex); 3714 fp_jobwait(job); 3715 } else { 3716 mutex_exit(&port->fp_mutex); 3717 } 3718 3719 if (job->job_result != FC_SUCCESS) { 3720 FP_TRACE(FP_NHEAD1(9, 0), 3721 "Can't logout all devices. Proceeding with" 3722 " port shutdown"); 3723 job->job_result = FC_SUCCESS; 3724 } 3725 3726 fctl_destroy_all_remote_ports(port); 3727 3728 mutex_enter(&port->fp_mutex); 3729 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 3730 mutex_exit(&port->fp_mutex); 3731 fp_ns_fini(port, job); 3732 } else { 3733 mutex_exit(&port->fp_mutex); 3734 } 3735 3736 if (flags) { 3737 job->job_flags = flags; 3738 } 3739 3740 mutex_enter(&port->fp_mutex); 3741 3742 } 3743 3744 3745 /* 3746 * Build the port driver's data structures based on the AL_PA list 3747 */ 3748 static void 3749 fp_get_loopmap(fc_local_port_t *port, job_request_t *job) 3750 { 3751 int rval; 3752 int flag; 3753 int count; 3754 uint32_t d_id; 3755 fc_remote_port_t *pd; 3756 fc_lilpmap_t *lilp_map; 3757 3758 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3759 3760 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 3761 job->job_result = FC_OFFLINE; 3762 mutex_exit(&port->fp_mutex); 3763 fp_jobdone(job); 3764 mutex_enter(&port->fp_mutex); 3765 return; 3766 } 3767 3768 if (port->fp_lilp_map.lilp_length == 0) { 3769 mutex_exit(&port->fp_mutex); 3770 job->job_result = FC_NO_MAP; 3771 fp_jobdone(job); 3772 mutex_enter(&port->fp_mutex); 3773 return; 3774 } 3775 mutex_exit(&port->fp_mutex); 3776 3777 lilp_map = &port->fp_lilp_map; 3778 job->job_counter = lilp_map->lilp_length; 3779 3780 if (job->job_code == JOB_PORT_GETMAP_PLOGI_ALL) { 3781 flag = FP_CMD_PLOGI_RETAIN; 3782 } else { 3783 flag = FP_CMD_PLOGI_DONT_CARE; 3784 } 3785 3786 for (count = 0; count < lilp_map->lilp_length; count++) { 3787 d_id = lilp_map->lilp_alpalist[count]; 3788 3789 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3790 fp_jobdone(job); 3791 continue; 3792 } 3793 3794 pd = fctl_get_remote_port_by_did(port, d_id); 3795 if (pd) { 3796 mutex_enter(&pd->pd_mutex); 3797 if (flag == FP_CMD_PLOGI_DONT_CARE || 3798 pd->pd_state == PORT_DEVICE_LOGGED_IN) { 3799 mutex_exit(&pd->pd_mutex); 3800 fp_jobdone(job); 3801 continue; 3802 } 3803 mutex_exit(&pd->pd_mutex); 3804 } 3805 3806 rval = fp_port_login(port, d_id, job, flag, 3807 KM_SLEEP, pd, NULL); 3808 if (rval != FC_SUCCESS) { 3809 fp_jobdone(job); 3810 } 3811 } 3812 3813 mutex_enter(&port->fp_mutex); 3814 } 3815 3816 3817 /* 3818 * Perform loop ONLINE processing 3819 */ 3820 static void 3821 fp_loop_online(fc_local_port_t *port, job_request_t *job, int orphan) 3822 { 3823 int count; 3824 int rval; 3825 uint32_t d_id; 3826 uint32_t listlen; 3827 fc_lilpmap_t *lilp_map; 3828 fc_remote_port_t *pd; 3829 fc_portmap_t *changelist; 3830 3831 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3832 3833 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online begin; port=%p, job=%p", 3834 port, job); 3835 3836 lilp_map = &port->fp_lilp_map; 3837 3838 if (lilp_map->lilp_length) { 3839 mutex_enter(&port->fp_mutex); 3840 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 3841 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 3842 mutex_exit(&port->fp_mutex); 3843 delay(drv_usectohz(PLDA_RR_TOV * 1000 * 1000)); 3844 } else { 3845 mutex_exit(&port->fp_mutex); 3846 } 3847 3848 job->job_counter = lilp_map->lilp_length; 3849 3850 for (count = 0; count < lilp_map->lilp_length; count++) { 3851 d_id = lilp_map->lilp_alpalist[count]; 3852 3853 if (d_id == (lilp_map->lilp_myalpa & 0xFF)) { 3854 fp_jobdone(job); 3855 continue; 3856 } 3857 3858 pd = fctl_get_remote_port_by_did(port, d_id); 3859 if (pd != NULL) { 3860 #ifdef DEBUG 3861 mutex_enter(&pd->pd_mutex); 3862 if (pd->pd_recepient == PD_PLOGI_INITIATOR) { 3863 ASSERT(pd->pd_type != PORT_DEVICE_OLD); 3864 } 3865 mutex_exit(&pd->pd_mutex); 3866 #endif 3867 fp_jobdone(job); 3868 continue; 3869 } 3870 3871 rval = fp_port_login(port, d_id, job, 3872 FP_CMD_PLOGI_DONT_CARE, KM_SLEEP, pd, NULL); 3873 3874 if (rval != FC_SUCCESS) { 3875 fp_jobdone(job); 3876 } 3877 } 3878 fp_jobwait(job); 3879 } 3880 listlen = 0; 3881 changelist = NULL; 3882 3883 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3884 mutex_enter(&port->fp_mutex); 3885 ASSERT(port->fp_statec_busy > 0); 3886 if (port->fp_statec_busy == 1) { 3887 mutex_exit(&port->fp_mutex); 3888 fctl_fillout_map(port, &changelist, &listlen, 3889 1, 0, orphan); 3890 3891 mutex_enter(&port->fp_mutex); 3892 if (port->fp_lilp_map.lilp_magic < MAGIC_LIRP) { 3893 ASSERT(port->fp_total_devices == 0); 3894 port->fp_total_devices = port->fp_dev_count; 3895 } 3896 } else { 3897 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 3898 } 3899 mutex_exit(&port->fp_mutex); 3900 } 3901 3902 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 3903 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 3904 listlen, listlen, KM_SLEEP); 3905 } else { 3906 mutex_enter(&port->fp_mutex); 3907 if (--port->fp_statec_busy == 0) { 3908 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 3909 } 3910 ASSERT(changelist == NULL && listlen == 0); 3911 mutex_exit(&port->fp_mutex); 3912 } 3913 3914 FP_TRACE(FP_NHEAD1(1, 0), "fp_loop_online end; port=%p, job=%p", 3915 port, job); 3916 } 3917 3918 3919 /* 3920 * Get an Arbitrated Loop map from the underlying FCA 3921 */ 3922 static int 3923 fp_get_lilpmap(fc_local_port_t *port, fc_lilpmap_t *lilp_map) 3924 { 3925 int rval; 3926 3927 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap Begin; port=%p, map=%p", 3928 port, lilp_map); 3929 3930 bzero((caddr_t)lilp_map, sizeof (fc_lilpmap_t)); 3931 rval = port->fp_fca_tran->fca_getmap(port->fp_fca_handle, lilp_map); 3932 lilp_map->lilp_magic &= 0xFF; /* Ignore upper byte */ 3933 3934 if (rval != FC_SUCCESS) { 3935 rval = FC_NO_MAP; 3936 } else if (lilp_map->lilp_length == 0 && 3937 (lilp_map->lilp_magic >= MAGIC_LISM && 3938 lilp_map->lilp_magic < MAGIC_LIRP)) { 3939 uchar_t lilp_length; 3940 3941 /* 3942 * Since the map length is zero, provide all 3943 * the valid AL_PAs for NL_ports discovery. 3944 */ 3945 lilp_length = sizeof (fp_valid_alpas) / 3946 sizeof (fp_valid_alpas[0]); 3947 lilp_map->lilp_length = lilp_length; 3948 bcopy(fp_valid_alpas, lilp_map->lilp_alpalist, 3949 lilp_length); 3950 } else { 3951 rval = fp_validate_lilp_map(lilp_map); 3952 3953 if (rval == FC_SUCCESS) { 3954 mutex_enter(&port->fp_mutex); 3955 port->fp_total_devices = lilp_map->lilp_length - 1; 3956 mutex_exit(&port->fp_mutex); 3957 } 3958 } 3959 3960 mutex_enter(&port->fp_mutex); 3961 if (rval != FC_SUCCESS && !(port->fp_soft_state & FP_SOFT_BAD_LINK)) { 3962 port->fp_soft_state |= FP_SOFT_BAD_LINK; 3963 mutex_exit(&port->fp_mutex); 3964 3965 if (port->fp_fca_tran->fca_reset(port->fp_fca_handle, 3966 FC_FCA_RESET_CORE) != FC_SUCCESS) { 3967 FP_TRACE(FP_NHEAD1(9, 0), 3968 "FCA reset failed after LILP map was found" 3969 " to be invalid"); 3970 } 3971 } else if (rval == FC_SUCCESS) { 3972 port->fp_soft_state &= ~FP_SOFT_BAD_LINK; 3973 mutex_exit(&port->fp_mutex); 3974 } else { 3975 mutex_exit(&port->fp_mutex); 3976 } 3977 3978 FP_TRACE(FP_NHEAD1(1, 0), "fp_get_lilpmap End; port=%p, map=%p", port, 3979 lilp_map); 3980 3981 return (rval); 3982 } 3983 3984 3985 /* 3986 * Perform Fabric Login: 3987 * 3988 * Return Values: 3989 * FC_SUCCESS 3990 * FC_FAILURE 3991 * FC_NOMEM 3992 * FC_TRANSPORT_ERROR 3993 * and a lot others defined in fc_error.h 3994 */ 3995 static int 3996 fp_fabric_login(fc_local_port_t *port, uint32_t s_id, job_request_t *job, 3997 int flag, int sleep) 3998 { 3999 int rval; 4000 fp_cmd_t *cmd; 4001 uchar_t class; 4002 4003 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4004 4005 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login Begin; port=%p, job=%p", 4006 port, job); 4007 4008 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4009 if (class == FC_TRAN_CLASS_INVALID) { 4010 return (FC_ELS_BAD); 4011 } 4012 4013 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4014 sizeof (la_els_logi_t), sleep, NULL); 4015 if (cmd == NULL) { 4016 return (FC_NOMEM); 4017 } 4018 4019 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4020 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4021 cmd->cmd_flags = flag; 4022 cmd->cmd_retry_count = fp_retry_count; 4023 cmd->cmd_ulp_pkt = NULL; 4024 4025 fp_xlogi_init(port, cmd, s_id, 0xFFFFFE, fp_flogi_intr, 4026 job, LA_ELS_FLOGI); 4027 4028 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 4029 if (rval != FC_SUCCESS) { 4030 fp_free_pkt(cmd); 4031 } 4032 4033 FP_TRACE(FP_NHEAD1(1, 0), "fp_fabric_login End; port=%p, job=%p", 4034 port, job); 4035 4036 return (rval); 4037 } 4038 4039 4040 /* 4041 * In some scenarios such as private loop device discovery period 4042 * the fc_remote_port_t data structure isn't allocated. The allocation 4043 * is done when the PLOGI is successful. In some other scenarios 4044 * such as Fabric topology, the fc_remote_port_t is already created 4045 * and initialized with appropriate values (as the NS provides 4046 * them) 4047 */ 4048 static int 4049 fp_port_login(fc_local_port_t *port, uint32_t d_id, job_request_t *job, 4050 int cmd_flag, int sleep, fc_remote_port_t *pd, fc_packet_t *ulp_pkt) 4051 { 4052 uchar_t class; 4053 fp_cmd_t *cmd; 4054 uint32_t src_id; 4055 fc_remote_port_t *tmp_pd; 4056 int relogin; 4057 int found = 0; 4058 4059 #ifdef DEBUG 4060 if (pd == NULL) { 4061 ASSERT(fctl_get_remote_port_by_did(port, d_id) == NULL); 4062 } 4063 #endif 4064 ASSERT(job->job_counter > 0); 4065 4066 class = fp_get_nextclass(port, FC_TRAN_CLASS_INVALID); 4067 if (class == FC_TRAN_CLASS_INVALID) { 4068 return (FC_ELS_BAD); 4069 } 4070 4071 mutex_enter(&port->fp_mutex); 4072 tmp_pd = fctl_lookup_pd_by_did(port, d_id); 4073 mutex_exit(&port->fp_mutex); 4074 4075 relogin = 1; 4076 if (tmp_pd) { 4077 mutex_enter(&tmp_pd->pd_mutex); 4078 if ((tmp_pd->pd_aux_flags & PD_DISABLE_RELOGIN) && 4079 !(tmp_pd->pd_aux_flags & PD_LOGGED_OUT)) { 4080 tmp_pd->pd_state = PORT_DEVICE_LOGGED_IN; 4081 relogin = 0; 4082 } 4083 mutex_exit(&tmp_pd->pd_mutex); 4084 } 4085 4086 if (!relogin) { 4087 mutex_enter(&tmp_pd->pd_mutex); 4088 if (tmp_pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4089 cmd_flag |= FP_CMD_PLOGI_RETAIN; 4090 } 4091 mutex_exit(&tmp_pd->pd_mutex); 4092 4093 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 4094 sizeof (la_els_adisc_t), sleep, tmp_pd); 4095 if (cmd == NULL) { 4096 return (FC_NOMEM); 4097 } 4098 4099 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4100 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4101 cmd->cmd_flags = cmd_flag; 4102 cmd->cmd_retry_count = fp_retry_count; 4103 cmd->cmd_ulp_pkt = ulp_pkt; 4104 4105 mutex_enter(&port->fp_mutex); 4106 mutex_enter(&tmp_pd->pd_mutex); 4107 fp_adisc_init(cmd, job); 4108 mutex_exit(&tmp_pd->pd_mutex); 4109 mutex_exit(&port->fp_mutex); 4110 4111 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_adisc_t); 4112 cmd->cmd_pkt.pkt_rsplen = sizeof (la_els_adisc_t); 4113 4114 } else { 4115 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 4116 sizeof (la_els_logi_t), sleep, pd); 4117 if (cmd == NULL) { 4118 return (FC_NOMEM); 4119 } 4120 4121 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 4122 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 4123 cmd->cmd_flags = cmd_flag; 4124 cmd->cmd_retry_count = fp_retry_count; 4125 cmd->cmd_ulp_pkt = ulp_pkt; 4126 4127 mutex_enter(&port->fp_mutex); 4128 src_id = port->fp_port_id.port_id; 4129 mutex_exit(&port->fp_mutex); 4130 4131 fp_xlogi_init(port, cmd, src_id, d_id, fp_plogi_intr, 4132 job, LA_ELS_PLOGI); 4133 } 4134 4135 if (pd) { 4136 mutex_enter(&pd->pd_mutex); 4137 pd->pd_flags = PD_ELS_IN_PROGRESS; 4138 mutex_exit(&pd->pd_mutex); 4139 } 4140 4141 /* npiv check to make sure we don't log into ourself */ 4142 if (relogin && 4143 ((port->fp_npiv_type == FC_NPIV_PORT) || 4144 (port->fp_npiv_flag == FC_NPIV_ENABLE))) { 4145 if ((d_id & 0xffff00) == 4146 (port->fp_port_id.port_id & 0xffff00)) { 4147 found = 1; 4148 } 4149 } 4150 4151 if (found || 4152 (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS)) { 4153 if (found) { 4154 fc_packet_t *pkt = &cmd->cmd_pkt; 4155 pkt->pkt_state = FC_PKT_NPORT_RJT; 4156 } 4157 if (pd) { 4158 mutex_enter(&pd->pd_mutex); 4159 pd->pd_flags = PD_IDLE; 4160 mutex_exit(&pd->pd_mutex); 4161 } 4162 4163 if (ulp_pkt) { 4164 fc_packet_t *pkt = &cmd->cmd_pkt; 4165 4166 ulp_pkt->pkt_state = pkt->pkt_state; 4167 ulp_pkt->pkt_reason = pkt->pkt_reason; 4168 ulp_pkt->pkt_action = pkt->pkt_action; 4169 ulp_pkt->pkt_expln = pkt->pkt_expln; 4170 } 4171 4172 fp_iodone(cmd); 4173 } 4174 4175 return (FC_SUCCESS); 4176 } 4177 4178 4179 /* 4180 * Register the LOGIN parameters with a port device 4181 */ 4182 static void 4183 fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 4184 la_els_logi_t *acc, uchar_t class) 4185 { 4186 fc_remote_node_t *node; 4187 4188 ASSERT(pd != NULL); 4189 4190 mutex_enter(&pd->pd_mutex); 4191 node = pd->pd_remote_nodep; 4192 if (pd->pd_login_count == 0) { 4193 pd->pd_login_count++; 4194 } 4195 4196 if (handle) { 4197 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp, 4198 (uint8_t *)&acc->common_service, 4199 sizeof (acc->common_service), DDI_DEV_AUTOINCR); 4200 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1, 4201 (uint8_t *)&acc->class_1, sizeof (acc->class_1), 4202 DDI_DEV_AUTOINCR); 4203 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2, 4204 (uint8_t *)&acc->class_2, sizeof (acc->class_2), 4205 DDI_DEV_AUTOINCR); 4206 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3, 4207 (uint8_t *)&acc->class_3, sizeof (acc->class_3), 4208 DDI_DEV_AUTOINCR); 4209 } else { 4210 pd->pd_csp = acc->common_service; 4211 pd->pd_clsp1 = acc->class_1; 4212 pd->pd_clsp2 = acc->class_2; 4213 pd->pd_clsp3 = acc->class_3; 4214 } 4215 4216 pd->pd_state = PORT_DEVICE_LOGGED_IN; 4217 pd->pd_login_class = class; 4218 mutex_exit(&pd->pd_mutex); 4219 4220 #ifndef __lock_lint 4221 ASSERT(fctl_get_remote_port_by_did(pd->pd_port, 4222 pd->pd_port_id.port_id) == pd); 4223 #endif 4224 4225 mutex_enter(&node->fd_mutex); 4226 if (handle) { 4227 FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv, 4228 (uint8_t *)acc->vendor_version, sizeof (node->fd_vv), 4229 DDI_DEV_AUTOINCR); 4230 } else { 4231 bcopy(acc->vendor_version, node->fd_vv, sizeof (node->fd_vv)); 4232 } 4233 mutex_exit(&node->fd_mutex); 4234 } 4235 4236 4237 /* 4238 * Mark the remote port as OFFLINE 4239 */ 4240 static void 4241 fp_remote_port_offline(fc_remote_port_t *pd) 4242 { 4243 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4244 if (pd->pd_login_count && 4245 ((pd->pd_aux_flags & PD_DISABLE_RELOGIN) == 0)) { 4246 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4247 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4248 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4249 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4250 pd->pd_login_class = 0; 4251 } 4252 pd->pd_type = PORT_DEVICE_OLD; 4253 pd->pd_flags = PD_IDLE; 4254 fctl_tc_reset(&pd->pd_logo_tc); 4255 } 4256 4257 4258 /* 4259 * Deregistration of a port device 4260 */ 4261 static void 4262 fp_unregister_login(fc_remote_port_t *pd) 4263 { 4264 fc_remote_node_t *node; 4265 4266 ASSERT(pd != NULL); 4267 4268 mutex_enter(&pd->pd_mutex); 4269 pd->pd_login_count = 0; 4270 bzero((caddr_t)&pd->pd_csp, sizeof (struct common_service)); 4271 bzero((caddr_t)&pd->pd_clsp1, sizeof (struct service_param)); 4272 bzero((caddr_t)&pd->pd_clsp2, sizeof (struct service_param)); 4273 bzero((caddr_t)&pd->pd_clsp3, sizeof (struct service_param)); 4274 4275 pd->pd_state = PORT_DEVICE_VALID; 4276 pd->pd_login_class = 0; 4277 node = pd->pd_remote_nodep; 4278 mutex_exit(&pd->pd_mutex); 4279 4280 mutex_enter(&node->fd_mutex); 4281 bzero(node->fd_vv, sizeof (node->fd_vv)); 4282 mutex_exit(&node->fd_mutex); 4283 } 4284 4285 4286 /* 4287 * Handle OFFLINE state of an FCA port 4288 */ 4289 static void 4290 fp_port_offline(fc_local_port_t *port, int notify) 4291 { 4292 int index; 4293 int statec; 4294 timeout_id_t tid; 4295 struct pwwn_hash *head; 4296 fc_remote_port_t *pd; 4297 4298 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4299 4300 for (index = 0; index < pwwn_table_size; index++) { 4301 head = &port->fp_pwwn_table[index]; 4302 pd = head->pwwn_head; 4303 while (pd != NULL) { 4304 mutex_enter(&pd->pd_mutex); 4305 fp_remote_port_offline(pd); 4306 fctl_delist_did_table(port, pd); 4307 mutex_exit(&pd->pd_mutex); 4308 pd = pd->pd_wwn_hnext; 4309 } 4310 } 4311 port->fp_total_devices = 0; 4312 4313 statec = 0; 4314 if (notify) { 4315 /* 4316 * Decrement the statec busy counter as we 4317 * are almost done with handling the state 4318 * change 4319 */ 4320 ASSERT(port->fp_statec_busy > 0); 4321 if (--port->fp_statec_busy == 0) { 4322 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4323 } 4324 mutex_exit(&port->fp_mutex); 4325 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, NULL, 4326 0, 0, KM_SLEEP); 4327 mutex_enter(&port->fp_mutex); 4328 4329 if (port->fp_statec_busy) { 4330 statec++; 4331 } 4332 } else if (port->fp_statec_busy > 1) { 4333 statec++; 4334 } 4335 4336 if ((tid = port->fp_offline_tid) != NULL) { 4337 mutex_exit(&port->fp_mutex); 4338 (void) untimeout(tid); 4339 mutex_enter(&port->fp_mutex); 4340 } 4341 4342 if (!statec) { 4343 port->fp_offline_tid = timeout(fp_offline_timeout, 4344 (caddr_t)port, fp_offline_ticks); 4345 } 4346 } 4347 4348 4349 /* 4350 * Offline devices and send up a state change notification to ULPs 4351 */ 4352 static void 4353 fp_offline_timeout(void *port_handle) 4354 { 4355 int ret; 4356 fc_local_port_t *port = port_handle; 4357 uint32_t listlen = 0; 4358 fc_portmap_t *changelist = NULL; 4359 4360 mutex_enter(&port->fp_mutex); 4361 4362 if ((FC_PORT_STATE_MASK(port->fp_state) != FC_STATE_OFFLINE) || 4363 (port->fp_soft_state & 4364 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 4365 port->fp_dev_count == 0 || port->fp_statec_busy) { 4366 port->fp_offline_tid = NULL; 4367 mutex_exit(&port->fp_mutex); 4368 return; 4369 } 4370 4371 mutex_exit(&port->fp_mutex); 4372 4373 FP_TRACE(FP_NHEAD2(9, 0), "OFFLINE timeout"); 4374 4375 if (port->fp_options & FP_CORE_ON_OFFLINE_TIMEOUT) { 4376 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4377 FC_FCA_CORE)) != FC_SUCCESS) { 4378 FP_TRACE(FP_NHEAD1(9, ret), 4379 "Failed to force adapter dump"); 4380 } else { 4381 FP_TRACE(FP_NHEAD1(9, 0), 4382 "Forced adapter dump successfully"); 4383 } 4384 } else if (port->fp_options & FP_RESET_CORE_ON_OFFLINE_TIMEOUT) { 4385 if ((ret = port->fp_fca_tran->fca_reset(port->fp_fca_handle, 4386 FC_FCA_RESET_CORE)) != FC_SUCCESS) { 4387 FP_TRACE(FP_NHEAD1(9, ret), 4388 "Failed to force adapter dump and reset"); 4389 } else { 4390 FP_TRACE(FP_NHEAD1(9, 0), 4391 "Forced adapter dump and reset successfully"); 4392 } 4393 } 4394 4395 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 4396 (void) fp_ulp_statec_cb(port, FC_STATE_OFFLINE, changelist, 4397 listlen, listlen, KM_SLEEP); 4398 4399 mutex_enter(&port->fp_mutex); 4400 port->fp_offline_tid = NULL; 4401 mutex_exit(&port->fp_mutex); 4402 } 4403 4404 4405 /* 4406 * Perform general purpose ELS request initialization 4407 */ 4408 static void 4409 fp_els_init(fp_cmd_t *cmd, uint32_t s_id, uint32_t d_id, 4410 void (*comp) (), job_request_t *job) 4411 { 4412 fc_packet_t *pkt; 4413 4414 pkt = &cmd->cmd_pkt; 4415 cmd->cmd_job = job; 4416 4417 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; 4418 pkt->pkt_cmd_fhdr.d_id = d_id; 4419 pkt->pkt_cmd_fhdr.s_id = s_id; 4420 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 4421 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ; 4422 pkt->pkt_cmd_fhdr.seq_id = 0; 4423 pkt->pkt_cmd_fhdr.df_ctl = 0; 4424 pkt->pkt_cmd_fhdr.seq_cnt = 0; 4425 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 4426 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 4427 pkt->pkt_cmd_fhdr.ro = 0; 4428 pkt->pkt_cmd_fhdr.rsvd = 0; 4429 pkt->pkt_comp = comp; 4430 pkt->pkt_timeout = FP_ELS_TIMEOUT; 4431 } 4432 4433 4434 /* 4435 * Initialize PLOGI/FLOGI ELS request 4436 */ 4437 static void 4438 fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id, 4439 uint32_t d_id, void (*intr) (), job_request_t *job, uchar_t ls_code) 4440 { 4441 ls_code_t payload; 4442 4443 fp_els_init(cmd, s_id, d_id, intr, job); 4444 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4445 4446 payload.ls_code = ls_code; 4447 payload.mbz = 0; 4448 4449 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, 4450 (uint8_t *)&port->fp_service_params, 4451 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params), 4452 DDI_DEV_AUTOINCR); 4453 4454 FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload, 4455 (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload), 4456 DDI_DEV_AUTOINCR); 4457 } 4458 4459 4460 /* 4461 * Initialize LOGO ELS request 4462 */ 4463 static void 4464 fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job) 4465 { 4466 fc_local_port_t *port; 4467 fc_packet_t *pkt; 4468 la_els_logo_t payload; 4469 4470 port = pd->pd_port; 4471 pkt = &cmd->cmd_pkt; 4472 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4473 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4474 4475 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4476 fp_logo_intr, job); 4477 4478 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4479 4480 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4481 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4482 4483 payload.ls_code.ls_code = LA_ELS_LOGO; 4484 payload.ls_code.mbz = 0; 4485 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 4486 payload.nport_id = port->fp_port_id; 4487 4488 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4489 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4490 } 4491 4492 /* 4493 * Initialize RNID ELS request 4494 */ 4495 static void 4496 fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job) 4497 { 4498 fc_local_port_t *port; 4499 fc_packet_t *pkt; 4500 la_els_rnid_t payload; 4501 fc_remote_port_t *pd; 4502 4503 pkt = &cmd->cmd_pkt; 4504 pd = pkt->pkt_pd; 4505 port = pd->pd_port; 4506 4507 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4508 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4509 4510 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4511 fp_rnid_intr, job); 4512 4513 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4514 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4515 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4516 4517 payload.ls_code.ls_code = LA_ELS_RNID; 4518 payload.ls_code.mbz = 0; 4519 payload.data_format = flag; 4520 4521 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4522 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4523 } 4524 4525 /* 4526 * Initialize RLS ELS request 4527 */ 4528 static void 4529 fp_rls_init(fp_cmd_t *cmd, job_request_t *job) 4530 { 4531 fc_local_port_t *port; 4532 fc_packet_t *pkt; 4533 la_els_rls_t payload; 4534 fc_remote_port_t *pd; 4535 4536 pkt = &cmd->cmd_pkt; 4537 pd = pkt->pkt_pd; 4538 port = pd->pd_port; 4539 4540 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4541 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4542 4543 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4544 fp_rls_intr, job); 4545 4546 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4547 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4548 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4549 4550 payload.ls_code.ls_code = LA_ELS_RLS; 4551 payload.ls_code.mbz = 0; 4552 payload.rls_portid = port->fp_port_id; 4553 4554 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4555 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4556 } 4557 4558 4559 /* 4560 * Initialize an ADISC ELS request 4561 */ 4562 static void 4563 fp_adisc_init(fp_cmd_t *cmd, job_request_t *job) 4564 { 4565 fc_local_port_t *port; 4566 fc_packet_t *pkt; 4567 la_els_adisc_t payload; 4568 fc_remote_port_t *pd; 4569 4570 pkt = &cmd->cmd_pkt; 4571 pd = pkt->pkt_pd; 4572 port = pd->pd_port; 4573 4574 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4575 ASSERT(MUTEX_HELD(&pd->pd_port->fp_mutex)); 4576 4577 fp_els_init(cmd, port->fp_port_id.port_id, pd->pd_port_id.port_id, 4578 fp_adisc_intr, job); 4579 4580 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 4581 pkt->pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 4582 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 4583 4584 payload.ls_code.ls_code = LA_ELS_ADISC; 4585 payload.ls_code.mbz = 0; 4586 payload.nport_id = port->fp_port_id; 4587 payload.port_wwn = port->fp_service_params.nport_ww_name; 4588 payload.node_wwn = port->fp_service_params.node_ww_name; 4589 payload.hard_addr = port->fp_hard_addr; 4590 4591 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 4592 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 4593 } 4594 4595 4596 /* 4597 * Send up a state change notification to ULPs. 4598 * Spawns a call to fctl_ulp_statec_cb in a taskq thread. 4599 */ 4600 static int 4601 fp_ulp_statec_cb(fc_local_port_t *port, uint32_t state, 4602 fc_portmap_t *changelist, uint32_t listlen, uint32_t alloc_len, int sleep) 4603 { 4604 fc_port_clist_t *clist; 4605 fc_remote_port_t *pd; 4606 int count; 4607 4608 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4609 4610 clist = kmem_zalloc(sizeof (*clist), sleep); 4611 if (clist == NULL) { 4612 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4613 return (FC_NOMEM); 4614 } 4615 4616 clist->clist_state = state; 4617 4618 mutex_enter(&port->fp_mutex); 4619 clist->clist_flags = port->fp_topology; 4620 mutex_exit(&port->fp_mutex); 4621 4622 clist->clist_port = (opaque_t)port; 4623 clist->clist_len = listlen; 4624 clist->clist_size = alloc_len; 4625 clist->clist_map = changelist; 4626 4627 /* 4628 * Bump the reference count of each fc_remote_port_t in this changelist. 4629 * This is necessary since these devices will be sitting in a taskq 4630 * and referenced later. When the state change notification is 4631 * complete, the reference counts will be decremented. 4632 */ 4633 for (count = 0; count < clist->clist_len; count++) { 4634 pd = clist->clist_map[count].map_pd; 4635 4636 if (pd != NULL) { 4637 mutex_enter(&pd->pd_mutex); 4638 ASSERT((pd->pd_ref_count >= 0) || 4639 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4640 pd->pd_ref_count++; 4641 4642 if (clist->clist_map[count].map_state != 4643 PORT_DEVICE_INVALID) { 4644 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4645 } 4646 4647 mutex_exit(&pd->pd_mutex); 4648 } 4649 } 4650 4651 #ifdef DEBUG 4652 /* 4653 * Sanity check for presence of OLD devices in the hash lists 4654 */ 4655 if (clist->clist_size) { 4656 ASSERT(clist->clist_map != NULL); 4657 for (count = 0; count < clist->clist_len; count++) { 4658 if (clist->clist_map[count].map_state == 4659 PORT_DEVICE_INVALID) { 4660 la_wwn_t pwwn; 4661 fc_portid_t d_id; 4662 4663 pd = clist->clist_map[count].map_pd; 4664 ASSERT(pd != NULL); 4665 4666 mutex_enter(&pd->pd_mutex); 4667 pwwn = pd->pd_port_name; 4668 d_id = pd->pd_port_id; 4669 mutex_exit(&pd->pd_mutex); 4670 4671 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4672 ASSERT(pd != clist->clist_map[count].map_pd); 4673 4674 pd = fctl_get_remote_port_by_did(port, 4675 d_id.port_id); 4676 ASSERT(pd != clist->clist_map[count].map_pd); 4677 } 4678 } 4679 } 4680 #endif 4681 4682 mutex_enter(&port->fp_mutex); 4683 4684 if (state == FC_STATE_ONLINE) { 4685 if (--port->fp_statec_busy == 0) { 4686 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 4687 } 4688 } 4689 mutex_exit(&port->fp_mutex); 4690 4691 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 4692 clist, KM_SLEEP); 4693 4694 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_statec fired; Port=%p," 4695 "state=%x, len=%d", port, state, listlen); 4696 4697 return (FC_SUCCESS); 4698 } 4699 4700 4701 /* 4702 * Send up a FC_STATE_DEVICE_CHANGE state notification to ULPs 4703 */ 4704 static int 4705 fp_ulp_devc_cb(fc_local_port_t *port, fc_portmap_t *changelist, 4706 uint32_t listlen, uint32_t alloc_len, int sleep, int sync) 4707 { 4708 int ret; 4709 fc_port_clist_t *clist; 4710 4711 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4712 4713 clist = kmem_zalloc(sizeof (*clist), sleep); 4714 if (clist == NULL) { 4715 kmem_free(changelist, alloc_len * sizeof (*changelist)); 4716 return (FC_NOMEM); 4717 } 4718 4719 clist->clist_state = FC_STATE_DEVICE_CHANGE; 4720 4721 mutex_enter(&port->fp_mutex); 4722 clist->clist_flags = port->fp_topology; 4723 mutex_exit(&port->fp_mutex); 4724 4725 clist->clist_port = (opaque_t)port; 4726 clist->clist_len = listlen; 4727 clist->clist_size = alloc_len; 4728 clist->clist_map = changelist; 4729 4730 /* Send sysevents for target state changes */ 4731 4732 if (clist->clist_size) { 4733 int count; 4734 fc_remote_port_t *pd; 4735 4736 ASSERT(clist->clist_map != NULL); 4737 for (count = 0; count < clist->clist_len; count++) { 4738 pd = clist->clist_map[count].map_pd; 4739 4740 /* 4741 * Bump reference counts on all fc_remote_port_t 4742 * structs in this list. We don't know when the task 4743 * will fire, and we don't need these fc_remote_port_t 4744 * structs going away behind our back. 4745 */ 4746 if (pd) { 4747 mutex_enter(&pd->pd_mutex); 4748 ASSERT((pd->pd_ref_count >= 0) || 4749 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)); 4750 pd->pd_ref_count++; 4751 mutex_exit(&pd->pd_mutex); 4752 } 4753 4754 if (clist->clist_map[count].map_state == 4755 PORT_DEVICE_VALID) { 4756 if (clist->clist_map[count].map_type == 4757 PORT_DEVICE_NEW) { 4758 /* Update our state change counter */ 4759 mutex_enter(&port->fp_mutex); 4760 port->fp_last_change++; 4761 mutex_exit(&port->fp_mutex); 4762 4763 /* Additions */ 4764 fp_log_target_event(port, 4765 ESC_SUNFC_TARGET_ADD, 4766 clist->clist_map[count].map_pwwn, 4767 clist->clist_map[count].map_did. 4768 port_id); 4769 } 4770 4771 } else if ((clist->clist_map[count].map_type == 4772 PORT_DEVICE_OLD) && 4773 (clist->clist_map[count].map_state == 4774 PORT_DEVICE_INVALID)) { 4775 /* Update our state change counter */ 4776 mutex_enter(&port->fp_mutex); 4777 port->fp_last_change++; 4778 mutex_exit(&port->fp_mutex); 4779 4780 /* 4781 * For removals, we don't decrement 4782 * pd_ref_count until after the ULP's 4783 * state change callback function has 4784 * completed. 4785 */ 4786 4787 /* Removals */ 4788 fp_log_target_event(port, 4789 ESC_SUNFC_TARGET_REMOVE, 4790 clist->clist_map[count].map_pwwn, 4791 clist->clist_map[count].map_did.port_id); 4792 } 4793 4794 if (clist->clist_map[count].map_state != 4795 PORT_DEVICE_INVALID) { 4796 /* 4797 * Indicate that the ULPs are now aware of 4798 * this device. 4799 */ 4800 4801 mutex_enter(&pd->pd_mutex); 4802 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 4803 mutex_exit(&pd->pd_mutex); 4804 } 4805 4806 #ifdef DEBUG 4807 /* 4808 * Sanity check for OLD devices in the hash lists 4809 */ 4810 if (pd && clist->clist_map[count].map_state == 4811 PORT_DEVICE_INVALID) { 4812 la_wwn_t pwwn; 4813 fc_portid_t d_id; 4814 4815 mutex_enter(&pd->pd_mutex); 4816 pwwn = pd->pd_port_name; 4817 d_id = pd->pd_port_id; 4818 mutex_exit(&pd->pd_mutex); 4819 4820 /* 4821 * This overwrites the 'pd' local variable. 4822 * Beware of this if 'pd' ever gets 4823 * referenced below this block. 4824 */ 4825 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 4826 ASSERT(pd != clist->clist_map[count].map_pd); 4827 4828 pd = fctl_get_remote_port_by_did(port, 4829 d_id.port_id); 4830 ASSERT(pd != clist->clist_map[count].map_pd); 4831 } 4832 #endif 4833 } 4834 } 4835 4836 if (sync) { 4837 clist->clist_wait = 1; 4838 mutex_init(&clist->clist_mutex, NULL, MUTEX_DRIVER, NULL); 4839 cv_init(&clist->clist_cv, NULL, CV_DRIVER, NULL); 4840 } 4841 4842 ret = taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, clist, sleep); 4843 if (sync && ret) { 4844 mutex_enter(&clist->clist_mutex); 4845 while (clist->clist_wait) { 4846 cv_wait(&clist->clist_cv, &clist->clist_mutex); 4847 } 4848 mutex_exit(&clist->clist_mutex); 4849 4850 mutex_destroy(&clist->clist_mutex); 4851 cv_destroy(&clist->clist_cv); 4852 kmem_free(clist, sizeof (*clist)); 4853 } 4854 4855 if (!ret) { 4856 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc dispatch failed; " 4857 "port=%p", port); 4858 kmem_free(clist->clist_map, 4859 sizeof (*(clist->clist_map)) * clist->clist_size); 4860 kmem_free(clist, sizeof (*clist)); 4861 } else { 4862 FP_TRACE(FP_NHEAD1(4, 0), "fp_ulp_devc fired; port=%p, len=%d", 4863 port, listlen); 4864 } 4865 4866 return (FC_SUCCESS); 4867 } 4868 4869 4870 /* 4871 * Perform PLOGI to the group of devices for ULPs 4872 */ 4873 static void 4874 fp_plogi_group(fc_local_port_t *port, job_request_t *job) 4875 { 4876 int offline; 4877 int count; 4878 int rval; 4879 uint32_t listlen; 4880 uint32_t done; 4881 uint32_t d_id; 4882 fc_remote_node_t *node; 4883 fc_remote_port_t *pd; 4884 fc_remote_port_t *tmp_pd; 4885 fc_packet_t *ulp_pkt; 4886 la_els_logi_t *els_data; 4887 ls_code_t ls_code; 4888 4889 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group begin; port=%p, job=%p", 4890 port, job); 4891 4892 done = 0; 4893 listlen = job->job_ulp_listlen; 4894 job->job_counter = job->job_ulp_listlen; 4895 4896 mutex_enter(&port->fp_mutex); 4897 offline = (port->fp_statec_busy || 4898 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ? 1 : 0; 4899 mutex_exit(&port->fp_mutex); 4900 4901 for (count = 0; count < listlen; count++) { 4902 ASSERT(job->job_ulp_pkts[count]->pkt_rsplen >= 4903 sizeof (la_els_logi_t)); 4904 4905 ulp_pkt = job->job_ulp_pkts[count]; 4906 pd = ulp_pkt->pkt_pd; 4907 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 4908 4909 if (offline) { 4910 done++; 4911 4912 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 4913 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4914 ulp_pkt->pkt_pd = NULL; 4915 ulp_pkt->pkt_comp(ulp_pkt); 4916 4917 job->job_ulp_pkts[count] = NULL; 4918 4919 fp_jobdone(job); 4920 continue; 4921 } 4922 4923 if (pd == NULL) { 4924 pd = fctl_get_remote_port_by_did(port, d_id); 4925 if (pd == NULL) { 4926 /* reset later */ 4927 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4928 continue; 4929 } 4930 mutex_enter(&pd->pd_mutex); 4931 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 4932 mutex_exit(&pd->pd_mutex); 4933 ulp_pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 4934 done++; 4935 ulp_pkt->pkt_comp(ulp_pkt); 4936 job->job_ulp_pkts[count] = NULL; 4937 fp_jobdone(job); 4938 } else { 4939 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4940 mutex_exit(&pd->pd_mutex); 4941 } 4942 continue; 4943 } 4944 4945 switch (ulp_pkt->pkt_state) { 4946 case FC_PKT_ELS_IN_PROGRESS: 4947 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 4948 /* FALLTHRU */ 4949 case FC_PKT_LOCAL_RJT: 4950 done++; 4951 ulp_pkt->pkt_comp(ulp_pkt); 4952 job->job_ulp_pkts[count] = NULL; 4953 fp_jobdone(job); 4954 continue; 4955 default: 4956 break; 4957 } 4958 4959 /* 4960 * Validate the pd corresponding to the d_id passed 4961 * by the ULPs 4962 */ 4963 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 4964 if ((tmp_pd == NULL) || (pd != tmp_pd)) { 4965 done++; 4966 ulp_pkt->pkt_state = FC_PKT_FAILURE; 4967 ulp_pkt->pkt_reason = FC_REASON_NO_CONNECTION; 4968 ulp_pkt->pkt_pd = NULL; 4969 ulp_pkt->pkt_comp(ulp_pkt); 4970 job->job_ulp_pkts[count] = NULL; 4971 fp_jobdone(job); 4972 continue; 4973 } 4974 4975 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group contd; " 4976 "port=%p, pd=%p", port, pd); 4977 4978 mutex_enter(&pd->pd_mutex); 4979 4980 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 4981 done++; 4982 els_data = (la_els_logi_t *)ulp_pkt->pkt_resp; 4983 4984 ls_code.ls_code = LA_ELS_ACC; 4985 ls_code.mbz = 0; 4986 4987 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4988 (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code, 4989 sizeof (ls_code_t), DDI_DEV_AUTOINCR); 4990 4991 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4992 (uint8_t *)&pd->pd_csp, 4993 (uint8_t *)&els_data->common_service, 4994 sizeof (pd->pd_csp), DDI_DEV_AUTOINCR); 4995 4996 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 4997 (uint8_t *)&pd->pd_port_name, 4998 (uint8_t *)&els_data->nport_ww_name, 4999 sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR); 5000 5001 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5002 (uint8_t *)&pd->pd_clsp1, 5003 (uint8_t *)&els_data->class_1, 5004 sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR); 5005 5006 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5007 (uint8_t *)&pd->pd_clsp2, 5008 (uint8_t *)&els_data->class_2, 5009 sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR); 5010 5011 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5012 (uint8_t *)&pd->pd_clsp3, 5013 (uint8_t *)&els_data->class_3, 5014 sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR); 5015 5016 node = pd->pd_remote_nodep; 5017 pd->pd_login_count++; 5018 pd->pd_flags = PD_IDLE; 5019 ulp_pkt->pkt_pd = pd; 5020 mutex_exit(&pd->pd_mutex); 5021 5022 mutex_enter(&node->fd_mutex); 5023 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5024 (uint8_t *)&node->fd_node_name, 5025 (uint8_t *)(&els_data->node_ww_name), 5026 sizeof (node->fd_node_name), DDI_DEV_AUTOINCR); 5027 5028 FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc, 5029 (uint8_t *)&node->fd_vv, 5030 (uint8_t *)(&els_data->vendor_version), 5031 sizeof (node->fd_vv), DDI_DEV_AUTOINCR); 5032 5033 mutex_exit(&node->fd_mutex); 5034 ulp_pkt->pkt_state = FC_PKT_SUCCESS; 5035 } else { 5036 5037 ulp_pkt->pkt_state = FC_PKT_FAILURE; /* reset later */ 5038 mutex_exit(&pd->pd_mutex); 5039 } 5040 5041 if (ulp_pkt->pkt_state != FC_PKT_FAILURE) { 5042 ulp_pkt->pkt_comp(ulp_pkt); 5043 job->job_ulp_pkts[count] = NULL; 5044 fp_jobdone(job); 5045 } 5046 } 5047 5048 if (done == listlen) { 5049 fp_jobwait(job); 5050 fctl_jobdone(job); 5051 return; 5052 } 5053 5054 job->job_counter = listlen - done; 5055 5056 for (count = 0; count < listlen; count++) { 5057 int cmd_flags; 5058 5059 if ((ulp_pkt = job->job_ulp_pkts[count]) == NULL) { 5060 continue; 5061 } 5062 5063 ASSERT(ulp_pkt->pkt_state == FC_PKT_FAILURE); 5064 5065 cmd_flags = FP_CMD_PLOGI_RETAIN; 5066 5067 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5068 ASSERT(d_id != 0); 5069 5070 pd = fctl_get_remote_port_by_did(port, d_id); 5071 5072 /* 5073 * We need to properly adjust the port device 5074 * reference counter before we assign the pd 5075 * to the ULP packets port device pointer. 5076 */ 5077 if (pd != NULL && ulp_pkt->pkt_pd == NULL) { 5078 mutex_enter(&pd->pd_mutex); 5079 pd->pd_ref_count++; 5080 mutex_exit(&pd->pd_mutex); 5081 FP_TRACE(FP_NHEAD1(3, 0), 5082 "fp_plogi_group: DID = 0x%x using new pd %p \ 5083 old pd NULL\n", d_id, pd); 5084 } else if (pd != NULL && ulp_pkt->pkt_pd != NULL && 5085 ulp_pkt->pkt_pd != pd) { 5086 mutex_enter(&pd->pd_mutex); 5087 pd->pd_ref_count++; 5088 mutex_exit(&pd->pd_mutex); 5089 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5090 ulp_pkt->pkt_pd->pd_ref_count--; 5091 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5092 FP_TRACE(FP_NHEAD1(3, 0), 5093 "fp_plogi_group: DID = 0x%x pkt_pd %p != pd %p\n", 5094 d_id, ulp_pkt->pkt_pd, pd); 5095 } else if (pd == NULL && ulp_pkt->pkt_pd != NULL) { 5096 mutex_enter(&ulp_pkt->pkt_pd->pd_mutex); 5097 ulp_pkt->pkt_pd->pd_ref_count--; 5098 mutex_exit(&ulp_pkt->pkt_pd->pd_mutex); 5099 FP_TRACE(FP_NHEAD1(3, 0), 5100 "fp_plogi_group: DID = 0x%x pd is NULL and \ 5101 pkt_pd = %p\n", d_id, ulp_pkt->pkt_pd); 5102 } 5103 5104 ulp_pkt->pkt_pd = pd; 5105 5106 if (pd != NULL) { 5107 mutex_enter(&pd->pd_mutex); 5108 d_id = pd->pd_port_id.port_id; 5109 pd->pd_flags = PD_ELS_IN_PROGRESS; 5110 mutex_exit(&pd->pd_mutex); 5111 } else { 5112 d_id = ulp_pkt->pkt_cmd_fhdr.d_id; 5113 #ifdef DEBUG 5114 pd = fctl_get_remote_port_by_did(port, d_id); 5115 ASSERT(pd == NULL); 5116 #endif 5117 /* 5118 * In the Fabric topology, use NS to create 5119 * port device, and if that fails still try 5120 * with PLOGI - which will make yet another 5121 * attempt to create after successful PLOGI 5122 */ 5123 mutex_enter(&port->fp_mutex); 5124 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 5125 mutex_exit(&port->fp_mutex); 5126 pd = fp_create_remote_port_by_ns(port, 5127 d_id, KM_SLEEP); 5128 if (pd) { 5129 cmd_flags |= FP_CMD_DELDEV_ON_ERROR; 5130 5131 mutex_enter(&pd->pd_mutex); 5132 pd->pd_flags = PD_ELS_IN_PROGRESS; 5133 mutex_exit(&pd->pd_mutex); 5134 5135 FP_TRACE(FP_NHEAD1(3, 0), 5136 "fp_plogi_group;" 5137 " NS created PD port=%p, job=%p," 5138 " pd=%p", port, job, pd); 5139 } 5140 } else { 5141 mutex_exit(&port->fp_mutex); 5142 } 5143 if ((ulp_pkt->pkt_pd == NULL) && (pd != NULL)) { 5144 FP_TRACE(FP_NHEAD1(3, 0), 5145 "fp_plogi_group;" 5146 "ulp_pkt's pd is NULL, get a pd %p", 5147 pd); 5148 mutex_enter(&pd->pd_mutex); 5149 pd->pd_ref_count++; 5150 mutex_exit(&pd->pd_mutex); 5151 } 5152 ulp_pkt->pkt_pd = pd; 5153 } 5154 5155 rval = fp_port_login(port, d_id, job, cmd_flags, 5156 KM_SLEEP, pd, ulp_pkt); 5157 5158 if (rval == FC_SUCCESS) { 5159 continue; 5160 } 5161 5162 if (rval == FC_STATEC_BUSY) { 5163 ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5164 ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5165 } else { 5166 ulp_pkt->pkt_state = FC_PKT_FAILURE; 5167 } 5168 5169 if (pd) { 5170 mutex_enter(&pd->pd_mutex); 5171 pd->pd_flags = PD_IDLE; 5172 mutex_exit(&pd->pd_mutex); 5173 } 5174 5175 if (cmd_flags & FP_CMD_DELDEV_ON_ERROR) { 5176 ASSERT(pd != NULL); 5177 5178 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_group: NS created," 5179 " PD removed; port=%p, job=%p", port, job); 5180 5181 mutex_enter(&pd->pd_mutex); 5182 pd->pd_ref_count--; 5183 node = pd->pd_remote_nodep; 5184 mutex_exit(&pd->pd_mutex); 5185 5186 ASSERT(node != NULL); 5187 5188 if (fctl_destroy_remote_port(port, pd) == 0) { 5189 fctl_destroy_remote_node(node); 5190 } 5191 ulp_pkt->pkt_pd = NULL; 5192 } 5193 ulp_pkt->pkt_comp(ulp_pkt); 5194 fp_jobdone(job); 5195 } 5196 5197 fp_jobwait(job); 5198 fctl_jobdone(job); 5199 5200 FP_TRACE(FP_NHEAD1(1, 0), "fp_plogi_group end: port=%p, job=%p", 5201 port, job); 5202 } 5203 5204 5205 /* 5206 * Name server request initialization 5207 */ 5208 static void 5209 fp_ns_init(fc_local_port_t *port, job_request_t *job, int sleep) 5210 { 5211 int rval; 5212 int count; 5213 int size; 5214 5215 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5216 5217 job->job_counter = 1; 5218 job->job_result = FC_SUCCESS; 5219 5220 rval = fp_port_login(port, 0xFFFFFC, job, FP_CMD_PLOGI_RETAIN, 5221 KM_SLEEP, NULL, NULL); 5222 5223 if (rval != FC_SUCCESS) { 5224 mutex_enter(&port->fp_mutex); 5225 port->fp_topology = FC_TOP_NO_NS; 5226 mutex_exit(&port->fp_mutex); 5227 return; 5228 } 5229 5230 fp_jobwait(job); 5231 5232 if (job->job_result != FC_SUCCESS) { 5233 mutex_enter(&port->fp_mutex); 5234 port->fp_topology = FC_TOP_NO_NS; 5235 mutex_exit(&port->fp_mutex); 5236 return; 5237 } 5238 5239 /* 5240 * At this time, we'll do NS registration for objects in the 5241 * ns_reg_cmds (see top of this file) array. 5242 * 5243 * Each time a ULP module registers with the transport, the 5244 * appropriate fc4 bit is set fc4 types and registered with 5245 * the NS for this support. Also, ULPs and FC admin utilities 5246 * may do registration for objects like IP address, symbolic 5247 * port/node name, Initial process associator at run time. 5248 */ 5249 size = sizeof (ns_reg_cmds) / sizeof (ns_reg_cmds[0]); 5250 job->job_counter = size; 5251 job->job_result = FC_SUCCESS; 5252 5253 for (count = 0; count < size; count++) { 5254 if (fp_ns_reg(port, NULL, ns_reg_cmds[count], 5255 job, 0, sleep) != FC_SUCCESS) { 5256 fp_jobdone(job); 5257 } 5258 } 5259 if (size) { 5260 fp_jobwait(job); 5261 } 5262 5263 job->job_result = FC_SUCCESS; 5264 5265 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 5266 5267 if (port->fp_dev_count < FP_MAX_DEVICES) { 5268 (void) fp_ns_get_devcount(port, job, 1, KM_SLEEP); 5269 } 5270 5271 job->job_counter = 1; 5272 5273 if (fp_ns_scr(port, job, FC_SCR_FULL_REGISTRATION, 5274 sleep) == FC_SUCCESS) { 5275 fp_jobwait(job); 5276 } 5277 } 5278 5279 5280 /* 5281 * Name server finish: 5282 * Unregister for RSCNs 5283 * Unregister all the host port objects in the Name Server 5284 * Perform LOGO with the NS; 5285 */ 5286 static void 5287 fp_ns_fini(fc_local_port_t *port, job_request_t *job) 5288 { 5289 fp_cmd_t *cmd; 5290 uchar_t class; 5291 uint32_t s_id; 5292 fc_packet_t *pkt; 5293 la_els_logo_t payload; 5294 5295 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5296 5297 job->job_counter = 1; 5298 5299 if (fp_ns_scr(port, job, FC_SCR_CLEAR_REGISTRATION, KM_SLEEP) != 5300 FC_SUCCESS) { 5301 fp_jobdone(job); 5302 } 5303 fp_jobwait(job); 5304 5305 job->job_counter = 1; 5306 5307 if (fp_ns_reg(port, NULL, NS_DA_ID, job, 0, KM_SLEEP) != FC_SUCCESS) { 5308 fp_jobdone(job); 5309 } 5310 fp_jobwait(job); 5311 5312 job->job_counter = 1; 5313 5314 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 5315 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, NULL); 5316 pkt = &cmd->cmd_pkt; 5317 5318 mutex_enter(&port->fp_mutex); 5319 class = port->fp_ns_login_class; 5320 s_id = port->fp_port_id.port_id; 5321 payload.nport_id = port->fp_port_id; 5322 mutex_exit(&port->fp_mutex); 5323 5324 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 5325 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 5326 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 5327 cmd->cmd_retry_count = 1; 5328 cmd->cmd_ulp_pkt = NULL; 5329 5330 if (port->fp_npiv_type == FC_NPIV_PORT) { 5331 fp_els_init(cmd, s_id, 0xFFFFFE, fp_logo_intr, job); 5332 } else { 5333 fp_els_init(cmd, s_id, 0xFFFFFC, fp_logo_intr, job); 5334 } 5335 5336 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 5337 5338 payload.ls_code.ls_code = LA_ELS_LOGO; 5339 payload.ls_code.mbz = 0; 5340 payload.nport_ww_name = port->fp_service_params.nport_ww_name; 5341 5342 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 5343 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 5344 5345 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 5346 fp_iodone(cmd); 5347 } 5348 fp_jobwait(job); 5349 } 5350 5351 5352 /* 5353 * NS Registration function. 5354 * 5355 * It should be seriously noted that FC-GS-2 currently doesn't support 5356 * an Object Registration by a D_ID other than the owner of the object. 5357 * What we are aiming at currently is to at least allow Symbolic Node/Port 5358 * Name registration for any N_Port Identifier by the host software. 5359 * 5360 * Anyway, if the second argument (fc_remote_port_t *) is NULL, this 5361 * function treats the request as Host NS Object. 5362 */ 5363 static int 5364 fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code, 5365 job_request_t *job, int polled, int sleep) 5366 { 5367 int rval; 5368 fc_portid_t s_id; 5369 fc_packet_t *pkt; 5370 fp_cmd_t *cmd; 5371 5372 if (pd == NULL) { 5373 mutex_enter(&port->fp_mutex); 5374 s_id = port->fp_port_id; 5375 mutex_exit(&port->fp_mutex); 5376 } else { 5377 mutex_enter(&pd->pd_mutex); 5378 s_id = pd->pd_port_id; 5379 mutex_exit(&pd->pd_mutex); 5380 } 5381 5382 if (polled) { 5383 job->job_counter = 1; 5384 } 5385 5386 switch (cmd_code) { 5387 case NS_RPN_ID: 5388 case NS_RNN_ID: { 5389 ns_rxn_req_t rxn; 5390 5391 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5392 sizeof (ns_rxn_req_t), sizeof (fc_reg_resp_t), sleep, NULL); 5393 if (cmd == NULL) { 5394 return (FC_NOMEM); 5395 } 5396 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5397 pkt = &cmd->cmd_pkt; 5398 5399 if (pd == NULL) { 5400 rxn.rxn_xname = ((cmd_code == NS_RPN_ID) ? 5401 (port->fp_service_params.nport_ww_name) : 5402 (port->fp_service_params.node_ww_name)); 5403 } else { 5404 if (cmd_code == NS_RPN_ID) { 5405 mutex_enter(&pd->pd_mutex); 5406 rxn.rxn_xname = pd->pd_port_name; 5407 mutex_exit(&pd->pd_mutex); 5408 } else { 5409 fc_remote_node_t *node; 5410 5411 mutex_enter(&pd->pd_mutex); 5412 node = pd->pd_remote_nodep; 5413 mutex_exit(&pd->pd_mutex); 5414 5415 mutex_enter(&node->fd_mutex); 5416 rxn.rxn_xname = node->fd_node_name; 5417 mutex_exit(&node->fd_mutex); 5418 } 5419 } 5420 rxn.rxn_port_id = s_id; 5421 5422 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn, 5423 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5424 sizeof (rxn), DDI_DEV_AUTOINCR); 5425 5426 break; 5427 } 5428 5429 case NS_RCS_ID: { 5430 ns_rcos_t rcos; 5431 5432 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5433 sizeof (ns_rcos_t), sizeof (fc_reg_resp_t), sleep, NULL); 5434 if (cmd == NULL) { 5435 return (FC_NOMEM); 5436 } 5437 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5438 pkt = &cmd->cmd_pkt; 5439 5440 if (pd == NULL) { 5441 rcos.rcos_cos = port->fp_cos; 5442 } else { 5443 mutex_enter(&pd->pd_mutex); 5444 rcos.rcos_cos = pd->pd_cos; 5445 mutex_exit(&pd->pd_mutex); 5446 } 5447 rcos.rcos_port_id = s_id; 5448 5449 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos, 5450 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5451 sizeof (rcos), DDI_DEV_AUTOINCR); 5452 5453 break; 5454 } 5455 5456 case NS_RFT_ID: { 5457 ns_rfc_type_t rfc; 5458 5459 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5460 sizeof (ns_rfc_type_t), sizeof (fc_reg_resp_t), sleep, 5461 NULL); 5462 if (cmd == NULL) { 5463 return (FC_NOMEM); 5464 } 5465 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5466 pkt = &cmd->cmd_pkt; 5467 5468 if (pd == NULL) { 5469 mutex_enter(&port->fp_mutex); 5470 bcopy(port->fp_fc4_types, rfc.rfc_types, 5471 sizeof (port->fp_fc4_types)); 5472 mutex_exit(&port->fp_mutex); 5473 } else { 5474 mutex_enter(&pd->pd_mutex); 5475 bcopy(pd->pd_fc4types, rfc.rfc_types, 5476 sizeof (pd->pd_fc4types)); 5477 mutex_exit(&pd->pd_mutex); 5478 } 5479 rfc.rfc_port_id = s_id; 5480 5481 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc, 5482 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5483 sizeof (rfc), DDI_DEV_AUTOINCR); 5484 5485 break; 5486 } 5487 5488 case NS_RSPN_ID: { 5489 uchar_t name_len; 5490 int pl_size; 5491 fc_portid_t spn; 5492 5493 if (pd == NULL) { 5494 mutex_enter(&port->fp_mutex); 5495 name_len = port->fp_sym_port_namelen; 5496 mutex_exit(&port->fp_mutex); 5497 } else { 5498 mutex_enter(&pd->pd_mutex); 5499 name_len = pd->pd_spn_len; 5500 mutex_exit(&pd->pd_mutex); 5501 } 5502 5503 pl_size = sizeof (fc_portid_t) + name_len + 1; 5504 5505 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + pl_size, 5506 sizeof (fc_reg_resp_t), sleep, NULL); 5507 if (cmd == NULL) { 5508 return (FC_NOMEM); 5509 } 5510 5511 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5512 5513 pkt = &cmd->cmd_pkt; 5514 5515 spn = s_id; 5516 5517 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *) 5518 (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn), 5519 DDI_DEV_AUTOINCR); 5520 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5521 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) 5522 + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR); 5523 5524 if (pd == NULL) { 5525 mutex_enter(&port->fp_mutex); 5526 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5527 (uint8_t *)port->fp_sym_port_name, (uint8_t *) 5528 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5529 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5530 mutex_exit(&port->fp_mutex); 5531 } else { 5532 mutex_enter(&pd->pd_mutex); 5533 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5534 (uint8_t *)pd->pd_spn, 5535 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5536 sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR); 5537 mutex_exit(&pd->pd_mutex); 5538 } 5539 break; 5540 } 5541 5542 case NS_RPT_ID: { 5543 ns_rpt_t rpt; 5544 5545 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5546 sizeof (ns_rpt_t), sizeof (fc_reg_resp_t), sleep, NULL); 5547 if (cmd == NULL) { 5548 return (FC_NOMEM); 5549 } 5550 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5551 pkt = &cmd->cmd_pkt; 5552 5553 if (pd == NULL) { 5554 rpt.rpt_type = port->fp_port_type; 5555 } else { 5556 mutex_enter(&pd->pd_mutex); 5557 rpt.rpt_type = pd->pd_porttype; 5558 mutex_exit(&pd->pd_mutex); 5559 } 5560 rpt.rpt_port_id = s_id; 5561 5562 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt, 5563 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5564 sizeof (rpt), DDI_DEV_AUTOINCR); 5565 5566 break; 5567 } 5568 5569 case NS_RIP_NN: { 5570 ns_rip_t rip; 5571 5572 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5573 sizeof (ns_rip_t), sizeof (fc_reg_resp_t), sleep, NULL); 5574 if (cmd == NULL) { 5575 return (FC_NOMEM); 5576 } 5577 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5578 pkt = &cmd->cmd_pkt; 5579 5580 if (pd == NULL) { 5581 rip.rip_node_name = 5582 port->fp_service_params.node_ww_name; 5583 bcopy(port->fp_ip_addr, rip.rip_ip_addr, 5584 sizeof (port->fp_ip_addr)); 5585 } else { 5586 fc_remote_node_t *node; 5587 5588 /* 5589 * The most correct implementation should have the IP 5590 * address in the fc_remote_node_t structure; I believe 5591 * Node WWN and IP address should have one to one 5592 * correlation (but guess what this is changing in 5593 * FC-GS-2 latest draft) 5594 */ 5595 mutex_enter(&pd->pd_mutex); 5596 node = pd->pd_remote_nodep; 5597 bcopy(pd->pd_ip_addr, rip.rip_ip_addr, 5598 sizeof (pd->pd_ip_addr)); 5599 mutex_exit(&pd->pd_mutex); 5600 5601 mutex_enter(&node->fd_mutex); 5602 rip.rip_node_name = node->fd_node_name; 5603 mutex_exit(&node->fd_mutex); 5604 } 5605 5606 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip, 5607 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5608 sizeof (rip), DDI_DEV_AUTOINCR); 5609 5610 break; 5611 } 5612 5613 case NS_RIPA_NN: { 5614 ns_ipa_t ipa; 5615 5616 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5617 sizeof (ns_ipa_t), sizeof (fc_reg_resp_t), sleep, NULL); 5618 if (cmd == NULL) { 5619 return (FC_NOMEM); 5620 } 5621 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5622 pkt = &cmd->cmd_pkt; 5623 5624 if (pd == NULL) { 5625 ipa.ipa_node_name = 5626 port->fp_service_params.node_ww_name; 5627 bcopy(port->fp_ipa, ipa.ipa_value, 5628 sizeof (port->fp_ipa)); 5629 } else { 5630 fc_remote_node_t *node; 5631 5632 mutex_enter(&pd->pd_mutex); 5633 node = pd->pd_remote_nodep; 5634 mutex_exit(&pd->pd_mutex); 5635 5636 mutex_enter(&node->fd_mutex); 5637 ipa.ipa_node_name = node->fd_node_name; 5638 bcopy(node->fd_ipa, ipa.ipa_value, 5639 sizeof (node->fd_ipa)); 5640 mutex_exit(&node->fd_mutex); 5641 } 5642 5643 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa, 5644 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5645 sizeof (ipa), DDI_DEV_AUTOINCR); 5646 5647 break; 5648 } 5649 5650 case NS_RSNN_NN: { 5651 uchar_t name_len; 5652 int pl_size; 5653 la_wwn_t snn; 5654 fc_remote_node_t *node = NULL; 5655 5656 if (pd == NULL) { 5657 mutex_enter(&port->fp_mutex); 5658 name_len = port->fp_sym_node_namelen; 5659 mutex_exit(&port->fp_mutex); 5660 } else { 5661 mutex_enter(&pd->pd_mutex); 5662 node = pd->pd_remote_nodep; 5663 mutex_exit(&pd->pd_mutex); 5664 5665 mutex_enter(&node->fd_mutex); 5666 name_len = node->fd_snn_len; 5667 mutex_exit(&node->fd_mutex); 5668 } 5669 5670 pl_size = sizeof (la_wwn_t) + name_len + 1; 5671 5672 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5673 pl_size, sizeof (fc_reg_resp_t), sleep, NULL); 5674 if (cmd == NULL) { 5675 return (FC_NOMEM); 5676 } 5677 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5678 5679 pkt = &cmd->cmd_pkt; 5680 5681 bcopy(&port->fp_service_params.node_ww_name, 5682 &snn, sizeof (la_wwn_t)); 5683 5684 if (pd == NULL) { 5685 mutex_enter(&port->fp_mutex); 5686 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5687 (uint8_t *)port->fp_sym_node_name, (uint8_t *) 5688 (pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5689 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5690 mutex_exit(&port->fp_mutex); 5691 } else { 5692 ASSERT(node != NULL); 5693 mutex_enter(&node->fd_mutex); 5694 FC_SET_CMD(port, pkt->pkt_cmd_acc, 5695 (uint8_t *)node->fd_snn, 5696 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) + 5697 sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR); 5698 mutex_exit(&node->fd_mutex); 5699 } 5700 5701 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn, 5702 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5703 sizeof (snn), DDI_DEV_AUTOINCR); 5704 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len, 5705 (uint8_t *)(pkt->pkt_cmd 5706 + sizeof (fc_ct_header_t) + sizeof (snn)), 5707 1, DDI_DEV_AUTOINCR); 5708 5709 break; 5710 } 5711 5712 case NS_DA_ID: { 5713 ns_remall_t rall; 5714 char tmp[4] = {0}; 5715 char *ptr; 5716 5717 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 5718 sizeof (ns_remall_t), sizeof (fc_reg_resp_t), sleep, NULL); 5719 5720 if (cmd == NULL) { 5721 return (FC_NOMEM); 5722 } 5723 5724 fp_ct_init(port, cmd, NULL, cmd_code, NULL, 0, 0, job); 5725 pkt = &cmd->cmd_pkt; 5726 5727 ptr = (char *)(&s_id); 5728 tmp[3] = *ptr++; 5729 tmp[2] = *ptr++; 5730 tmp[1] = *ptr++; 5731 tmp[0] = *ptr; 5732 #if defined(_BIT_FIELDS_LTOH) 5733 bcopy((caddr_t)tmp, (caddr_t)(&rall.rem_port_id), 4); 5734 #else 5735 rall.rem_port_id = s_id; 5736 #endif 5737 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall, 5738 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 5739 sizeof (rall), DDI_DEV_AUTOINCR); 5740 5741 break; 5742 } 5743 5744 default: 5745 return (FC_FAILURE); 5746 } 5747 5748 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 5749 5750 if (rval != FC_SUCCESS) { 5751 job->job_result = rval; 5752 fp_iodone(cmd); 5753 } 5754 5755 if (polled) { 5756 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 5757 fp_jobwait(job); 5758 } else { 5759 rval = FC_SUCCESS; 5760 } 5761 5762 return (rval); 5763 } 5764 5765 5766 /* 5767 * Common interrupt handler 5768 */ 5769 static int 5770 fp_common_intr(fc_packet_t *pkt, int iodone) 5771 { 5772 int rval = FC_FAILURE; 5773 fp_cmd_t *cmd; 5774 fc_local_port_t *port; 5775 5776 cmd = pkt->pkt_ulp_private; 5777 port = cmd->cmd_port; 5778 5779 /* 5780 * Fail fast the upper layer requests if 5781 * a state change has occurred amidst. 5782 */ 5783 mutex_enter(&port->fp_mutex); 5784 if (cmd->cmd_ulp_pkt != NULL && port->fp_statec_busy) { 5785 mutex_exit(&port->fp_mutex); 5786 cmd->cmd_ulp_pkt->pkt_state = FC_PKT_PORT_OFFLINE; 5787 cmd->cmd_ulp_pkt->pkt_reason = FC_REASON_OFFLINE; 5788 } else if (!(port->fp_soft_state & 5789 (FP_SOFT_IN_DETACH | FP_DETACH_INPROGRESS))) { 5790 mutex_exit(&port->fp_mutex); 5791 5792 switch (pkt->pkt_state) { 5793 case FC_PKT_LOCAL_BSY: 5794 case FC_PKT_FABRIC_BSY: 5795 case FC_PKT_NPORT_BSY: 5796 case FC_PKT_TIMEOUT: 5797 cmd->cmd_retry_interval = (pkt->pkt_state == 5798 FC_PKT_TIMEOUT) ? 0 : fp_retry_delay; 5799 rval = fp_retry_cmd(pkt); 5800 break; 5801 5802 case FC_PKT_FABRIC_RJT: 5803 case FC_PKT_NPORT_RJT: 5804 case FC_PKT_LOCAL_RJT: 5805 case FC_PKT_LS_RJT: 5806 case FC_PKT_FS_RJT: 5807 case FC_PKT_BA_RJT: 5808 rval = fp_handle_reject(pkt); 5809 break; 5810 5811 default: 5812 if (pkt->pkt_resp_resid) { 5813 cmd->cmd_retry_interval = 0; 5814 rval = fp_retry_cmd(pkt); 5815 } 5816 break; 5817 } 5818 } else { 5819 mutex_exit(&port->fp_mutex); 5820 } 5821 5822 if (rval != FC_SUCCESS && iodone) { 5823 fp_iodone(cmd); 5824 rval = FC_SUCCESS; 5825 } 5826 5827 return (rval); 5828 } 5829 5830 5831 /* 5832 * Some not so long winding theory on point to point topology: 5833 * 5834 * In the ACC payload, if the D_ID is ZERO and the common service 5835 * parameters indicate N_Port, then the topology is POINT TO POINT. 5836 * 5837 * In a point to point topology with an N_Port, during Fabric Login, 5838 * the destination N_Port will check with our WWN and decide if it 5839 * needs to issue PLOGI or not. That means, FLOGI could potentially 5840 * trigger an unsolicited PLOGI from an N_Port. The Unsolicited 5841 * PLOGI creates the device handles. 5842 * 5843 * Assuming that the host port WWN is greater than the other N_Port 5844 * WWN, then we become the master (be aware that this isn't the word 5845 * used in the FC standards) and initiate the PLOGI. 5846 * 5847 */ 5848 static void 5849 fp_flogi_intr(fc_packet_t *pkt) 5850 { 5851 int state; 5852 int f_port; 5853 uint32_t s_id; 5854 uint32_t d_id; 5855 fp_cmd_t *cmd; 5856 fc_local_port_t *port; 5857 la_wwn_t *swwn; 5858 la_wwn_t dwwn; 5859 la_wwn_t nwwn; 5860 fc_remote_port_t *pd; 5861 la_els_logi_t *acc; 5862 com_svc_t csp; 5863 ls_code_t resp; 5864 5865 cmd = pkt->pkt_ulp_private; 5866 port = cmd->cmd_port; 5867 5868 mutex_enter(&port->fp_mutex); 5869 port->fp_out_fpcmds--; 5870 mutex_exit(&port->fp_mutex); 5871 5872 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr; port=%p, pkt=%p, state=%x", 5873 port, pkt, pkt->pkt_state); 5874 5875 if (FP_IS_PKT_ERROR(pkt)) { 5876 (void) fp_common_intr(pkt, 1); 5877 return; 5878 } 5879 5880 /* 5881 * Currently, we don't need to swap bytes here because qlc is faking the 5882 * response for us and so endianness is getting taken care of. But we 5883 * have to fix this and generalize this at some point 5884 */ 5885 acc = (la_els_logi_t *)pkt->pkt_resp; 5886 5887 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 5888 sizeof (resp), DDI_DEV_AUTOINCR); 5889 5890 ASSERT(resp.ls_code == LA_ELS_ACC); 5891 if (resp.ls_code != LA_ELS_ACC) { 5892 (void) fp_common_intr(pkt, 1); 5893 return; 5894 } 5895 5896 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp, 5897 (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR); 5898 5899 f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0; 5900 5901 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 5902 5903 mutex_enter(&port->fp_mutex); 5904 state = FC_PORT_STATE_MASK(port->fp_state); 5905 mutex_exit(&port->fp_mutex); 5906 5907 if (f_port == 0) { 5908 if (state != FC_STATE_LOOP) { 5909 swwn = &port->fp_service_params.nport_ww_name; 5910 5911 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn, 5912 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 5913 DDI_DEV_AUTOINCR); 5914 5915 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 5916 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 5917 DDI_DEV_AUTOINCR); 5918 5919 mutex_enter(&port->fp_mutex); 5920 5921 port->fp_topology = FC_TOP_PT_PT; 5922 port->fp_total_devices = 1; 5923 if (fctl_wwn_cmp(swwn, &dwwn) >= 0) { 5924 port->fp_ptpt_master = 1; 5925 /* 5926 * Let us choose 'X' as S_ID and 'Y' 5927 * as D_ID and that'll work; hopefully 5928 * If not, it will get changed. 5929 */ 5930 s_id = port->fp_instance + FP_DEFAULT_SID; 5931 d_id = port->fp_instance + FP_DEFAULT_DID; 5932 port->fp_port_id.port_id = s_id; 5933 mutex_exit(&port->fp_mutex); 5934 5935 FP_TRACE(FP_NHEAD1(1, 0), "fp_flogi_intr: fp %x" 5936 "pd %x", port->fp_port_id.port_id, d_id); 5937 pd = fctl_create_remote_port(port, 5938 &nwwn, &dwwn, d_id, PD_PLOGI_INITIATOR, 5939 KM_NOSLEEP); 5940 if (pd == NULL) { 5941 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 5942 0, NULL, "couldn't create device" 5943 " d_id=%X", d_id); 5944 fp_iodone(cmd); 5945 return; 5946 } 5947 5948 cmd->cmd_pkt.pkt_tran_flags = 5949 pkt->pkt_tran_flags; 5950 cmd->cmd_pkt.pkt_tran_type = pkt->pkt_tran_type; 5951 cmd->cmd_flags = FP_CMD_PLOGI_RETAIN; 5952 cmd->cmd_retry_count = fp_retry_count; 5953 5954 fp_xlogi_init(port, cmd, s_id, d_id, 5955 fp_plogi_intr, cmd->cmd_job, LA_ELS_PLOGI); 5956 5957 (&cmd->cmd_pkt)->pkt_pd = pd; 5958 5959 /* 5960 * We've just created this fc_remote_port_t, and 5961 * we're about to use it to send a PLOGI, so 5962 * bump the reference count right now. When 5963 * the packet is freed, the reference count will 5964 * be decremented. The ULP may also start using 5965 * it, so mark it as given away as well. 5966 */ 5967 pd->pd_ref_count++; 5968 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 5969 5970 if (fp_sendcmd(port, cmd, 5971 port->fp_fca_handle) == FC_SUCCESS) { 5972 return; 5973 } 5974 } else { 5975 /* 5976 * The device handles will be created when the 5977 * unsolicited PLOGI is completed successfully 5978 */ 5979 port->fp_ptpt_master = 0; 5980 mutex_exit(&port->fp_mutex); 5981 } 5982 } 5983 pkt->pkt_state = FC_PKT_FAILURE; 5984 } else { 5985 if (f_port) { 5986 mutex_enter(&port->fp_mutex); 5987 if (state == FC_STATE_LOOP) { 5988 port->fp_topology = FC_TOP_PUBLIC_LOOP; 5989 } else { 5990 port->fp_topology = FC_TOP_FABRIC; 5991 5992 FC_GET_RSP(port, pkt->pkt_resp_acc, 5993 (uint8_t *)&port->fp_fabric_name, 5994 (uint8_t *)&acc->node_ww_name, 5995 sizeof (la_wwn_t), 5996 DDI_DEV_AUTOINCR); 5997 } 5998 port->fp_port_id.port_id = pkt->pkt_resp_fhdr.d_id; 5999 mutex_exit(&port->fp_mutex); 6000 } else { 6001 pkt->pkt_state = FC_PKT_FAILURE; 6002 } 6003 } 6004 fp_iodone(cmd); 6005 } 6006 6007 6008 /* 6009 * Handle solicited PLOGI response 6010 */ 6011 static void 6012 fp_plogi_intr(fc_packet_t *pkt) 6013 { 6014 int nl_port; 6015 int bailout; 6016 uint32_t d_id; 6017 fp_cmd_t *cmd; 6018 la_els_logi_t *acc; 6019 fc_local_port_t *port; 6020 fc_remote_port_t *pd; 6021 la_wwn_t nwwn; 6022 la_wwn_t pwwn; 6023 ls_code_t resp; 6024 6025 nl_port = 0; 6026 cmd = pkt->pkt_ulp_private; 6027 port = cmd->cmd_port; 6028 d_id = pkt->pkt_cmd_fhdr.d_id; 6029 6030 #ifndef __lock_lint 6031 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6032 #endif 6033 6034 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: port=%p, job=%p, d_id=%x," 6035 " jcount=%d pkt=%p, state=%x", port, cmd->cmd_job, d_id, 6036 cmd->cmd_job->job_counter, pkt, pkt->pkt_state); 6037 6038 /* 6039 * Bail out early on ULP initiated requests if the 6040 * state change has occurred 6041 */ 6042 mutex_enter(&port->fp_mutex); 6043 port->fp_out_fpcmds--; 6044 bailout = ((port->fp_statec_busy || 6045 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6046 cmd->cmd_ulp_pkt) ? 1 : 0; 6047 mutex_exit(&port->fp_mutex); 6048 6049 if (FP_IS_PKT_ERROR(pkt) || bailout) { 6050 int skip_msg = 0; 6051 int giveup = 0; 6052 6053 if (cmd->cmd_ulp_pkt) { 6054 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6055 cmd->cmd_ulp_pkt->pkt_reason = pkt->pkt_reason; 6056 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6057 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6058 } 6059 6060 /* 6061 * If an unsolicited cross login already created 6062 * a device speed up the discovery by not retrying 6063 * the command mindlessly. 6064 */ 6065 if (pkt->pkt_pd == NULL && 6066 fctl_get_remote_port_by_did(port, d_id) != NULL) { 6067 fp_iodone(cmd); 6068 return; 6069 } 6070 6071 if (pkt->pkt_pd != NULL) { 6072 giveup = (pkt->pkt_pd->pd_recepient == 6073 PD_PLOGI_RECEPIENT) ? 1 : 0; 6074 if (giveup) { 6075 /* 6076 * This pd is marked as plogi 6077 * recipient, stop retrying 6078 */ 6079 FP_TRACE(FP_NHEAD1(3, 0), 6080 "fp_plogi_intr: stop retry as" 6081 " a cross login was accepted" 6082 " from d_id=%x, port=%p.", 6083 d_id, port); 6084 fp_iodone(cmd); 6085 return; 6086 } 6087 } 6088 6089 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6090 return; 6091 } 6092 6093 if ((pd = fctl_get_remote_port_by_did(port, d_id)) != NULL) { 6094 mutex_enter(&pd->pd_mutex); 6095 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 6096 skip_msg++; 6097 } 6098 mutex_exit(&pd->pd_mutex); 6099 } 6100 6101 mutex_enter(&port->fp_mutex); 6102 if (!bailout && !(skip_msg && port->fp_statec_busy) && 6103 port->fp_statec_busy <= 1 && 6104 pkt->pkt_reason != FC_REASON_FCAL_OPN_FAIL) { 6105 mutex_exit(&port->fp_mutex); 6106 /* 6107 * In case of Login Collisions, JNI HBAs returns the 6108 * FC pkt back to the Initiator with the state set to 6109 * FC_PKT_LS_RJT and reason to FC_REASON_LOGICAL_ERROR. 6110 * QLC HBAs handles such cases in the FW and doesnot 6111 * return the LS_RJT with Logical error when 6112 * login collision happens. 6113 */ 6114 if ((pkt->pkt_state != FC_PKT_LS_RJT) || 6115 (pkt->pkt_reason != FC_REASON_LOGICAL_ERROR)) { 6116 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6117 "PLOGI to %x failed", d_id); 6118 } 6119 FP_TRACE(FP_NHEAD2(9, 0), 6120 "PLOGI to %x failed. state=%x reason=%x.", 6121 d_id, pkt->pkt_state, pkt->pkt_reason); 6122 } else { 6123 mutex_exit(&port->fp_mutex); 6124 } 6125 6126 fp_iodone(cmd); 6127 return; 6128 } 6129 6130 acc = (la_els_logi_t *)pkt->pkt_resp; 6131 6132 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc, 6133 sizeof (resp), DDI_DEV_AUTOINCR); 6134 6135 ASSERT(resp.ls_code == LA_ELS_ACC); 6136 if (resp.ls_code != LA_ELS_ACC) { 6137 (void) fp_common_intr(pkt, 1); 6138 return; 6139 } 6140 6141 if (d_id == FS_NAME_SERVER || d_id == FS_FABRIC_CONTROLLER) { 6142 mutex_enter(&port->fp_mutex); 6143 port->fp_ns_login_class = FC_TRAN_CLASS(pkt->pkt_tran_flags); 6144 mutex_exit(&port->fp_mutex); 6145 fp_iodone(cmd); 6146 return; 6147 } 6148 6149 ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp); 6150 6151 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 6152 (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t), 6153 DDI_DEV_AUTOINCR); 6154 6155 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 6156 (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t), 6157 DDI_DEV_AUTOINCR); 6158 6159 ASSERT(fctl_is_wwn_zero(&pwwn) == FC_FAILURE); 6160 ASSERT(fctl_is_wwn_zero(&nwwn) == FC_FAILURE); 6161 6162 if ((pd = pkt->pkt_pd) == NULL) { 6163 pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6164 if (pd == NULL) { 6165 FP_TRACE(FP_NHEAD2(9, 0), "fp_plogi_intr: fp %x pd %x", 6166 port->fp_port_id.port_id, d_id); 6167 pd = fctl_create_remote_port(port, &nwwn, &pwwn, d_id, 6168 PD_PLOGI_INITIATOR, KM_NOSLEEP); 6169 if (pd == NULL) { 6170 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6171 "couldn't create port device handles" 6172 " d_id=%x", d_id); 6173 fp_iodone(cmd); 6174 return; 6175 } 6176 } else { 6177 fc_remote_port_t *tmp_pd; 6178 6179 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6180 if (tmp_pd != NULL) { 6181 fp_iodone(cmd); 6182 return; 6183 } 6184 6185 mutex_enter(&port->fp_mutex); 6186 mutex_enter(&pd->pd_mutex); 6187 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN) || 6188 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6189 cmd->cmd_flags |= FP_CMD_PLOGI_RETAIN; 6190 } 6191 6192 if (pd->pd_type == PORT_DEVICE_OLD) { 6193 if (pd->pd_port_id.port_id != d_id) { 6194 fctl_delist_did_table(port, pd); 6195 pd->pd_type = PORT_DEVICE_CHANGED; 6196 pd->pd_port_id.port_id = d_id; 6197 } else { 6198 pd->pd_type = PORT_DEVICE_NOCHANGE; 6199 } 6200 } 6201 6202 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6203 char ww_name[17]; 6204 6205 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6206 6207 mutex_exit(&pd->pd_mutex); 6208 mutex_exit(&port->fp_mutex); 6209 FP_TRACE(FP_NHEAD2(9, 0), 6210 "Possible Duplicate name or address" 6211 " identifiers in the PLOGI response" 6212 " D_ID=%x, PWWN=%s: Please check the" 6213 " configuration", d_id, ww_name); 6214 fp_iodone(cmd); 6215 return; 6216 } 6217 fctl_enlist_did_table(port, pd); 6218 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6219 mutex_exit(&pd->pd_mutex); 6220 mutex_exit(&port->fp_mutex); 6221 } 6222 } else { 6223 fc_remote_port_t *tmp_pd, *new_wwn_pd; 6224 6225 tmp_pd = fctl_get_remote_port_by_did(port, d_id); 6226 new_wwn_pd = fctl_get_remote_port_by_pwwn(port, &pwwn); 6227 6228 mutex_enter(&port->fp_mutex); 6229 mutex_enter(&pd->pd_mutex); 6230 if (fctl_wwn_cmp(&pd->pd_port_name, &pwwn) == 0) { 6231 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_intr: d_id=%x," 6232 " pd_state=%x pd_type=%x", d_id, pd->pd_state, 6233 pd->pd_type); 6234 if ((pd->pd_state == PORT_DEVICE_LOGGED_IN && 6235 pd->pd_type == PORT_DEVICE_OLD) || 6236 (pd->pd_aux_flags & PD_LOGGED_OUT)) { 6237 pd->pd_type = PORT_DEVICE_NOCHANGE; 6238 } else if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 6239 pd->pd_type = PORT_DEVICE_NEW; 6240 } 6241 } else { 6242 char old_name[17]; 6243 char new_name[17]; 6244 6245 fc_wwn_to_str(&pd->pd_port_name, old_name); 6246 fc_wwn_to_str(&pwwn, new_name); 6247 6248 FP_TRACE(FP_NHEAD1(9, 0), 6249 "fp_plogi_intr: PWWN of a device with D_ID=%x " 6250 "changed. New PWWN = %s, OLD PWWN = %s ; tmp_pd:%p " 6251 "pd:%p new_wwn_pd:%p, cmd_ulp_pkt:%p, bailout:0x%x", 6252 d_id, new_name, old_name, tmp_pd, pd, new_wwn_pd, 6253 cmd->cmd_ulp_pkt, bailout); 6254 6255 FP_TRACE(FP_NHEAD2(9, 0), 6256 "PWWN of a device with D_ID=%x changed." 6257 " New PWWN = %s, OLD PWWN = %s", d_id, 6258 new_name, old_name); 6259 6260 if (cmd->cmd_ulp_pkt && !bailout) { 6261 fc_remote_node_t *rnodep; 6262 fc_portmap_t *changelist; 6263 fc_portmap_t *listptr; 6264 int len = 1; 6265 /* # entries in changelist */ 6266 6267 fctl_delist_pwwn_table(port, pd); 6268 6269 /* 6270 * Lets now check if there already is a pd with 6271 * this new WWN in the table. If so, we'll mark 6272 * it as invalid 6273 */ 6274 6275 if (new_wwn_pd) { 6276 /* 6277 * There is another pd with in the pwwn 6278 * table with the same WWN that we got 6279 * in the PLOGI payload. We have to get 6280 * it out of the pwwn table, update the 6281 * pd's state (fp_fillout_old_map does 6282 * this for us) and add it to the 6283 * changelist that goes up to ULPs. 6284 * 6285 * len is length of changelist and so 6286 * increment it. 6287 */ 6288 len++; 6289 6290 if (tmp_pd != pd) { 6291 /* 6292 * Odd case where pwwn and did 6293 * tables are out of sync but 6294 * we will handle that too. See 6295 * more comments below. 6296 * 6297 * One more device that ULPs 6298 * should know about and so len 6299 * gets incremented again. 6300 */ 6301 len++; 6302 } 6303 6304 listptr = changelist = kmem_zalloc(len * 6305 sizeof (*changelist), KM_SLEEP); 6306 6307 mutex_enter(&new_wwn_pd->pd_mutex); 6308 rnodep = new_wwn_pd->pd_remote_nodep; 6309 mutex_exit(&new_wwn_pd->pd_mutex); 6310 6311 /* 6312 * Hold the fd_mutex since 6313 * fctl_copy_portmap_held expects it. 6314 * Preserve lock hierarchy by grabbing 6315 * fd_mutex before pd_mutex 6316 */ 6317 if (rnodep) { 6318 mutex_enter(&rnodep->fd_mutex); 6319 } 6320 mutex_enter(&new_wwn_pd->pd_mutex); 6321 fp_fillout_old_map_held(listptr++, 6322 new_wwn_pd, 0); 6323 mutex_exit(&new_wwn_pd->pd_mutex); 6324 if (rnodep) { 6325 mutex_exit(&rnodep->fd_mutex); 6326 } 6327 6328 /* 6329 * Safety check : 6330 * Lets ensure that the pwwn and did 6331 * tables are in sync. Ideally, we 6332 * should not find that these two pd's 6333 * are different. 6334 */ 6335 if (tmp_pd != pd) { 6336 mutex_enter(&tmp_pd->pd_mutex); 6337 rnodep = 6338 tmp_pd->pd_remote_nodep; 6339 mutex_exit(&tmp_pd->pd_mutex); 6340 6341 /* As above grab fd_mutex */ 6342 if (rnodep) { 6343 mutex_enter(&rnodep-> 6344 fd_mutex); 6345 } 6346 mutex_enter(&tmp_pd->pd_mutex); 6347 6348 fp_fillout_old_map_held( 6349 listptr++, tmp_pd, 0); 6350 6351 mutex_exit(&tmp_pd->pd_mutex); 6352 if (rnodep) { 6353 mutex_exit(&rnodep-> 6354 fd_mutex); 6355 } 6356 6357 /* 6358 * Now add "pd" (not tmp_pd) 6359 * to fp_did_table to sync it up 6360 * with fp_pwwn_table 6361 * 6362 * pd->pd_mutex is already held 6363 * at this point 6364 */ 6365 fctl_enlist_did_table(port, pd); 6366 } 6367 } else { 6368 listptr = changelist = kmem_zalloc( 6369 sizeof (*changelist), KM_SLEEP); 6370 } 6371 6372 ASSERT(changelist != NULL); 6373 6374 fp_fillout_changed_map(listptr, pd, &d_id, 6375 &pwwn); 6376 fctl_enlist_pwwn_table(port, pd); 6377 6378 mutex_exit(&pd->pd_mutex); 6379 mutex_exit(&port->fp_mutex); 6380 6381 fp_iodone(cmd); 6382 6383 (void) fp_ulp_devc_cb(port, changelist, len, 6384 len, KM_NOSLEEP, 0); 6385 6386 return; 6387 } 6388 } 6389 6390 if (pd->pd_porttype.port_type == FC_NS_PORT_NL) { 6391 nl_port = 1; 6392 } 6393 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6394 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6395 } 6396 6397 mutex_exit(&pd->pd_mutex); 6398 mutex_exit(&port->fp_mutex); 6399 6400 if (tmp_pd == NULL) { 6401 mutex_enter(&port->fp_mutex); 6402 mutex_enter(&pd->pd_mutex); 6403 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 6404 char ww_name[17]; 6405 6406 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6407 mutex_exit(&pd->pd_mutex); 6408 mutex_exit(&port->fp_mutex); 6409 FP_TRACE(FP_NHEAD2(9, 0), 6410 "Possible Duplicate name or address" 6411 " identifiers in the PLOGI response" 6412 " D_ID=%x, PWWN=%s: Please check the" 6413 " configuration", d_id, ww_name); 6414 fp_iodone(cmd); 6415 return; 6416 } 6417 fctl_enlist_did_table(port, pd); 6418 pd->pd_aux_flags &= ~PD_LOGGED_OUT; 6419 mutex_exit(&pd->pd_mutex); 6420 mutex_exit(&port->fp_mutex); 6421 } 6422 } 6423 fp_register_login(&pkt->pkt_resp_acc, pd, acc, 6424 FC_TRAN_CLASS(pkt->pkt_tran_flags)); 6425 6426 if (cmd->cmd_ulp_pkt) { 6427 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6428 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6429 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6430 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6431 if (pd != NULL) { 6432 FP_TRACE(FP_NHEAD1(9, 0), 6433 "fp_plogi_intr;" 6434 "ulp_pkt's pd is NULL, get a pd %p", 6435 pd); 6436 mutex_enter(&pd->pd_mutex); 6437 pd->pd_ref_count++; 6438 mutex_exit(&pd->pd_mutex); 6439 } 6440 cmd->cmd_ulp_pkt->pkt_pd = pd; 6441 } 6442 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6443 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6444 sizeof (fc_frame_hdr_t)); 6445 bcopy((caddr_t)pkt->pkt_resp, 6446 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6447 sizeof (la_els_logi_t)); 6448 } 6449 6450 mutex_enter(&port->fp_mutex); 6451 if (port->fp_topology == FC_TOP_PRIVATE_LOOP || nl_port) { 6452 mutex_enter(&pd->pd_mutex); 6453 6454 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6455 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6456 cmd->cmd_retry_count = fp_retry_count; 6457 6458 /* 6459 * If the fc_remote_port_t pointer is not set in the given 6460 * fc_packet_t, then this fc_remote_port_t must have just 6461 * been created. Save the pointer and also increment the 6462 * fc_remote_port_t reference count. 6463 */ 6464 if (pkt->pkt_pd == NULL) { 6465 pkt->pkt_pd = pd; 6466 pd->pd_ref_count++; /* It's in use! */ 6467 } 6468 6469 fp_adisc_init(cmd, cmd->cmd_job); 6470 6471 pkt->pkt_cmdlen = sizeof (la_els_adisc_t); 6472 pkt->pkt_rsplen = sizeof (la_els_adisc_t); 6473 6474 mutex_exit(&pd->pd_mutex); 6475 mutex_exit(&port->fp_mutex); 6476 6477 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6478 return; 6479 } 6480 } else { 6481 mutex_exit(&port->fp_mutex); 6482 } 6483 6484 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6485 mutex_enter(&port->fp_mutex); 6486 mutex_enter(&pd->pd_mutex); 6487 6488 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6489 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6490 cmd->cmd_retry_count = fp_retry_count; 6491 6492 fp_logo_init(pd, cmd, cmd->cmd_job); 6493 6494 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6495 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6496 6497 mutex_exit(&pd->pd_mutex); 6498 mutex_exit(&port->fp_mutex); 6499 6500 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 6501 return; 6502 } 6503 6504 } 6505 fp_iodone(cmd); 6506 } 6507 6508 6509 /* 6510 * Handle solicited ADISC response 6511 */ 6512 static void 6513 fp_adisc_intr(fc_packet_t *pkt) 6514 { 6515 int rval; 6516 int bailout; 6517 fp_cmd_t *cmd; 6518 fc_local_port_t *port; 6519 fc_remote_port_t *pd; 6520 la_els_adisc_t *acc; 6521 ls_code_t resp; 6522 fc_hardaddr_t ha; 6523 fc_portmap_t *changelist; 6524 int initiator, adiscfail = 0; 6525 6526 pd = pkt->pkt_pd; 6527 cmd = pkt->pkt_ulp_private; 6528 port = cmd->cmd_port; 6529 6530 #ifndef __lock_lint 6531 ASSERT(cmd->cmd_job && cmd->cmd_job->job_counter); 6532 #endif 6533 6534 ASSERT(pd != NULL && port != NULL && cmd != NULL); 6535 6536 mutex_enter(&port->fp_mutex); 6537 port->fp_out_fpcmds--; 6538 bailout = ((port->fp_statec_busy || 6539 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) && 6540 cmd->cmd_ulp_pkt) ? 1 : 0; 6541 mutex_exit(&port->fp_mutex); 6542 6543 if (bailout) { 6544 fp_iodone(cmd); 6545 return; 6546 } 6547 6548 if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) { 6549 acc = (la_els_adisc_t *)pkt->pkt_resp; 6550 6551 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6552 (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR); 6553 6554 if (resp.ls_code == LA_ELS_ACC) { 6555 int is_private; 6556 6557 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha, 6558 (uint8_t *)&acc->hard_addr, sizeof (ha), 6559 DDI_DEV_AUTOINCR); 6560 6561 mutex_enter(&port->fp_mutex); 6562 6563 is_private = 6564 (port->fp_topology == FC_TOP_PRIVATE_LOOP) ? 1 : 0; 6565 6566 mutex_enter(&pd->pd_mutex); 6567 if ((pd->pd_aux_flags & PD_IN_DID_QUEUE) == 0) { 6568 fctl_enlist_did_table(port, pd); 6569 } 6570 mutex_exit(&pd->pd_mutex); 6571 6572 mutex_exit(&port->fp_mutex); 6573 6574 mutex_enter(&pd->pd_mutex); 6575 if (pd->pd_type != PORT_DEVICE_NEW) { 6576 if (is_private && (pd->pd_hard_addr.hard_addr != 6577 ha.hard_addr)) { 6578 pd->pd_type = PORT_DEVICE_CHANGED; 6579 } else { 6580 pd->pd_type = PORT_DEVICE_NOCHANGE; 6581 } 6582 } 6583 6584 if (is_private && (ha.hard_addr && 6585 pd->pd_port_id.port_id != ha.hard_addr)) { 6586 char ww_name[17]; 6587 6588 fc_wwn_to_str(&pd->pd_port_name, ww_name); 6589 6590 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6591 "NL_Port Identifier %x doesn't match" 6592 " with Hard Address %x, Will use Port" 6593 " WWN %s", pd->pd_port_id.port_id, 6594 ha.hard_addr, ww_name); 6595 6596 pd->pd_hard_addr.hard_addr = 0; 6597 } else { 6598 pd->pd_hard_addr.hard_addr = ha.hard_addr; 6599 } 6600 mutex_exit(&pd->pd_mutex); 6601 } else { 6602 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6603 return; 6604 } 6605 } 6606 } else { 6607 if (fp_common_intr(pkt, 0) == FC_SUCCESS) { 6608 return; 6609 } 6610 6611 mutex_enter(&port->fp_mutex); 6612 if (port->fp_statec_busy <= 1) { 6613 mutex_exit(&port->fp_mutex); 6614 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, pkt, 6615 "ADISC to %x failed, cmd_flags=%x", 6616 pkt->pkt_cmd_fhdr.d_id, cmd->cmd_flags); 6617 cmd->cmd_flags &= ~FP_CMD_PLOGI_RETAIN; 6618 adiscfail = 1; 6619 } else { 6620 mutex_exit(&port->fp_mutex); 6621 } 6622 } 6623 6624 if (cmd->cmd_ulp_pkt) { 6625 cmd->cmd_ulp_pkt->pkt_state = pkt->pkt_state; 6626 cmd->cmd_ulp_pkt->pkt_action = pkt->pkt_action; 6627 cmd->cmd_ulp_pkt->pkt_expln = pkt->pkt_expln; 6628 if (cmd->cmd_ulp_pkt->pkt_pd == NULL) { 6629 cmd->cmd_ulp_pkt->pkt_pd = pd; 6630 FP_TRACE(FP_NHEAD1(9, 0), 6631 "fp_adisc__intr;" 6632 "ulp_pkt's pd is NULL, get a pd %p", 6633 pd); 6634 6635 } 6636 bcopy((caddr_t)&pkt->pkt_resp_fhdr, 6637 (caddr_t)&cmd->cmd_ulp_pkt->pkt_resp_fhdr, 6638 sizeof (fc_frame_hdr_t)); 6639 bcopy((caddr_t)pkt->pkt_resp, 6640 (caddr_t)cmd->cmd_ulp_pkt->pkt_resp, 6641 sizeof (la_els_adisc_t)); 6642 } 6643 6644 if ((cmd->cmd_flags & FP_CMD_PLOGI_RETAIN) == 0) { 6645 FP_TRACE(FP_NHEAD1(9, 0), 6646 "fp_adisc_intr: Perform LOGO.cmd_flags=%x, " 6647 "fp_retry_count=%x, ulp_pkt=%p", 6648 cmd->cmd_flags, fp_retry_count, cmd->cmd_ulp_pkt); 6649 6650 mutex_enter(&port->fp_mutex); 6651 mutex_enter(&pd->pd_mutex); 6652 6653 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 6654 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 6655 cmd->cmd_retry_count = fp_retry_count; 6656 6657 fp_logo_init(pd, cmd, cmd->cmd_job); 6658 6659 pkt->pkt_cmdlen = sizeof (la_els_logo_t); 6660 pkt->pkt_rsplen = FP_PORT_IDENTIFIER_LEN; 6661 6662 mutex_exit(&pd->pd_mutex); 6663 mutex_exit(&port->fp_mutex); 6664 6665 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 6666 if (adiscfail) { 6667 mutex_enter(&pd->pd_mutex); 6668 initiator = 6669 ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0); 6670 pd->pd_state = PORT_DEVICE_VALID; 6671 pd->pd_aux_flags |= PD_LOGGED_OUT; 6672 if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) { 6673 pd->pd_type = PORT_DEVICE_NEW; 6674 } else { 6675 pd->pd_type = PORT_DEVICE_NOCHANGE; 6676 } 6677 mutex_exit(&pd->pd_mutex); 6678 6679 changelist = 6680 kmem_zalloc(sizeof (*changelist), KM_SLEEP); 6681 6682 if (initiator) { 6683 fp_unregister_login(pd); 6684 fctl_copy_portmap(changelist, pd); 6685 } else { 6686 fp_fillout_old_map(changelist, pd, 0); 6687 } 6688 6689 FP_TRACE(FP_NHEAD1(9, 0), 6690 "fp_adisc_intr: Dev change notification " 6691 "to ULP port=%p, pd=%p, map_type=%x map_state=%x " 6692 "map_flags=%x initiator=%d", port, pd, 6693 changelist->map_type, changelist->map_state, 6694 changelist->map_flags, initiator); 6695 6696 (void) fp_ulp_devc_cb(port, changelist, 6697 1, 1, KM_SLEEP, 0); 6698 } 6699 if (rval == FC_SUCCESS) { 6700 return; 6701 } 6702 } 6703 fp_iodone(cmd); 6704 } 6705 6706 6707 /* 6708 * Handle solicited LOGO response 6709 */ 6710 static void 6711 fp_logo_intr(fc_packet_t *pkt) 6712 { 6713 ls_code_t resp; 6714 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6715 6716 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6717 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6718 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6719 6720 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6721 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6722 6723 if (FP_IS_PKT_ERROR(pkt)) { 6724 (void) fp_common_intr(pkt, 1); 6725 return; 6726 } 6727 6728 ASSERT(resp.ls_code == LA_ELS_ACC); 6729 if (resp.ls_code != LA_ELS_ACC) { 6730 (void) fp_common_intr(pkt, 1); 6731 return; 6732 } 6733 6734 if (pkt->pkt_pd != NULL) { 6735 fp_unregister_login(pkt->pkt_pd); 6736 } 6737 6738 fp_iodone(pkt->pkt_ulp_private); 6739 } 6740 6741 6742 /* 6743 * Handle solicited RNID response 6744 */ 6745 static void 6746 fp_rnid_intr(fc_packet_t *pkt) 6747 { 6748 ls_code_t resp; 6749 job_request_t *job; 6750 fp_cmd_t *cmd; 6751 la_els_rnid_acc_t *acc; 6752 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6753 6754 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6755 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6756 cmd = pkt->pkt_ulp_private; 6757 6758 mutex_enter(&cmd->cmd_port->fp_mutex); 6759 cmd->cmd_port->fp_out_fpcmds--; 6760 mutex_exit(&cmd->cmd_port->fp_mutex); 6761 6762 job = cmd->cmd_job; 6763 ASSERT(job->job_private != NULL); 6764 6765 /* If failure or LS_RJT then retry the packet, if needed */ 6766 if (pkt->pkt_state != FC_PKT_SUCCESS || resp.ls_code != LA_ELS_ACC) { 6767 (void) fp_common_intr(pkt, 1); 6768 return; 6769 } 6770 6771 /* Save node_id memory allocated in ioctl code */ 6772 acc = (la_els_rnid_acc_t *)pkt->pkt_resp; 6773 6774 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6775 (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR); 6776 6777 /* wakeup the ioctl thread and free the pkt */ 6778 fp_iodone(cmd); 6779 } 6780 6781 6782 /* 6783 * Handle solicited RLS response 6784 */ 6785 static void 6786 fp_rls_intr(fc_packet_t *pkt) 6787 { 6788 ls_code_t resp; 6789 job_request_t *job; 6790 fp_cmd_t *cmd; 6791 la_els_rls_acc_t *acc; 6792 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 6793 6794 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, 6795 (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR); 6796 cmd = pkt->pkt_ulp_private; 6797 6798 mutex_enter(&cmd->cmd_port->fp_mutex); 6799 cmd->cmd_port->fp_out_fpcmds--; 6800 mutex_exit(&cmd->cmd_port->fp_mutex); 6801 6802 job = cmd->cmd_job; 6803 ASSERT(job->job_private != NULL); 6804 6805 /* If failure or LS_RJT then retry the packet, if needed */ 6806 if (FP_IS_PKT_ERROR(pkt) || resp.ls_code != LA_ELS_ACC) { 6807 (void) fp_common_intr(pkt, 1); 6808 return; 6809 } 6810 6811 /* Save link error status block in memory allocated in ioctl code */ 6812 acc = (la_els_rls_acc_t *)pkt->pkt_resp; 6813 6814 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private, 6815 (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t), 6816 DDI_DEV_AUTOINCR); 6817 6818 /* wakeup the ioctl thread and free the pkt */ 6819 fp_iodone(cmd); 6820 } 6821 6822 6823 /* 6824 * A solicited command completion interrupt (mostly for commands 6825 * that require almost no post processing such as SCR ELS) 6826 */ 6827 static void 6828 fp_intr(fc_packet_t *pkt) 6829 { 6830 mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6831 ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--; 6832 mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex); 6833 6834 if (FP_IS_PKT_ERROR(pkt)) { 6835 (void) fp_common_intr(pkt, 1); 6836 return; 6837 } 6838 fp_iodone(pkt->pkt_ulp_private); 6839 } 6840 6841 6842 /* 6843 * Handle the underlying port's state change 6844 */ 6845 static void 6846 fp_statec_cb(opaque_t port_handle, uint32_t state) 6847 { 6848 fc_local_port_t *port = port_handle; 6849 job_request_t *job; 6850 6851 /* 6852 * If it is not possible to process the callbacks 6853 * just drop the callback on the floor; Don't bother 6854 * to do something that isn't safe at this time 6855 */ 6856 mutex_enter(&port->fp_mutex); 6857 if ((port->fp_soft_state & 6858 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 6859 (FC_PORT_STATE_MASK(port->fp_state) == FC_PORT_STATE_MASK(state))) { 6860 mutex_exit(&port->fp_mutex); 6861 return; 6862 } 6863 6864 if (port->fp_statec_busy == 0) { 6865 port->fp_soft_state |= FP_SOFT_IN_STATEC_CB; 6866 #ifdef DEBUG 6867 } else { 6868 ASSERT(port->fp_soft_state & FP_SOFT_IN_STATEC_CB); 6869 #endif 6870 } 6871 6872 port->fp_statec_busy++; 6873 6874 /* 6875 * For now, force the trusted method of device authentication (by 6876 * PLOGI) when LIPs do not involve OFFLINE to ONLINE transition. 6877 */ 6878 if (FC_PORT_STATE_MASK(state) == FC_STATE_LIP || 6879 FC_PORT_STATE_MASK(state) == FC_STATE_LIP_LBIT_SET) { 6880 state = FC_PORT_SPEED_MASK(port->fp_state) | FC_STATE_LOOP; 6881 fp_port_offline(port, 0); 6882 } 6883 mutex_exit(&port->fp_mutex); 6884 6885 switch (FC_PORT_STATE_MASK(state)) { 6886 case FC_STATE_OFFLINE: 6887 job = fctl_alloc_job(JOB_PORT_OFFLINE, 6888 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6889 if (job == NULL) { 6890 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6891 " fp_statec_cb() couldn't submit a job " 6892 " to the thread: failing.."); 6893 mutex_enter(&port->fp_mutex); 6894 if (--port->fp_statec_busy == 0) { 6895 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6896 } 6897 mutex_exit(&port->fp_mutex); 6898 return; 6899 } 6900 mutex_enter(&port->fp_mutex); 6901 /* 6902 * Zero out this field so that we do not retain 6903 * the fabric name as its no longer valid 6904 */ 6905 bzero(&port->fp_fabric_name, sizeof (la_wwn_t)); 6906 port->fp_state = state; 6907 mutex_exit(&port->fp_mutex); 6908 6909 fctl_enque_job(port, job); 6910 break; 6911 6912 case FC_STATE_ONLINE: 6913 case FC_STATE_LOOP: 6914 mutex_enter(&port->fp_mutex); 6915 port->fp_state = state; 6916 6917 if (port->fp_offline_tid) { 6918 timeout_id_t tid; 6919 6920 tid = port->fp_offline_tid; 6921 port->fp_offline_tid = NULL; 6922 mutex_exit(&port->fp_mutex); 6923 (void) untimeout(tid); 6924 } else { 6925 mutex_exit(&port->fp_mutex); 6926 } 6927 6928 job = fctl_alloc_job(JOB_PORT_ONLINE, 6929 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6930 if (job == NULL) { 6931 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6932 "fp_statec_cb() couldn't submit a job " 6933 "to the thread: failing.."); 6934 6935 mutex_enter(&port->fp_mutex); 6936 if (--port->fp_statec_busy == 0) { 6937 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6938 } 6939 mutex_exit(&port->fp_mutex); 6940 return; 6941 } 6942 fctl_enque_job(port, job); 6943 break; 6944 6945 case FC_STATE_RESET_REQUESTED: 6946 mutex_enter(&port->fp_mutex); 6947 port->fp_state = FC_STATE_OFFLINE; 6948 port->fp_soft_state |= FP_SOFT_IN_FCA_RESET; 6949 mutex_exit(&port->fp_mutex); 6950 /* FALLTHROUGH */ 6951 6952 case FC_STATE_RESET: 6953 job = fctl_alloc_job(JOB_ULP_NOTIFY, 6954 JOB_TYPE_FCTL_ASYNC, NULL, NULL, KM_NOSLEEP); 6955 if (job == NULL) { 6956 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 6957 "fp_statec_cb() couldn't submit a job" 6958 " to the thread: failing.."); 6959 6960 mutex_enter(&port->fp_mutex); 6961 if (--port->fp_statec_busy == 0) { 6962 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6963 } 6964 mutex_exit(&port->fp_mutex); 6965 return; 6966 } 6967 6968 /* squeeze into some field in the job structure */ 6969 job->job_ulp_listlen = FC_PORT_STATE_MASK(state); 6970 fctl_enque_job(port, job); 6971 break; 6972 6973 case FC_STATE_TARGET_PORT_RESET: 6974 (void) fp_ulp_notify(port, state, KM_NOSLEEP); 6975 /* FALLTHROUGH */ 6976 6977 case FC_STATE_NAMESERVICE: 6978 /* FALLTHROUGH */ 6979 6980 default: 6981 mutex_enter(&port->fp_mutex); 6982 if (--port->fp_statec_busy == 0) { 6983 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 6984 } 6985 mutex_exit(&port->fp_mutex); 6986 break; 6987 } 6988 } 6989 6990 6991 /* 6992 * Register with the Name Server for RSCNs 6993 */ 6994 static int 6995 fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func, 6996 int sleep) 6997 { 6998 uint32_t s_id; 6999 uchar_t class; 7000 fc_scr_req_t payload; 7001 fp_cmd_t *cmd; 7002 fc_packet_t *pkt; 7003 7004 mutex_enter(&port->fp_mutex); 7005 s_id = port->fp_port_id.port_id; 7006 class = port->fp_ns_login_class; 7007 mutex_exit(&port->fp_mutex); 7008 7009 cmd = fp_alloc_pkt(port, sizeof (fc_scr_req_t), 7010 sizeof (fc_scr_resp_t), sleep, NULL); 7011 if (cmd == NULL) { 7012 return (FC_NOMEM); 7013 } 7014 7015 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 7016 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 7017 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 7018 cmd->cmd_retry_count = fp_retry_count; 7019 cmd->cmd_ulp_pkt = NULL; 7020 7021 pkt = &cmd->cmd_pkt; 7022 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 7023 7024 fp_els_init(cmd, s_id, 0xFFFFFD, fp_intr, job); 7025 7026 payload.ls_code.ls_code = LA_ELS_SCR; 7027 payload.ls_code.mbz = 0; 7028 payload.scr_rsvd = 0; 7029 payload.scr_func = scr_func; 7030 7031 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 7032 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 7033 7034 job->job_counter = 1; 7035 7036 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 7037 fp_iodone(cmd); 7038 } 7039 7040 return (FC_SUCCESS); 7041 } 7042 7043 7044 /* 7045 * There are basically two methods to determine the total number of 7046 * devices out in the NS database; Reading the details of the two 7047 * methods described below, it shouldn't be hard to identify which 7048 * of the two methods is better. 7049 * 7050 * Method 1. 7051 * Iteratively issue GANs until all ports identifiers are walked 7052 * 7053 * Method 2. 7054 * Issue GID_PT (get port Identifiers) with Maximum residual 7055 * field in the request CT HEADER set to accommodate only the 7056 * CT HEADER in the response frame. And if FC-GS2 has been 7057 * carefully read, the NS here has a chance to FS_ACC the 7058 * request and indicate the residual size in the FS_ACC. 7059 * 7060 * Method 2 is wonderful, although it's not mandatory for the NS 7061 * to update the Maximum/Residual Field as can be seen in 4.3.1.6 7062 * (note with particular care the use of the auxiliary verb 'may') 7063 * 7064 */ 7065 static int 7066 fp_ns_get_devcount(fc_local_port_t *port, job_request_t *job, int create, 7067 int sleep) 7068 { 7069 int flags; 7070 int rval; 7071 uint32_t src_id; 7072 fctl_ns_req_t *ns_cmd; 7073 7074 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 7075 7076 mutex_enter(&port->fp_mutex); 7077 src_id = port->fp_port_id.port_id; 7078 mutex_exit(&port->fp_mutex); 7079 7080 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7081 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pt_t), 7082 sizeof (ns_resp_gid_pt_t), 0, 7083 (FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF), sleep); 7084 7085 if (ns_cmd == NULL) { 7086 return (FC_NOMEM); 7087 } 7088 7089 ns_cmd->ns_cmd_code = NS_GID_PT; 7090 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.port_type 7091 = FC_NS_PORT_NX; /* All port types */ 7092 ((ns_req_gid_pt_t *)(ns_cmd->ns_cmd_buf))->port_type.rsvd = 0; 7093 7094 } else { 7095 uint32_t ns_flags; 7096 7097 ns_flags = FCTL_NS_GET_DEV_COUNT | FCTL_NS_NO_DATA_BUF; 7098 if (create) { 7099 ns_flags |= FCTL_NS_CREATE_DEVICE; 7100 } 7101 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 7102 sizeof (ns_resp_gan_t), sizeof (int), ns_flags, sleep); 7103 7104 if (ns_cmd == NULL) { 7105 return (FC_NOMEM); 7106 } 7107 ns_cmd->ns_gan_index = 0; 7108 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 7109 ns_cmd->ns_cmd_code = NS_GA_NXT; 7110 ns_cmd->ns_gan_max = 0xFFFF; 7111 7112 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = src_id; 7113 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 7114 } 7115 7116 flags = job->job_flags; 7117 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 7118 job->job_counter = 1; 7119 7120 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 7121 job->job_flags = flags; 7122 7123 if (!create && (port->fp_options & FP_NS_SMART_COUNT)) { 7124 uint16_t max_resid; 7125 7126 /* 7127 * Revert to scanning the NS if NS_GID_PT isn't 7128 * helping us figure out total number of devices. 7129 */ 7130 if (job->job_result != FC_SUCCESS || 7131 ns_cmd->ns_resp_hdr.ct_cmdrsp != FS_ACC_IU) { 7132 mutex_enter(&port->fp_mutex); 7133 port->fp_options &= ~FP_NS_SMART_COUNT; 7134 mutex_exit(&port->fp_mutex); 7135 7136 fctl_free_ns_cmd(ns_cmd); 7137 return (fp_ns_get_devcount(port, job, create, sleep)); 7138 } 7139 7140 mutex_enter(&port->fp_mutex); 7141 port->fp_total_devices = 1; 7142 max_resid = ns_cmd->ns_resp_hdr.ct_aiusize; 7143 if (max_resid) { 7144 /* 7145 * Since port identifier is 4 bytes and max_resid 7146 * is also in WORDS, max_resid simply indicates 7147 * the total number of port identifiers not 7148 * transferred 7149 */ 7150 port->fp_total_devices += max_resid; 7151 } 7152 mutex_exit(&port->fp_mutex); 7153 } 7154 mutex_enter(&port->fp_mutex); 7155 port->fp_total_devices = *((int *)ns_cmd->ns_data_buf); 7156 mutex_exit(&port->fp_mutex); 7157 fctl_free_ns_cmd(ns_cmd); 7158 7159 return (rval); 7160 } 7161 7162 /* 7163 * One heck of a function to serve userland. 7164 */ 7165 static int 7166 fp_fciocmd(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 7167 { 7168 int rval = 0; 7169 int jcode; 7170 uint32_t ret; 7171 uchar_t open_flag; 7172 fcio_t *kfcio; 7173 job_request_t *job; 7174 boolean_t use32 = B_FALSE; 7175 7176 #ifdef _MULTI_DATAMODEL 7177 switch (ddi_model_convert_from(mode & FMODELS)) { 7178 case DDI_MODEL_ILP32: 7179 use32 = B_TRUE; 7180 break; 7181 7182 case DDI_MODEL_NONE: 7183 default: 7184 break; 7185 } 7186 #endif 7187 7188 mutex_enter(&port->fp_mutex); 7189 if (port->fp_soft_state & (FP_SOFT_IN_STATEC_CB | 7190 FP_SOFT_IN_UNSOL_CB)) { 7191 fcio->fcio_errno = FC_STATEC_BUSY; 7192 mutex_exit(&port->fp_mutex); 7193 rval = EAGAIN; 7194 if (fp_fcio_copyout(fcio, data, mode)) { 7195 rval = EFAULT; 7196 } 7197 return (rval); 7198 } 7199 open_flag = port->fp_flag; 7200 mutex_exit(&port->fp_mutex); 7201 7202 if (fp_check_perms(open_flag, fcio->fcio_cmd) != FC_SUCCESS) { 7203 fcio->fcio_errno = FC_FAILURE; 7204 rval = EACCES; 7205 if (fp_fcio_copyout(fcio, data, mode)) { 7206 rval = EFAULT; 7207 } 7208 return (rval); 7209 } 7210 7211 /* 7212 * If an exclusive open was demanded during open, don't let 7213 * either innocuous or devil threads to share the file 7214 * descriptor and fire down exclusive access commands 7215 */ 7216 mutex_enter(&port->fp_mutex); 7217 if (port->fp_flag & FP_EXCL) { 7218 if (port->fp_flag & FP_EXCL_BUSY) { 7219 mutex_exit(&port->fp_mutex); 7220 fcio->fcio_errno = FC_FAILURE; 7221 return (EBUSY); 7222 } 7223 port->fp_flag |= FP_EXCL_BUSY; 7224 } 7225 mutex_exit(&port->fp_mutex); 7226 7227 fcio->fcio_errno = FC_SUCCESS; 7228 7229 switch (fcio->fcio_cmd) { 7230 case FCIO_GET_HOST_PARAMS: { 7231 fc_port_dev_t *val; 7232 fc_port_dev32_t *val32; 7233 int index; 7234 int lilp_device_count; 7235 fc_lilpmap_t *lilp_map; 7236 uchar_t *alpa_list; 7237 7238 if (use32 == B_TRUE) { 7239 if (fcio->fcio_olen != sizeof (*val32) || 7240 fcio->fcio_xfer != FCIO_XFER_READ) { 7241 rval = EINVAL; 7242 break; 7243 } 7244 } else { 7245 if (fcio->fcio_olen != sizeof (*val) || 7246 fcio->fcio_xfer != FCIO_XFER_READ) { 7247 rval = EINVAL; 7248 break; 7249 } 7250 } 7251 7252 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7253 7254 mutex_enter(&port->fp_mutex); 7255 val->dev_did = port->fp_port_id; 7256 val->dev_hard_addr = port->fp_hard_addr; 7257 val->dev_pwwn = port->fp_service_params.nport_ww_name; 7258 val->dev_nwwn = port->fp_service_params.node_ww_name; 7259 val->dev_state = port->fp_state; 7260 7261 lilp_map = &port->fp_lilp_map; 7262 alpa_list = &lilp_map->lilp_alpalist[0]; 7263 lilp_device_count = lilp_map->lilp_length; 7264 for (index = 0; index < lilp_device_count; index++) { 7265 uint32_t d_id; 7266 7267 d_id = alpa_list[index]; 7268 if (d_id == port->fp_port_id.port_id) { 7269 break; 7270 } 7271 } 7272 val->dev_did.priv_lilp_posit = (uint8_t)(index & 0xff); 7273 7274 bcopy(port->fp_fc4_types, val->dev_type, 7275 sizeof (port->fp_fc4_types)); 7276 mutex_exit(&port->fp_mutex); 7277 7278 if (use32 == B_TRUE) { 7279 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7280 7281 val32->dev_did = val->dev_did; 7282 val32->dev_hard_addr = val->dev_hard_addr; 7283 val32->dev_pwwn = val->dev_pwwn; 7284 val32->dev_nwwn = val->dev_nwwn; 7285 val32->dev_state = val->dev_state; 7286 val32->dev_did.priv_lilp_posit = 7287 val->dev_did.priv_lilp_posit; 7288 7289 bcopy(val->dev_type, val32->dev_type, 7290 sizeof (port->fp_fc4_types)); 7291 7292 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7293 fcio->fcio_olen, mode) == 0) { 7294 if (fp_fcio_copyout(fcio, data, mode)) { 7295 rval = EFAULT; 7296 } 7297 } else { 7298 rval = EFAULT; 7299 } 7300 7301 kmem_free(val32, sizeof (*val32)); 7302 } else { 7303 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7304 fcio->fcio_olen, mode) == 0) { 7305 if (fp_fcio_copyout(fcio, data, mode)) { 7306 rval = EFAULT; 7307 } 7308 } else { 7309 rval = EFAULT; 7310 } 7311 } 7312 7313 /* need to free "val" here */ 7314 kmem_free(val, sizeof (*val)); 7315 break; 7316 } 7317 7318 case FCIO_GET_OTHER_ADAPTER_PORTS: { 7319 uint32_t index; 7320 char *tmpPath; 7321 fc_local_port_t *tmpPort; 7322 7323 if (fcio->fcio_olen < MAXPATHLEN || 7324 fcio->fcio_ilen != sizeof (uint32_t)) { 7325 rval = EINVAL; 7326 break; 7327 } 7328 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7329 rval = EFAULT; 7330 break; 7331 } 7332 7333 tmpPort = fctl_get_adapter_port_by_index(port, index); 7334 if (tmpPort == NULL) { 7335 FP_TRACE(FP_NHEAD1(9, 0), 7336 "User supplied index out of range"); 7337 fcio->fcio_errno = FC_BADPORT; 7338 rval = EFAULT; 7339 if (fp_fcio_copyout(fcio, data, mode)) { 7340 rval = EFAULT; 7341 } 7342 break; 7343 } 7344 7345 tmpPath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7346 (void) ddi_pathname(tmpPort->fp_port_dip, tmpPath); 7347 if (fp_copyout((void *)tmpPath, (void *)fcio->fcio_obuf, 7348 MAXPATHLEN, mode) == 0) { 7349 if (fp_fcio_copyout(fcio, data, mode)) { 7350 rval = EFAULT; 7351 } 7352 } else { 7353 rval = EFAULT; 7354 } 7355 kmem_free(tmpPath, MAXPATHLEN); 7356 break; 7357 } 7358 7359 case FCIO_NPIV_GET_ADAPTER_ATTRIBUTES: 7360 case FCIO_GET_ADAPTER_ATTRIBUTES: { 7361 fc_hba_adapter_attributes_t *val; 7362 fc_hba_adapter_attributes32_t *val32; 7363 7364 if (use32 == B_TRUE) { 7365 if (fcio->fcio_olen < sizeof (*val32) || 7366 fcio->fcio_xfer != FCIO_XFER_READ) { 7367 rval = EINVAL; 7368 break; 7369 } 7370 } else { 7371 if (fcio->fcio_olen < sizeof (*val) || 7372 fcio->fcio_xfer != FCIO_XFER_READ) { 7373 rval = EINVAL; 7374 break; 7375 } 7376 } 7377 7378 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7379 val->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; 7380 mutex_enter(&port->fp_mutex); 7381 bcopy(port->fp_hba_port_attrs.manufacturer, 7382 val->Manufacturer, 7383 sizeof (val->Manufacturer)); 7384 bcopy(port->fp_hba_port_attrs.serial_number, 7385 val->SerialNumber, 7386 sizeof (val->SerialNumber)); 7387 bcopy(port->fp_hba_port_attrs.model, 7388 val->Model, 7389 sizeof (val->Model)); 7390 bcopy(port->fp_hba_port_attrs.model_description, 7391 val->ModelDescription, 7392 sizeof (val->ModelDescription)); 7393 bcopy(port->fp_sym_node_name, val->NodeSymbolicName, 7394 port->fp_sym_node_namelen); 7395 bcopy(port->fp_hba_port_attrs.hardware_version, 7396 val->HardwareVersion, 7397 sizeof (val->HardwareVersion)); 7398 bcopy(port->fp_hba_port_attrs.option_rom_version, 7399 val->OptionROMVersion, 7400 sizeof (val->OptionROMVersion)); 7401 bcopy(port->fp_hba_port_attrs.firmware_version, 7402 val->FirmwareVersion, 7403 sizeof (val->FirmwareVersion)); 7404 val->VendorSpecificID = 7405 port->fp_hba_port_attrs.vendor_specific_id; 7406 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7407 &val->NodeWWN.raw_wwn, 7408 sizeof (val->NodeWWN.raw_wwn)); 7409 7410 7411 bcopy(port->fp_hba_port_attrs.driver_name, 7412 val->DriverName, 7413 sizeof (val->DriverName)); 7414 bcopy(port->fp_hba_port_attrs.driver_version, 7415 val->DriverVersion, 7416 sizeof (val->DriverVersion)); 7417 mutex_exit(&port->fp_mutex); 7418 7419 if (fcio->fcio_cmd == FCIO_GET_ADAPTER_ATTRIBUTES) { 7420 val->NumberOfPorts = fctl_count_fru_ports(port, 0); 7421 } else { 7422 val->NumberOfPorts = fctl_count_fru_ports(port, 1); 7423 } 7424 7425 if (use32 == B_TRUE) { 7426 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7427 val32->version = val->version; 7428 bcopy(val->Manufacturer, val32->Manufacturer, 7429 sizeof (val->Manufacturer)); 7430 bcopy(val->SerialNumber, val32->SerialNumber, 7431 sizeof (val->SerialNumber)); 7432 bcopy(val->Model, val32->Model, 7433 sizeof (val->Model)); 7434 bcopy(val->ModelDescription, val32->ModelDescription, 7435 sizeof (val->ModelDescription)); 7436 bcopy(val->NodeSymbolicName, val32->NodeSymbolicName, 7437 sizeof (val->NodeSymbolicName)); 7438 bcopy(val->HardwareVersion, val32->HardwareVersion, 7439 sizeof (val->HardwareVersion)); 7440 bcopy(val->OptionROMVersion, val32->OptionROMVersion, 7441 sizeof (val->OptionROMVersion)); 7442 bcopy(val->FirmwareVersion, val32->FirmwareVersion, 7443 sizeof (val->FirmwareVersion)); 7444 val32->VendorSpecificID = val->VendorSpecificID; 7445 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7446 sizeof (val->NodeWWN.raw_wwn)); 7447 bcopy(val->DriverName, val32->DriverName, 7448 sizeof (val->DriverName)); 7449 bcopy(val->DriverVersion, val32->DriverVersion, 7450 sizeof (val->DriverVersion)); 7451 7452 val32->NumberOfPorts = val->NumberOfPorts; 7453 7454 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7455 fcio->fcio_olen, mode) == 0) { 7456 if (fp_fcio_copyout(fcio, data, mode)) { 7457 rval = EFAULT; 7458 } 7459 } else { 7460 rval = EFAULT; 7461 } 7462 7463 kmem_free(val32, sizeof (*val32)); 7464 } else { 7465 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7466 fcio->fcio_olen, mode) == 0) { 7467 if (fp_fcio_copyout(fcio, data, mode)) { 7468 rval = EFAULT; 7469 } 7470 } else { 7471 rval = EFAULT; 7472 } 7473 } 7474 7475 kmem_free(val, sizeof (*val)); 7476 break; 7477 } 7478 7479 case FCIO_GET_NPIV_ATTRIBUTES: { 7480 fc_hba_npiv_attributes_t *attrs; 7481 7482 attrs = kmem_zalloc(sizeof (*attrs), KM_SLEEP); 7483 mutex_enter(&port->fp_mutex); 7484 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7485 &attrs->NodeWWN.raw_wwn, 7486 sizeof (attrs->NodeWWN.raw_wwn)); 7487 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7488 &attrs->PortWWN.raw_wwn, 7489 sizeof (attrs->PortWWN.raw_wwn)); 7490 mutex_exit(&port->fp_mutex); 7491 if (fp_copyout((void *)attrs, (void *)fcio->fcio_obuf, 7492 fcio->fcio_olen, mode) == 0) { 7493 if (fp_fcio_copyout(fcio, data, mode)) { 7494 rval = EFAULT; 7495 } 7496 } else { 7497 rval = EFAULT; 7498 } 7499 kmem_free(attrs, sizeof (*attrs)); 7500 break; 7501 } 7502 7503 case FCIO_DELETE_NPIV_PORT: { 7504 fc_local_port_t *tmpport; 7505 char ww_pname[17]; 7506 la_wwn_t vwwn[1]; 7507 7508 FP_TRACE(FP_NHEAD1(1, 0), "Delete NPIV Port"); 7509 if (ddi_copyin(fcio->fcio_ibuf, 7510 &vwwn, sizeof (la_wwn_t), mode)) { 7511 rval = EFAULT; 7512 break; 7513 } 7514 7515 fc_wwn_to_str(&vwwn[0], ww_pname); 7516 FP_TRACE(FP_NHEAD1(3, 0), 7517 "Delete NPIV Port %s", ww_pname); 7518 tmpport = fc_delete_npiv_port(port, &vwwn[0]); 7519 if (tmpport == NULL) { 7520 FP_TRACE(FP_NHEAD1(3, 0), 7521 "Delete NPIV Port : no found"); 7522 rval = EFAULT; 7523 } else { 7524 fc_local_port_t *nextport = tmpport->fp_port_next; 7525 fc_local_port_t *prevport = tmpport->fp_port_prev; 7526 int portlen, portindex, ret; 7527 7528 portlen = sizeof (portindex); 7529 ret = ddi_prop_op(DDI_DEV_T_ANY, 7530 tmpport->fp_port_dip, PROP_LEN_AND_VAL_BUF, 7531 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 7532 (caddr_t)&portindex, &portlen); 7533 if (ret != DDI_SUCCESS) { 7534 rval = EFAULT; 7535 break; 7536 } 7537 if (ndi_devi_offline(tmpport->fp_port_dip, 7538 NDI_DEVI_REMOVE) != DDI_SUCCESS) { 7539 FP_TRACE(FP_NHEAD1(1, 0), 7540 "Delete NPIV Port failed"); 7541 mutex_enter(&port->fp_mutex); 7542 tmpport->fp_npiv_state = 0; 7543 mutex_exit(&port->fp_mutex); 7544 rval = EFAULT; 7545 } else { 7546 mutex_enter(&port->fp_mutex); 7547 nextport->fp_port_prev = prevport; 7548 prevport->fp_port_next = nextport; 7549 if (port == port->fp_port_next) { 7550 port->fp_port_next = 7551 port->fp_port_prev = NULL; 7552 } 7553 port->fp_npiv_portnum--; 7554 FP_TRACE(FP_NHEAD1(3, 0), 7555 "Delete NPIV Port %d", portindex); 7556 port->fp_npiv_portindex[portindex-1] = 0; 7557 mutex_exit(&port->fp_mutex); 7558 } 7559 } 7560 break; 7561 } 7562 7563 case FCIO_CREATE_NPIV_PORT: { 7564 char ww_nname[17], ww_pname[17]; 7565 la_npiv_create_entry_t entrybuf; 7566 uint32_t vportindex = 0; 7567 int npiv_ret = 0; 7568 char *portname, *fcaname; 7569 7570 portname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7571 (void) ddi_pathname(port->fp_port_dip, portname); 7572 fcaname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 7573 (void) ddi_pathname(port->fp_fca_dip, fcaname); 7574 FP_TRACE(FP_NHEAD1(1, 0), 7575 "Create NPIV port %s %s %s", portname, fcaname, 7576 ddi_driver_name(port->fp_fca_dip)); 7577 kmem_free(portname, MAXPATHLEN); 7578 kmem_free(fcaname, MAXPATHLEN); 7579 if (ddi_copyin(fcio->fcio_ibuf, 7580 &entrybuf, sizeof (la_npiv_create_entry_t), mode)) { 7581 rval = EFAULT; 7582 break; 7583 } 7584 7585 fc_wwn_to_str(&entrybuf.VNodeWWN, ww_nname); 7586 fc_wwn_to_str(&entrybuf.VPortWWN, ww_pname); 7587 vportindex = entrybuf.vindex; 7588 FP_TRACE(FP_NHEAD1(3, 0), 7589 "Create NPIV Port %s %s %d", 7590 ww_nname, ww_pname, vportindex); 7591 7592 if (fc_get_npiv_port(port, &entrybuf.VPortWWN)) { 7593 rval = EFAULT; 7594 break; 7595 } 7596 npiv_ret = fctl_fca_create_npivport(port->fp_fca_dip, 7597 port->fp_port_dip, ww_nname, ww_pname, &vportindex); 7598 if (npiv_ret == NDI_SUCCESS) { 7599 mutex_enter(&port->fp_mutex); 7600 port->fp_npiv_portnum++; 7601 mutex_exit(&port->fp_mutex); 7602 if (fp_copyout((void *)&vportindex, 7603 (void *)fcio->fcio_obuf, 7604 fcio->fcio_olen, mode) == 0) { 7605 if (fp_fcio_copyout(fcio, data, mode)) { 7606 rval = EFAULT; 7607 } 7608 } else { 7609 rval = EFAULT; 7610 } 7611 } else { 7612 rval = EFAULT; 7613 } 7614 FP_TRACE(FP_NHEAD1(3, 0), 7615 "Create NPIV Port %d %d", npiv_ret, vportindex); 7616 break; 7617 } 7618 7619 case FCIO_GET_NPIV_PORT_LIST: { 7620 fc_hba_npiv_port_list_t *list; 7621 int count; 7622 7623 if ((fcio->fcio_xfer != FCIO_XFER_READ) || 7624 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { 7625 rval = EINVAL; 7626 break; 7627 } 7628 7629 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 7630 list->version = FC_HBA_LIST_VERSION; 7631 /* build npiv port list */ 7632 count = fc_ulp_get_npiv_port_list(port, (char *)list->hbaPaths); 7633 if (count < 0) { 7634 rval = ENXIO; 7635 FP_TRACE(FP_NHEAD1(1, 0), "Build NPIV Port List error"); 7636 kmem_free(list, fcio->fcio_olen); 7637 break; 7638 } 7639 list->numAdapters = count; 7640 7641 if (fp_copyout((void *)list, (void *)fcio->fcio_obuf, 7642 fcio->fcio_olen, mode) == 0) { 7643 if (fp_fcio_copyout(fcio, data, mode)) { 7644 FP_TRACE(FP_NHEAD1(1, 0), 7645 "Copy NPIV Port data error"); 7646 rval = EFAULT; 7647 } 7648 } else { 7649 FP_TRACE(FP_NHEAD1(1, 0), "Copy NPIV Port List error"); 7650 rval = EFAULT; 7651 } 7652 kmem_free(list, fcio->fcio_olen); 7653 break; 7654 } 7655 7656 case FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES: { 7657 fc_hba_port_npiv_attributes_t *val; 7658 7659 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7660 val->version = FC_HBA_PORT_NPIV_ATTRIBUTES_VERSION; 7661 7662 mutex_enter(&port->fp_mutex); 7663 val->npivflag = port->fp_npiv_flag; 7664 val->lastChange = port->fp_last_change; 7665 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7666 &val->PortWWN.raw_wwn, 7667 sizeof (val->PortWWN.raw_wwn)); 7668 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7669 &val->NodeWWN.raw_wwn, 7670 sizeof (val->NodeWWN.raw_wwn)); 7671 mutex_exit(&port->fp_mutex); 7672 7673 val->NumberOfNPIVPorts = fc_ulp_get_npiv_port_num(port); 7674 if (port->fp_npiv_type != FC_NPIV_PORT) { 7675 val->MaxNumberOfNPIVPorts = 7676 port->fp_fca_tran->fca_num_npivports; 7677 } else { 7678 val->MaxNumberOfNPIVPorts = 0; 7679 } 7680 7681 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7682 fcio->fcio_olen, mode) == 0) { 7683 if (fp_fcio_copyout(fcio, data, mode)) { 7684 rval = EFAULT; 7685 } 7686 } else { 7687 rval = EFAULT; 7688 } 7689 kmem_free(val, sizeof (*val)); 7690 break; 7691 } 7692 7693 case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: { 7694 fc_hba_port_attributes_t *val; 7695 fc_hba_port_attributes32_t *val32; 7696 7697 if (use32 == B_TRUE) { 7698 if (fcio->fcio_olen < sizeof (*val32) || 7699 fcio->fcio_xfer != FCIO_XFER_READ) { 7700 rval = EINVAL; 7701 break; 7702 } 7703 } else { 7704 if (fcio->fcio_olen < sizeof (*val) || 7705 fcio->fcio_xfer != FCIO_XFER_READ) { 7706 rval = EINVAL; 7707 break; 7708 } 7709 } 7710 7711 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7712 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7713 mutex_enter(&port->fp_mutex); 7714 val->lastChange = port->fp_last_change; 7715 val->fp_minor = port->fp_instance; 7716 7717 bcopy(&port->fp_service_params.nport_ww_name.raw_wwn, 7718 &val->PortWWN.raw_wwn, 7719 sizeof (val->PortWWN.raw_wwn)); 7720 bcopy(&port->fp_service_params.node_ww_name.raw_wwn, 7721 &val->NodeWWN.raw_wwn, 7722 sizeof (val->NodeWWN.raw_wwn)); 7723 bcopy(&port->fp_fabric_name, &val->FabricName.raw_wwn, 7724 sizeof (val->FabricName.raw_wwn)); 7725 7726 val->PortFcId = port->fp_port_id.port_id; 7727 7728 switch (FC_PORT_STATE_MASK(port->fp_state)) { 7729 case FC_STATE_OFFLINE: 7730 val->PortState = FC_HBA_PORTSTATE_OFFLINE; 7731 break; 7732 case FC_STATE_ONLINE: 7733 case FC_STATE_LOOP: 7734 case FC_STATE_NAMESERVICE: 7735 val->PortState = FC_HBA_PORTSTATE_ONLINE; 7736 break; 7737 default: 7738 val->PortState = FC_HBA_PORTSTATE_UNKNOWN; 7739 break; 7740 } 7741 7742 /* Translate from LV to FC-HBA port type codes */ 7743 switch (port->fp_port_type.port_type) { 7744 case FC_NS_PORT_N: 7745 val->PortType = FC_HBA_PORTTYPE_NPORT; 7746 break; 7747 case FC_NS_PORT_NL: 7748 /* Actually means loop for us */ 7749 val->PortType = FC_HBA_PORTTYPE_LPORT; 7750 break; 7751 case FC_NS_PORT_F: 7752 val->PortType = FC_HBA_PORTTYPE_FPORT; 7753 break; 7754 case FC_NS_PORT_FL: 7755 val->PortType = FC_HBA_PORTTYPE_FLPORT; 7756 break; 7757 case FC_NS_PORT_E: 7758 val->PortType = FC_HBA_PORTTYPE_EPORT; 7759 break; 7760 default: 7761 val->PortType = FC_HBA_PORTTYPE_OTHER; 7762 break; 7763 } 7764 7765 7766 /* 7767 * If fp has decided that the topology is public loop, 7768 * we will indicate that using the appropriate 7769 * FC HBA API constant. 7770 */ 7771 switch (port->fp_topology) { 7772 case FC_TOP_PUBLIC_LOOP: 7773 val->PortType = FC_HBA_PORTTYPE_NLPORT; 7774 break; 7775 7776 case FC_TOP_PT_PT: 7777 val->PortType = FC_HBA_PORTTYPE_PTP; 7778 break; 7779 7780 case FC_TOP_UNKNOWN: 7781 /* 7782 * This should cover the case where nothing is connected 7783 * to the port. Crystal+ is p'bly an exception here. 7784 * For Crystal+, port 0 will come up as private loop 7785 * (i.e fp_bind_state will be FC_STATE_LOOP) even when 7786 * nothing is connected to it. 7787 * Current plan is to let userland handle this. 7788 */ 7789 if (port->fp_bind_state == FC_STATE_OFFLINE) { 7790 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7791 } 7792 break; 7793 7794 default: 7795 /* 7796 * Do Nothing. 7797 * Unused: 7798 * val->PortType = FC_HBA_PORTTYPE_GPORT; 7799 */ 7800 break; 7801 } 7802 7803 val->PortSupportedClassofService = 7804 port->fp_hba_port_attrs.supported_cos; 7805 val->PortSupportedFc4Types[0] = 0; 7806 bcopy(port->fp_fc4_types, val->PortActiveFc4Types, 7807 sizeof (val->PortActiveFc4Types)); 7808 bcopy(port->fp_sym_port_name, val->PortSymbolicName, 7809 port->fp_sym_port_namelen); 7810 val->PortSupportedSpeed = 7811 port->fp_hba_port_attrs.supported_speed; 7812 7813 switch (FC_PORT_SPEED_MASK(port->fp_state)) { 7814 case FC_STATE_1GBIT_SPEED: 7815 val->PortSpeed = FC_HBA_PORTSPEED_1GBIT; 7816 break; 7817 case FC_STATE_2GBIT_SPEED: 7818 val->PortSpeed = FC_HBA_PORTSPEED_2GBIT; 7819 break; 7820 case FC_STATE_4GBIT_SPEED: 7821 val->PortSpeed = FC_HBA_PORTSPEED_4GBIT; 7822 break; 7823 case FC_STATE_8GBIT_SPEED: 7824 val->PortSpeed = FC_HBA_PORTSPEED_8GBIT; 7825 break; 7826 case FC_STATE_10GBIT_SPEED: 7827 val->PortSpeed = FC_HBA_PORTSPEED_10GBIT; 7828 break; 7829 case FC_STATE_16GBIT_SPEED: 7830 val->PortSpeed = FC_HBA_PORTSPEED_16GBIT; 7831 break; 7832 default: 7833 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7834 break; 7835 } 7836 val->PortMaxFrameSize = port->fp_hba_port_attrs.max_frame_size; 7837 val->NumberofDiscoveredPorts = port->fp_dev_count; 7838 mutex_exit(&port->fp_mutex); 7839 7840 if (use32 == B_TRUE) { 7841 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7842 val32->version = val->version; 7843 val32->lastChange = val->lastChange; 7844 val32->fp_minor = val->fp_minor; 7845 7846 bcopy(&val->PortWWN.raw_wwn, &val32->PortWWN.raw_wwn, 7847 sizeof (val->PortWWN.raw_wwn)); 7848 bcopy(&val->NodeWWN.raw_wwn, &val32->NodeWWN.raw_wwn, 7849 sizeof (val->NodeWWN.raw_wwn)); 7850 val32->PortFcId = val->PortFcId; 7851 val32->PortState = val->PortState; 7852 val32->PortType = val->PortType; 7853 7854 val32->PortSupportedClassofService = 7855 val->PortSupportedClassofService; 7856 bcopy(val->PortActiveFc4Types, 7857 val32->PortActiveFc4Types, 7858 sizeof (val->PortActiveFc4Types)); 7859 bcopy(val->PortSymbolicName, val32->PortSymbolicName, 7860 sizeof (val->PortSymbolicName)); 7861 bcopy(&val->FabricName, &val32->FabricName, 7862 sizeof (val->FabricName.raw_wwn)); 7863 val32->PortSupportedSpeed = val->PortSupportedSpeed; 7864 val32->PortSpeed = val->PortSpeed; 7865 7866 val32->PortMaxFrameSize = val->PortMaxFrameSize; 7867 val32->NumberofDiscoveredPorts = 7868 val->NumberofDiscoveredPorts; 7869 7870 if (fp_copyout((void *)val32, (void *)fcio->fcio_obuf, 7871 fcio->fcio_olen, mode) == 0) { 7872 if (fp_fcio_copyout(fcio, data, mode)) { 7873 rval = EFAULT; 7874 } 7875 } else { 7876 rval = EFAULT; 7877 } 7878 7879 kmem_free(val32, sizeof (*val32)); 7880 } else { 7881 if (fp_copyout((void *)val, (void *)fcio->fcio_obuf, 7882 fcio->fcio_olen, mode) == 0) { 7883 if (fp_fcio_copyout(fcio, data, mode)) { 7884 rval = EFAULT; 7885 } 7886 } else { 7887 rval = EFAULT; 7888 } 7889 } 7890 7891 kmem_free(val, sizeof (*val)); 7892 break; 7893 } 7894 7895 case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: { 7896 fc_hba_port_attributes_t *val; 7897 fc_hba_port_attributes32_t *val32; 7898 uint32_t index = 0; 7899 fc_remote_port_t *tmp_pd; 7900 7901 if (use32 == B_TRUE) { 7902 if (fcio->fcio_olen < sizeof (*val32) || 7903 fcio->fcio_xfer != FCIO_XFER_READ) { 7904 rval = EINVAL; 7905 break; 7906 } 7907 } else { 7908 if (fcio->fcio_olen < sizeof (*val) || 7909 fcio->fcio_xfer != FCIO_XFER_READ) { 7910 rval = EINVAL; 7911 break; 7912 } 7913 } 7914 7915 if (ddi_copyin(fcio->fcio_ibuf, &index, sizeof (index), mode)) { 7916 rval = EFAULT; 7917 break; 7918 } 7919 7920 if (index >= port->fp_dev_count) { 7921 FP_TRACE(FP_NHEAD1(9, 0), 7922 "User supplied index out of range"); 7923 fcio->fcio_errno = FC_OUTOFBOUNDS; 7924 rval = EINVAL; 7925 if (fp_fcio_copyout(fcio, data, mode)) { 7926 rval = EFAULT; 7927 } 7928 break; 7929 } 7930 7931 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 7932 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 7933 7934 mutex_enter(&port->fp_mutex); 7935 tmp_pd = fctl_lookup_pd_by_index(port, index); 7936 7937 if (tmp_pd == NULL) { 7938 fcio->fcio_errno = FC_BADPORT; 7939 rval = EINVAL; 7940 } else { 7941 val->lastChange = port->fp_last_change; 7942 val->fp_minor = port->fp_instance; 7943 7944 mutex_enter(&tmp_pd->pd_mutex); 7945 bcopy(&tmp_pd->pd_port_name.raw_wwn, 7946 &val->PortWWN.raw_wwn, 7947 sizeof (val->PortWWN.raw_wwn)); 7948 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 7949 &val->NodeWWN.raw_wwn, 7950 sizeof (val->NodeWWN.raw_wwn)); 7951 val->PortFcId = tmp_pd->pd_port_id.port_id; 7952 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 7953 tmp_pd->pd_spn_len); 7954 val->PortSupportedClassofService = tmp_pd->pd_cos; 7955 /* 7956 * we will assume the sizeof these pd_fc4types and 7957 * portActiveFc4Types will remain the same. we could 7958 * add in a check for it, but we decided it was unneeded 7959 */ 7960 bcopy((caddr_t)tmp_pd->pd_fc4types, 7961 val->PortActiveFc4Types, 7962 sizeof (tmp_pd->pd_fc4types)); 7963 val->PortState = 7964 fp_map_remote_port_state(tmp_pd->pd_state); 7965 mutex_exit(&tmp_pd->pd_mutex); 7966 7967 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 7968 val->PortSupportedFc4Types[0] = 0; 7969 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7970 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 7971 val->PortMaxFrameSize = 0; 7972 val->NumberofDiscoveredPorts = 0; 7973 7974 if (use32 == B_TRUE) { 7975 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 7976 val32->version = val->version; 7977 val32->lastChange = val->lastChange; 7978 val32->fp_minor = val->fp_minor; 7979 7980 bcopy(&val->PortWWN.raw_wwn, 7981 &val32->PortWWN.raw_wwn, 7982 sizeof (val->PortWWN.raw_wwn)); 7983 bcopy(&val->NodeWWN.raw_wwn, 7984 &val32->NodeWWN.raw_wwn, 7985 sizeof (val->NodeWWN.raw_wwn)); 7986 val32->PortFcId = val->PortFcId; 7987 bcopy(val->PortSymbolicName, 7988 val32->PortSymbolicName, 7989 sizeof (val->PortSymbolicName)); 7990 val32->PortSupportedClassofService = 7991 val->PortSupportedClassofService; 7992 bcopy(val->PortActiveFc4Types, 7993 val32->PortActiveFc4Types, 7994 sizeof (tmp_pd->pd_fc4types)); 7995 7996 val32->PortType = val->PortType; 7997 val32->PortState = val->PortState; 7998 val32->PortSupportedFc4Types[0] = 7999 val->PortSupportedFc4Types[0]; 8000 val32->PortSupportedSpeed = 8001 val->PortSupportedSpeed; 8002 val32->PortSpeed = val->PortSpeed; 8003 val32->PortMaxFrameSize = 8004 val->PortMaxFrameSize; 8005 val32->NumberofDiscoveredPorts = 8006 val->NumberofDiscoveredPorts; 8007 8008 if (fp_copyout((void *)val32, 8009 (void *)fcio->fcio_obuf, 8010 fcio->fcio_olen, mode) == 0) { 8011 if (fp_fcio_copyout(fcio, 8012 data, mode)) { 8013 rval = EFAULT; 8014 } 8015 } else { 8016 rval = EFAULT; 8017 } 8018 8019 kmem_free(val32, sizeof (*val32)); 8020 } else { 8021 if (fp_copyout((void *)val, 8022 (void *)fcio->fcio_obuf, 8023 fcio->fcio_olen, mode) == 0) { 8024 if (fp_fcio_copyout(fcio, data, mode)) { 8025 rval = EFAULT; 8026 } 8027 } else { 8028 rval = EFAULT; 8029 } 8030 } 8031 } 8032 8033 mutex_exit(&port->fp_mutex); 8034 kmem_free(val, sizeof (*val)); 8035 break; 8036 } 8037 8038 case FCIO_GET_PORT_ATTRIBUTES: { 8039 fc_hba_port_attributes_t *val; 8040 fc_hba_port_attributes32_t *val32; 8041 la_wwn_t wwn; 8042 fc_remote_port_t *tmp_pd; 8043 8044 if (use32 == B_TRUE) { 8045 if (fcio->fcio_olen < sizeof (*val32) || 8046 fcio->fcio_xfer != FCIO_XFER_READ) { 8047 rval = EINVAL; 8048 break; 8049 } 8050 } else { 8051 if (fcio->fcio_olen < sizeof (*val) || 8052 fcio->fcio_xfer != FCIO_XFER_READ) { 8053 rval = EINVAL; 8054 break; 8055 } 8056 } 8057 8058 if (ddi_copyin(fcio->fcio_ibuf, &wwn, sizeof (wwn), mode)) { 8059 rval = EFAULT; 8060 break; 8061 } 8062 8063 val = kmem_zalloc(sizeof (*val), KM_SLEEP); 8064 val->version = FC_HBA_PORT_ATTRIBUTES_VERSION; 8065 8066 mutex_enter(&port->fp_mutex); 8067 tmp_pd = fctl_lookup_pd_by_wwn(port, wwn); 8068 val->lastChange = port->fp_last_change; 8069 val->fp_minor = port->fp_instance; 8070 mutex_exit(&port->fp_mutex); 8071 8072 if (tmp_pd == NULL) { 8073 fcio->fcio_errno = FC_BADWWN; 8074 rval = EINVAL; 8075 } else { 8076 mutex_enter(&tmp_pd->pd_mutex); 8077 bcopy(&tmp_pd->pd_port_name.raw_wwn, 8078 &val->PortWWN.raw_wwn, 8079 sizeof (val->PortWWN.raw_wwn)); 8080 bcopy(&tmp_pd->pd_remote_nodep->fd_node_name.raw_wwn, 8081 &val->NodeWWN.raw_wwn, 8082 sizeof (val->NodeWWN.raw_wwn)); 8083 val->PortFcId = tmp_pd->pd_port_id.port_id; 8084 bcopy(tmp_pd->pd_spn, val->PortSymbolicName, 8085 tmp_pd->pd_spn_len); 8086 val->PortSupportedClassofService = tmp_pd->pd_cos; 8087 val->PortType = FC_HBA_PORTTYPE_UNKNOWN; 8088 val->PortState = 8089 fp_map_remote_port_state(tmp_pd->pd_state); 8090 val->PortSupportedFc4Types[0] = 0; 8091 /* 8092 * we will assume the sizeof these pd_fc4types and 8093 * portActiveFc4Types will remain the same. we could 8094 * add in a check for it, but we decided it was unneeded 8095 */ 8096 bcopy((caddr_t)tmp_pd->pd_fc4types, 8097 val->PortActiveFc4Types, 8098 sizeof (tmp_pd->pd_fc4types)); 8099 val->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8100 val->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN; 8101 val->PortMaxFrameSize = 0; 8102 val->NumberofDiscoveredPorts = 0; 8103 mutex_exit(&tmp_pd->pd_mutex); 8104 8105 if (use32 == B_TRUE) { 8106 val32 = kmem_zalloc(sizeof (*val32), KM_SLEEP); 8107 val32->version = val->version; 8108 val32->lastChange = val->lastChange; 8109 val32->fp_minor = val->fp_minor; 8110 bcopy(&val->PortWWN.raw_wwn, 8111 &val32->PortWWN.raw_wwn, 8112 sizeof (val->PortWWN.raw_wwn)); 8113 bcopy(&val->NodeWWN.raw_wwn, 8114 &val32->NodeWWN.raw_wwn, 8115 sizeof (val->NodeWWN.raw_wwn)); 8116 val32->PortFcId = val->PortFcId; 8117 bcopy(val->PortSymbolicName, 8118 val32->PortSymbolicName, 8119 sizeof (val->PortSymbolicName)); 8120 val32->PortSupportedClassofService = 8121 val->PortSupportedClassofService; 8122 val32->PortType = val->PortType; 8123 val32->PortState = val->PortState; 8124 val32->PortSupportedFc4Types[0] = 8125 val->PortSupportedFc4Types[0]; 8126 bcopy(val->PortActiveFc4Types, 8127 val32->PortActiveFc4Types, 8128 sizeof (tmp_pd->pd_fc4types)); 8129 val32->PortSupportedSpeed = 8130 val->PortSupportedSpeed; 8131 val32->PortSpeed = val->PortSpeed; 8132 val32->PortMaxFrameSize = val->PortMaxFrameSize; 8133 val32->NumberofDiscoveredPorts = 8134 val->NumberofDiscoveredPorts; 8135 8136 if (fp_copyout((void *)val32, 8137 (void *)fcio->fcio_obuf, 8138 fcio->fcio_olen, mode) == 0) { 8139 if (fp_fcio_copyout(fcio, data, mode)) { 8140 rval = EFAULT; 8141 } 8142 } else { 8143 rval = EFAULT; 8144 } 8145 8146 kmem_free(val32, sizeof (*val32)); 8147 } else { 8148 if (fp_copyout((void *)val, 8149 (void *)fcio->fcio_obuf, 8150 fcio->fcio_olen, mode) == 0) { 8151 if (fp_fcio_copyout(fcio, data, mode)) { 8152 rval = EFAULT; 8153 } 8154 } else { 8155 rval = EFAULT; 8156 } 8157 } 8158 } 8159 kmem_free(val, sizeof (*val)); 8160 break; 8161 } 8162 8163 case FCIO_GET_NUM_DEVS: { 8164 int num_devices; 8165 8166 if (fcio->fcio_olen != sizeof (num_devices) || 8167 fcio->fcio_xfer != FCIO_XFER_READ) { 8168 rval = EINVAL; 8169 break; 8170 } 8171 8172 mutex_enter(&port->fp_mutex); 8173 switch (port->fp_topology) { 8174 case FC_TOP_PRIVATE_LOOP: 8175 case FC_TOP_PT_PT: 8176 num_devices = port->fp_total_devices; 8177 fcio->fcio_errno = FC_SUCCESS; 8178 break; 8179 8180 case FC_TOP_PUBLIC_LOOP: 8181 case FC_TOP_FABRIC: 8182 mutex_exit(&port->fp_mutex); 8183 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, 8184 NULL, KM_SLEEP); 8185 ASSERT(job != NULL); 8186 8187 /* 8188 * In FC-GS-2 the Name Server doesn't send out 8189 * RSCNs for any Name Server Database updates 8190 * When it is finally fixed there is no need 8191 * to probe as below and should be removed. 8192 */ 8193 (void) fp_ns_get_devcount(port, job, 0, KM_SLEEP); 8194 fctl_dealloc_job(job); 8195 8196 mutex_enter(&port->fp_mutex); 8197 num_devices = port->fp_total_devices; 8198 fcio->fcio_errno = FC_SUCCESS; 8199 break; 8200 8201 case FC_TOP_NO_NS: 8202 /* FALLTHROUGH */ 8203 case FC_TOP_UNKNOWN: 8204 /* FALLTHROUGH */ 8205 default: 8206 num_devices = 0; 8207 fcio->fcio_errno = FC_SUCCESS; 8208 break; 8209 } 8210 mutex_exit(&port->fp_mutex); 8211 8212 if (fp_copyout((void *)&num_devices, 8213 (void *)fcio->fcio_obuf, fcio->fcio_olen, 8214 mode) == 0) { 8215 if (fp_fcio_copyout(fcio, data, mode)) { 8216 rval = EFAULT; 8217 } 8218 } else { 8219 rval = EFAULT; 8220 } 8221 break; 8222 } 8223 8224 case FCIO_GET_DEV_LIST: { 8225 int num_devices; 8226 int new_count; 8227 int map_size; 8228 8229 if (fcio->fcio_xfer != FCIO_XFER_READ || 8230 fcio->fcio_alen != sizeof (new_count)) { 8231 rval = EINVAL; 8232 break; 8233 } 8234 8235 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 8236 8237 mutex_enter(&port->fp_mutex); 8238 if (num_devices < port->fp_total_devices) { 8239 fcio->fcio_errno = FC_TOOMANY; 8240 new_count = port->fp_total_devices; 8241 mutex_exit(&port->fp_mutex); 8242 8243 if (fp_copyout((void *)&new_count, 8244 (void *)fcio->fcio_abuf, 8245 sizeof (new_count), mode)) { 8246 rval = EFAULT; 8247 break; 8248 } 8249 8250 if (fp_fcio_copyout(fcio, data, mode)) { 8251 rval = EFAULT; 8252 break; 8253 } 8254 rval = EINVAL; 8255 break; 8256 } 8257 8258 if (port->fp_total_devices <= 0) { 8259 fcio->fcio_errno = FC_NO_MAP; 8260 new_count = port->fp_total_devices; 8261 mutex_exit(&port->fp_mutex); 8262 8263 if (fp_copyout((void *)&new_count, 8264 (void *)fcio->fcio_abuf, 8265 sizeof (new_count), mode)) { 8266 rval = EFAULT; 8267 break; 8268 } 8269 8270 if (fp_fcio_copyout(fcio, data, mode)) { 8271 rval = EFAULT; 8272 break; 8273 } 8274 rval = EINVAL; 8275 break; 8276 } 8277 8278 switch (port->fp_topology) { 8279 case FC_TOP_PRIVATE_LOOP: 8280 if (fp_fillout_loopmap(port, fcio, 8281 mode) != FC_SUCCESS) { 8282 rval = EFAULT; 8283 break; 8284 } 8285 if (fp_fcio_copyout(fcio, data, mode)) { 8286 rval = EFAULT; 8287 } 8288 break; 8289 8290 case FC_TOP_PT_PT: 8291 if (fp_fillout_p2pmap(port, fcio, 8292 mode) != FC_SUCCESS) { 8293 rval = EFAULT; 8294 break; 8295 } 8296 if (fp_fcio_copyout(fcio, data, mode)) { 8297 rval = EFAULT; 8298 } 8299 break; 8300 8301 case FC_TOP_PUBLIC_LOOP: 8302 case FC_TOP_FABRIC: { 8303 fctl_ns_req_t *ns_cmd; 8304 8305 map_size = 8306 sizeof (fc_port_dev_t) * port->fp_total_devices; 8307 8308 mutex_exit(&port->fp_mutex); 8309 8310 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 8311 sizeof (ns_resp_gan_t), map_size, 8312 (FCTL_NS_FILL_NS_MAP | FCTL_NS_BUF_IS_USERLAND), 8313 KM_SLEEP); 8314 ASSERT(ns_cmd != NULL); 8315 8316 ns_cmd->ns_gan_index = 0; 8317 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 8318 ns_cmd->ns_cmd_code = NS_GA_NXT; 8319 ns_cmd->ns_gan_max = map_size / sizeof (fc_port_dev_t); 8320 8321 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, 8322 NULL, KM_SLEEP); 8323 ASSERT(job != NULL); 8324 8325 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 8326 8327 if (ret != FC_SUCCESS || 8328 job->job_result != FC_SUCCESS) { 8329 fctl_free_ns_cmd(ns_cmd); 8330 8331 fcio->fcio_errno = job->job_result; 8332 new_count = 0; 8333 if (fp_copyout((void *)&new_count, 8334 (void *)fcio->fcio_abuf, 8335 sizeof (new_count), mode)) { 8336 fctl_dealloc_job(job); 8337 mutex_enter(&port->fp_mutex); 8338 rval = EFAULT; 8339 break; 8340 } 8341 8342 if (fp_fcio_copyout(fcio, data, mode)) { 8343 fctl_dealloc_job(job); 8344 mutex_enter(&port->fp_mutex); 8345 rval = EFAULT; 8346 break; 8347 } 8348 rval = EIO; 8349 mutex_enter(&port->fp_mutex); 8350 break; 8351 } 8352 fctl_dealloc_job(job); 8353 8354 new_count = ns_cmd->ns_gan_index; 8355 if (fp_copyout((void *)&new_count, 8356 (void *)fcio->fcio_abuf, sizeof (new_count), 8357 mode)) { 8358 rval = EFAULT; 8359 fctl_free_ns_cmd(ns_cmd); 8360 mutex_enter(&port->fp_mutex); 8361 break; 8362 } 8363 8364 if (fp_copyout((void *)ns_cmd->ns_data_buf, 8365 (void *)fcio->fcio_obuf, sizeof (fc_port_dev_t) * 8366 ns_cmd->ns_gan_index, mode)) { 8367 rval = EFAULT; 8368 fctl_free_ns_cmd(ns_cmd); 8369 mutex_enter(&port->fp_mutex); 8370 break; 8371 } 8372 fctl_free_ns_cmd(ns_cmd); 8373 8374 if (fp_fcio_copyout(fcio, data, mode)) { 8375 rval = EFAULT; 8376 } 8377 mutex_enter(&port->fp_mutex); 8378 break; 8379 } 8380 8381 case FC_TOP_NO_NS: 8382 /* FALLTHROUGH */ 8383 case FC_TOP_UNKNOWN: 8384 /* FALLTHROUGH */ 8385 default: 8386 fcio->fcio_errno = FC_NO_MAP; 8387 num_devices = port->fp_total_devices; 8388 8389 if (fp_copyout((void *)&new_count, 8390 (void *)fcio->fcio_abuf, 8391 sizeof (new_count), mode)) { 8392 rval = EFAULT; 8393 break; 8394 } 8395 8396 if (fp_fcio_copyout(fcio, data, mode)) { 8397 rval = EFAULT; 8398 break; 8399 } 8400 rval = EINVAL; 8401 break; 8402 } 8403 mutex_exit(&port->fp_mutex); 8404 break; 8405 } 8406 8407 case FCIO_GET_SYM_PNAME: { 8408 rval = ENOTSUP; 8409 break; 8410 } 8411 8412 case FCIO_GET_SYM_NNAME: { 8413 rval = ENOTSUP; 8414 break; 8415 } 8416 8417 case FCIO_SET_SYM_PNAME: { 8418 rval = ENOTSUP; 8419 break; 8420 } 8421 8422 case FCIO_SET_SYM_NNAME: { 8423 rval = ENOTSUP; 8424 break; 8425 } 8426 8427 case FCIO_GET_LOGI_PARAMS: { 8428 la_wwn_t pwwn; 8429 la_wwn_t *my_pwwn; 8430 la_els_logi_t *params; 8431 la_els_logi32_t *params32; 8432 fc_remote_node_t *node; 8433 fc_remote_port_t *pd; 8434 8435 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8436 (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || 8437 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { 8438 rval = EINVAL; 8439 break; 8440 } 8441 8442 if (use32 == B_TRUE) { 8443 if (fcio->fcio_olen != sizeof (la_els_logi32_t)) { 8444 rval = EINVAL; 8445 break; 8446 } 8447 } else { 8448 if (fcio->fcio_olen != sizeof (la_els_logi_t)) { 8449 rval = EINVAL; 8450 break; 8451 } 8452 } 8453 8454 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8455 rval = EFAULT; 8456 break; 8457 } 8458 8459 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8460 if (pd == NULL) { 8461 mutex_enter(&port->fp_mutex); 8462 my_pwwn = &port->fp_service_params.nport_ww_name; 8463 mutex_exit(&port->fp_mutex); 8464 8465 if (fctl_wwn_cmp(&pwwn, my_pwwn) != 0) { 8466 rval = ENXIO; 8467 break; 8468 } 8469 8470 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8471 mutex_enter(&port->fp_mutex); 8472 *params = port->fp_service_params; 8473 mutex_exit(&port->fp_mutex); 8474 } else { 8475 params = kmem_zalloc(sizeof (*params), KM_SLEEP); 8476 8477 mutex_enter(&pd->pd_mutex); 8478 params->ls_code.mbz = params->ls_code.ls_code = 0; 8479 params->common_service = pd->pd_csp; 8480 params->nport_ww_name = pd->pd_port_name; 8481 params->class_1 = pd->pd_clsp1; 8482 params->class_2 = pd->pd_clsp2; 8483 params->class_3 = pd->pd_clsp3; 8484 node = pd->pd_remote_nodep; 8485 mutex_exit(&pd->pd_mutex); 8486 8487 bzero(params->reserved, sizeof (params->reserved)); 8488 8489 mutex_enter(&node->fd_mutex); 8490 bcopy(node->fd_vv, params->vendor_version, 8491 sizeof (node->fd_vv)); 8492 params->node_ww_name = node->fd_node_name; 8493 mutex_exit(&node->fd_mutex); 8494 8495 fctl_release_remote_port(pd); 8496 } 8497 8498 if (use32 == B_TRUE) { 8499 params32 = kmem_zalloc(sizeof (*params32), KM_SLEEP); 8500 8501 params32->ls_code.mbz = params->ls_code.mbz; 8502 params32->common_service = params->common_service; 8503 params32->nport_ww_name = params->nport_ww_name; 8504 params32->class_1 = params->class_1; 8505 params32->class_2 = params->class_2; 8506 params32->class_3 = params->class_3; 8507 bzero(params32->reserved, sizeof (params32->reserved)); 8508 bcopy(params->vendor_version, params32->vendor_version, 8509 sizeof (node->fd_vv)); 8510 params32->node_ww_name = params->node_ww_name; 8511 8512 if (ddi_copyout((void *)params32, 8513 (void *)fcio->fcio_obuf, 8514 sizeof (*params32), mode)) { 8515 rval = EFAULT; 8516 } 8517 8518 kmem_free(params32, sizeof (*params32)); 8519 } else { 8520 if (ddi_copyout((void *)params, (void *)fcio->fcio_obuf, 8521 sizeof (*params), mode)) { 8522 rval = EFAULT; 8523 } 8524 } 8525 8526 kmem_free(params, sizeof (*params)); 8527 if (fp_fcio_copyout(fcio, data, mode)) { 8528 rval = EFAULT; 8529 } 8530 break; 8531 } 8532 8533 case FCIO_DEV_LOGOUT: 8534 case FCIO_DEV_LOGIN: 8535 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8536 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8537 rval = EINVAL; 8538 8539 if (fp_fcio_copyout(fcio, data, mode)) { 8540 rval = EFAULT; 8541 } 8542 break; 8543 } 8544 8545 if (fcio->fcio_cmd == FCIO_DEV_LOGIN) { 8546 jcode = JOB_FCIO_LOGIN; 8547 } else { 8548 jcode = JOB_FCIO_LOGOUT; 8549 } 8550 8551 kfcio = kmem_zalloc(sizeof (*kfcio), KM_SLEEP); 8552 bcopy(fcio, kfcio, sizeof (*fcio)); 8553 8554 if (kfcio->fcio_ilen) { 8555 kfcio->fcio_ibuf = kmem_zalloc(kfcio->fcio_ilen, 8556 KM_SLEEP); 8557 8558 if (ddi_copyin((void *)fcio->fcio_ibuf, 8559 (void *)kfcio->fcio_ibuf, kfcio->fcio_ilen, 8560 mode)) { 8561 rval = EFAULT; 8562 8563 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8564 kmem_free(kfcio, sizeof (*kfcio)); 8565 fcio->fcio_errno = job->job_result; 8566 if (fp_fcio_copyout(fcio, data, mode)) { 8567 rval = EFAULT; 8568 } 8569 break; 8570 } 8571 } 8572 8573 job = fctl_alloc_job(jcode, 0, NULL, NULL, KM_SLEEP); 8574 job->job_private = kfcio; 8575 8576 fctl_enque_job(port, job); 8577 fctl_jobwait(job); 8578 8579 rval = job->job_result; 8580 8581 fcio->fcio_errno = kfcio->fcio_errno; 8582 if (fp_fcio_copyout(fcio, data, mode)) { 8583 rval = EFAULT; 8584 } 8585 8586 kmem_free(kfcio->fcio_ibuf, kfcio->fcio_ilen); 8587 kmem_free(kfcio, sizeof (*kfcio)); 8588 fctl_dealloc_job(job); 8589 break; 8590 8591 case FCIO_GET_STATE: { 8592 la_wwn_t pwwn; 8593 uint32_t state; 8594 fc_remote_port_t *pd; 8595 fctl_ns_req_t *ns_cmd; 8596 8597 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8598 fcio->fcio_olen != sizeof (state) || 8599 (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 || 8600 (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { 8601 rval = EINVAL; 8602 break; 8603 } 8604 8605 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8606 rval = EFAULT; 8607 break; 8608 } 8609 fcio->fcio_errno = 0; 8610 8611 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8612 if (pd == NULL) { 8613 mutex_enter(&port->fp_mutex); 8614 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 8615 mutex_exit(&port->fp_mutex); 8616 job = fctl_alloc_job(JOB_PLOGI_ONE, 0, 8617 NULL, NULL, KM_SLEEP); 8618 8619 job->job_counter = 1; 8620 job->job_result = FC_SUCCESS; 8621 8622 ns_cmd = fctl_alloc_ns_cmd( 8623 sizeof (ns_req_gid_pn_t), 8624 sizeof (ns_resp_gid_pn_t), 8625 sizeof (ns_resp_gid_pn_t), 8626 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 8627 ASSERT(ns_cmd != NULL); 8628 8629 ns_cmd->ns_cmd_code = NS_GID_PN; 8630 ((ns_req_gid_pn_t *) 8631 (ns_cmd->ns_cmd_buf))->pwwn = pwwn; 8632 8633 ret = fp_ns_query(port, ns_cmd, job, 8634 1, KM_SLEEP); 8635 8636 if (ret != FC_SUCCESS || job->job_result != 8637 FC_SUCCESS) { 8638 if (ret != FC_SUCCESS) { 8639 fcio->fcio_errno = ret; 8640 } else { 8641 fcio->fcio_errno = 8642 job->job_result; 8643 } 8644 rval = EIO; 8645 } else { 8646 state = PORT_DEVICE_INVALID; 8647 } 8648 fctl_free_ns_cmd(ns_cmd); 8649 fctl_dealloc_job(job); 8650 } else { 8651 mutex_exit(&port->fp_mutex); 8652 fcio->fcio_errno = FC_BADWWN; 8653 rval = ENXIO; 8654 } 8655 } else { 8656 mutex_enter(&pd->pd_mutex); 8657 state = pd->pd_state; 8658 mutex_exit(&pd->pd_mutex); 8659 8660 fctl_release_remote_port(pd); 8661 } 8662 8663 if (!rval) { 8664 if (ddi_copyout((void *)&state, 8665 (void *)fcio->fcio_obuf, sizeof (state), 8666 mode)) { 8667 rval = EFAULT; 8668 } 8669 } 8670 if (fp_fcio_copyout(fcio, data, mode)) { 8671 rval = EFAULT; 8672 } 8673 break; 8674 } 8675 8676 case FCIO_DEV_REMOVE: { 8677 la_wwn_t pwwn; 8678 fc_portmap_t *changelist; 8679 fc_remote_port_t *pd; 8680 8681 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 8682 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8683 rval = EINVAL; 8684 break; 8685 } 8686 8687 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, sizeof (pwwn), mode)) { 8688 rval = EFAULT; 8689 break; 8690 } 8691 8692 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 8693 if (pd == NULL) { 8694 rval = ENXIO; 8695 fcio->fcio_errno = FC_BADWWN; 8696 if (fp_fcio_copyout(fcio, data, mode)) { 8697 rval = EFAULT; 8698 } 8699 break; 8700 } 8701 8702 mutex_enter(&pd->pd_mutex); 8703 if (pd->pd_ref_count > 1) { 8704 mutex_exit(&pd->pd_mutex); 8705 8706 rval = EBUSY; 8707 fcio->fcio_errno = FC_FAILURE; 8708 fctl_release_remote_port(pd); 8709 8710 if (fp_fcio_copyout(fcio, data, mode)) { 8711 rval = EFAULT; 8712 } 8713 break; 8714 } 8715 mutex_exit(&pd->pd_mutex); 8716 8717 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 8718 8719 fctl_copy_portmap(changelist, pd); 8720 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 8721 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 8722 8723 fctl_release_remote_port(pd); 8724 break; 8725 } 8726 8727 case FCIO_GET_FCODE_REV: { 8728 caddr_t fcode_rev; 8729 fc_fca_pm_t pm; 8730 8731 if (fcio->fcio_olen < FC_FCODE_REV_SIZE || 8732 fcio->fcio_xfer != FCIO_XFER_READ) { 8733 rval = EINVAL; 8734 break; 8735 } 8736 bzero((caddr_t)&pm, sizeof (pm)); 8737 8738 fcode_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8739 8740 pm.pm_cmd_flags = FC_FCA_PM_READ; 8741 pm.pm_cmd_code = FC_PORT_GET_FCODE_REV; 8742 pm.pm_data_len = fcio->fcio_olen; 8743 pm.pm_data_buf = fcode_rev; 8744 8745 ret = port->fp_fca_tran->fca_port_manage( 8746 port->fp_fca_handle, &pm); 8747 8748 if (ret == FC_SUCCESS) { 8749 if (ddi_copyout((void *)fcode_rev, 8750 (void *)fcio->fcio_obuf, 8751 fcio->fcio_olen, mode) == 0) { 8752 if (fp_fcio_copyout(fcio, data, mode)) { 8753 rval = EFAULT; 8754 } 8755 } else { 8756 rval = EFAULT; 8757 } 8758 } else { 8759 /* 8760 * check if buffer was not large enough to obtain 8761 * FCODE version. 8762 */ 8763 if (pm.pm_data_len > fcio->fcio_olen) { 8764 rval = ENOMEM; 8765 } else { 8766 rval = EIO; 8767 } 8768 fcio->fcio_errno = ret; 8769 if (fp_fcio_copyout(fcio, data, mode)) { 8770 rval = EFAULT; 8771 } 8772 } 8773 kmem_free(fcode_rev, fcio->fcio_olen); 8774 break; 8775 } 8776 8777 case FCIO_GET_FW_REV: { 8778 caddr_t fw_rev; 8779 fc_fca_pm_t pm; 8780 8781 if (fcio->fcio_olen < FC_FW_REV_SIZE || 8782 fcio->fcio_xfer != FCIO_XFER_READ) { 8783 rval = EINVAL; 8784 break; 8785 } 8786 bzero((caddr_t)&pm, sizeof (pm)); 8787 8788 fw_rev = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 8789 8790 pm.pm_cmd_flags = FC_FCA_PM_READ; 8791 pm.pm_cmd_code = FC_PORT_GET_FW_REV; 8792 pm.pm_data_len = fcio->fcio_olen; 8793 pm.pm_data_buf = fw_rev; 8794 8795 ret = port->fp_fca_tran->fca_port_manage( 8796 port->fp_fca_handle, &pm); 8797 8798 if (ret == FC_SUCCESS) { 8799 if (ddi_copyout((void *)fw_rev, 8800 (void *)fcio->fcio_obuf, 8801 fcio->fcio_olen, mode) == 0) { 8802 if (fp_fcio_copyout(fcio, data, mode)) { 8803 rval = EFAULT; 8804 } 8805 } else { 8806 rval = EFAULT; 8807 } 8808 } else { 8809 if (fp_fcio_copyout(fcio, data, mode)) { 8810 rval = EFAULT; 8811 } 8812 rval = EIO; 8813 } 8814 kmem_free(fw_rev, fcio->fcio_olen); 8815 break; 8816 } 8817 8818 case FCIO_GET_DUMP_SIZE: { 8819 uint32_t dump_size; 8820 fc_fca_pm_t pm; 8821 8822 if (fcio->fcio_olen != sizeof (dump_size) || 8823 fcio->fcio_xfer != FCIO_XFER_READ) { 8824 rval = EINVAL; 8825 break; 8826 } 8827 bzero((caddr_t)&pm, sizeof (pm)); 8828 pm.pm_cmd_flags = FC_FCA_PM_READ; 8829 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8830 pm.pm_data_len = sizeof (dump_size); 8831 pm.pm_data_buf = (caddr_t)&dump_size; 8832 8833 ret = port->fp_fca_tran->fca_port_manage( 8834 port->fp_fca_handle, &pm); 8835 8836 if (ret == FC_SUCCESS) { 8837 if (ddi_copyout((void *)&dump_size, 8838 (void *)fcio->fcio_obuf, sizeof (dump_size), 8839 mode) == 0) { 8840 if (fp_fcio_copyout(fcio, data, mode)) { 8841 rval = EFAULT; 8842 } 8843 } else { 8844 rval = EFAULT; 8845 } 8846 } else { 8847 fcio->fcio_errno = ret; 8848 rval = EIO; 8849 if (fp_fcio_copyout(fcio, data, mode)) { 8850 rval = EFAULT; 8851 } 8852 } 8853 break; 8854 } 8855 8856 case FCIO_DOWNLOAD_FW: { 8857 caddr_t firmware; 8858 fc_fca_pm_t pm; 8859 8860 if (fcio->fcio_ilen <= 0 || 8861 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8862 rval = EINVAL; 8863 break; 8864 } 8865 8866 firmware = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8867 if (ddi_copyin(fcio->fcio_ibuf, firmware, 8868 fcio->fcio_ilen, mode)) { 8869 rval = EFAULT; 8870 kmem_free(firmware, fcio->fcio_ilen); 8871 break; 8872 } 8873 8874 bzero((caddr_t)&pm, sizeof (pm)); 8875 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8876 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW; 8877 pm.pm_data_len = fcio->fcio_ilen; 8878 pm.pm_data_buf = firmware; 8879 8880 ret = port->fp_fca_tran->fca_port_manage( 8881 port->fp_fca_handle, &pm); 8882 8883 kmem_free(firmware, fcio->fcio_ilen); 8884 8885 if (ret != FC_SUCCESS) { 8886 fcio->fcio_errno = ret; 8887 rval = EIO; 8888 if (fp_fcio_copyout(fcio, data, mode)) { 8889 rval = EFAULT; 8890 } 8891 } 8892 break; 8893 } 8894 8895 case FCIO_DOWNLOAD_FCODE: { 8896 caddr_t fcode; 8897 fc_fca_pm_t pm; 8898 8899 if (fcio->fcio_ilen <= 0 || 8900 fcio->fcio_xfer != FCIO_XFER_WRITE) { 8901 rval = EINVAL; 8902 break; 8903 } 8904 8905 fcode = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 8906 if (ddi_copyin(fcio->fcio_ibuf, fcode, 8907 fcio->fcio_ilen, mode)) { 8908 rval = EFAULT; 8909 kmem_free(fcode, fcio->fcio_ilen); 8910 break; 8911 } 8912 8913 bzero((caddr_t)&pm, sizeof (pm)); 8914 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 8915 pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE; 8916 pm.pm_data_len = fcio->fcio_ilen; 8917 pm.pm_data_buf = fcode; 8918 8919 ret = port->fp_fca_tran->fca_port_manage( 8920 port->fp_fca_handle, &pm); 8921 8922 kmem_free(fcode, fcio->fcio_ilen); 8923 8924 if (ret != FC_SUCCESS) { 8925 fcio->fcio_errno = ret; 8926 rval = EIO; 8927 if (fp_fcio_copyout(fcio, data, mode)) { 8928 rval = EFAULT; 8929 } 8930 } 8931 break; 8932 } 8933 8934 case FCIO_FORCE_DUMP: 8935 ret = port->fp_fca_tran->fca_reset( 8936 port->fp_fca_handle, FC_FCA_CORE); 8937 8938 if (ret != FC_SUCCESS) { 8939 fcio->fcio_errno = ret; 8940 rval = EIO; 8941 if (fp_fcio_copyout(fcio, data, mode)) { 8942 rval = EFAULT; 8943 } 8944 } 8945 break; 8946 8947 case FCIO_GET_DUMP: { 8948 caddr_t dump; 8949 uint32_t dump_size; 8950 fc_fca_pm_t pm; 8951 8952 if (fcio->fcio_xfer != FCIO_XFER_READ) { 8953 rval = EINVAL; 8954 break; 8955 } 8956 bzero((caddr_t)&pm, sizeof (pm)); 8957 8958 pm.pm_cmd_flags = FC_FCA_PM_READ; 8959 pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; 8960 pm.pm_data_len = sizeof (dump_size); 8961 pm.pm_data_buf = (caddr_t)&dump_size; 8962 8963 ret = port->fp_fca_tran->fca_port_manage( 8964 port->fp_fca_handle, &pm); 8965 8966 if (ret != FC_SUCCESS) { 8967 fcio->fcio_errno = ret; 8968 rval = EIO; 8969 if (fp_fcio_copyout(fcio, data, mode)) { 8970 rval = EFAULT; 8971 } 8972 break; 8973 } 8974 if (fcio->fcio_olen != dump_size) { 8975 fcio->fcio_errno = FC_NOMEM; 8976 rval = EINVAL; 8977 if (fp_fcio_copyout(fcio, data, mode)) { 8978 rval = EFAULT; 8979 } 8980 break; 8981 } 8982 8983 dump = kmem_zalloc(dump_size, KM_SLEEP); 8984 8985 bzero((caddr_t)&pm, sizeof (pm)); 8986 pm.pm_cmd_flags = FC_FCA_PM_READ; 8987 pm.pm_cmd_code = FC_PORT_GET_DUMP; 8988 pm.pm_data_len = dump_size; 8989 pm.pm_data_buf = dump; 8990 8991 ret = port->fp_fca_tran->fca_port_manage( 8992 port->fp_fca_handle, &pm); 8993 8994 if (ret == FC_SUCCESS) { 8995 if (ddi_copyout((void *)dump, (void *)fcio->fcio_obuf, 8996 dump_size, mode) == 0) { 8997 if (fp_fcio_copyout(fcio, data, mode)) { 8998 rval = EFAULT; 8999 } 9000 } else { 9001 rval = EFAULT; 9002 } 9003 } else { 9004 fcio->fcio_errno = ret; 9005 rval = EIO; 9006 if (fp_fcio_copyout(fcio, data, mode)) { 9007 rval = EFAULT; 9008 } 9009 } 9010 kmem_free(dump, dump_size); 9011 break; 9012 } 9013 9014 case FCIO_GET_TOPOLOGY: { 9015 uint32_t user_topology; 9016 9017 if (fcio->fcio_xfer != FCIO_XFER_READ || 9018 fcio->fcio_olen != sizeof (user_topology)) { 9019 rval = EINVAL; 9020 break; 9021 } 9022 9023 mutex_enter(&port->fp_mutex); 9024 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 9025 user_topology = FC_TOP_UNKNOWN; 9026 } else { 9027 user_topology = port->fp_topology; 9028 } 9029 mutex_exit(&port->fp_mutex); 9030 9031 if (ddi_copyout((void *)&user_topology, 9032 (void *)fcio->fcio_obuf, sizeof (user_topology), 9033 mode)) { 9034 rval = EFAULT; 9035 } 9036 break; 9037 } 9038 9039 case FCIO_RESET_LINK: { 9040 la_wwn_t pwwn; 9041 9042 /* 9043 * Look at the output buffer field; if this field has zero 9044 * bytes then attempt to reset the local link/loop. If the 9045 * fcio_ibuf field points to a WWN, see if it's an NL_Port, 9046 * and if yes, determine the LFA and reset the remote LIP 9047 * by LINIT ELS. 9048 */ 9049 9050 if (fcio->fcio_xfer != FCIO_XFER_WRITE || 9051 fcio->fcio_ilen != sizeof (pwwn)) { 9052 rval = EINVAL; 9053 break; 9054 } 9055 9056 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9057 sizeof (pwwn), mode)) { 9058 rval = EFAULT; 9059 break; 9060 } 9061 9062 mutex_enter(&port->fp_mutex); 9063 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 9064 mutex_exit(&port->fp_mutex); 9065 break; 9066 } 9067 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 9068 mutex_exit(&port->fp_mutex); 9069 9070 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, KM_SLEEP); 9071 if (job == NULL) { 9072 rval = ENOMEM; 9073 break; 9074 } 9075 job->job_counter = 1; 9076 job->job_private = (void *)&pwwn; 9077 9078 fctl_enque_job(port, job); 9079 fctl_jobwait(job); 9080 9081 mutex_enter(&port->fp_mutex); 9082 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 9083 mutex_exit(&port->fp_mutex); 9084 9085 if (job->job_result != FC_SUCCESS) { 9086 fcio->fcio_errno = job->job_result; 9087 rval = EIO; 9088 if (fp_fcio_copyout(fcio, data, mode)) { 9089 rval = EFAULT; 9090 } 9091 } 9092 fctl_dealloc_job(job); 9093 break; 9094 } 9095 9096 case FCIO_RESET_HARD: 9097 ret = port->fp_fca_tran->fca_reset( 9098 port->fp_fca_handle, FC_FCA_RESET); 9099 if (ret != FC_SUCCESS) { 9100 fcio->fcio_errno = ret; 9101 rval = EIO; 9102 if (fp_fcio_copyout(fcio, data, mode)) { 9103 rval = EFAULT; 9104 } 9105 } 9106 break; 9107 9108 case FCIO_RESET_HARD_CORE: 9109 ret = port->fp_fca_tran->fca_reset( 9110 port->fp_fca_handle, FC_FCA_RESET_CORE); 9111 if (ret != FC_SUCCESS) { 9112 rval = EIO; 9113 fcio->fcio_errno = ret; 9114 if (fp_fcio_copyout(fcio, data, mode)) { 9115 rval = EFAULT; 9116 } 9117 } 9118 break; 9119 9120 case FCIO_DIAG: { 9121 fc_fca_pm_t pm; 9122 9123 bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); 9124 9125 /* Validate user buffer from ioctl call. */ 9126 if (((fcio->fcio_ilen > 0) && (fcio->fcio_ibuf == NULL)) || 9127 ((fcio->fcio_ilen <= 0) && (fcio->fcio_ibuf != NULL)) || 9128 ((fcio->fcio_alen > 0) && (fcio->fcio_abuf == NULL)) || 9129 ((fcio->fcio_alen <= 0) && (fcio->fcio_abuf != NULL)) || 9130 ((fcio->fcio_olen > 0) && (fcio->fcio_obuf == NULL)) || 9131 ((fcio->fcio_olen <= 0) && (fcio->fcio_obuf != NULL))) { 9132 rval = EFAULT; 9133 break; 9134 } 9135 9136 if ((pm.pm_cmd_len = fcio->fcio_ilen) > 0) { 9137 pm.pm_cmd_buf = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 9138 if (ddi_copyin(fcio->fcio_ibuf, pm.pm_cmd_buf, 9139 fcio->fcio_ilen, mode)) { 9140 rval = EFAULT; 9141 goto fp_fcio_diag_cleanup; 9142 } 9143 } 9144 9145 if ((pm.pm_data_len = fcio->fcio_alen) > 0) { 9146 pm.pm_data_buf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP); 9147 if (ddi_copyin(fcio->fcio_abuf, pm.pm_data_buf, 9148 fcio->fcio_alen, mode)) { 9149 rval = EFAULT; 9150 goto fp_fcio_diag_cleanup; 9151 } 9152 } 9153 9154 if ((pm.pm_stat_len = fcio->fcio_olen) > 0) { 9155 pm.pm_stat_buf = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 9156 } 9157 9158 pm.pm_cmd_code = FC_PORT_DIAG; 9159 pm.pm_cmd_flags = fcio->fcio_cmd_flags; 9160 9161 ret = port->fp_fca_tran->fca_port_manage( 9162 port->fp_fca_handle, &pm); 9163 9164 if (ret != FC_SUCCESS) { 9165 if (ret == FC_INVALID_REQUEST) { 9166 rval = ENOTTY; 9167 } else { 9168 rval = EIO; 9169 } 9170 9171 fcio->fcio_errno = ret; 9172 if (fp_fcio_copyout(fcio, data, mode)) { 9173 rval = EFAULT; 9174 } 9175 goto fp_fcio_diag_cleanup; 9176 } 9177 9178 /* 9179 * pm_stat_len will contain the number of status bytes 9180 * an FCA driver requires to return the complete status 9181 * of the requested diag operation. If the user buffer 9182 * is not large enough to hold the entire status, We 9183 * copy only the portion of data the fits in the buffer and 9184 * return a ENOMEM to the user application. 9185 */ 9186 if (pm.pm_stat_len > fcio->fcio_olen) { 9187 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 9188 "fp:FCIO_DIAG:status buffer too small\n"); 9189 9190 rval = ENOMEM; 9191 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9192 fcio->fcio_olen, mode)) { 9193 rval = EFAULT; 9194 goto fp_fcio_diag_cleanup; 9195 } 9196 } else { 9197 /* 9198 * Copy only data pm_stat_len bytes of data 9199 */ 9200 if (ddi_copyout(pm.pm_stat_buf, fcio->fcio_obuf, 9201 pm.pm_stat_len, mode)) { 9202 rval = EFAULT; 9203 goto fp_fcio_diag_cleanup; 9204 } 9205 } 9206 9207 if (fp_fcio_copyout(fcio, data, mode)) { 9208 rval = EFAULT; 9209 } 9210 9211 fp_fcio_diag_cleanup: 9212 if (pm.pm_cmd_buf != NULL) { 9213 kmem_free(pm.pm_cmd_buf, fcio->fcio_ilen); 9214 } 9215 if (pm.pm_data_buf != NULL) { 9216 kmem_free(pm.pm_data_buf, fcio->fcio_alen); 9217 } 9218 if (pm.pm_stat_buf != NULL) { 9219 kmem_free(pm.pm_stat_buf, fcio->fcio_olen); 9220 } 9221 9222 break; 9223 } 9224 9225 case FCIO_GET_NODE_ID: { 9226 /* validate parameters */ 9227 if (fcio->fcio_xfer != FCIO_XFER_READ || 9228 fcio->fcio_olen < sizeof (fc_rnid_t)) { 9229 rval = EINVAL; 9230 break; 9231 } 9232 9233 rval = fp_get_rnid(port, data, mode, fcio); 9234 9235 /* ioctl handling is over */ 9236 break; 9237 } 9238 9239 case FCIO_SEND_NODE_ID: { 9240 la_wwn_t pwwn; 9241 9242 /* validate parameters */ 9243 if (fcio->fcio_ilen != sizeof (la_wwn_t) || 9244 fcio->fcio_xfer != FCIO_XFER_READ) { 9245 rval = EINVAL; 9246 break; 9247 } 9248 9249 if (ddi_copyin(fcio->fcio_ibuf, &pwwn, 9250 sizeof (la_wwn_t), mode)) { 9251 rval = EFAULT; 9252 break; 9253 } 9254 9255 rval = fp_send_rnid(port, data, mode, fcio, &pwwn); 9256 9257 /* ioctl handling is over */ 9258 break; 9259 } 9260 9261 case FCIO_SET_NODE_ID: { 9262 if (fcio->fcio_ilen != sizeof (fc_rnid_t) || 9263 (fcio->fcio_xfer != FCIO_XFER_WRITE)) { 9264 rval = EINVAL; 9265 break; 9266 } 9267 9268 rval = fp_set_rnid(port, data, mode, fcio); 9269 break; 9270 } 9271 9272 case FCIO_LINK_STATUS: { 9273 fc_portid_t rls_req; 9274 fc_rls_acc_t *rls_acc; 9275 fc_fca_pm_t pm; 9276 uint32_t dest, src_id; 9277 fp_cmd_t *cmd; 9278 fc_remote_port_t *pd; 9279 uchar_t pd_flags; 9280 9281 /* validate parameters */ 9282 if (fcio->fcio_ilen != sizeof (fc_portid_t) || 9283 fcio->fcio_olen != sizeof (fc_rls_acc_t) || 9284 fcio->fcio_xfer != FCIO_XFER_RW) { 9285 rval = EINVAL; 9286 break; 9287 } 9288 9289 if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && 9290 (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { 9291 rval = EINVAL; 9292 break; 9293 } 9294 9295 if (ddi_copyin((void *)fcio->fcio_ibuf, (void *)&rls_req, 9296 sizeof (fc_portid_t), mode)) { 9297 rval = EFAULT; 9298 break; 9299 } 9300 9301 9302 /* Determine the destination of the RLS frame */ 9303 if (fcio->fcio_cmd_flags == FCIO_CFLAGS_RLS_DEST_FPORT) { 9304 dest = FS_FABRIC_F_PORT; 9305 } else { 9306 dest = rls_req.port_id; 9307 } 9308 9309 mutex_enter(&port->fp_mutex); 9310 src_id = port->fp_port_id.port_id; 9311 mutex_exit(&port->fp_mutex); 9312 9313 /* If dest is zero OR same as FCA ID, then use port_manage() */ 9314 if (dest == 0 || dest == src_id) { 9315 9316 /* Allocate memory for link error status block */ 9317 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9318 ASSERT(rls_acc != NULL); 9319 9320 /* Prepare the port management structure */ 9321 bzero((caddr_t)&pm, sizeof (pm)); 9322 9323 pm.pm_cmd_flags = FC_FCA_PM_READ; 9324 pm.pm_cmd_code = FC_PORT_RLS; 9325 pm.pm_data_len = sizeof (*rls_acc); 9326 pm.pm_data_buf = (caddr_t)rls_acc; 9327 9328 /* Get the adapter's link error status block */ 9329 ret = port->fp_fca_tran->fca_port_manage( 9330 port->fp_fca_handle, &pm); 9331 9332 if (ret == FC_SUCCESS) { 9333 /* xfer link status block to userland */ 9334 if (ddi_copyout((void *)rls_acc, 9335 (void *)fcio->fcio_obuf, 9336 sizeof (*rls_acc), mode) == 0) { 9337 if (fp_fcio_copyout(fcio, data, 9338 mode)) { 9339 rval = EFAULT; 9340 } 9341 } else { 9342 rval = EFAULT; 9343 } 9344 } else { 9345 rval = EIO; 9346 fcio->fcio_errno = ret; 9347 if (fp_fcio_copyout(fcio, data, mode)) { 9348 rval = EFAULT; 9349 } 9350 } 9351 9352 kmem_free(rls_acc, sizeof (*rls_acc)); 9353 9354 /* ioctl handling is over */ 9355 break; 9356 } 9357 9358 /* 9359 * Send RLS to the destination port. 9360 * Having RLS frame destination is as FPORT is not yet 9361 * supported and will be implemented in future, if needed. 9362 * Following call to get "pd" will fail if dest is FPORT 9363 */ 9364 pd = fctl_hold_remote_port_by_did(port, dest); 9365 if (pd == NULL) { 9366 fcio->fcio_errno = FC_BADOBJECT; 9367 rval = ENXIO; 9368 if (fp_fcio_copyout(fcio, data, mode)) { 9369 rval = EFAULT; 9370 } 9371 break; 9372 } 9373 9374 mutex_enter(&pd->pd_mutex); 9375 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 9376 mutex_exit(&pd->pd_mutex); 9377 fctl_release_remote_port(pd); 9378 9379 fcio->fcio_errno = FC_LOGINREQ; 9380 rval = EINVAL; 9381 if (fp_fcio_copyout(fcio, data, mode)) { 9382 rval = EFAULT; 9383 } 9384 break; 9385 } 9386 ASSERT(pd->pd_login_count >= 1); 9387 mutex_exit(&pd->pd_mutex); 9388 9389 /* 9390 * Allocate job structure and set job_code as DUMMY, 9391 * because we will not go through the job thread. 9392 * Instead fp_sendcmd() is called directly here. 9393 */ 9394 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9395 NULL, NULL, KM_SLEEP); 9396 ASSERT(job != NULL); 9397 9398 job->job_counter = 1; 9399 9400 cmd = fp_alloc_pkt(port, sizeof (la_els_rls_t), 9401 sizeof (la_els_rls_acc_t), KM_SLEEP, pd); 9402 if (cmd == NULL) { 9403 fcio->fcio_errno = FC_NOMEM; 9404 rval = ENOMEM; 9405 9406 fctl_release_remote_port(pd); 9407 9408 fctl_dealloc_job(job); 9409 if (fp_fcio_copyout(fcio, data, mode)) { 9410 rval = EFAULT; 9411 } 9412 break; 9413 } 9414 9415 /* Allocate memory for link error status block */ 9416 rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP); 9417 9418 mutex_enter(&port->fp_mutex); 9419 mutex_enter(&pd->pd_mutex); 9420 9421 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9422 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9423 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9424 cmd->cmd_retry_count = 1; 9425 cmd->cmd_ulp_pkt = NULL; 9426 9427 fp_rls_init(cmd, job); 9428 9429 job->job_private = (void *)rls_acc; 9430 9431 pd_flags = pd->pd_flags; 9432 pd->pd_flags = PD_ELS_IN_PROGRESS; 9433 9434 mutex_exit(&pd->pd_mutex); 9435 mutex_exit(&port->fp_mutex); 9436 9437 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9438 fctl_jobwait(job); 9439 9440 fcio->fcio_errno = job->job_result; 9441 if (job->job_result == FC_SUCCESS) { 9442 ASSERT(pd != NULL); 9443 /* 9444 * link error status block is now available. 9445 * Copy it to userland 9446 */ 9447 ASSERT(job->job_private == (void *)rls_acc); 9448 if (ddi_copyout((void *)rls_acc, 9449 (void *)fcio->fcio_obuf, 9450 sizeof (*rls_acc), mode) == 0) { 9451 if (fp_fcio_copyout(fcio, data, 9452 mode)) { 9453 rval = EFAULT; 9454 } 9455 } else { 9456 rval = EFAULT; 9457 } 9458 } else { 9459 rval = EIO; 9460 } 9461 } else { 9462 rval = EIO; 9463 fp_free_pkt(cmd); 9464 } 9465 9466 if (rval) { 9467 mutex_enter(&port->fp_mutex); 9468 mutex_enter(&pd->pd_mutex); 9469 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 9470 pd->pd_flags = pd_flags; 9471 } 9472 mutex_exit(&pd->pd_mutex); 9473 mutex_exit(&port->fp_mutex); 9474 } 9475 9476 fctl_release_remote_port(pd); 9477 fctl_dealloc_job(job); 9478 kmem_free(rls_acc, sizeof (*rls_acc)); 9479 9480 if (fp_fcio_copyout(fcio, data, mode)) { 9481 rval = EFAULT; 9482 } 9483 break; 9484 } 9485 9486 case FCIO_NS: { 9487 fc_ns_cmd_t *ns_req; 9488 fc_ns_cmd32_t *ns_req32; 9489 fctl_ns_req_t *ns_cmd; 9490 9491 if (use32 == B_TRUE) { 9492 if (fcio->fcio_ilen != sizeof (*ns_req32)) { 9493 rval = EINVAL; 9494 break; 9495 } 9496 9497 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9498 ns_req32 = kmem_zalloc(sizeof (*ns_req32), KM_SLEEP); 9499 9500 if (ddi_copyin(fcio->fcio_ibuf, ns_req32, 9501 sizeof (*ns_req32), mode)) { 9502 rval = EFAULT; 9503 kmem_free(ns_req, sizeof (*ns_req)); 9504 kmem_free(ns_req32, sizeof (*ns_req32)); 9505 break; 9506 } 9507 9508 ns_req->ns_flags = ns_req32->ns_flags; 9509 ns_req->ns_cmd = ns_req32->ns_cmd; 9510 ns_req->ns_req_len = ns_req32->ns_req_len; 9511 ns_req->ns_req_payload = ns_req32->ns_req_payload; 9512 ns_req->ns_resp_len = ns_req32->ns_resp_len; 9513 ns_req->ns_resp_payload = ns_req32->ns_resp_payload; 9514 ns_req->ns_fctl_private = ns_req32->ns_fctl_private; 9515 ns_req->ns_resp_hdr = ns_req32->ns_resp_hdr; 9516 9517 kmem_free(ns_req32, sizeof (*ns_req32)); 9518 } else { 9519 if (fcio->fcio_ilen != sizeof (*ns_req)) { 9520 rval = EINVAL; 9521 break; 9522 } 9523 9524 ns_req = kmem_zalloc(sizeof (*ns_req), KM_SLEEP); 9525 9526 if (ddi_copyin(fcio->fcio_ibuf, ns_req, 9527 sizeof (fc_ns_cmd_t), mode)) { 9528 rval = EFAULT; 9529 kmem_free(ns_req, sizeof (*ns_req)); 9530 break; 9531 } 9532 } 9533 9534 if (ns_req->ns_req_len <= 0) { 9535 rval = EINVAL; 9536 kmem_free(ns_req, sizeof (*ns_req)); 9537 break; 9538 } 9539 9540 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 9541 ASSERT(job != NULL); 9542 9543 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 9544 ns_req->ns_resp_len, ns_req->ns_resp_len, 9545 FCTL_NS_FILL_NS_MAP, KM_SLEEP); 9546 ASSERT(ns_cmd != NULL); 9547 ns_cmd->ns_cmd_code = ns_req->ns_cmd; 9548 9549 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 9550 ns_cmd->ns_gan_max = 1; 9551 ns_cmd->ns_gan_index = 0; 9552 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 9553 } 9554 9555 if (ddi_copyin(ns_req->ns_req_payload, 9556 ns_cmd->ns_cmd_buf, ns_req->ns_req_len, mode)) { 9557 rval = EFAULT; 9558 fctl_free_ns_cmd(ns_cmd); 9559 fctl_dealloc_job(job); 9560 kmem_free(ns_req, sizeof (*ns_req)); 9561 break; 9562 } 9563 9564 job->job_private = (void *)ns_cmd; 9565 fctl_enque_job(port, job); 9566 fctl_jobwait(job); 9567 rval = job->job_result; 9568 9569 if (rval == FC_SUCCESS) { 9570 if (ns_req->ns_resp_len) { 9571 if (ddi_copyout(ns_cmd->ns_data_buf, 9572 ns_req->ns_resp_payload, 9573 ns_cmd->ns_data_len, mode)) { 9574 rval = EFAULT; 9575 fctl_free_ns_cmd(ns_cmd); 9576 fctl_dealloc_job(job); 9577 kmem_free(ns_req, sizeof (*ns_req)); 9578 break; 9579 } 9580 } 9581 } else { 9582 rval = EIO; 9583 } 9584 ns_req->ns_resp_hdr = ns_cmd->ns_resp_hdr; 9585 fctl_free_ns_cmd(ns_cmd); 9586 fctl_dealloc_job(job); 9587 kmem_free(ns_req, sizeof (*ns_req)); 9588 9589 if (fp_fcio_copyout(fcio, data, mode)) { 9590 rval = EFAULT; 9591 } 9592 break; 9593 } 9594 9595 default: 9596 rval = ENOTTY; 9597 break; 9598 } 9599 9600 /* 9601 * If set, reset the EXCL busy bit to 9602 * receive other exclusive access commands 9603 */ 9604 mutex_enter(&port->fp_mutex); 9605 if (port->fp_flag & FP_EXCL_BUSY) { 9606 port->fp_flag &= ~FP_EXCL_BUSY; 9607 } 9608 mutex_exit(&port->fp_mutex); 9609 9610 return (rval); 9611 } 9612 9613 9614 /* 9615 * This function assumes that the response length 9616 * is same regardless of data model (LP32 or LP64) 9617 * which is true for all the ioctls currently 9618 * supported. 9619 */ 9620 static int 9621 fp_copyout(void *from, void *to, size_t len, int mode) 9622 { 9623 return (ddi_copyout(from, to, len, mode)); 9624 } 9625 9626 /* 9627 * This function does the set rnid 9628 */ 9629 static int 9630 fp_set_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9631 { 9632 int rval = 0; 9633 fc_rnid_t *rnid; 9634 fc_fca_pm_t pm; 9635 9636 /* Allocate memory for node id block */ 9637 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9638 9639 if (ddi_copyin(fcio->fcio_ibuf, rnid, sizeof (fc_rnid_t), mode)) { 9640 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", EFAULT); 9641 kmem_free(rnid, sizeof (fc_rnid_t)); 9642 return (EFAULT); 9643 } 9644 9645 /* Prepare the port management structure */ 9646 bzero((caddr_t)&pm, sizeof (pm)); 9647 9648 pm.pm_cmd_flags = FC_FCA_PM_WRITE; 9649 pm.pm_cmd_code = FC_PORT_SET_NODE_ID; 9650 pm.pm_data_len = sizeof (*rnid); 9651 pm.pm_data_buf = (caddr_t)rnid; 9652 9653 /* Get the adapter's node data */ 9654 rval = port->fp_fca_tran->fca_port_manage( 9655 port->fp_fca_handle, &pm); 9656 9657 if (rval != FC_SUCCESS) { 9658 fcio->fcio_errno = rval; 9659 rval = EIO; 9660 if (fp_fcio_copyout(fcio, data, mode)) { 9661 rval = EFAULT; 9662 } 9663 } else { 9664 mutex_enter(&port->fp_mutex); 9665 /* copy to the port structure */ 9666 bcopy(rnid, &port->fp_rnid_params, 9667 sizeof (port->fp_rnid_params)); 9668 mutex_exit(&port->fp_mutex); 9669 } 9670 9671 kmem_free(rnid, sizeof (fc_rnid_t)); 9672 9673 if (rval != FC_SUCCESS) { 9674 FP_TRACE(FP_NHEAD1(3, 0), "fp_set_rnid: failed = %d", rval); 9675 } 9676 9677 return (rval); 9678 } 9679 9680 /* 9681 * This function does the local pwwn get rnid 9682 */ 9683 static int 9684 fp_get_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio) 9685 { 9686 fc_rnid_t *rnid; 9687 fc_fca_pm_t pm; 9688 int rval = 0; 9689 uint32_t ret; 9690 9691 /* Allocate memory for rnid data block */ 9692 rnid = kmem_zalloc(sizeof (fc_rnid_t), KM_SLEEP); 9693 9694 mutex_enter(&port->fp_mutex); 9695 if (port->fp_rnid_init == 1) { 9696 bcopy(&port->fp_rnid_params, rnid, sizeof (fc_rnid_t)); 9697 mutex_exit(&port->fp_mutex); 9698 /* xfer node info to userland */ 9699 if (ddi_copyout((void *)rnid, (void *)fcio->fcio_obuf, 9700 sizeof (*rnid), mode) == 0) { 9701 if (fp_fcio_copyout(fcio, data, mode)) { 9702 rval = EFAULT; 9703 } 9704 } else { 9705 rval = EFAULT; 9706 } 9707 9708 kmem_free(rnid, sizeof (fc_rnid_t)); 9709 9710 if (rval != FC_SUCCESS) { 9711 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", 9712 rval); 9713 } 9714 9715 return (rval); 9716 } 9717 mutex_exit(&port->fp_mutex); 9718 9719 /* Prepare the port management structure */ 9720 bzero((caddr_t)&pm, sizeof (pm)); 9721 9722 pm.pm_cmd_flags = FC_FCA_PM_READ; 9723 pm.pm_cmd_code = FC_PORT_GET_NODE_ID; 9724 pm.pm_data_len = sizeof (fc_rnid_t); 9725 pm.pm_data_buf = (caddr_t)rnid; 9726 9727 /* Get the adapter's node data */ 9728 ret = port->fp_fca_tran->fca_port_manage( 9729 port->fp_fca_handle, 9730 &pm); 9731 9732 if (ret == FC_SUCCESS) { 9733 /* initialize in the port_info */ 9734 mutex_enter(&port->fp_mutex); 9735 port->fp_rnid_init = 1; 9736 bcopy(rnid, &port->fp_rnid_params, sizeof (*rnid)); 9737 mutex_exit(&port->fp_mutex); 9738 9739 /* xfer node info to userland */ 9740 if (ddi_copyout((void *)rnid, 9741 (void *)fcio->fcio_obuf, 9742 sizeof (*rnid), mode) == 0) { 9743 if (fp_fcio_copyout(fcio, data, 9744 mode)) { 9745 rval = EFAULT; 9746 } 9747 } else { 9748 rval = EFAULT; 9749 } 9750 } else { 9751 rval = EIO; 9752 fcio->fcio_errno = ret; 9753 if (fp_fcio_copyout(fcio, data, mode)) { 9754 rval = EFAULT; 9755 } 9756 } 9757 9758 kmem_free(rnid, sizeof (fc_rnid_t)); 9759 9760 if (rval != FC_SUCCESS) { 9761 FP_TRACE(FP_NHEAD1(3, 0), "fp_get_rnid: failed = %d", rval); 9762 } 9763 9764 return (rval); 9765 } 9766 9767 static int 9768 fp_send_rnid(fc_local_port_t *port, intptr_t data, int mode, fcio_t *fcio, 9769 la_wwn_t *pwwn) 9770 { 9771 int rval = 0; 9772 fc_remote_port_t *pd; 9773 fp_cmd_t *cmd; 9774 job_request_t *job; 9775 la_els_rnid_acc_t *rnid_acc; 9776 9777 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 9778 if (pd == NULL) { 9779 /* 9780 * We can safely assume that the destination port 9781 * is logged in. Either the user land will explicitly 9782 * login before issuing RNID ioctl or the device would 9783 * have been configured, meaning already logged in. 9784 */ 9785 9786 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", ENXIO); 9787 9788 return (ENXIO); 9789 } 9790 /* 9791 * Allocate job structure and set job_code as DUMMY, 9792 * because we will not go thorugh the job thread. 9793 * Instead fp_sendcmd() is called directly here. 9794 */ 9795 job = fctl_alloc_job(JOB_DUMMY, JOB_TYPE_FP_ASYNC, 9796 NULL, NULL, KM_SLEEP); 9797 9798 ASSERT(job != NULL); 9799 9800 job->job_counter = 1; 9801 9802 cmd = fp_alloc_pkt(port, sizeof (la_els_rnid_t), 9803 sizeof (la_els_rnid_acc_t), KM_SLEEP, pd); 9804 if (cmd == NULL) { 9805 fcio->fcio_errno = FC_NOMEM; 9806 rval = ENOMEM; 9807 9808 fctl_dealloc_job(job); 9809 if (fp_fcio_copyout(fcio, data, mode)) { 9810 rval = EFAULT; 9811 } 9812 9813 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9814 9815 return (rval); 9816 } 9817 9818 /* Allocate memory for node id accept block */ 9819 rnid_acc = kmem_zalloc(sizeof (la_els_rnid_acc_t), KM_SLEEP); 9820 9821 mutex_enter(&port->fp_mutex); 9822 mutex_enter(&pd->pd_mutex); 9823 9824 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 9825 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 9826 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 9827 cmd->cmd_retry_count = 1; 9828 cmd->cmd_ulp_pkt = NULL; 9829 9830 fp_rnid_init(cmd, fcio->fcio_cmd_flags, job); 9831 9832 job->job_private = (void *)rnid_acc; 9833 9834 pd->pd_flags = PD_ELS_IN_PROGRESS; 9835 9836 mutex_exit(&pd->pd_mutex); 9837 mutex_exit(&port->fp_mutex); 9838 9839 if (fp_sendcmd(port, cmd, port->fp_fca_handle) == FC_SUCCESS) { 9840 fctl_jobwait(job); 9841 fcio->fcio_errno = job->job_result; 9842 if (job->job_result == FC_SUCCESS) { 9843 int rnid_cnt; 9844 ASSERT(pd != NULL); 9845 /* 9846 * node id block is now available. 9847 * Copy it to userland 9848 */ 9849 ASSERT(job->job_private == (void *)rnid_acc); 9850 9851 /* get the response length */ 9852 rnid_cnt = sizeof (ls_code_t) + sizeof (fc_rnid_hdr_t) + 9853 rnid_acc->hdr.cmn_len + 9854 rnid_acc->hdr.specific_len; 9855 9856 if (fcio->fcio_olen < rnid_cnt) { 9857 rval = EINVAL; 9858 } else if (ddi_copyout((void *)rnid_acc, 9859 (void *)fcio->fcio_obuf, 9860 rnid_cnt, mode) == 0) { 9861 if (fp_fcio_copyout(fcio, data, 9862 mode)) { 9863 rval = EFAULT; 9864 } 9865 } else { 9866 rval = EFAULT; 9867 } 9868 } else { 9869 rval = EIO; 9870 } 9871 } else { 9872 rval = EIO; 9873 if (pd) { 9874 mutex_enter(&pd->pd_mutex); 9875 pd->pd_flags = PD_IDLE; 9876 mutex_exit(&pd->pd_mutex); 9877 } 9878 fp_free_pkt(cmd); 9879 } 9880 9881 fctl_dealloc_job(job); 9882 kmem_free(rnid_acc, sizeof (la_els_rnid_acc_t)); 9883 9884 if (fp_fcio_copyout(fcio, data, mode)) { 9885 rval = EFAULT; 9886 } 9887 9888 if (rval != FC_SUCCESS) { 9889 FP_TRACE(FP_NHEAD1(3, 0), "fp_send_rnid: failed = %d", rval); 9890 } 9891 9892 return (rval); 9893 } 9894 9895 /* 9896 * Copy out to userland 9897 */ 9898 static int 9899 fp_fcio_copyout(fcio_t *fcio, intptr_t data, int mode) 9900 { 9901 int rval; 9902 9903 #ifdef _MULTI_DATAMODEL 9904 switch (ddi_model_convert_from(mode & FMODELS)) { 9905 case DDI_MODEL_ILP32: { 9906 struct fcio32 fcio32; 9907 9908 fcio32.fcio_xfer = fcio->fcio_xfer; 9909 fcio32.fcio_cmd = fcio->fcio_cmd; 9910 fcio32.fcio_flags = fcio->fcio_flags; 9911 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags; 9912 fcio32.fcio_ilen = fcio->fcio_ilen; 9913 fcio32.fcio_ibuf = 9914 (caddr32_t)(uintptr_t)fcio->fcio_ibuf; 9915 fcio32.fcio_olen = fcio->fcio_olen; 9916 fcio32.fcio_obuf = 9917 (caddr32_t)(uintptr_t)fcio->fcio_obuf; 9918 fcio32.fcio_alen = fcio->fcio_alen; 9919 fcio32.fcio_abuf = 9920 (caddr32_t)(uintptr_t)fcio->fcio_abuf; 9921 fcio32.fcio_errno = fcio->fcio_errno; 9922 9923 rval = ddi_copyout((void *)&fcio32, (void *)data, 9924 sizeof (struct fcio32), mode); 9925 break; 9926 } 9927 case DDI_MODEL_NONE: 9928 rval = ddi_copyout((void *)fcio, (void *)data, 9929 sizeof (fcio_t), mode); 9930 break; 9931 } 9932 #else 9933 rval = ddi_copyout((void *)fcio, (void *)data, sizeof (fcio_t), mode); 9934 #endif 9935 9936 return (rval); 9937 } 9938 9939 9940 static void 9941 fp_p2p_online(fc_local_port_t *port, job_request_t *job) 9942 { 9943 uint32_t listlen; 9944 fc_portmap_t *changelist; 9945 9946 ASSERT(MUTEX_HELD(&port->fp_mutex)); 9947 ASSERT(port->fp_topology == FC_TOP_PT_PT); 9948 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 9949 9950 listlen = 0; 9951 changelist = NULL; 9952 9953 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 9954 if (port->fp_statec_busy > 1) { 9955 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 9956 } 9957 } 9958 mutex_exit(&port->fp_mutex); 9959 9960 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 9961 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 9962 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 9963 listlen, listlen, KM_SLEEP); 9964 9965 mutex_enter(&port->fp_mutex); 9966 } else { 9967 ASSERT(changelist == NULL && listlen == 0); 9968 mutex_enter(&port->fp_mutex); 9969 if (--port->fp_statec_busy == 0) { 9970 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 9971 } 9972 } 9973 } 9974 9975 static int 9976 fp_fillout_p2pmap(fc_local_port_t *port, fcio_t *fcio, int mode) 9977 { 9978 int rval; 9979 int count; 9980 int index; 9981 int num_devices; 9982 fc_remote_node_t *node; 9983 fc_port_dev_t *devlist; 9984 struct pwwn_hash *head; 9985 fc_remote_port_t *pd; 9986 9987 ASSERT(MUTEX_HELD(&port->fp_mutex)); 9988 9989 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 9990 9991 devlist = kmem_zalloc(sizeof (fc_port_dev_t) * num_devices, KM_SLEEP); 9992 9993 for (count = index = 0; index < pwwn_table_size; index++) { 9994 head = &port->fp_pwwn_table[index]; 9995 pd = head->pwwn_head; 9996 while (pd != NULL) { 9997 mutex_enter(&pd->pd_mutex); 9998 if (pd->pd_state == PORT_DEVICE_INVALID) { 9999 mutex_exit(&pd->pd_mutex); 10000 pd = pd->pd_wwn_hnext; 10001 continue; 10002 } 10003 10004 devlist[count].dev_state = pd->pd_state; 10005 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10006 devlist[count].dev_did = pd->pd_port_id; 10007 devlist[count].dev_did.priv_lilp_posit = 10008 (uint8_t)(index & 0xff); 10009 bcopy((caddr_t)pd->pd_fc4types, 10010 (caddr_t)devlist[count].dev_type, 10011 sizeof (pd->pd_fc4types)); 10012 10013 bcopy((caddr_t)&pd->pd_port_name, 10014 (caddr_t)&devlist[count].dev_pwwn, 10015 sizeof (la_wwn_t)); 10016 10017 node = pd->pd_remote_nodep; 10018 mutex_exit(&pd->pd_mutex); 10019 10020 if (node) { 10021 mutex_enter(&node->fd_mutex); 10022 bcopy((caddr_t)&node->fd_node_name, 10023 (caddr_t)&devlist[count].dev_nwwn, 10024 sizeof (la_wwn_t)); 10025 mutex_exit(&node->fd_mutex); 10026 } 10027 count++; 10028 if (count >= num_devices) { 10029 goto found; 10030 } 10031 } 10032 } 10033 found: 10034 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10035 sizeof (count), mode)) { 10036 rval = FC_FAILURE; 10037 } else if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10038 sizeof (fc_port_dev_t) * num_devices, mode)) { 10039 rval = FC_FAILURE; 10040 } else { 10041 rval = FC_SUCCESS; 10042 } 10043 10044 kmem_free(devlist, sizeof (fc_port_dev_t) * num_devices); 10045 10046 return (rval); 10047 } 10048 10049 10050 /* 10051 * Handle Fabric ONLINE 10052 */ 10053 static void 10054 fp_fabric_online(fc_local_port_t *port, job_request_t *job) 10055 { 10056 int index; 10057 int rval; 10058 int dbg_count; 10059 int count = 0; 10060 char ww_name[17]; 10061 uint32_t d_id; 10062 uint32_t listlen; 10063 fctl_ns_req_t *ns_cmd; 10064 struct pwwn_hash *head; 10065 fc_remote_port_t *pd; 10066 fc_remote_port_t *npd; 10067 fc_portmap_t *changelist; 10068 10069 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10070 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 10071 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 10072 10073 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 10074 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 10075 0, KM_SLEEP); 10076 10077 ASSERT(ns_cmd != NULL); 10078 10079 ns_cmd->ns_cmd_code = NS_GID_PN; 10080 10081 /* 10082 * Check if orphans are showing up now 10083 */ 10084 if (port->fp_orphan_count) { 10085 fc_orphan_t *orp; 10086 fc_orphan_t *norp = NULL; 10087 fc_orphan_t *prev = NULL; 10088 10089 for (orp = port->fp_orphan_list; orp; orp = norp) { 10090 norp = orp->orp_next; 10091 mutex_exit(&port->fp_mutex); 10092 orp->orp_nscan++; 10093 10094 job->job_counter = 1; 10095 job->job_result = FC_SUCCESS; 10096 10097 ((ns_req_gid_pn_t *) 10098 (ns_cmd->ns_cmd_buf))->pwwn = orp->orp_pwwn; 10099 ((ns_resp_gid_pn_t *) 10100 ns_cmd->ns_data_buf)->pid.port_id = 0; 10101 ((ns_resp_gid_pn_t *) 10102 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 10103 10104 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10105 if (rval == FC_SUCCESS) { 10106 d_id = 10107 BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10108 pd = fp_create_remote_port_by_ns(port, 10109 d_id, KM_SLEEP); 10110 10111 if (pd != NULL) { 10112 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10113 10114 fp_printf(port, CE_WARN, FP_LOG_ONLY, 10115 0, NULL, "N_x Port with D_ID=%x," 10116 " PWWN=%s reappeared in fabric", 10117 d_id, ww_name); 10118 10119 mutex_enter(&port->fp_mutex); 10120 if (prev) { 10121 prev->orp_next = orp->orp_next; 10122 } else { 10123 ASSERT(orp == 10124 port->fp_orphan_list); 10125 port->fp_orphan_list = 10126 orp->orp_next; 10127 } 10128 port->fp_orphan_count--; 10129 mutex_exit(&port->fp_mutex); 10130 kmem_free(orp, sizeof (*orp)); 10131 count++; 10132 10133 mutex_enter(&pd->pd_mutex); 10134 pd->pd_flags = PD_ELS_MARK; 10135 10136 mutex_exit(&pd->pd_mutex); 10137 } else { 10138 prev = orp; 10139 } 10140 } else { 10141 if (orp->orp_nscan == FC_ORPHAN_SCAN_LIMIT) { 10142 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 10143 10144 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, 10145 NULL, 10146 " Port WWN %s removed from orphan" 10147 " list after %d scans", ww_name, 10148 orp->orp_nscan); 10149 10150 mutex_enter(&port->fp_mutex); 10151 if (prev) { 10152 prev->orp_next = orp->orp_next; 10153 } else { 10154 ASSERT(orp == 10155 port->fp_orphan_list); 10156 port->fp_orphan_list = 10157 orp->orp_next; 10158 } 10159 port->fp_orphan_count--; 10160 mutex_exit(&port->fp_mutex); 10161 10162 kmem_free(orp, sizeof (*orp)); 10163 } else { 10164 prev = orp; 10165 } 10166 } 10167 mutex_enter(&port->fp_mutex); 10168 } 10169 } 10170 10171 /* 10172 * Walk the Port WWN hash table, reestablish LOGIN 10173 * if a LOGIN is already performed on a particular 10174 * device; Any failure to LOGIN should mark the 10175 * port device OLD. 10176 */ 10177 for (index = 0; index < pwwn_table_size; index++) { 10178 head = &port->fp_pwwn_table[index]; 10179 npd = head->pwwn_head; 10180 10181 while ((pd = npd) != NULL) { 10182 la_wwn_t *pwwn; 10183 10184 npd = pd->pd_wwn_hnext; 10185 10186 /* 10187 * Don't count in the port devices that are new 10188 * unless the total number of devices visible 10189 * through this port is less than FP_MAX_DEVICES 10190 */ 10191 mutex_enter(&pd->pd_mutex); 10192 if (port->fp_dev_count >= FP_MAX_DEVICES || 10193 (port->fp_options & FP_TARGET_MODE)) { 10194 if (pd->pd_type == PORT_DEVICE_NEW || 10195 pd->pd_flags == PD_ELS_MARK || 10196 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10197 mutex_exit(&pd->pd_mutex); 10198 continue; 10199 } 10200 } else { 10201 if (pd->pd_flags == PD_ELS_MARK || 10202 pd->pd_recepient != PD_PLOGI_INITIATOR) { 10203 mutex_exit(&pd->pd_mutex); 10204 continue; 10205 } 10206 pd->pd_type = PORT_DEVICE_OLD; 10207 } 10208 count++; 10209 10210 /* 10211 * Consult with the name server about D_ID changes 10212 */ 10213 job->job_counter = 1; 10214 job->job_result = FC_SUCCESS; 10215 10216 ((ns_req_gid_pn_t *) 10217 (ns_cmd->ns_cmd_buf))->pwwn = pd->pd_port_name; 10218 ((ns_resp_gid_pn_t *) 10219 ns_cmd->ns_data_buf)->pid.port_id = 0; 10220 10221 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)-> 10222 pid.priv_lilp_posit = 0; 10223 10224 pwwn = &pd->pd_port_name; 10225 pd->pd_flags = PD_ELS_MARK; 10226 10227 mutex_exit(&pd->pd_mutex); 10228 mutex_exit(&port->fp_mutex); 10229 10230 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 10231 if (rval != FC_SUCCESS) { 10232 fc_wwn_to_str(pwwn, ww_name); 10233 10234 mutex_enter(&pd->pd_mutex); 10235 d_id = pd->pd_port_id.port_id; 10236 pd->pd_type = PORT_DEVICE_DELETE; 10237 mutex_exit(&pd->pd_mutex); 10238 10239 FP_TRACE(FP_NHEAD1(3, 0), 10240 "fp_fabric_online: PD " 10241 "disappeared; d_id=%x, PWWN=%s", 10242 d_id, ww_name); 10243 10244 FP_TRACE(FP_NHEAD2(9, 0), 10245 "N_x Port with D_ID=%x, PWWN=%s" 10246 " disappeared from fabric", d_id, 10247 ww_name); 10248 10249 mutex_enter(&port->fp_mutex); 10250 continue; 10251 } 10252 10253 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 10254 10255 mutex_enter(&port->fp_mutex); 10256 mutex_enter(&pd->pd_mutex); 10257 if (d_id != pd->pd_port_id.port_id) { 10258 fctl_delist_did_table(port, pd); 10259 fc_wwn_to_str(pwwn, ww_name); 10260 10261 FP_TRACE(FP_NHEAD2(9, 0), 10262 "D_ID of a device with PWWN %s changed." 10263 " New D_ID = %x, OLD D_ID = %x", ww_name, 10264 d_id, pd->pd_port_id.port_id); 10265 10266 pd->pd_port_id.port_id = BE_32(d_id); 10267 pd->pd_type = PORT_DEVICE_CHANGED; 10268 fctl_enlist_did_table(port, pd); 10269 } 10270 mutex_exit(&pd->pd_mutex); 10271 10272 } 10273 } 10274 10275 if (ns_cmd) { 10276 fctl_free_ns_cmd(ns_cmd); 10277 } 10278 10279 listlen = 0; 10280 changelist = NULL; 10281 if (count) { 10282 if (port->fp_soft_state & FP_SOFT_IN_FCA_RESET) { 10283 port->fp_soft_state &= ~FP_SOFT_IN_FCA_RESET; 10284 mutex_exit(&port->fp_mutex); 10285 delay(drv_usectohz(FLA_RR_TOV * 1000 * 1000)); 10286 mutex_enter(&port->fp_mutex); 10287 } 10288 10289 dbg_count = 0; 10290 10291 job->job_counter = count; 10292 10293 for (index = 0; index < pwwn_table_size; index++) { 10294 head = &port->fp_pwwn_table[index]; 10295 npd = head->pwwn_head; 10296 10297 while ((pd = npd) != NULL) { 10298 npd = pd->pd_wwn_hnext; 10299 10300 mutex_enter(&pd->pd_mutex); 10301 if (pd->pd_flags != PD_ELS_MARK) { 10302 mutex_exit(&pd->pd_mutex); 10303 continue; 10304 } 10305 10306 dbg_count++; 10307 10308 /* 10309 * If it is already marked deletion, nothing 10310 * else to do. 10311 */ 10312 if (pd->pd_type == PORT_DEVICE_DELETE) { 10313 pd->pd_type = PORT_DEVICE_OLD; 10314 10315 mutex_exit(&pd->pd_mutex); 10316 mutex_exit(&port->fp_mutex); 10317 fp_jobdone(job); 10318 mutex_enter(&port->fp_mutex); 10319 10320 continue; 10321 } 10322 10323 /* 10324 * If it is freshly discovered out of 10325 * the orphan list, nothing else to do 10326 */ 10327 if (pd->pd_type == PORT_DEVICE_NEW) { 10328 pd->pd_flags = PD_IDLE; 10329 10330 mutex_exit(&pd->pd_mutex); 10331 mutex_exit(&port->fp_mutex); 10332 fp_jobdone(job); 10333 mutex_enter(&port->fp_mutex); 10334 10335 continue; 10336 } 10337 10338 pd->pd_flags = PD_IDLE; 10339 d_id = pd->pd_port_id.port_id; 10340 10341 /* 10342 * Explicitly mark all devices OLD; successful 10343 * PLOGI should reset this to either NO_CHANGE 10344 * or CHANGED. 10345 */ 10346 if (pd->pd_type != PORT_DEVICE_CHANGED) { 10347 pd->pd_type = PORT_DEVICE_OLD; 10348 } 10349 10350 mutex_exit(&pd->pd_mutex); 10351 mutex_exit(&port->fp_mutex); 10352 10353 rval = fp_port_login(port, d_id, job, 10354 FP_CMD_PLOGI_RETAIN, KM_SLEEP, pd, NULL); 10355 10356 if (rval != FC_SUCCESS) { 10357 fp_jobdone(job); 10358 } 10359 mutex_enter(&port->fp_mutex); 10360 } 10361 } 10362 mutex_exit(&port->fp_mutex); 10363 10364 ASSERT(dbg_count == count); 10365 fp_jobwait(job); 10366 10367 mutex_enter(&port->fp_mutex); 10368 10369 ASSERT(port->fp_statec_busy > 0); 10370 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10371 if (port->fp_statec_busy > 1) { 10372 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10373 } 10374 } 10375 mutex_exit(&port->fp_mutex); 10376 } else { 10377 ASSERT(port->fp_statec_busy > 0); 10378 if (port->fp_statec_busy > 1) { 10379 job->job_flags |= JOB_CANCEL_ULP_NOTIFICATION; 10380 } 10381 mutex_exit(&port->fp_mutex); 10382 } 10383 10384 if ((job->job_flags & JOB_CANCEL_ULP_NOTIFICATION) == 0) { 10385 fctl_fillout_map(port, &changelist, &listlen, 1, 0, 0); 10386 10387 (void) fp_ulp_statec_cb(port, FC_STATE_ONLINE, changelist, 10388 listlen, listlen, KM_SLEEP); 10389 10390 mutex_enter(&port->fp_mutex); 10391 } else { 10392 ASSERT(changelist == NULL && listlen == 0); 10393 mutex_enter(&port->fp_mutex); 10394 if (--port->fp_statec_busy == 0) { 10395 port->fp_soft_state &= ~FP_SOFT_IN_STATEC_CB; 10396 } 10397 } 10398 } 10399 10400 10401 /* 10402 * Fill out device list for userland ioctl in private loop 10403 */ 10404 static int 10405 fp_fillout_loopmap(fc_local_port_t *port, fcio_t *fcio, int mode) 10406 { 10407 int rval; 10408 int count; 10409 int index; 10410 int num_devices; 10411 fc_remote_node_t *node; 10412 fc_port_dev_t *devlist; 10413 int lilp_device_count; 10414 fc_lilpmap_t *lilp_map; 10415 uchar_t *alpa_list; 10416 10417 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10418 10419 num_devices = fcio->fcio_olen / sizeof (fc_port_dev_t); 10420 if (port->fp_total_devices > port->fp_dev_count && 10421 num_devices >= port->fp_total_devices) { 10422 job_request_t *job; 10423 10424 mutex_exit(&port->fp_mutex); 10425 job = fctl_alloc_job(JOB_PORT_GETMAP, 0, NULL, NULL, KM_SLEEP); 10426 job->job_counter = 1; 10427 10428 mutex_enter(&port->fp_mutex); 10429 fp_get_loopmap(port, job); 10430 mutex_exit(&port->fp_mutex); 10431 10432 fp_jobwait(job); 10433 fctl_dealloc_job(job); 10434 } else { 10435 mutex_exit(&port->fp_mutex); 10436 } 10437 devlist = kmem_zalloc(sizeof (*devlist) * num_devices, KM_SLEEP); 10438 10439 mutex_enter(&port->fp_mutex); 10440 10441 /* 10442 * Applications are accustomed to getting the device list in 10443 * LILP map order. The HBA firmware usually returns the device 10444 * map in the LILP map order and diagnostic applications would 10445 * prefer to receive in the device list in that order too 10446 */ 10447 lilp_map = &port->fp_lilp_map; 10448 alpa_list = &lilp_map->lilp_alpalist[0]; 10449 10450 /* 10451 * the length field corresponds to the offset in the LILP frame 10452 * which begins with 1. The thing to note here is that the 10453 * lilp_device_count is 1 more than fp->fp_total_devices since 10454 * the host adapter's alpa also shows up in the lilp map. We 10455 * don't however return details of the host adapter since 10456 * fctl_get_remote_port_by_did fails for the host adapter's ALPA 10457 * and applications are required to issue the FCIO_GET_HOST_PARAMS 10458 * ioctl to obtain details about the host adapter port. 10459 */ 10460 lilp_device_count = lilp_map->lilp_length; 10461 10462 for (count = index = 0; index < lilp_device_count && 10463 count < num_devices; index++) { 10464 uint32_t d_id; 10465 fc_remote_port_t *pd; 10466 10467 d_id = alpa_list[index]; 10468 10469 mutex_exit(&port->fp_mutex); 10470 pd = fctl_get_remote_port_by_did(port, d_id); 10471 mutex_enter(&port->fp_mutex); 10472 10473 if (pd != NULL) { 10474 mutex_enter(&pd->pd_mutex); 10475 10476 if (pd->pd_state == PORT_DEVICE_INVALID) { 10477 mutex_exit(&pd->pd_mutex); 10478 continue; 10479 } 10480 10481 devlist[count].dev_state = pd->pd_state; 10482 devlist[count].dev_hard_addr = pd->pd_hard_addr; 10483 devlist[count].dev_did = pd->pd_port_id; 10484 devlist[count].dev_did.priv_lilp_posit = 10485 (uint8_t)(index & 0xff); 10486 bcopy((caddr_t)pd->pd_fc4types, 10487 (caddr_t)devlist[count].dev_type, 10488 sizeof (pd->pd_fc4types)); 10489 10490 bcopy((caddr_t)&pd->pd_port_name, 10491 (caddr_t)&devlist[count].dev_pwwn, 10492 sizeof (la_wwn_t)); 10493 10494 node = pd->pd_remote_nodep; 10495 mutex_exit(&pd->pd_mutex); 10496 10497 if (node) { 10498 mutex_enter(&node->fd_mutex); 10499 bcopy((caddr_t)&node->fd_node_name, 10500 (caddr_t)&devlist[count].dev_nwwn, 10501 sizeof (la_wwn_t)); 10502 mutex_exit(&node->fd_mutex); 10503 } 10504 count++; 10505 } 10506 } 10507 10508 if (fp_copyout((void *)&count, (void *)fcio->fcio_abuf, 10509 sizeof (count), mode)) { 10510 rval = FC_FAILURE; 10511 } 10512 10513 if (fp_copyout((void *)devlist, (void *)fcio->fcio_obuf, 10514 sizeof (fc_port_dev_t) * num_devices, mode)) { 10515 rval = FC_FAILURE; 10516 } else { 10517 rval = FC_SUCCESS; 10518 } 10519 10520 kmem_free(devlist, sizeof (*devlist) * num_devices); 10521 ASSERT(MUTEX_HELD(&port->fp_mutex)); 10522 10523 return (rval); 10524 } 10525 10526 10527 /* 10528 * Completion function for responses to unsolicited commands 10529 */ 10530 static void 10531 fp_unsol_intr(fc_packet_t *pkt) 10532 { 10533 fp_cmd_t *cmd; 10534 fc_local_port_t *port; 10535 10536 cmd = pkt->pkt_ulp_private; 10537 port = cmd->cmd_port; 10538 10539 mutex_enter(&port->fp_mutex); 10540 port->fp_out_fpcmds--; 10541 mutex_exit(&port->fp_mutex); 10542 10543 if (pkt->pkt_state != FC_PKT_SUCCESS) { 10544 fp_printf(port, CE_WARN, FP_LOG_ONLY, 0, pkt, 10545 "couldn't post response to unsolicited request;" 10546 " ox_id=%x rx_id=%x", pkt->pkt_cmd_fhdr.ox_id, 10547 pkt->pkt_resp_fhdr.rx_id); 10548 } 10549 10550 if (cmd == port->fp_els_resp_pkt) { 10551 mutex_enter(&port->fp_mutex); 10552 port->fp_els_resp_pkt_busy = 0; 10553 mutex_exit(&port->fp_mutex); 10554 return; 10555 } 10556 10557 fp_free_pkt(cmd); 10558 } 10559 10560 10561 /* 10562 * solicited LINIT ELS completion function 10563 */ 10564 static void 10565 fp_linit_intr(fc_packet_t *pkt) 10566 { 10567 fp_cmd_t *cmd; 10568 job_request_t *job; 10569 fc_linit_resp_t acc; 10570 fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port; 10571 10572 cmd = (fp_cmd_t *)pkt->pkt_ulp_private; 10573 10574 mutex_enter(&cmd->cmd_port->fp_mutex); 10575 cmd->cmd_port->fp_out_fpcmds--; 10576 mutex_exit(&cmd->cmd_port->fp_mutex); 10577 10578 if (FP_IS_PKT_ERROR(pkt)) { 10579 (void) fp_common_intr(pkt, 1); 10580 return; 10581 } 10582 10583 job = cmd->cmd_job; 10584 10585 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc, 10586 (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR); 10587 if (acc.status != FC_LINIT_SUCCESS) { 10588 job->job_result = FC_FAILURE; 10589 } else { 10590 job->job_result = FC_SUCCESS; 10591 } 10592 10593 fp_iodone(cmd); 10594 } 10595 10596 10597 /* 10598 * Decode the unsolicited request; For FC-4 Device and Link data frames 10599 * notify the registered ULP of this FC-4 type right here. For Unsolicited 10600 * ELS requests, submit a request to the job_handler thread to work on it. 10601 * The intent is to act quickly on the FC-4 unsolicited link and data frames 10602 * and save much of the interrupt time processing of unsolicited ELS requests 10603 * and hand it off to the job_handler thread. 10604 */ 10605 static void 10606 fp_unsol_cb(opaque_t port_handle, fc_unsol_buf_t *buf, uint32_t type) 10607 { 10608 uchar_t r_ctl; 10609 uchar_t ls_code; 10610 uint32_t s_id; 10611 uint32_t rscn_count = FC_INVALID_RSCN_COUNT; 10612 uint32_t cb_arg; 10613 fp_cmd_t *cmd; 10614 fc_local_port_t *port; 10615 job_request_t *job; 10616 fc_remote_port_t *pd; 10617 10618 port = port_handle; 10619 10620 FP_TRACE(FP_NHEAD1(1, 0), "fp_unsol_cb: s_id=%x," 10621 " d_id=%x, type=%x, r_ctl=%x, f_ctl=%x" 10622 " seq_id=%x, df_ctl=%x, seq_cnt=%x, ox_id=%x, rx_id=%x" 10623 " ro=%x, buffer[0]:%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10624 buf->ub_frame.type, buf->ub_frame.r_ctl, buf->ub_frame.f_ctl, 10625 buf->ub_frame.seq_id, buf->ub_frame.df_ctl, buf->ub_frame.seq_cnt, 10626 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro, 10627 buf->ub_buffer[0]); 10628 10629 if (type & 0x80000000) { 10630 /* 10631 * Huh ? Nothing much can be done without 10632 * a valid buffer. So just exit. 10633 */ 10634 return; 10635 } 10636 /* 10637 * If the unsolicited interrupts arrive while it isn't 10638 * safe to handle unsolicited callbacks; Drop them, yes, 10639 * drop them on the floor 10640 */ 10641 mutex_enter(&port->fp_mutex); 10642 port->fp_active_ubs++; 10643 if ((port->fp_soft_state & 10644 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN)) || 10645 FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 10646 10647 FP_TRACE(FP_NHEAD1(3, 0), "fp_unsol_cb: port state is " 10648 "not ONLINE. s_id=%x, d_id=%x, type=%x, " 10649 "seq_id=%x, ox_id=%x, rx_id=%x" 10650 "ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 10651 buf->ub_frame.type, buf->ub_frame.seq_id, 10652 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 10653 10654 ASSERT(port->fp_active_ubs > 0); 10655 if (--(port->fp_active_ubs) == 0) { 10656 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10657 } 10658 10659 mutex_exit(&port->fp_mutex); 10660 10661 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10662 1, &buf->ub_token); 10663 10664 return; 10665 } 10666 10667 r_ctl = buf->ub_frame.r_ctl; 10668 s_id = buf->ub_frame.s_id; 10669 if (port->fp_active_ubs == 1) { 10670 port->fp_soft_state |= FP_SOFT_IN_UNSOL_CB; 10671 } 10672 10673 if (r_ctl == R_CTL_ELS_REQ && buf->ub_buffer[0] == LA_ELS_LOGO && 10674 port->fp_statec_busy) { 10675 mutex_exit(&port->fp_mutex); 10676 pd = fctl_get_remote_port_by_did(port, s_id); 10677 if (pd) { 10678 mutex_enter(&pd->pd_mutex); 10679 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10680 FP_TRACE(FP_NHEAD1(3, 0), 10681 "LOGO for LOGGED IN D_ID %x", 10682 buf->ub_frame.s_id); 10683 pd->pd_state = PORT_DEVICE_VALID; 10684 } 10685 mutex_exit(&pd->pd_mutex); 10686 } 10687 10688 mutex_enter(&port->fp_mutex); 10689 ASSERT(port->fp_active_ubs > 0); 10690 if (--(port->fp_active_ubs) == 0) { 10691 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10692 } 10693 mutex_exit(&port->fp_mutex); 10694 10695 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10696 1, &buf->ub_token); 10697 10698 FP_TRACE(FP_NHEAD1(3, 0), 10699 "fp_unsol_cb() bailing out LOGO for D_ID %x", 10700 buf->ub_frame.s_id); 10701 return; 10702 } 10703 10704 if (port->fp_els_resp_pkt_busy == 0) { 10705 if (r_ctl == R_CTL_ELS_REQ) { 10706 ls_code = buf->ub_buffer[0]; 10707 10708 switch (ls_code) { 10709 case LA_ELS_PLOGI: 10710 case LA_ELS_FLOGI: 10711 port->fp_els_resp_pkt_busy = 1; 10712 mutex_exit(&port->fp_mutex); 10713 fp_i_handle_unsol_els(port, buf); 10714 10715 mutex_enter(&port->fp_mutex); 10716 ASSERT(port->fp_active_ubs > 0); 10717 if (--(port->fp_active_ubs) == 0) { 10718 port->fp_soft_state &= 10719 ~FP_SOFT_IN_UNSOL_CB; 10720 } 10721 mutex_exit(&port->fp_mutex); 10722 port->fp_fca_tran->fca_ub_release( 10723 port->fp_fca_handle, 1, &buf->ub_token); 10724 10725 return; 10726 case LA_ELS_RSCN: 10727 if (++(port)->fp_rscn_count == 10728 FC_INVALID_RSCN_COUNT) { 10729 ++(port)->fp_rscn_count; 10730 } 10731 rscn_count = port->fp_rscn_count; 10732 break; 10733 10734 default: 10735 break; 10736 } 10737 } 10738 } else if ((r_ctl == R_CTL_ELS_REQ) && 10739 (buf->ub_buffer[0] == LA_ELS_RSCN)) { 10740 if (++port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10741 ++port->fp_rscn_count; 10742 } 10743 rscn_count = port->fp_rscn_count; 10744 } 10745 10746 mutex_exit(&port->fp_mutex); 10747 10748 switch (r_ctl & R_CTL_ROUTING) { 10749 case R_CTL_DEVICE_DATA: 10750 /* 10751 * If the unsolicited buffer is a CT IU, 10752 * have the job_handler thread work on it. 10753 */ 10754 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 10755 break; 10756 } 10757 /* FALLTHROUGH */ 10758 10759 case R_CTL_FC4_SVC: { 10760 int sendup = 0; 10761 10762 /* 10763 * If a LOGIN isn't performed before this request 10764 * shut the door on this port with a reply that a 10765 * LOGIN is required. We make an exception however 10766 * for IP broadcast packets and pass them through 10767 * to the IP ULP(s) to handle broadcast requests. 10768 * This is not a problem for private loop devices 10769 * but for fabric topologies we don't log into the 10770 * remote ports during port initialization and 10771 * the ULPs need to log into requesting ports on 10772 * demand. 10773 */ 10774 pd = fctl_get_remote_port_by_did(port, s_id); 10775 if (pd) { 10776 mutex_enter(&pd->pd_mutex); 10777 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 10778 sendup++; 10779 } 10780 mutex_exit(&pd->pd_mutex); 10781 } else if ((pd == NULL) && 10782 (buf->ub_frame.type == FC_TYPE_IS8802_SNAP) && 10783 (buf->ub_frame.d_id == 0xffffff || 10784 buf->ub_frame.d_id == 0x00)) { 10785 /* brodacst IP frame - so sendup via job thread */ 10786 break; 10787 } 10788 10789 /* 10790 * Send all FC4 services via job thread too 10791 */ 10792 if ((r_ctl & R_CTL_ROUTING) == R_CTL_FC4_SVC) { 10793 break; 10794 } 10795 10796 if (sendup || !FC_IS_REAL_DEVICE(s_id)) { 10797 fctl_ulp_unsol_cb(port, buf, buf->ub_frame.type); 10798 return; 10799 } 10800 10801 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10802 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 10803 0, KM_NOSLEEP, pd); 10804 if (cmd != NULL) { 10805 fp_els_rjt_init(port, cmd, buf, 10806 FC_ACTION_NON_RETRYABLE, 10807 FC_REASON_LOGIN_REQUIRED, NULL); 10808 10809 if (fp_sendcmd(port, cmd, 10810 port->fp_fca_handle) != FC_SUCCESS) { 10811 fp_free_pkt(cmd); 10812 } 10813 } 10814 } 10815 10816 mutex_enter(&port->fp_mutex); 10817 ASSERT(port->fp_active_ubs > 0); 10818 if (--(port->fp_active_ubs) == 0) { 10819 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10820 } 10821 mutex_exit(&port->fp_mutex); 10822 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10823 1, &buf->ub_token); 10824 10825 return; 10826 } 10827 10828 default: 10829 break; 10830 } 10831 10832 /* 10833 * Submit a Request to the job_handler thread to work 10834 * on the unsolicited request. The potential side effect 10835 * of this is that the unsolicited buffer takes a little 10836 * longer to get released but we save interrupt time in 10837 * the bargain. 10838 */ 10839 cb_arg = (rscn_count == FC_INVALID_RSCN_COUNT) ? NULL : rscn_count; 10840 10841 /* 10842 * One way that the rscn_count will get used is described below : 10843 * 10844 * 1. fp_unsol_cb() gets an RSCN and updates fp_rscn_count. 10845 * 2. Before mutex is released, a copy of it is stored in rscn_count. 10846 * 3. The count is passed to job thread as JOB_UNSOL_REQUEST (below) 10847 * by overloading the job_cb_arg to pass the rscn_count 10848 * 4. When one of the routines processing the RSCN picks it up (ex: 10849 * fp_validate_rscn_page()), it passes this count in the map 10850 * structure (as part of the map_rscn_info structure member) to the 10851 * ULPs. 10852 * 5. When ULPs make calls back to the transport (example interfaces for 10853 * this are fc_ulp_transport(), fc_ulp_login(), fc_issue_els()), they 10854 * can now pass back this count as part of the fc_packet's 10855 * pkt_ulp_rscn_count member. fcp does this currently. 10856 * 6. When transport gets a call to transport a command on the wire, it 10857 * will check to see if there is a valid pkt_ulp_rsvd1 field in the 10858 * fc_packet. If there is, it will match that info with the current 10859 * rscn_count on that instance of the port. If they don't match up 10860 * then there was a newer RSCN. The ULP gets back an error code which 10861 * informs it about it - FC_DEVICE_BUSY_NEW_RSCN. 10862 * 7. At this point the ULP is free to make up its own mind as to how to 10863 * handle this. Currently, fcp will reset its retry counters and keep 10864 * retrying the operation it was doing in anticipation of getting a 10865 * new state change call back for the new RSCN. 10866 */ 10867 job = fctl_alloc_job(JOB_UNSOL_REQUEST, 0, NULL, 10868 (opaque_t)(uintptr_t)cb_arg, KM_NOSLEEP); 10869 if (job == NULL) { 10870 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, "fp_unsol_cb() " 10871 "couldn't submit a job to the thread, failing.."); 10872 10873 mutex_enter(&port->fp_mutex); 10874 10875 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 10876 --port->fp_rscn_count; 10877 } 10878 10879 ASSERT(port->fp_active_ubs > 0); 10880 if (--(port->fp_active_ubs) == 0) { 10881 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 10882 } 10883 10884 mutex_exit(&port->fp_mutex); 10885 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 10886 1, &buf->ub_token); 10887 10888 return; 10889 } 10890 job->job_private = (void *)buf; 10891 fctl_enque_job(port, job); 10892 } 10893 10894 10895 /* 10896 * Handle unsolicited requests 10897 */ 10898 static void 10899 fp_handle_unsol_buf(fc_local_port_t *port, fc_unsol_buf_t *buf, 10900 job_request_t *job) 10901 { 10902 uchar_t r_ctl; 10903 uchar_t ls_code; 10904 uint32_t s_id; 10905 fp_cmd_t *cmd; 10906 fc_remote_port_t *pd; 10907 fp_unsol_spec_t *ub_spec; 10908 10909 r_ctl = buf->ub_frame.r_ctl; 10910 s_id = buf->ub_frame.s_id; 10911 10912 switch (r_ctl & R_CTL_ROUTING) { 10913 case R_CTL_EXTENDED_SVC: 10914 if (r_ctl != R_CTL_ELS_REQ) { 10915 break; 10916 } 10917 10918 ls_code = buf->ub_buffer[0]; 10919 switch (ls_code) { 10920 case LA_ELS_LOGO: 10921 case LA_ELS_ADISC: 10922 case LA_ELS_PRLO: 10923 pd = fctl_get_remote_port_by_did(port, s_id); 10924 if (pd == NULL) { 10925 if (!FC_IS_REAL_DEVICE(s_id)) { 10926 break; 10927 } 10928 if (!FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10929 break; 10930 } 10931 if ((cmd = fp_alloc_pkt(port, 10932 sizeof (la_els_rjt_t), 0, KM_SLEEP, 10933 NULL)) == NULL) { 10934 /* 10935 * Can this actually fail when 10936 * given KM_SLEEP? (Could be used 10937 * this way in a number of places.) 10938 */ 10939 break; 10940 } 10941 10942 fp_els_rjt_init(port, cmd, buf, 10943 FC_ACTION_NON_RETRYABLE, 10944 FC_REASON_INVALID_LINK_CTRL, job); 10945 10946 if (fp_sendcmd(port, cmd, 10947 port->fp_fca_handle) != FC_SUCCESS) { 10948 fp_free_pkt(cmd); 10949 } 10950 10951 break; 10952 } 10953 if (ls_code == LA_ELS_LOGO) { 10954 fp_handle_unsol_logo(port, buf, pd, job); 10955 } else if (ls_code == LA_ELS_ADISC) { 10956 fp_handle_unsol_adisc(port, buf, pd, job); 10957 } else { 10958 fp_handle_unsol_prlo(port, buf, pd, job); 10959 } 10960 break; 10961 10962 case LA_ELS_PLOGI: 10963 fp_handle_unsol_plogi(port, buf, job, KM_SLEEP); 10964 break; 10965 10966 case LA_ELS_FLOGI: 10967 fp_handle_unsol_flogi(port, buf, job, KM_SLEEP); 10968 break; 10969 10970 case LA_ELS_RSCN: 10971 fp_handle_unsol_rscn(port, buf, job, KM_SLEEP); 10972 break; 10973 10974 default: 10975 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 10976 ub_spec->port = port; 10977 ub_spec->buf = buf; 10978 10979 (void) taskq_dispatch(port->fp_taskq, 10980 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 10981 return; 10982 } 10983 break; 10984 10985 case R_CTL_BASIC_SVC: 10986 /* 10987 * The unsolicited basic link services could be ABTS 10988 * and RMC (Or even a NOP). Just BA_RJT them until 10989 * such time there arises a need to handle them more 10990 * carefully. 10991 */ 10992 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 10993 cmd = fp_alloc_pkt(port, sizeof (la_ba_rjt_t), 10994 0, KM_SLEEP, NULL); 10995 if (cmd != NULL) { 10996 fp_ba_rjt_init(port, cmd, buf, job); 10997 if (fp_sendcmd(port, cmd, 10998 port->fp_fca_handle) != FC_SUCCESS) { 10999 fp_free_pkt(cmd); 11000 } 11001 } 11002 } 11003 break; 11004 11005 case R_CTL_DEVICE_DATA: 11006 if (buf->ub_frame.type == FC_TYPE_FC_SERVICES) { 11007 /* 11008 * Mostly this is of type FC_TYPE_FC_SERVICES. 11009 * As we don't like any Unsolicited FC services 11010 * requests, we would do well to RJT them as 11011 * well. 11012 */ 11013 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11014 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11015 0, KM_SLEEP, NULL); 11016 if (cmd != NULL) { 11017 fp_els_rjt_init(port, cmd, buf, 11018 FC_ACTION_NON_RETRYABLE, 11019 FC_REASON_INVALID_LINK_CTRL, job); 11020 11021 if (fp_sendcmd(port, cmd, 11022 port->fp_fca_handle) != 11023 FC_SUCCESS) { 11024 fp_free_pkt(cmd); 11025 } 11026 } 11027 } 11028 break; 11029 } 11030 /* FALLTHROUGH */ 11031 11032 case R_CTL_FC4_SVC: 11033 ub_spec = kmem_zalloc(sizeof (*ub_spec), KM_SLEEP); 11034 ub_spec->port = port; 11035 ub_spec->buf = buf; 11036 11037 (void) taskq_dispatch(port->fp_taskq, 11038 fp_ulp_unsol_cb, ub_spec, KM_SLEEP); 11039 return; 11040 11041 case R_CTL_LINK_CTL: 11042 /* 11043 * Turn deaf ear on unsolicited link control frames. 11044 * Typical unsolicited link control Frame is an LCR 11045 * (to reset End to End credit to the default login 11046 * value and abort current sequences for all classes) 11047 * An intelligent microcode/firmware should handle 11048 * this transparently at its level and not pass all 11049 * the way up here. 11050 * 11051 * Possible responses to LCR are R_RDY, F_RJT, P_RJT 11052 * or F_BSY. P_RJT is chosen to be the most appropriate 11053 * at this time. 11054 */ 11055 /* FALLTHROUGH */ 11056 11057 default: 11058 /* 11059 * Just reject everything else as an invalid request. 11060 */ 11061 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11062 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11063 0, KM_SLEEP, NULL); 11064 if (cmd != NULL) { 11065 fp_els_rjt_init(port, cmd, buf, 11066 FC_ACTION_NON_RETRYABLE, 11067 FC_REASON_INVALID_LINK_CTRL, job); 11068 11069 if (fp_sendcmd(port, cmd, 11070 port->fp_fca_handle) != FC_SUCCESS) { 11071 fp_free_pkt(cmd); 11072 } 11073 } 11074 } 11075 break; 11076 } 11077 11078 mutex_enter(&port->fp_mutex); 11079 ASSERT(port->fp_active_ubs > 0); 11080 if (--(port->fp_active_ubs) == 0) { 11081 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 11082 } 11083 mutex_exit(&port->fp_mutex); 11084 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 11085 1, &buf->ub_token); 11086 } 11087 11088 11089 /* 11090 * Prepare a BA_RJT and send it over. 11091 */ 11092 static void 11093 fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11094 job_request_t *job) 11095 { 11096 fc_packet_t *pkt; 11097 la_ba_rjt_t payload; 11098 11099 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11100 11101 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11102 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11103 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11104 cmd->cmd_retry_count = 1; 11105 cmd->cmd_ulp_pkt = NULL; 11106 11107 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11108 cmd->cmd_job = job; 11109 11110 pkt = &cmd->cmd_pkt; 11111 11112 fp_unsol_resp_init(pkt, buf, R_CTL_LS_BA_RJT, FC_TYPE_BASIC_LS); 11113 11114 payload.reserved = 0; 11115 payload.reason_code = FC_REASON_CMD_UNSUPPORTED; 11116 payload.explanation = FC_EXPLN_NONE; 11117 payload.vendor = 0; 11118 11119 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11120 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11121 } 11122 11123 11124 /* 11125 * Prepare an LS_RJT and send it over 11126 */ 11127 static void 11128 fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11129 uchar_t action, uchar_t reason, job_request_t *job) 11130 { 11131 fc_packet_t *pkt; 11132 la_els_rjt_t payload; 11133 11134 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11135 11136 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11137 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11138 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11139 cmd->cmd_retry_count = 1; 11140 cmd->cmd_ulp_pkt = NULL; 11141 11142 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11143 cmd->cmd_job = job; 11144 11145 pkt = &cmd->cmd_pkt; 11146 11147 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11148 11149 payload.ls_code.ls_code = LA_ELS_RJT; 11150 payload.ls_code.mbz = 0; 11151 payload.action = action; 11152 payload.reason = reason; 11153 payload.reserved = 0; 11154 payload.vu = 0; 11155 11156 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11157 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11158 } 11159 11160 /* 11161 * Function: fp_prlo_acc_init 11162 * 11163 * Description: Initializes an Link Service Accept for a PRLO. 11164 * 11165 * Arguments: *port Local port through which the PRLO was 11166 * received. 11167 * cmd Command that will carry the accept. 11168 * *buf Unsolicited buffer containing the PRLO 11169 * request. 11170 * job Job request. 11171 * sleep Allocation mode. 11172 * 11173 * Return Value: *cmd Command containing the response. 11174 * 11175 * Context: Depends on the parameter sleep. 11176 */ 11177 fp_cmd_t * 11178 fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd, 11179 fc_unsol_buf_t *buf, job_request_t *job, int sleep) 11180 { 11181 fp_cmd_t *cmd; 11182 fc_packet_t *pkt; 11183 la_els_prlo_t *req; 11184 size_t len; 11185 uint16_t flags; 11186 11187 req = (la_els_prlo_t *)buf->ub_buffer; 11188 len = (size_t)ntohs(req->payload_length); 11189 11190 /* 11191 * The payload of the accept to a PRLO has to be the exact match of 11192 * the payload of the request (at the exception of the code). 11193 */ 11194 cmd = fp_alloc_pkt(port, (int)len, 0, sleep, pd); 11195 11196 if (cmd) { 11197 /* 11198 * The fp command was successfully allocated. 11199 */ 11200 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11201 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11202 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11203 cmd->cmd_retry_count = 1; 11204 cmd->cmd_ulp_pkt = NULL; 11205 11206 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11207 cmd->cmd_job = job; 11208 11209 pkt = &cmd->cmd_pkt; 11210 11211 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, 11212 FC_TYPE_EXTENDED_LS); 11213 11214 /* The code is overwritten for the copy. */ 11215 req->ls_code = LA_ELS_ACC; 11216 /* Response code is set. */ 11217 flags = ntohs(req->flags); 11218 flags &= ~SP_RESP_CODE_MASK; 11219 flags |= SP_RESP_CODE_REQ_EXECUTED; 11220 req->flags = htons(flags); 11221 11222 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req, 11223 (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR); 11224 } 11225 return (cmd); 11226 } 11227 11228 /* 11229 * Prepare an ACC response to an ELS request 11230 */ 11231 static void 11232 fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 11233 job_request_t *job) 11234 { 11235 fc_packet_t *pkt; 11236 ls_code_t payload; 11237 11238 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 11239 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 11240 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 11241 cmd->cmd_retry_count = 1; 11242 cmd->cmd_ulp_pkt = NULL; 11243 11244 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 11245 cmd->cmd_job = job; 11246 11247 pkt = &cmd->cmd_pkt; 11248 11249 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 11250 11251 payload.ls_code = LA_ELS_ACC; 11252 payload.mbz = 0; 11253 11254 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 11255 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 11256 } 11257 11258 /* 11259 * Unsolicited PRLO handler 11260 * 11261 * A Process Logout should be handled by the ULP that established it. However, 11262 * some devices send a PRLO to trigger a PLOGI followed by a PRLI. This happens 11263 * when a device implicitly logs out an initiator (for whatever reason) and 11264 * tries to get that initiator to restablish the connection (PLOGI and PRLI). 11265 * The logical thing to do for the device would be to send a LOGO in response 11266 * to any FC4 frame sent by the initiator. Some devices choose, however, to send 11267 * a PRLO instead. 11268 * 11269 * From a Fibre Channel standpoint a PRLO calls for a PRLI. There's no reason to 11270 * think that the Port Login has been lost. If we follow the Fibre Channel 11271 * protocol to the letter a PRLI should be sent after accepting the PRLO. If 11272 * the Port Login has also been lost, the remote port will reject the PRLI 11273 * indicating that we must PLOGI first. The initiator will then turn around and 11274 * send a PLOGI. The way Leadville is layered and the way the ULP interface 11275 * is defined doesn't allow this scenario to be followed easily. If FCP were to 11276 * handle the PRLO and attempt the PRLI, the reject indicating that a PLOGI is 11277 * needed would be received by FCP. FCP would have, then, to tell the transport 11278 * (fp) to PLOGI. The problem is, the transport would still think the Port 11279 * Login is valid and there is no way for FCP to tell the transport: "PLOGI even 11280 * if you think it's not necessary". To work around that difficulty, the PRLO 11281 * is treated by the transport as a LOGO. The downside to it is a Port Login 11282 * may be disrupted (if a PLOGI wasn't actually needed) and another ULP (that 11283 * has nothing to do with the PRLO) may be impacted. However, this is a 11284 * scenario very unlikely to happen. As of today the only ULP in Leadville 11285 * using PRLI/PRLOs is FCP. For a PRLO to disrupt another ULP (that would be 11286 * FCIP), a SCSI target would have to be running FCP and FCIP (which is very 11287 * unlikely). 11288 */ 11289 static void 11290 fp_handle_unsol_prlo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11291 fc_remote_port_t *pd, job_request_t *job) 11292 { 11293 int busy; 11294 int rval; 11295 int retain; 11296 fp_cmd_t *cmd; 11297 fc_portmap_t *listptr; 11298 boolean_t tolerance; 11299 la_els_prlo_t *req; 11300 11301 req = (la_els_prlo_t *)buf->ub_buffer; 11302 11303 if ((ntohs(req->payload_length) != 11304 (sizeof (service_parameter_page_t) + sizeof (ls_code_t))) || 11305 (req->page_length != sizeof (service_parameter_page_t))) { 11306 /* 11307 * We are being very restrictive. Only on page per 11308 * payload. If it is not the case we reject the ELS although 11309 * we should reply indicating we handle only single page 11310 * per PRLO. 11311 */ 11312 goto fp_reject_prlo; 11313 } 11314 11315 if (ntohs(req->payload_length) > buf->ub_bufsize) { 11316 /* 11317 * This is in case the payload advertizes a size bigger than 11318 * what it really is. 11319 */ 11320 goto fp_reject_prlo; 11321 } 11322 11323 mutex_enter(&port->fp_mutex); 11324 busy = port->fp_statec_busy; 11325 mutex_exit(&port->fp_mutex); 11326 11327 mutex_enter(&pd->pd_mutex); 11328 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11329 if (!busy) { 11330 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11331 pd->pd_state == PORT_DEVICE_INVALID || 11332 pd->pd_flags == PD_ELS_IN_PROGRESS || 11333 pd->pd_type == PORT_DEVICE_OLD) { 11334 busy++; 11335 } 11336 } 11337 11338 if (busy) { 11339 mutex_exit(&pd->pd_mutex); 11340 11341 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11342 "pd=%p - busy", 11343 pd->pd_port_id.port_id, pd); 11344 11345 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11346 goto fp_reject_prlo; 11347 } 11348 } else { 11349 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11350 11351 if (tolerance) { 11352 fctl_tc_reset(&pd->pd_logo_tc); 11353 retain = 0; 11354 pd->pd_state = PORT_DEVICE_INVALID; 11355 } 11356 11357 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11358 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11359 tolerance, retain); 11360 11361 pd->pd_aux_flags |= PD_LOGGED_OUT; 11362 mutex_exit(&pd->pd_mutex); 11363 11364 cmd = fp_prlo_acc_init(port, pd, buf, job, KM_SLEEP); 11365 if (cmd == NULL) { 11366 return; 11367 } 11368 11369 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11370 if (rval != FC_SUCCESS) { 11371 fp_free_pkt(cmd); 11372 return; 11373 } 11374 11375 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11376 11377 if (retain) { 11378 fp_unregister_login(pd); 11379 fctl_copy_portmap(listptr, pd); 11380 } else { 11381 uint32_t d_id; 11382 char ww_name[17]; 11383 11384 mutex_enter(&pd->pd_mutex); 11385 d_id = pd->pd_port_id.port_id; 11386 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11387 mutex_exit(&pd->pd_mutex); 11388 11389 FP_TRACE(FP_NHEAD2(9, 0), 11390 "N_x Port with D_ID=%x, PWWN=%s logged out" 11391 " %d times in %d us; Giving up", d_id, ww_name, 11392 FC_LOGO_TOLERANCE_LIMIT, 11393 FC_LOGO_TOLERANCE_TIME_LIMIT); 11394 11395 fp_fillout_old_map(listptr, pd, 0); 11396 listptr->map_type = PORT_DEVICE_OLD; 11397 } 11398 11399 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11400 return; 11401 } 11402 11403 fp_reject_prlo: 11404 11405 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 0, KM_SLEEP, pd); 11406 if (cmd != NULL) { 11407 fp_els_rjt_init(port, cmd, buf, FC_ACTION_NON_RETRYABLE, 11408 FC_REASON_INVALID_LINK_CTRL, job); 11409 11410 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 11411 fp_free_pkt(cmd); 11412 } 11413 } 11414 } 11415 11416 /* 11417 * Unsolicited LOGO handler 11418 */ 11419 static void 11420 fp_handle_unsol_logo(fc_local_port_t *port, fc_unsol_buf_t *buf, 11421 fc_remote_port_t *pd, job_request_t *job) 11422 { 11423 int busy; 11424 int rval; 11425 int retain; 11426 fp_cmd_t *cmd; 11427 fc_portmap_t *listptr; 11428 boolean_t tolerance; 11429 11430 mutex_enter(&port->fp_mutex); 11431 busy = port->fp_statec_busy; 11432 mutex_exit(&port->fp_mutex); 11433 11434 mutex_enter(&pd->pd_mutex); 11435 tolerance = fctl_tc_increment(&pd->pd_logo_tc); 11436 if (!busy) { 11437 if (pd->pd_state != PORT_DEVICE_LOGGED_IN || 11438 pd->pd_state == PORT_DEVICE_INVALID || 11439 pd->pd_flags == PD_ELS_IN_PROGRESS || 11440 pd->pd_type == PORT_DEVICE_OLD) { 11441 busy++; 11442 } 11443 } 11444 11445 if (busy) { 11446 mutex_exit(&pd->pd_mutex); 11447 11448 FP_TRACE(FP_NHEAD1(5, 0), "Logout; D_ID=%x," 11449 "pd=%p - busy", 11450 pd->pd_port_id.port_id, pd); 11451 11452 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11453 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 11454 0, KM_SLEEP, pd); 11455 if (cmd != NULL) { 11456 fp_els_rjt_init(port, cmd, buf, 11457 FC_ACTION_NON_RETRYABLE, 11458 FC_REASON_INVALID_LINK_CTRL, job); 11459 11460 if (fp_sendcmd(port, cmd, 11461 port->fp_fca_handle) != FC_SUCCESS) { 11462 fp_free_pkt(cmd); 11463 } 11464 } 11465 } 11466 } else { 11467 retain = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 11468 11469 if (tolerance) { 11470 fctl_tc_reset(&pd->pd_logo_tc); 11471 retain = 0; 11472 pd->pd_state = PORT_DEVICE_INVALID; 11473 } 11474 11475 FP_TRACE(FP_NHEAD1(5, 0), "Accepting LOGO; d_id=%x, pd=%p," 11476 " tolerance=%d retain=%d", pd->pd_port_id.port_id, pd, 11477 tolerance, retain); 11478 11479 pd->pd_aux_flags |= PD_LOGGED_OUT; 11480 mutex_exit(&pd->pd_mutex); 11481 11482 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, 11483 KM_SLEEP, pd); 11484 if (cmd == NULL) { 11485 return; 11486 } 11487 11488 fp_els_acc_init(port, cmd, buf, job); 11489 11490 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 11491 if (rval != FC_SUCCESS) { 11492 fp_free_pkt(cmd); 11493 return; 11494 } 11495 11496 listptr = kmem_zalloc(sizeof (fc_portmap_t), KM_SLEEP); 11497 11498 if (retain) { 11499 job_request_t *job; 11500 fctl_ns_req_t *ns_cmd; 11501 11502 /* 11503 * when get LOGO, first try to get PID from nameserver 11504 * if failed, then we do not need 11505 * send PLOGI to that remote port 11506 */ 11507 job = fctl_alloc_job( 11508 JOB_NS_CMD, 0, NULL, (opaque_t)port, KM_SLEEP); 11509 11510 if (job != NULL) { 11511 ns_cmd = fctl_alloc_ns_cmd( 11512 sizeof (ns_req_gid_pn_t), 11513 sizeof (ns_resp_gid_pn_t), 11514 sizeof (ns_resp_gid_pn_t), 11515 0, KM_SLEEP); 11516 if (ns_cmd != NULL) { 11517 int ret; 11518 job->job_result = FC_SUCCESS; 11519 ns_cmd->ns_cmd_code = NS_GID_PN; 11520 ((ns_req_gid_pn_t *) 11521 (ns_cmd->ns_cmd_buf))->pwwn = 11522 pd->pd_port_name; 11523 ret = fp_ns_query( 11524 port, ns_cmd, job, 1, KM_SLEEP); 11525 if ((ret != FC_SUCCESS) || 11526 (job->job_result != FC_SUCCESS)) { 11527 fctl_free_ns_cmd(ns_cmd); 11528 fctl_dealloc_job(job); 11529 FP_TRACE(FP_NHEAD2(9, 0), 11530 "NS query failed,", 11531 " delete pd"); 11532 goto delete_pd; 11533 } 11534 fctl_free_ns_cmd(ns_cmd); 11535 } 11536 fctl_dealloc_job(job); 11537 } 11538 fp_unregister_login(pd); 11539 fctl_copy_portmap(listptr, pd); 11540 } else { 11541 uint32_t d_id; 11542 char ww_name[17]; 11543 11544 delete_pd: 11545 mutex_enter(&pd->pd_mutex); 11546 d_id = pd->pd_port_id.port_id; 11547 fc_wwn_to_str(&pd->pd_port_name, ww_name); 11548 mutex_exit(&pd->pd_mutex); 11549 11550 FP_TRACE(FP_NHEAD2(9, 0), 11551 "N_x Port with D_ID=%x, PWWN=%s logged out" 11552 " %d times in %d us; Giving up", d_id, ww_name, 11553 FC_LOGO_TOLERANCE_LIMIT, 11554 FC_LOGO_TOLERANCE_TIME_LIMIT); 11555 11556 fp_fillout_old_map(listptr, pd, 0); 11557 listptr->map_type = PORT_DEVICE_OLD; 11558 } 11559 11560 (void) fp_ulp_devc_cb(port, listptr, 1, 1, KM_SLEEP, 0); 11561 } 11562 } 11563 11564 11565 /* 11566 * Perform general purpose preparation of a response to an unsolicited request 11567 */ 11568 static void 11569 fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf, 11570 uchar_t r_ctl, uchar_t type) 11571 { 11572 pkt->pkt_cmd_fhdr.r_ctl = r_ctl; 11573 pkt->pkt_cmd_fhdr.d_id = buf->ub_frame.s_id; 11574 pkt->pkt_cmd_fhdr.s_id = buf->ub_frame.d_id; 11575 pkt->pkt_cmd_fhdr.type = type; 11576 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT; 11577 pkt->pkt_cmd_fhdr.seq_id = buf->ub_frame.seq_id; 11578 pkt->pkt_cmd_fhdr.df_ctl = buf->ub_frame.df_ctl; 11579 pkt->pkt_cmd_fhdr.seq_cnt = buf->ub_frame.seq_cnt; 11580 pkt->pkt_cmd_fhdr.ox_id = buf->ub_frame.ox_id; 11581 pkt->pkt_cmd_fhdr.rx_id = buf->ub_frame.rx_id; 11582 pkt->pkt_cmd_fhdr.ro = 0; 11583 pkt->pkt_cmd_fhdr.rsvd = 0; 11584 pkt->pkt_comp = fp_unsol_intr; 11585 pkt->pkt_timeout = FP_ELS_TIMEOUT; 11586 pkt->pkt_ub_resp_token = (opaque_t)buf; 11587 } 11588 11589 /* 11590 * Immediate handling of unsolicited FLOGI and PLOGI requests. In the 11591 * early development days of public loop soc+ firmware, numerous problems 11592 * were encountered (the details are undocumented and history now) which 11593 * led to the birth of this function. 11594 * 11595 * If a pre-allocated unsolicited response packet is free, send out an 11596 * immediate response, otherwise submit the request to the port thread 11597 * to do the deferred processing. 11598 */ 11599 static void 11600 fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf) 11601 { 11602 int sent; 11603 int f_port; 11604 int do_acc; 11605 fp_cmd_t *cmd; 11606 la_els_logi_t *payload; 11607 fc_remote_port_t *pd; 11608 char dww_name[17]; 11609 11610 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 11611 11612 cmd = port->fp_els_resp_pkt; 11613 11614 mutex_enter(&port->fp_mutex); 11615 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11616 mutex_exit(&port->fp_mutex); 11617 11618 switch (buf->ub_buffer[0]) { 11619 case LA_ELS_PLOGI: { 11620 int small; 11621 11622 payload = (la_els_logi_t *)buf->ub_buffer; 11623 11624 f_port = FP_IS_F_PORT(payload-> 11625 common_service.cmn_features) ? 1 : 0; 11626 11627 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 11628 &payload->nport_ww_name); 11629 pd = fctl_get_remote_port_by_pwwn(port, 11630 &payload->nport_ww_name); 11631 if (pd) { 11632 mutex_enter(&pd->pd_mutex); 11633 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11634 /* 11635 * Most likely this means a cross login is in 11636 * progress or a device about to be yanked out. 11637 * Only accept the plogi if my wwn is smaller. 11638 */ 11639 if (pd->pd_type == PORT_DEVICE_OLD) { 11640 sent = 1; 11641 } 11642 /* 11643 * Stop plogi request (if any) 11644 * attempt from local side to speedup 11645 * the discovery progress. 11646 * Mark the pd as PD_PLOGI_RECEPIENT. 11647 */ 11648 if (f_port == 0 && small < 0) { 11649 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11650 } 11651 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11652 11653 mutex_exit(&pd->pd_mutex); 11654 11655 FP_TRACE(FP_NHEAD1(3, 0), "fp_i_handle_unsol_els: " 11656 "Unsol PLOGI received. PD still exists in the " 11657 "PWWN list. pd=%p PWWN=%s, sent=%x", 11658 pd, dww_name, sent); 11659 11660 if (f_port == 0 && small < 0) { 11661 FP_TRACE(FP_NHEAD1(3, 0), 11662 "fp_i_handle_unsol_els: Mark the pd" 11663 " as plogi recipient, pd=%p, PWWN=%s" 11664 ", sent=%x", 11665 pd, dww_name, sent); 11666 } 11667 } else { 11668 sent = 0; 11669 } 11670 11671 /* 11672 * To avoid Login collisions, accept only if my WWN 11673 * is smaller than the requester (A curious side note 11674 * would be that this rule may not satisfy the PLOGIs 11675 * initiated by the switch from not-so-well known 11676 * ports such as 0xFFFC41) 11677 */ 11678 if ((f_port == 0 && small < 0) || 11679 (((small > 0 && do_acc) || 11680 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11681 if (fp_is_class_supported(port->fp_cos, 11682 buf->ub_class) == FC_FAILURE) { 11683 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11684 cmd->cmd_pkt.pkt_cmdlen = 11685 sizeof (la_els_rjt_t); 11686 cmd->cmd_pkt.pkt_rsplen = 0; 11687 fp_els_rjt_init(port, cmd, buf, 11688 FC_ACTION_NON_RETRYABLE, 11689 FC_REASON_CLASS_NOT_SUPP, NULL); 11690 FP_TRACE(FP_NHEAD1(3, 0), 11691 "fp_i_handle_unsol_els: " 11692 "Unsupported class. " 11693 "Rejecting PLOGI"); 11694 11695 } else { 11696 mutex_enter(&port->fp_mutex); 11697 port->fp_els_resp_pkt_busy = 0; 11698 mutex_exit(&port->fp_mutex); 11699 return; 11700 } 11701 } else { 11702 cmd->cmd_pkt.pkt_cmdlen = 11703 sizeof (la_els_logi_t); 11704 cmd->cmd_pkt.pkt_rsplen = 0; 11705 11706 /* 11707 * If fp_port_id is zero and topology is 11708 * Point-to-Point, get the local port id from 11709 * the d_id in the PLOGI request. 11710 * If the outgoing FLOGI hasn't been accepted, 11711 * the topology will be unknown here. But it's 11712 * still safe to save the d_id to fp_port_id, 11713 * just because it will be overwritten later 11714 * if the topology is not Point-to-Point. 11715 */ 11716 mutex_enter(&port->fp_mutex); 11717 if ((port->fp_port_id.port_id == 0) && 11718 (port->fp_topology == FC_TOP_PT_PT || 11719 port->fp_topology == FC_TOP_UNKNOWN)) { 11720 port->fp_port_id.port_id = 11721 buf->ub_frame.d_id; 11722 } 11723 mutex_exit(&port->fp_mutex); 11724 11725 /* 11726 * Sometime later, we should validate 11727 * the service parameters instead of 11728 * just accepting it. 11729 */ 11730 fp_login_acc_init(port, cmd, buf, NULL, 11731 KM_NOSLEEP); 11732 FP_TRACE(FP_NHEAD1(3, 0), 11733 "fp_i_handle_unsol_els: Accepting PLOGI," 11734 " f_port=%d, small=%d, do_acc=%d," 11735 " sent=%d.", f_port, small, do_acc, 11736 sent); 11737 } 11738 } else { 11739 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 11740 port->fp_options & FP_SEND_RJT) { 11741 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11742 cmd->cmd_pkt.pkt_rsplen = 0; 11743 fp_els_rjt_init(port, cmd, buf, 11744 FC_ACTION_NON_RETRYABLE, 11745 FC_REASON_LOGICAL_BSY, NULL); 11746 FP_TRACE(FP_NHEAD1(3, 0), 11747 "fp_i_handle_unsol_els: " 11748 "Rejecting PLOGI with Logical Busy." 11749 "Possible Login collision."); 11750 } else { 11751 mutex_enter(&port->fp_mutex); 11752 port->fp_els_resp_pkt_busy = 0; 11753 mutex_exit(&port->fp_mutex); 11754 return; 11755 } 11756 } 11757 break; 11758 } 11759 11760 case LA_ELS_FLOGI: 11761 if (fp_is_class_supported(port->fp_cos, 11762 buf->ub_class) == FC_FAILURE) { 11763 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11764 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11765 cmd->cmd_pkt.pkt_rsplen = 0; 11766 fp_els_rjt_init(port, cmd, buf, 11767 FC_ACTION_NON_RETRYABLE, 11768 FC_REASON_CLASS_NOT_SUPP, NULL); 11769 FP_TRACE(FP_NHEAD1(3, 0), 11770 "fp_i_handle_unsol_els: " 11771 "Unsupported Class. Rejecting FLOGI."); 11772 } else { 11773 mutex_enter(&port->fp_mutex); 11774 port->fp_els_resp_pkt_busy = 0; 11775 mutex_exit(&port->fp_mutex); 11776 return; 11777 } 11778 } else { 11779 mutex_enter(&port->fp_mutex); 11780 if (FC_PORT_STATE_MASK(port->fp_state) != 11781 FC_STATE_ONLINE || (port->fp_port_id.port_id && 11782 buf->ub_frame.s_id == port->fp_port_id.port_id)) { 11783 mutex_exit(&port->fp_mutex); 11784 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11785 cmd->cmd_pkt.pkt_cmdlen = 11786 sizeof (la_els_rjt_t); 11787 cmd->cmd_pkt.pkt_rsplen = 0; 11788 fp_els_rjt_init(port, cmd, buf, 11789 FC_ACTION_NON_RETRYABLE, 11790 FC_REASON_INVALID_LINK_CTRL, 11791 NULL); 11792 FP_TRACE(FP_NHEAD1(3, 0), 11793 "fp_i_handle_unsol_els: " 11794 "Invalid Link Ctrl. " 11795 "Rejecting FLOGI."); 11796 } else { 11797 mutex_enter(&port->fp_mutex); 11798 port->fp_els_resp_pkt_busy = 0; 11799 mutex_exit(&port->fp_mutex); 11800 return; 11801 } 11802 } else { 11803 mutex_exit(&port->fp_mutex); 11804 cmd->cmd_pkt.pkt_cmdlen = 11805 sizeof (la_els_logi_t); 11806 cmd->cmd_pkt.pkt_rsplen = 0; 11807 /* 11808 * Let's not aggressively validate the N_Port's 11809 * service parameters until PLOGI. Suffice it 11810 * to give a hint that we are an N_Port and we 11811 * are game to some serious stuff here. 11812 */ 11813 fp_login_acc_init(port, cmd, buf, 11814 NULL, KM_NOSLEEP); 11815 FP_TRACE(FP_NHEAD1(3, 0), 11816 "fp_i_handle_unsol_els: " 11817 "Accepting FLOGI."); 11818 } 11819 } 11820 break; 11821 11822 default: 11823 return; 11824 } 11825 11826 if ((fp_sendcmd(port, cmd, port->fp_fca_handle)) != FC_SUCCESS) { 11827 mutex_enter(&port->fp_mutex); 11828 port->fp_els_resp_pkt_busy = 0; 11829 mutex_exit(&port->fp_mutex); 11830 } 11831 } 11832 11833 11834 /* 11835 * Handle unsolicited PLOGI request 11836 */ 11837 static void 11838 fp_handle_unsol_plogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 11839 job_request_t *job, int sleep) 11840 { 11841 int sent; 11842 int small; 11843 int f_port; 11844 int do_acc; 11845 fp_cmd_t *cmd; 11846 la_wwn_t *swwn; 11847 la_wwn_t *dwwn; 11848 la_els_logi_t *payload; 11849 fc_remote_port_t *pd; 11850 char dww_name[17]; 11851 11852 payload = (la_els_logi_t *)buf->ub_buffer; 11853 f_port = FP_IS_F_PORT(payload->common_service.cmn_features) ? 1 : 0; 11854 11855 mutex_enter(&port->fp_mutex); 11856 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 11857 mutex_exit(&port->fp_mutex); 11858 11859 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: s_id=%x, d_id=%x," 11860 "type=%x, f_ctl=%x" 11861 " seq_id=%x, ox_id=%x, rx_id=%x" 11862 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 11863 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 11864 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 11865 11866 swwn = &port->fp_service_params.nport_ww_name; 11867 dwwn = &payload->nport_ww_name; 11868 small = fctl_wwn_cmp(swwn, dwwn); 11869 pd = fctl_get_remote_port_by_pwwn(port, dwwn); 11870 if (pd) { 11871 mutex_enter(&pd->pd_mutex); 11872 sent = (pd->pd_flags == PD_ELS_IN_PROGRESS) ? 1 : 0; 11873 /* 11874 * Most likely this means a cross login is in 11875 * progress or a device about to be yanked out. 11876 * Only accept the plogi if my wwn is smaller. 11877 */ 11878 11879 if (pd->pd_type == PORT_DEVICE_OLD) { 11880 sent = 1; 11881 } 11882 /* 11883 * Stop plogi request (if any) 11884 * attempt from local side to speedup 11885 * the discovery progress. 11886 * Mark the pd as PD_PLOGI_RECEPIENT. 11887 */ 11888 if (f_port == 0 && small < 0) { 11889 pd->pd_recepient = PD_PLOGI_RECEPIENT; 11890 } 11891 fc_wwn_to_str(&pd->pd_port_name, dww_name); 11892 11893 mutex_exit(&pd->pd_mutex); 11894 11895 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: Unsol PLOGI" 11896 " received. PD still exists in the PWWN list. pd=%p " 11897 "PWWN=%s, sent=%x", pd, dww_name, sent); 11898 11899 if (f_port == 0 && small < 0) { 11900 FP_TRACE(FP_NHEAD1(3, 0), 11901 "fp_handle_unsol_plogi: Mark the pd" 11902 " as plogi recipient, pd=%p, PWWN=%s" 11903 ", sent=%x", 11904 pd, dww_name, sent); 11905 } 11906 } else { 11907 sent = 0; 11908 } 11909 11910 /* 11911 * Avoid Login collisions by accepting only if my WWN is smaller. 11912 * 11913 * A side note: There is no need to start a PLOGI from this end in 11914 * this context if login isn't going to be accepted for the 11915 * above reason as either a LIP (in private loop), RSCN (in 11916 * fabric topology), or an FLOGI (in point to point - Huh ? 11917 * check FC-PH) would normally drive the PLOGI from this end. 11918 * At this point of time there is no need for an inbound PLOGI 11919 * to kick an outbound PLOGI when it is going to be rejected 11920 * for the reason of WWN being smaller. However it isn't hard 11921 * to do that either (when such a need arises, start a timer 11922 * for a duration that extends beyond a normal device discovery 11923 * time and check if an outbound PLOGI did go before that, if 11924 * none fire one) 11925 * 11926 * Unfortunately, as it turned out, during booting, it is possible 11927 * to miss another initiator in the same loop as port driver 11928 * instances are serially attached. While preserving the above 11929 * comments for belly laughs, please kick an outbound PLOGI in 11930 * a non-switch environment (which is a pt pt between N_Ports or 11931 * a private loop) 11932 * 11933 * While preserving the above comments for amusement, send an 11934 * ACC if the PLOGI is going to be rejected for WWN being smaller 11935 * when no discovery is in progress at this end. Turn around 11936 * and make the port device as the PLOGI initiator, so that 11937 * during subsequent link/loop initialization, this end drives 11938 * the PLOGI (In fact both ends do in this particular case, but 11939 * only one wins) 11940 * 11941 * Make sure the PLOGIs initiated by the switch from not-so-well-known 11942 * ports (such as 0xFFFC41) are accepted too. 11943 */ 11944 if ((f_port == 0 && small < 0) || (((small > 0 && do_acc) || 11945 FC_MUST_ACCEPT_D_ID(buf->ub_frame.s_id)) && sent == 0)) { 11946 if (fp_is_class_supported(port->fp_cos, 11947 buf->ub_class) == FC_FAILURE) { 11948 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 11949 cmd = fp_alloc_pkt(port, 11950 sizeof (la_els_logi_t), 0, sleep, pd); 11951 if (cmd == NULL) { 11952 return; 11953 } 11954 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 11955 cmd->cmd_pkt.pkt_rsplen = 0; 11956 fp_els_rjt_init(port, cmd, buf, 11957 FC_ACTION_NON_RETRYABLE, 11958 FC_REASON_CLASS_NOT_SUPP, job); 11959 FP_TRACE(FP_NHEAD1(3, 0), 11960 "fp_handle_unsol_plogi: " 11961 "Unsupported class. rejecting PLOGI"); 11962 } 11963 } else { 11964 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 11965 0, sleep, pd); 11966 if (cmd == NULL) { 11967 return; 11968 } 11969 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_logi_t); 11970 cmd->cmd_pkt.pkt_rsplen = 0; 11971 11972 /* 11973 * Sometime later, we should validate the service 11974 * parameters instead of just accepting it. 11975 */ 11976 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 11977 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 11978 "Accepting PLOGI, f_port=%d, small=%d, " 11979 "do_acc=%d, sent=%d.", f_port, small, do_acc, 11980 sent); 11981 11982 /* 11983 * If fp_port_id is zero and topology is 11984 * Point-to-Point, get the local port id from 11985 * the d_id in the PLOGI request. 11986 * If the outgoing FLOGI hasn't been accepted, 11987 * the topology will be unknown here. But it's 11988 * still safe to save the d_id to fp_port_id, 11989 * just because it will be overwritten later 11990 * if the topology is not Point-to-Point. 11991 */ 11992 mutex_enter(&port->fp_mutex); 11993 if ((port->fp_port_id.port_id == 0) && 11994 (port->fp_topology == FC_TOP_PT_PT || 11995 port->fp_topology == FC_TOP_UNKNOWN)) { 11996 port->fp_port_id.port_id = 11997 buf->ub_frame.d_id; 11998 } 11999 mutex_exit(&port->fp_mutex); 12000 } 12001 } else { 12002 if (FP_IS_CLASS_1_OR_2(buf->ub_class) || 12003 port->fp_options & FP_SEND_RJT) { 12004 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12005 0, sleep, pd); 12006 if (cmd == NULL) { 12007 return; 12008 } 12009 cmd->cmd_pkt.pkt_cmdlen = sizeof (la_els_rjt_t); 12010 cmd->cmd_pkt.pkt_rsplen = 0; 12011 /* 12012 * Send out Logical busy to indicate 12013 * the detection of PLOGI collision 12014 */ 12015 fp_els_rjt_init(port, cmd, buf, 12016 FC_ACTION_NON_RETRYABLE, 12017 FC_REASON_LOGICAL_BSY, job); 12018 12019 fc_wwn_to_str(dwwn, dww_name); 12020 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_plogi: " 12021 "Rejecting Unsol PLOGI with Logical Busy." 12022 "possible PLOGI collision. PWWN=%s, sent=%x", 12023 dww_name, sent); 12024 } else { 12025 return; 12026 } 12027 } 12028 12029 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12030 fp_free_pkt(cmd); 12031 } 12032 } 12033 12034 12035 /* 12036 * Handle mischievous turning over of our own FLOGI requests back to 12037 * us by the SOC+ microcode. In other words, look at the class of such 12038 * bone headed requests, if 1 or 2, bluntly P_RJT them, if 3 drop them 12039 * on the floor 12040 */ 12041 static void 12042 fp_handle_unsol_flogi(fc_local_port_t *port, fc_unsol_buf_t *buf, 12043 job_request_t *job, int sleep) 12044 { 12045 uint32_t state; 12046 uint32_t s_id; 12047 fp_cmd_t *cmd; 12048 12049 if (fp_is_class_supported(port->fp_cos, buf->ub_class) == FC_FAILURE) { 12050 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12051 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12052 0, sleep, NULL); 12053 if (cmd == NULL) { 12054 return; 12055 } 12056 fp_els_rjt_init(port, cmd, buf, 12057 FC_ACTION_NON_RETRYABLE, 12058 FC_REASON_CLASS_NOT_SUPP, job); 12059 } else { 12060 return; 12061 } 12062 } else { 12063 12064 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi:" 12065 " s_id=%x, d_id=%x, type=%x, f_ctl=%x" 12066 " seq_id=%x, ox_id=%x, rx_id=%x, ro=%x", 12067 buf->ub_frame.s_id, buf->ub_frame.d_id, 12068 buf->ub_frame.type, buf->ub_frame.f_ctl, 12069 buf->ub_frame.seq_id, buf->ub_frame.ox_id, 12070 buf->ub_frame.rx_id, buf->ub_frame.ro); 12071 12072 mutex_enter(&port->fp_mutex); 12073 state = FC_PORT_STATE_MASK(port->fp_state); 12074 s_id = port->fp_port_id.port_id; 12075 mutex_exit(&port->fp_mutex); 12076 12077 if (state != FC_STATE_ONLINE || 12078 (s_id && buf->ub_frame.s_id == s_id)) { 12079 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 12080 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 12081 0, sleep, NULL); 12082 if (cmd == NULL) { 12083 return; 12084 } 12085 fp_els_rjt_init(port, cmd, buf, 12086 FC_ACTION_NON_RETRYABLE, 12087 FC_REASON_INVALID_LINK_CTRL, job); 12088 FP_TRACE(FP_NHEAD1(3, 0), 12089 "fp_handle_unsol_flogi: " 12090 "Rejecting PLOGI. Invalid Link CTRL"); 12091 } else { 12092 return; 12093 } 12094 } else { 12095 cmd = fp_alloc_pkt(port, sizeof (la_els_logi_t), 12096 0, sleep, NULL); 12097 if (cmd == NULL) { 12098 return; 12099 } 12100 /* 12101 * Let's not aggressively validate the N_Port's 12102 * service parameters until PLOGI. Suffice it 12103 * to give a hint that we are an N_Port and we 12104 * are game to some serious stuff here. 12105 */ 12106 fp_login_acc_init(port, cmd, buf, job, KM_SLEEP); 12107 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_flogi: " 12108 "Accepting PLOGI"); 12109 } 12110 } 12111 12112 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12113 fp_free_pkt(cmd); 12114 } 12115 } 12116 12117 12118 /* 12119 * Perform PLOGI accept 12120 */ 12121 static void 12122 fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 12123 job_request_t *job, int sleep) 12124 { 12125 fc_packet_t *pkt; 12126 fc_portmap_t *listptr; 12127 la_els_logi_t payload; 12128 12129 ASSERT(buf != NULL); 12130 12131 /* 12132 * If we are sending ACC to PLOGI and we haven't already 12133 * create port and node device handles, let's create them 12134 * here. 12135 */ 12136 if (buf->ub_buffer[0] == LA_ELS_PLOGI && 12137 FC_IS_REAL_DEVICE(buf->ub_frame.s_id)) { 12138 int small; 12139 int do_acc; 12140 fc_remote_port_t *pd; 12141 la_els_logi_t *req; 12142 12143 req = (la_els_logi_t *)buf->ub_buffer; 12144 small = fctl_wwn_cmp(&port->fp_service_params.nport_ww_name, 12145 &req->nport_ww_name); 12146 12147 mutex_enter(&port->fp_mutex); 12148 do_acc = (port->fp_statec_busy == 0) ? 1 : 0; 12149 mutex_exit(&port->fp_mutex); 12150 12151 FP_TRACE(FP_NHEAD1(3, 0), "fp_plogi_acc_init fp %x, pd %x", 12152 port->fp_port_id.port_id, buf->ub_frame.s_id); 12153 pd = fctl_create_remote_port(port, &req->node_ww_name, 12154 &req->nport_ww_name, buf->ub_frame.s_id, 12155 PD_PLOGI_RECEPIENT, sleep); 12156 if (pd == NULL) { 12157 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: " 12158 "Couldn't create port device for d_id:0x%x", 12159 buf->ub_frame.s_id); 12160 12161 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 12162 "couldn't create port device d_id=%x", 12163 buf->ub_frame.s_id); 12164 } else { 12165 /* 12166 * usoc currently returns PLOGIs inline and 12167 * the maximum buffer size is 60 bytes or so. 12168 * So attempt not to look beyond what is in 12169 * the unsolicited buffer 12170 * 12171 * JNI also traverses this path sometimes 12172 */ 12173 if (buf->ub_bufsize >= sizeof (la_els_logi_t)) { 12174 fp_register_login(NULL, pd, req, buf->ub_class); 12175 } else { 12176 mutex_enter(&pd->pd_mutex); 12177 if (pd->pd_login_count == 0) { 12178 pd->pd_login_count++; 12179 } 12180 pd->pd_state = PORT_DEVICE_LOGGED_IN; 12181 pd->pd_login_class = buf->ub_class; 12182 mutex_exit(&pd->pd_mutex); 12183 } 12184 12185 listptr = kmem_zalloc(sizeof (fc_portmap_t), sleep); 12186 if (listptr != NULL) { 12187 fctl_copy_portmap(listptr, pd); 12188 (void) fp_ulp_devc_cb(port, listptr, 12189 1, 1, sleep, 0); 12190 } 12191 12192 if (small > 0 && do_acc) { 12193 mutex_enter(&pd->pd_mutex); 12194 pd->pd_recepient = PD_PLOGI_INITIATOR; 12195 mutex_exit(&pd->pd_mutex); 12196 } 12197 } 12198 } 12199 12200 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 12201 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 12202 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12203 cmd->cmd_retry_count = 1; 12204 cmd->cmd_ulp_pkt = NULL; 12205 12206 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12207 cmd->cmd_job = job; 12208 12209 pkt = &cmd->cmd_pkt; 12210 12211 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 12212 12213 payload = port->fp_service_params; 12214 payload.ls_code.ls_code = LA_ELS_ACC; 12215 12216 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12217 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12218 12219 FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x " 12220 "bufsize:0x%x sizeof (la_els_logi):0x%x " 12221 "port's wwn:0x%01x%03x%04x%08x requestor's wwn:0x%01x%03x%04x%08x " 12222 "statec_busy:0x%x", buf->ub_buffer[0], buf->ub_frame.s_id, 12223 buf->ub_bufsize, sizeof (la_els_logi_t), 12224 port->fp_service_params.nport_ww_name.w.naa_id, 12225 port->fp_service_params.nport_ww_name.w.nport_id, 12226 port->fp_service_params.nport_ww_name.w.wwn_hi, 12227 port->fp_service_params.nport_ww_name.w.wwn_lo, 12228 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.naa_id, 12229 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.nport_id, 12230 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_hi, 12231 ((la_els_logi_t *)buf->ub_buffer)->nport_ww_name.w.wwn_lo, 12232 port->fp_statec_busy); 12233 } 12234 12235 12236 #define RSCN_EVENT_NAME_LEN 256 12237 12238 /* 12239 * Handle RSCNs 12240 */ 12241 static void 12242 fp_handle_unsol_rscn(fc_local_port_t *port, fc_unsol_buf_t *buf, 12243 job_request_t *job, int sleep) 12244 { 12245 uint32_t mask; 12246 fp_cmd_t *cmd; 12247 uint32_t count; 12248 int listindex; 12249 int16_t len; 12250 fc_rscn_t *payload; 12251 fc_portmap_t *listptr; 12252 fctl_ns_req_t *ns_cmd; 12253 fc_affected_id_t *page; 12254 caddr_t nvname; 12255 nvlist_t *attr_list = NULL; 12256 12257 mutex_enter(&port->fp_mutex); 12258 if (!FC_IS_TOP_SWITCH(port->fp_topology)) { 12259 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12260 --port->fp_rscn_count; 12261 } 12262 mutex_exit(&port->fp_mutex); 12263 return; 12264 } 12265 mutex_exit(&port->fp_mutex); 12266 12267 cmd = fp_alloc_pkt(port, FP_PORT_IDENTIFIER_LEN, 0, sleep, NULL); 12268 if (cmd != NULL) { 12269 fp_els_acc_init(port, cmd, buf, job); 12270 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 12271 fp_free_pkt(cmd); 12272 } 12273 } 12274 12275 payload = (fc_rscn_t *)buf->ub_buffer; 12276 ASSERT(payload->rscn_code == LA_ELS_RSCN); 12277 ASSERT(payload->rscn_len == FP_PORT_IDENTIFIER_LEN); 12278 12279 len = payload->rscn_payload_len - FP_PORT_IDENTIFIER_LEN; 12280 12281 if (len <= 0) { 12282 mutex_enter(&port->fp_mutex); 12283 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12284 --port->fp_rscn_count; 12285 } 12286 mutex_exit(&port->fp_mutex); 12287 12288 return; 12289 } 12290 12291 ASSERT((len & 0x3) == 0); /* Must be power of 4 */ 12292 count = (len >> 2) << 1; /* number of pages multiplied by 2 */ 12293 12294 listptr = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 12295 page = (fc_affected_id_t *)(buf->ub_buffer + sizeof (fc_rscn_t)); 12296 12297 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12298 12299 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpn_id_t), 12300 sizeof (ns_resp_gpn_id_t), sizeof (ns_resp_gpn_id_t), 12301 0, sleep); 12302 if (ns_cmd == NULL) { 12303 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12304 12305 mutex_enter(&port->fp_mutex); 12306 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 12307 --port->fp_rscn_count; 12308 } 12309 mutex_exit(&port->fp_mutex); 12310 12311 return; 12312 } 12313 12314 ns_cmd->ns_cmd_code = NS_GPN_ID; 12315 12316 FP_TRACE(FP_NHEAD1(3, 0), "fp_handle_unsol_rscn: s_id=%x, d_id=%x," 12317 "type=%x, f_ctl=%x seq_id=%x, ox_id=%x, rx_id=%x" 12318 " ro=%x", buf->ub_frame.s_id, buf->ub_frame.d_id, 12319 buf->ub_frame.type, buf->ub_frame.f_ctl, buf->ub_frame.seq_id, 12320 buf->ub_frame.ox_id, buf->ub_frame.rx_id, buf->ub_frame.ro); 12321 12322 /* Only proceed if we can allocate nvname and the nvlist */ 12323 if ((nvname = kmem_zalloc(RSCN_EVENT_NAME_LEN, KM_NOSLEEP)) != NULL && 12324 nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 12325 KM_NOSLEEP) == DDI_SUCCESS) { 12326 if (!(attr_list && nvlist_add_uint32(attr_list, "instance", 12327 port->fp_instance) == DDI_SUCCESS && 12328 nvlist_add_byte_array(attr_list, "port-wwn", 12329 port->fp_service_params.nport_ww_name.raw_wwn, 12330 sizeof (la_wwn_t)) == DDI_SUCCESS)) { 12331 nvlist_free(attr_list); 12332 attr_list = NULL; 12333 } 12334 } 12335 12336 for (listindex = 0; len; len -= FP_PORT_IDENTIFIER_LEN, page++) { 12337 /* Add affected page to the event payload */ 12338 if (attr_list != NULL) { 12339 (void) snprintf(nvname, RSCN_EVENT_NAME_LEN, 12340 "affected_page_%d", listindex); 12341 if (attr_list && nvlist_add_uint32(attr_list, nvname, 12342 ntohl(*(uint32_t *)page)) != DDI_SUCCESS) { 12343 /* We don't send a partial event, so dump it */ 12344 nvlist_free(attr_list); 12345 attr_list = NULL; 12346 } 12347 } 12348 /* 12349 * Query the NS to get the Port WWN for this 12350 * affected D_ID. 12351 */ 12352 mask = 0; 12353 switch (page->aff_format & FC_RSCN_ADDRESS_MASK) { 12354 case FC_RSCN_PORT_ADDRESS: 12355 fp_validate_rscn_page(port, page, job, ns_cmd, 12356 listptr, &listindex, sleep); 12357 12358 if (listindex == 0) { 12359 /* 12360 * We essentially did not process this RSCN. So, 12361 * ULPs are not going to be called and so we 12362 * decrement the rscn_count 12363 */ 12364 mutex_enter(&port->fp_mutex); 12365 if (--port->fp_rscn_count == 12366 FC_INVALID_RSCN_COUNT) { 12367 --port->fp_rscn_count; 12368 } 12369 mutex_exit(&port->fp_mutex); 12370 } 12371 break; 12372 12373 case FC_RSCN_AREA_ADDRESS: 12374 mask = 0xFFFF00; 12375 /* FALLTHROUGH */ 12376 12377 case FC_RSCN_DOMAIN_ADDRESS: 12378 if (!mask) { 12379 mask = 0xFF0000; 12380 } 12381 fp_validate_area_domain(port, page->aff_d_id, mask, 12382 job, sleep); 12383 break; 12384 12385 case FC_RSCN_FABRIC_ADDRESS: 12386 /* 12387 * We need to discover all the devices on this 12388 * port. 12389 */ 12390 fp_validate_area_domain(port, 0, 0, job, sleep); 12391 break; 12392 12393 default: 12394 break; 12395 } 12396 } 12397 if (attr_list != NULL) { 12398 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, 12399 EC_SUNFC, ESC_SUNFC_PORT_RSCN, attr_list, 12400 NULL, DDI_SLEEP); 12401 nvlist_free(attr_list); 12402 } else { 12403 FP_TRACE(FP_NHEAD1(9, 0), 12404 "RSCN handled, but event not sent to userland"); 12405 } 12406 if (nvname != NULL) { 12407 kmem_free(nvname, RSCN_EVENT_NAME_LEN); 12408 } 12409 12410 if (ns_cmd) { 12411 fctl_free_ns_cmd(ns_cmd); 12412 } 12413 12414 if (listindex) { 12415 #ifdef DEBUG 12416 page = (fc_affected_id_t *)(buf->ub_buffer + 12417 sizeof (fc_rscn_t)); 12418 12419 if (listptr->map_did.port_id != page->aff_d_id) { 12420 FP_TRACE(FP_NHEAD1(9, 0), 12421 "PORT RSCN: processed=%x, reporting=%x", 12422 listptr->map_did.port_id, page->aff_d_id); 12423 } 12424 #endif 12425 12426 (void) fp_ulp_devc_cb(port, listptr, listindex, count, 12427 sleep, 0); 12428 } else { 12429 kmem_free(listptr, sizeof (fc_portmap_t) * count); 12430 } 12431 } 12432 12433 12434 /* 12435 * Fill out old map for ULPs with fp_mutex, fd_mutex and pd_mutex held 12436 */ 12437 static void 12438 fp_fillout_old_map_held(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12439 { 12440 int is_switch; 12441 int initiator; 12442 fc_local_port_t *port; 12443 12444 port = pd->pd_port; 12445 12446 /* This function has the following bunch of assumptions */ 12447 ASSERT(port != NULL); 12448 ASSERT(MUTEX_HELD(&port->fp_mutex)); 12449 ASSERT(MUTEX_HELD(&pd->pd_remote_nodep->fd_mutex)); 12450 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12451 12452 pd->pd_state = PORT_DEVICE_INVALID; 12453 pd->pd_type = PORT_DEVICE_OLD; 12454 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12455 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12456 12457 fctl_delist_did_table(port, pd); 12458 fctl_delist_pwwn_table(port, pd); 12459 12460 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map_held: port=%p, d_id=%x" 12461 " removed the PD=%p from DID and PWWN tables", 12462 port, pd->pd_port_id.port_id, pd); 12463 12464 if ((!flag) && port && initiator && is_switch) { 12465 (void) fctl_add_orphan_held(port, pd); 12466 } 12467 fctl_copy_portmap_held(map, pd); 12468 map->map_pd = pd; 12469 } 12470 12471 /* 12472 * Fill out old map for ULPs 12473 */ 12474 static void 12475 fp_fillout_old_map(fc_portmap_t *map, fc_remote_port_t *pd, uchar_t flag) 12476 { 12477 int is_switch; 12478 int initiator; 12479 fc_local_port_t *port; 12480 12481 mutex_enter(&pd->pd_mutex); 12482 port = pd->pd_port; 12483 mutex_exit(&pd->pd_mutex); 12484 12485 mutex_enter(&port->fp_mutex); 12486 mutex_enter(&pd->pd_mutex); 12487 12488 pd->pd_state = PORT_DEVICE_INVALID; 12489 pd->pd_type = PORT_DEVICE_OLD; 12490 initiator = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 12491 is_switch = FC_IS_TOP_SWITCH(port->fp_topology); 12492 12493 fctl_delist_did_table(port, pd); 12494 fctl_delist_pwwn_table(port, pd); 12495 12496 FP_TRACE(FP_NHEAD1(6, 0), "fp_fillout_old_map: port=%p, d_id=%x" 12497 " removed the PD=%p from DID and PWWN tables", 12498 port, pd->pd_port_id.port_id, pd); 12499 12500 mutex_exit(&pd->pd_mutex); 12501 mutex_exit(&port->fp_mutex); 12502 12503 ASSERT(port != NULL); 12504 if ((!flag) && port && initiator && is_switch) { 12505 (void) fctl_add_orphan(port, pd, KM_NOSLEEP); 12506 } 12507 fctl_copy_portmap(map, pd); 12508 map->map_pd = pd; 12509 } 12510 12511 12512 /* 12513 * Fillout Changed Map for ULPs 12514 */ 12515 static void 12516 fp_fillout_changed_map(fc_portmap_t *map, fc_remote_port_t *pd, 12517 uint32_t *new_did, la_wwn_t *new_pwwn) 12518 { 12519 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 12520 12521 pd->pd_type = PORT_DEVICE_CHANGED; 12522 if (new_did) { 12523 pd->pd_port_id.port_id = *new_did; 12524 } 12525 if (new_pwwn) { 12526 pd->pd_port_name = *new_pwwn; 12527 } 12528 mutex_exit(&pd->pd_mutex); 12529 12530 fctl_copy_portmap(map, pd); 12531 12532 mutex_enter(&pd->pd_mutex); 12533 pd->pd_type = PORT_DEVICE_NOCHANGE; 12534 } 12535 12536 12537 /* 12538 * Fillout New Name Server map 12539 */ 12540 static void 12541 fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle, 12542 fc_portmap_t *port_map, ns_resp_gan_t *gan_resp, uint32_t d_id) 12543 { 12544 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12545 12546 if (handle) { 12547 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn, 12548 (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn), 12549 DDI_DEV_AUTOINCR); 12550 FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn, 12551 (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn), 12552 DDI_DEV_AUTOINCR); 12553 FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types, 12554 (uint8_t *)gan_resp->gan_fc4types, 12555 sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR); 12556 } else { 12557 bcopy(&gan_resp->gan_pwwn, &port_map->map_pwwn, 12558 sizeof (gan_resp->gan_pwwn)); 12559 bcopy(&gan_resp->gan_nwwn, &port_map->map_nwwn, 12560 sizeof (gan_resp->gan_nwwn)); 12561 bcopy(gan_resp->gan_fc4types, port_map->map_fc4_types, 12562 sizeof (gan_resp->gan_fc4types)); 12563 } 12564 port_map->map_did.port_id = d_id; 12565 port_map->map_did.priv_lilp_posit = 0; 12566 port_map->map_hard_addr.hard_addr = 0; 12567 port_map->map_hard_addr.rsvd = 0; 12568 port_map->map_state = PORT_DEVICE_INVALID; 12569 port_map->map_type = PORT_DEVICE_NEW; 12570 port_map->map_flags = 0; 12571 port_map->map_pd = NULL; 12572 12573 (void) fctl_remove_if_orphan(port, &port_map->map_pwwn); 12574 12575 ASSERT(port != NULL); 12576 } 12577 12578 12579 /* 12580 * Perform LINIT ELS 12581 */ 12582 static int 12583 fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep, 12584 job_request_t *job) 12585 { 12586 int rval; 12587 uint32_t d_id; 12588 uint32_t s_id; 12589 uint32_t lfa; 12590 uchar_t class; 12591 uint32_t ret; 12592 fp_cmd_t *cmd; 12593 fc_porttype_t ptype; 12594 fc_packet_t *pkt; 12595 fc_linit_req_t payload; 12596 fc_remote_port_t *pd; 12597 12598 rval = 0; 12599 12600 ASSERT(job != NULL); 12601 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12602 12603 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 12604 if (pd == NULL) { 12605 fctl_ns_req_t *ns_cmd; 12606 12607 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 12608 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 12609 0, sleep); 12610 12611 if (ns_cmd == NULL) { 12612 return (FC_NOMEM); 12613 } 12614 job->job_result = FC_SUCCESS; 12615 ns_cmd->ns_cmd_code = NS_GID_PN; 12616 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 12617 12618 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12619 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12620 fctl_free_ns_cmd(ns_cmd); 12621 return (FC_FAILURE); 12622 } 12623 bcopy(ns_cmd->ns_data_buf, (caddr_t)&d_id, sizeof (d_id)); 12624 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 12625 12626 fctl_free_ns_cmd(ns_cmd); 12627 lfa = d_id & 0xFFFF00; 12628 12629 /* 12630 * Given this D_ID, get the port type to see if 12631 * we can do LINIT on the LFA 12632 */ 12633 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gpt_id_t), 12634 sizeof (ns_resp_gpt_id_t), sizeof (ns_resp_gpt_id_t), 12635 0, sleep); 12636 12637 if (ns_cmd == NULL) { 12638 return (FC_NOMEM); 12639 } 12640 12641 job->job_result = FC_SUCCESS; 12642 ns_cmd->ns_cmd_code = NS_GPT_ID; 12643 12644 ((ns_req_gpt_id_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id; 12645 ((ns_req_gpt_id_t *) 12646 (ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 12647 12648 ret = fp_ns_query(port, ns_cmd, job, 1, sleep); 12649 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 12650 fctl_free_ns_cmd(ns_cmd); 12651 return (FC_FAILURE); 12652 } 12653 bcopy(ns_cmd->ns_data_buf, (caddr_t)&ptype, sizeof (ptype)); 12654 12655 fctl_free_ns_cmd(ns_cmd); 12656 12657 switch (ptype.port_type) { 12658 case FC_NS_PORT_NL: 12659 case FC_NS_PORT_F_NL: 12660 case FC_NS_PORT_FL: 12661 break; 12662 12663 default: 12664 return (FC_FAILURE); 12665 } 12666 } else { 12667 mutex_enter(&pd->pd_mutex); 12668 ptype = pd->pd_porttype; 12669 12670 switch (pd->pd_porttype.port_type) { 12671 case FC_NS_PORT_NL: 12672 case FC_NS_PORT_F_NL: 12673 case FC_NS_PORT_FL: 12674 lfa = pd->pd_port_id.port_id & 0xFFFF00; 12675 break; 12676 12677 default: 12678 mutex_exit(&pd->pd_mutex); 12679 return (FC_FAILURE); 12680 } 12681 mutex_exit(&pd->pd_mutex); 12682 } 12683 12684 mutex_enter(&port->fp_mutex); 12685 s_id = port->fp_port_id.port_id; 12686 class = port->fp_ns_login_class; 12687 mutex_exit(&port->fp_mutex); 12688 12689 cmd = fp_alloc_pkt(port, sizeof (fc_linit_req_t), 12690 sizeof (fc_linit_resp_t), sleep, pd); 12691 if (cmd == NULL) { 12692 return (FC_NOMEM); 12693 } 12694 12695 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12696 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12697 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 12698 cmd->cmd_retry_count = fp_retry_count; 12699 cmd->cmd_ulp_pkt = NULL; 12700 12701 pkt = &cmd->cmd_pkt; 12702 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 12703 12704 fp_els_init(cmd, s_id, lfa, fp_linit_intr, job); 12705 12706 /* 12707 * How does LIP work by the way ? 12708 * If the L_Port receives three consecutive identical ordered 12709 * sets whose first two characters (fully decoded) are equal to 12710 * the values shown in Table 3 of FC-AL-2 then the L_Port shall 12711 * recognize a Loop Initialization Primitive sequence. The 12712 * character 3 determines the type of lip: 12713 * LIP(F7) Normal LIP 12714 * LIP(F8) Loop Failure LIP 12715 * 12716 * The possible combination for the 3rd and 4th bytes are: 12717 * F7, F7 Normal Lip - No valid AL_PA 12718 * F8, F8 Loop Failure - No valid AL_PA 12719 * F7, AL_PS Normal Lip - Valid source AL_PA 12720 * F8, AL_PS Loop Failure - Valid source AL_PA 12721 * AL_PD AL_PS Loop reset of AL_PD originated by AL_PS 12722 * And Normal Lip for all other loop members 12723 * 0xFF AL_PS Vendor specific reset of all loop members 12724 * 12725 * Now, it may not always be that we, at the source, may have an 12726 * AL_PS (AL_PA of source) for 4th character slot, so we decide 12727 * to do (Normal Lip, No Valid AL_PA), that means, in the LINIT 12728 * payload we are going to set: 12729 * lip_b3 = 0xF7; Normal LIP 12730 * lip_b4 = 0xF7; No valid source AL_PA 12731 */ 12732 payload.ls_code.ls_code = LA_ELS_LINIT; 12733 payload.ls_code.mbz = 0; 12734 payload.rsvd = 0; 12735 payload.func = 0; /* Let Fabric determine the best way */ 12736 payload.lip_b3 = 0xF7; /* Normal LIP */ 12737 payload.lip_b4 = 0xF7; /* No valid source AL_PA */ 12738 12739 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 12740 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 12741 12742 job->job_counter = 1; 12743 12744 ret = fp_sendcmd(port, cmd, port->fp_fca_handle); 12745 if (ret == FC_SUCCESS) { 12746 fp_jobwait(job); 12747 rval = job->job_result; 12748 } else { 12749 rval = FC_FAILURE; 12750 fp_free_pkt(cmd); 12751 } 12752 12753 return (rval); 12754 } 12755 12756 12757 /* 12758 * Fill out the device handles with GAN response 12759 */ 12760 static void 12761 fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd, 12762 ns_resp_gan_t *gan_resp) 12763 { 12764 fc_remote_node_t *node; 12765 fc_porttype_t type; 12766 fc_local_port_t *port; 12767 12768 ASSERT(pd != NULL); 12769 ASSERT(handle != NULL); 12770 12771 port = pd->pd_port; 12772 12773 FP_TRACE(FP_NHEAD1(1, 0), "GAN PD stuffing; pd=%p," 12774 " port_id=%x, sym_len=%d fc4-type=%x", 12775 pd, gan_resp->gan_type_id.rsvd, 12776 gan_resp->gan_spnlen, gan_resp->gan_fc4types[0]); 12777 12778 mutex_enter(&pd->pd_mutex); 12779 12780 FC_GET_RSP(port, *handle, (uint8_t *)&type, 12781 (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR); 12782 12783 pd->pd_porttype.port_type = type.port_type; 12784 pd->pd_porttype.rsvd = 0; 12785 12786 pd->pd_spn_len = gan_resp->gan_spnlen; 12787 if (pd->pd_spn_len) { 12788 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn, 12789 (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len, 12790 DDI_DEV_AUTOINCR); 12791 } 12792 12793 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr, 12794 (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr), 12795 DDI_DEV_AUTOINCR); 12796 FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos, 12797 (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos), 12798 DDI_DEV_AUTOINCR); 12799 FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types, 12800 (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types), 12801 DDI_DEV_AUTOINCR); 12802 12803 node = pd->pd_remote_nodep; 12804 mutex_exit(&pd->pd_mutex); 12805 12806 mutex_enter(&node->fd_mutex); 12807 12808 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa, 12809 (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa), 12810 DDI_DEV_AUTOINCR); 12811 12812 node->fd_snn_len = gan_resp->gan_snnlen; 12813 if (node->fd_snn_len) { 12814 FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn, 12815 (uint8_t *)gan_resp->gan_snname, node->fd_snn_len, 12816 DDI_DEV_AUTOINCR); 12817 } 12818 12819 mutex_exit(&node->fd_mutex); 12820 } 12821 12822 12823 /* 12824 * Handles all NS Queries (also means that this function 12825 * doesn't handle NS object registration) 12826 */ 12827 static int 12828 fp_ns_query(fc_local_port_t *port, fctl_ns_req_t *ns_cmd, job_request_t *job, 12829 int polled, int sleep) 12830 { 12831 int rval; 12832 fp_cmd_t *cmd; 12833 12834 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12835 12836 if (ns_cmd->ns_cmd_code == NS_GA_NXT) { 12837 FP_TRACE(FP_NHEAD1(1, 0), "fp_ns_query GA_NXT fp %x pd %x", 12838 port->fp_port_id.port_id, ns_cmd->ns_gan_sid); 12839 } 12840 12841 if (ns_cmd->ns_cmd_size == 0) { 12842 return (FC_FAILURE); 12843 } 12844 12845 cmd = fp_alloc_pkt(port, sizeof (fc_ct_header_t) + 12846 ns_cmd->ns_cmd_size, sizeof (fc_ct_header_t) + 12847 ns_cmd->ns_resp_size, sleep, NULL); 12848 if (cmd == NULL) { 12849 return (FC_NOMEM); 12850 } 12851 12852 fp_ct_init(port, cmd, ns_cmd, ns_cmd->ns_cmd_code, ns_cmd->ns_cmd_buf, 12853 ns_cmd->ns_cmd_size, ns_cmd->ns_resp_size, job); 12854 12855 if (polled) { 12856 job->job_counter = 1; 12857 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 12858 } 12859 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 12860 if (rval != FC_SUCCESS) { 12861 job->job_result = rval; 12862 fp_iodone(cmd); 12863 if (polled == 0) { 12864 /* 12865 * Return FC_SUCCESS to indicate that 12866 * fp_iodone is performed already. 12867 */ 12868 rval = FC_SUCCESS; 12869 } 12870 } 12871 12872 if (polled) { 12873 fp_jobwait(job); 12874 rval = job->job_result; 12875 } 12876 12877 return (rval); 12878 } 12879 12880 12881 /* 12882 * Initialize Common Transport request 12883 */ 12884 static void 12885 fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd, 12886 uint16_t cmd_code, caddr_t cmd_buf, uint16_t cmd_len, 12887 uint16_t resp_len, job_request_t *job) 12888 { 12889 uint32_t s_id; 12890 uchar_t class; 12891 fc_packet_t *pkt; 12892 fc_ct_header_t ct; 12893 12894 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 12895 12896 mutex_enter(&port->fp_mutex); 12897 s_id = port->fp_port_id.port_id; 12898 class = port->fp_ns_login_class; 12899 mutex_exit(&port->fp_mutex); 12900 12901 cmd->cmd_job = job; 12902 cmd->cmd_private = ns_cmd; 12903 pkt = &cmd->cmd_pkt; 12904 12905 ct.ct_rev = CT_REV; 12906 ct.ct_inid = 0; 12907 ct.ct_fcstype = FCSTYPE_DIRECTORY; 12908 ct.ct_fcssubtype = FCSSUB_DS_NAME_SERVER; 12909 ct.ct_options = 0; 12910 ct.ct_reserved1 = 0; 12911 ct.ct_cmdrsp = cmd_code; 12912 ct.ct_aiusize = resp_len >> 2; 12913 ct.ct_reserved2 = 0; 12914 ct.ct_reason = 0; 12915 ct.ct_expln = 0; 12916 ct.ct_vendor = 0; 12917 12918 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct, 12919 (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR); 12920 12921 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 12922 pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC; 12923 pkt->pkt_cmd_fhdr.s_id = s_id; 12924 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 12925 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | 12926 F_CTL_FIRST_SEQ | F_CTL_END_SEQ; 12927 pkt->pkt_cmd_fhdr.seq_id = 0; 12928 pkt->pkt_cmd_fhdr.df_ctl = 0; 12929 pkt->pkt_cmd_fhdr.seq_cnt = 0; 12930 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 12931 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 12932 pkt->pkt_cmd_fhdr.ro = 0; 12933 pkt->pkt_cmd_fhdr.rsvd = 0; 12934 12935 pkt->pkt_comp = fp_ns_intr; 12936 pkt->pkt_ulp_private = (opaque_t)cmd; 12937 pkt->pkt_timeout = FP_NS_TIMEOUT; 12938 12939 if (cmd_buf) { 12940 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf, 12941 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 12942 cmd_len, DDI_DEV_AUTOINCR); 12943 } 12944 12945 cmd->cmd_transport = port->fp_fca_tran->fca_transport; 12946 12947 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | class; 12948 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 12949 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 12950 cmd->cmd_retry_count = fp_retry_count; 12951 cmd->cmd_ulp_pkt = NULL; 12952 } 12953 12954 12955 /* 12956 * Name Server request interrupt routine 12957 */ 12958 static void 12959 fp_ns_intr(fc_packet_t *pkt) 12960 { 12961 fp_cmd_t *cmd; 12962 fc_local_port_t *port; 12963 fc_ct_header_t resp_hdr; 12964 fc_ct_header_t cmd_hdr; 12965 fctl_ns_req_t *ns_cmd; 12966 12967 cmd = pkt->pkt_ulp_private; 12968 port = cmd->cmd_port; 12969 12970 mutex_enter(&port->fp_mutex); 12971 port->fp_out_fpcmds--; 12972 mutex_exit(&port->fp_mutex); 12973 12974 FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr, 12975 (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR); 12976 ns_cmd = (fctl_ns_req_t *) 12977 (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private); 12978 if (!FP_IS_PKT_ERROR(pkt)) { 12979 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr, 12980 (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr), 12981 DDI_DEV_AUTOINCR); 12982 12983 /* 12984 * On x86 architectures, make sure the resp_hdr is big endian. 12985 * This macro is a NOP on sparc architectures mainly because 12986 * we don't want to end up wasting time since the end result 12987 * is going to be the same. 12988 */ 12989 MAKE_BE_32(&resp_hdr); 12990 12991 if (ns_cmd) { 12992 /* 12993 * Always copy out the response CT_HDR 12994 */ 12995 bcopy(&resp_hdr, &ns_cmd->ns_resp_hdr, 12996 sizeof (resp_hdr)); 12997 } 12998 12999 if (resp_hdr.ct_cmdrsp == FS_RJT_IU) { 13000 pkt->pkt_state = FC_PKT_FS_RJT; 13001 pkt->pkt_reason = resp_hdr.ct_reason; 13002 pkt->pkt_expln = resp_hdr.ct_expln; 13003 } 13004 } 13005 13006 if (FP_IS_PKT_ERROR(pkt)) { 13007 if (ns_cmd) { 13008 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13009 ASSERT(ns_cmd->ns_pd != NULL); 13010 13011 /* Mark it OLD if not already done */ 13012 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13013 ns_cmd->ns_pd->pd_type = PORT_DEVICE_OLD; 13014 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13015 } 13016 13017 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13018 fctl_free_ns_cmd(ns_cmd); 13019 ((fp_cmd_t *) 13020 (pkt->pkt_ulp_private))->cmd_private = NULL; 13021 } 13022 13023 } 13024 13025 FP_TRACE(FP_NHEAD2(9, 0), "%x NS failure pkt state=%x" 13026 "reason=%x, expln=%x, NSCMD=%04X, NSRSP=%04X", 13027 port->fp_port_id.port_id, pkt->pkt_state, 13028 pkt->pkt_reason, pkt->pkt_expln, 13029 cmd_hdr.ct_cmdrsp, resp_hdr.ct_cmdrsp); 13030 13031 (void) fp_common_intr(pkt, 1); 13032 13033 return; 13034 } 13035 13036 if (resp_hdr.ct_cmdrsp != FS_ACC_IU) { 13037 uint32_t d_id; 13038 fc_local_port_t *port; 13039 fp_cmd_t *cmd; 13040 13041 d_id = pkt->pkt_cmd_fhdr.d_id; 13042 cmd = pkt->pkt_ulp_private; 13043 port = cmd->cmd_port; 13044 FP_TRACE(FP_NHEAD2(9, 0), 13045 "Bogus NS response received for D_ID=%x", d_id); 13046 } 13047 13048 if (cmd_hdr.ct_cmdrsp == NS_GA_NXT) { 13049 fp_gan_handler(pkt, ns_cmd); 13050 return; 13051 } 13052 13053 if (cmd_hdr.ct_cmdrsp >= NS_GPN_ID && 13054 cmd_hdr.ct_cmdrsp <= NS_GID_PT) { 13055 if (ns_cmd) { 13056 if ((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0) { 13057 fp_ns_query_handler(pkt, ns_cmd); 13058 return; 13059 } 13060 } 13061 } 13062 13063 fp_iodone(pkt->pkt_ulp_private); 13064 } 13065 13066 13067 /* 13068 * Process NS_GAN response 13069 */ 13070 static void 13071 fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13072 { 13073 int my_did; 13074 fc_portid_t d_id; 13075 fp_cmd_t *cmd; 13076 fc_local_port_t *port; 13077 fc_remote_port_t *pd; 13078 ns_req_gan_t gan_req; 13079 ns_resp_gan_t *gan_resp; 13080 13081 ASSERT(ns_cmd != NULL); 13082 13083 cmd = pkt->pkt_ulp_private; 13084 port = cmd->cmd_port; 13085 13086 gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t)); 13087 13088 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id, 13089 (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR); 13090 13091 *(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id); 13092 13093 /* 13094 * In this case the priv_lilp_posit field in reality 13095 * is actually represents the relative position on a private loop. 13096 * So zero it while dealing with Port Identifiers. 13097 */ 13098 d_id.priv_lilp_posit = 0; 13099 pd = fctl_get_remote_port_by_did(port, d_id.port_id); 13100 if (ns_cmd->ns_gan_sid == d_id.port_id) { 13101 /* 13102 * We've come a full circle; time to get out. 13103 */ 13104 fp_iodone(cmd); 13105 return; 13106 } 13107 13108 if (ns_cmd->ns_gan_sid == FCTL_GAN_START_ID) { 13109 ns_cmd->ns_gan_sid = d_id.port_id; 13110 } 13111 13112 mutex_enter(&port->fp_mutex); 13113 my_did = (d_id.port_id == port->fp_port_id.port_id) ? 1 : 0; 13114 mutex_exit(&port->fp_mutex); 13115 13116 FP_TRACE(FP_NHEAD1(1, 0), "GAN response; port=%p, fp %x pd %x", port, 13117 port->fp_port_id.port_id, d_id.port_id); 13118 if (my_did == 0) { 13119 la_wwn_t pwwn; 13120 la_wwn_t nwwn; 13121 13122 FP_TRACE(FP_NHEAD1(1, 0), "GAN response details; " 13123 "port=%p, d_id=%x, type_id=%x, " 13124 "pwwn=%x %x %x %x %x %x %x %x, " 13125 "nwwn=%x %x %x %x %x %x %x %x", 13126 port, d_id.port_id, gan_resp->gan_type_id, 13127 13128 gan_resp->gan_pwwn.raw_wwn[0], 13129 gan_resp->gan_pwwn.raw_wwn[1], 13130 gan_resp->gan_pwwn.raw_wwn[2], 13131 gan_resp->gan_pwwn.raw_wwn[3], 13132 gan_resp->gan_pwwn.raw_wwn[4], 13133 gan_resp->gan_pwwn.raw_wwn[5], 13134 gan_resp->gan_pwwn.raw_wwn[6], 13135 gan_resp->gan_pwwn.raw_wwn[7], 13136 13137 gan_resp->gan_nwwn.raw_wwn[0], 13138 gan_resp->gan_nwwn.raw_wwn[1], 13139 gan_resp->gan_nwwn.raw_wwn[2], 13140 gan_resp->gan_nwwn.raw_wwn[3], 13141 gan_resp->gan_nwwn.raw_wwn[4], 13142 gan_resp->gan_nwwn.raw_wwn[5], 13143 gan_resp->gan_nwwn.raw_wwn[6], 13144 gan_resp->gan_nwwn.raw_wwn[7]); 13145 13146 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn, 13147 (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn), 13148 DDI_DEV_AUTOINCR); 13149 13150 FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn, 13151 (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn), 13152 DDI_DEV_AUTOINCR); 13153 13154 if (ns_cmd->ns_flags & FCTL_NS_CREATE_DEVICE && pd == NULL) { 13155 FP_TRACE(FP_NHEAD1(1, 0), "fp %x gan_hander create" 13156 "pd %x", port->fp_port_id.port_id, d_id.port_id); 13157 pd = fctl_create_remote_port(port, &nwwn, &pwwn, 13158 d_id.port_id, PD_PLOGI_INITIATOR, KM_NOSLEEP); 13159 } 13160 if (pd != NULL) { 13161 fp_stuff_device_with_gan(&pkt->pkt_resp_acc, 13162 pd, gan_resp); 13163 } 13164 13165 if (ns_cmd->ns_flags & FCTL_NS_GET_DEV_COUNT) { 13166 *((int *)ns_cmd->ns_data_buf) += 1; 13167 } 13168 13169 if (ns_cmd->ns_flags & FCTL_NS_FILL_NS_MAP) { 13170 ASSERT((ns_cmd->ns_flags & FCTL_NS_NO_DATA_BUF) == 0); 13171 13172 if (ns_cmd->ns_flags & FCTL_NS_BUF_IS_USERLAND) { 13173 fc_port_dev_t *userbuf; 13174 13175 userbuf = ((fc_port_dev_t *) 13176 ns_cmd->ns_data_buf) + 13177 ns_cmd->ns_gan_index++; 13178 13179 userbuf->dev_did = d_id; 13180 13181 FC_GET_RSP(port, pkt->pkt_resp_acc, 13182 (uint8_t *)userbuf->dev_type, 13183 (uint8_t *)gan_resp->gan_fc4types, 13184 sizeof (userbuf->dev_type), 13185 DDI_DEV_AUTOINCR); 13186 13187 userbuf->dev_nwwn = nwwn; 13188 userbuf->dev_pwwn = pwwn; 13189 13190 if (pd != NULL) { 13191 mutex_enter(&pd->pd_mutex); 13192 userbuf->dev_state = pd->pd_state; 13193 userbuf->dev_hard_addr = 13194 pd->pd_hard_addr; 13195 mutex_exit(&pd->pd_mutex); 13196 } else { 13197 userbuf->dev_state = 13198 PORT_DEVICE_INVALID; 13199 } 13200 } else if (ns_cmd->ns_flags & 13201 FCTL_NS_BUF_IS_FC_PORTMAP) { 13202 fc_portmap_t *map; 13203 13204 map = ((fc_portmap_t *) 13205 ns_cmd->ns_data_buf) + 13206 ns_cmd->ns_gan_index++; 13207 13208 /* 13209 * First fill it like any new map 13210 * and update the port device info 13211 * below. 13212 */ 13213 fp_fillout_new_nsmap(port, &pkt->pkt_resp_acc, 13214 map, gan_resp, d_id.port_id); 13215 if (pd != NULL) { 13216 fctl_copy_portmap(map, pd); 13217 } else { 13218 map->map_state = PORT_DEVICE_INVALID; 13219 map->map_type = PORT_DEVICE_NOCHANGE; 13220 } 13221 } else { 13222 caddr_t dst_ptr; 13223 13224 dst_ptr = ns_cmd->ns_data_buf + 13225 (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++; 13226 13227 FC_GET_RSP(port, pkt->pkt_resp_acc, 13228 (uint8_t *)dst_ptr, (uint8_t *)gan_resp, 13229 NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR); 13230 } 13231 } else { 13232 ns_cmd->ns_gan_index++; 13233 } 13234 if (ns_cmd->ns_gan_index >= ns_cmd->ns_gan_max) { 13235 fp_iodone(cmd); 13236 return; 13237 } 13238 } 13239 13240 gan_req.pid = d_id; 13241 13242 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req, 13243 (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)), 13244 sizeof (gan_req), DDI_DEV_AUTOINCR); 13245 13246 if (cmd->cmd_transport(port->fp_fca_handle, pkt) != FC_SUCCESS) { 13247 pkt->pkt_state = FC_PKT_TRAN_ERROR; 13248 fp_iodone(cmd); 13249 } else { 13250 mutex_enter(&port->fp_mutex); 13251 port->fp_out_fpcmds++; 13252 mutex_exit(&port->fp_mutex); 13253 } 13254 } 13255 13256 13257 /* 13258 * Handle NS Query interrupt 13259 */ 13260 static void 13261 fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd) 13262 { 13263 fp_cmd_t *cmd; 13264 fc_local_port_t *port; 13265 caddr_t src_ptr; 13266 uint32_t xfer_len; 13267 13268 cmd = pkt->pkt_ulp_private; 13269 port = cmd->cmd_port; 13270 13271 xfer_len = ns_cmd->ns_resp_size; 13272 13273 FP_TRACE(FP_NHEAD1(1, 0), "NS Query response, cmd_code=%x, xfer_len=%x", 13274 ns_cmd->ns_cmd_code, xfer_len); 13275 13276 if (ns_cmd->ns_cmd_code == NS_GPN_ID) { 13277 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13278 13279 FP_TRACE(FP_NHEAD1(6, 0), "GPN_ID results; %x %x %x %x %x", 13280 src_ptr[0], src_ptr[1], src_ptr[2], src_ptr[3], src_ptr[4]); 13281 } 13282 13283 if (xfer_len <= ns_cmd->ns_data_len) { 13284 src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t); 13285 FC_GET_RSP(port, pkt->pkt_resp_acc, 13286 (uint8_t *)ns_cmd->ns_data_buf, 13287 (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR); 13288 } 13289 13290 if (ns_cmd->ns_flags & FCTL_NS_VALIDATE_PD) { 13291 ASSERT(ns_cmd->ns_pd != NULL); 13292 13293 mutex_enter(&ns_cmd->ns_pd->pd_mutex); 13294 if (ns_cmd->ns_pd->pd_type == PORT_DEVICE_OLD) { 13295 ns_cmd->ns_pd->pd_type = PORT_DEVICE_NOCHANGE; 13296 } 13297 mutex_exit(&ns_cmd->ns_pd->pd_mutex); 13298 } 13299 13300 if (ns_cmd->ns_flags & FCTL_NS_ASYNC_REQUEST) { 13301 fctl_free_ns_cmd(ns_cmd); 13302 ((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private = NULL; 13303 } 13304 fp_iodone(cmd); 13305 } 13306 13307 13308 /* 13309 * Handle unsolicited ADISC ELS request 13310 */ 13311 static void 13312 fp_handle_unsol_adisc(fc_local_port_t *port, fc_unsol_buf_t *buf, 13313 fc_remote_port_t *pd, job_request_t *job) 13314 { 13315 int rval; 13316 fp_cmd_t *cmd; 13317 13318 FP_TRACE(FP_NHEAD1(5, 0), "ADISC; port=%p, D_ID=%x state=%x, pd=%p", 13319 port, pd->pd_port_id.port_id, pd->pd_state, pd); 13320 mutex_enter(&pd->pd_mutex); 13321 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 13322 mutex_exit(&pd->pd_mutex); 13323 if (FP_IS_CLASS_1_OR_2(buf->ub_class)) { 13324 cmd = fp_alloc_pkt(port, sizeof (la_els_rjt_t), 13325 0, KM_SLEEP, pd); 13326 if (cmd != NULL) { 13327 fp_els_rjt_init(port, cmd, buf, 13328 FC_ACTION_NON_RETRYABLE, 13329 FC_REASON_INVALID_LINK_CTRL, job); 13330 13331 if (fp_sendcmd(port, cmd, 13332 port->fp_fca_handle) != FC_SUCCESS) { 13333 fp_free_pkt(cmd); 13334 } 13335 } 13336 } 13337 } else { 13338 mutex_exit(&pd->pd_mutex); 13339 /* 13340 * Yes, yes, we don't have a hard address. But we 13341 * we should still respond. Huh ? Visit 21.19.2 13342 * of FC-PH-2 which essentially says that if an 13343 * NL_Port doesn't have a hard address, or if a port 13344 * does not have FC-AL capability, it shall report 13345 * zeroes in this field. 13346 */ 13347 cmd = fp_alloc_pkt(port, sizeof (la_els_adisc_t), 13348 0, KM_SLEEP, pd); 13349 if (cmd == NULL) { 13350 return; 13351 } 13352 fp_adisc_acc_init(port, cmd, buf, job); 13353 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13354 if (rval != FC_SUCCESS) { 13355 fp_free_pkt(cmd); 13356 } 13357 } 13358 } 13359 13360 13361 /* 13362 * Initialize ADISC response. 13363 */ 13364 static void 13365 fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf, 13366 job_request_t *job) 13367 { 13368 fc_packet_t *pkt; 13369 la_els_adisc_t payload; 13370 13371 cmd->cmd_pkt.pkt_tran_flags = buf->ub_class; 13372 cmd->cmd_pkt.pkt_tran_type = FC_PKT_OUTBOUND; 13373 cmd->cmd_flags = FP_CMD_CFLAG_UNDEFINED; 13374 cmd->cmd_retry_count = 1; 13375 cmd->cmd_ulp_pkt = NULL; 13376 13377 cmd->cmd_transport = port->fp_fca_tran->fca_els_send; 13378 cmd->cmd_job = job; 13379 13380 pkt = &cmd->cmd_pkt; 13381 13382 fp_unsol_resp_init(pkt, buf, R_CTL_ELS_RSP, FC_TYPE_EXTENDED_LS); 13383 13384 payload.ls_code.ls_code = LA_ELS_ACC; 13385 payload.ls_code.mbz = 0; 13386 13387 mutex_enter(&port->fp_mutex); 13388 payload.nport_id = port->fp_port_id; 13389 payload.hard_addr = port->fp_hard_addr; 13390 mutex_exit(&port->fp_mutex); 13391 13392 payload.port_wwn = port->fp_service_params.nport_ww_name; 13393 payload.node_wwn = port->fp_service_params.node_ww_name; 13394 13395 FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload, 13396 (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR); 13397 } 13398 13399 13400 /* 13401 * Hold and Install the requested ULP drivers 13402 */ 13403 static void 13404 fp_load_ulp_modules(dev_info_t *dip, fc_local_port_t *port) 13405 { 13406 int len; 13407 int count; 13408 int data_len; 13409 major_t ulp_major; 13410 caddr_t ulp_name; 13411 caddr_t data_ptr; 13412 caddr_t data_buf; 13413 13414 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13415 13416 data_buf = NULL; 13417 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 13418 DDI_PROP_DONTPASS, "load-ulp-list", 13419 (caddr_t)&data_buf, &data_len) != DDI_PROP_SUCCESS) { 13420 return; 13421 } 13422 13423 len = strlen(data_buf); 13424 port->fp_ulp_nload = fctl_atoi(data_buf, 10); 13425 13426 data_ptr = data_buf + len + 1; 13427 for (count = 0; count < port->fp_ulp_nload; count++) { 13428 len = strlen(data_ptr) + 1; 13429 ulp_name = kmem_zalloc(len, KM_SLEEP); 13430 bcopy(data_ptr, ulp_name, len); 13431 13432 ulp_major = ddi_name_to_major(ulp_name); 13433 13434 if (ulp_major != (major_t)-1) { 13435 if (modload("drv", ulp_name) < 0) { 13436 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 13437 0, NULL, "failed to load %s", 13438 ulp_name); 13439 } 13440 } else { 13441 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 13442 "%s isn't a valid driver", ulp_name); 13443 } 13444 13445 kmem_free(ulp_name, len); 13446 data_ptr += len; /* Skip to next field */ 13447 } 13448 13449 /* 13450 * Free the memory allocated by DDI 13451 */ 13452 if (data_buf != NULL) { 13453 kmem_free(data_buf, data_len); 13454 } 13455 } 13456 13457 13458 /* 13459 * Perform LOGO operation 13460 */ 13461 static int 13462 fp_logout(fc_local_port_t *port, fc_remote_port_t *pd, job_request_t *job) 13463 { 13464 int rval; 13465 fp_cmd_t *cmd; 13466 13467 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13468 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 13469 13470 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 13471 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 13472 13473 mutex_enter(&port->fp_mutex); 13474 mutex_enter(&pd->pd_mutex); 13475 13476 ASSERT(pd->pd_state == PORT_DEVICE_LOGGED_IN); 13477 ASSERT(pd->pd_login_count == 1); 13478 13479 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 13480 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 13481 cmd->cmd_flags = 0; 13482 cmd->cmd_retry_count = 1; 13483 cmd->cmd_ulp_pkt = NULL; 13484 13485 fp_logo_init(pd, cmd, job); 13486 13487 mutex_exit(&pd->pd_mutex); 13488 mutex_exit(&port->fp_mutex); 13489 13490 rval = fp_sendcmd(port, cmd, port->fp_fca_handle); 13491 if (rval != FC_SUCCESS) { 13492 fp_iodone(cmd); 13493 } 13494 13495 return (rval); 13496 } 13497 13498 13499 /* 13500 * Perform Port attach callbacks to registered ULPs 13501 */ 13502 static void 13503 fp_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd) 13504 { 13505 fp_soft_attach_t *att; 13506 13507 att = kmem_zalloc(sizeof (*att), KM_SLEEP); 13508 att->att_cmd = cmd; 13509 att->att_port = port; 13510 13511 /* 13512 * We need to remember whether or not fctl_busy_port 13513 * succeeded so we know whether or not to call 13514 * fctl_idle_port when the task is complete. 13515 */ 13516 13517 if (fctl_busy_port(port) == 0) { 13518 att->att_need_pm_idle = B_TRUE; 13519 } else { 13520 att->att_need_pm_idle = B_FALSE; 13521 } 13522 13523 (void) taskq_dispatch(port->fp_taskq, fp_ulp_port_attach, 13524 att, KM_SLEEP); 13525 } 13526 13527 13528 /* 13529 * Forward state change notifications on to interested ULPs. 13530 * Spawns a call to fctl_ulp_statec_cb() in a taskq thread to do all the 13531 * real work. 13532 */ 13533 static int 13534 fp_ulp_notify(fc_local_port_t *port, uint32_t statec, int sleep) 13535 { 13536 fc_port_clist_t *clist; 13537 13538 clist = kmem_zalloc(sizeof (*clist), sleep); 13539 if (clist == NULL) { 13540 return (FC_NOMEM); 13541 } 13542 13543 clist->clist_state = statec; 13544 13545 mutex_enter(&port->fp_mutex); 13546 clist->clist_flags = port->fp_topology; 13547 mutex_exit(&port->fp_mutex); 13548 13549 clist->clist_port = (opaque_t)port; 13550 clist->clist_len = 0; 13551 clist->clist_size = 0; 13552 clist->clist_map = NULL; 13553 13554 (void) taskq_dispatch(port->fp_taskq, fctl_ulp_statec_cb, 13555 clist, KM_SLEEP); 13556 13557 return (FC_SUCCESS); 13558 } 13559 13560 13561 /* 13562 * Get name server map 13563 */ 13564 static int 13565 fp_ns_getmap(fc_local_port_t *port, job_request_t *job, fc_portmap_t **map, 13566 uint32_t *len, uint32_t sid) 13567 { 13568 int ret; 13569 fctl_ns_req_t *ns_cmd; 13570 13571 /* 13572 * Don't let the allocator do anything for response; 13573 * we have have buffer ready to fillout. 13574 */ 13575 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13576 sizeof (ns_resp_gan_t), 0, (FCTL_NS_FILL_NS_MAP | 13577 FCTL_NS_BUF_IS_FC_PORTMAP), KM_SLEEP); 13578 13579 ns_cmd->ns_data_len = sizeof (**map) * (*len); 13580 ns_cmd->ns_data_buf = (caddr_t)*map; 13581 13582 ASSERT(ns_cmd != NULL); 13583 13584 ns_cmd->ns_gan_index = 0; 13585 ns_cmd->ns_gan_sid = sid; 13586 ns_cmd->ns_cmd_code = NS_GA_NXT; 13587 ns_cmd->ns_gan_max = *len; 13588 13589 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13590 13591 if (ns_cmd->ns_gan_index != *len) { 13592 *len = ns_cmd->ns_gan_index; 13593 } 13594 ns_cmd->ns_data_len = 0; 13595 ns_cmd->ns_data_buf = NULL; 13596 fctl_free_ns_cmd(ns_cmd); 13597 13598 return (ret); 13599 } 13600 13601 13602 /* 13603 * Create a remote port in Fabric topology by using NS services 13604 */ 13605 static fc_remote_port_t * 13606 fp_create_remote_port_by_ns(fc_local_port_t *port, uint32_t d_id, int sleep) 13607 { 13608 int rval; 13609 job_request_t *job; 13610 fctl_ns_req_t *ns_cmd; 13611 fc_remote_port_t *pd; 13612 13613 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13614 13615 FP_TRACE(FP_NHEAD1(1, 0), "PD creation begin; port=%p, d_id=%x", 13616 port, d_id); 13617 13618 #ifdef DEBUG 13619 mutex_enter(&port->fp_mutex); 13620 ASSERT(FC_IS_TOP_SWITCH(port->fp_topology)); 13621 mutex_exit(&port->fp_mutex); 13622 #endif 13623 13624 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, (opaque_t)port, sleep); 13625 if (job == NULL) { 13626 return (NULL); 13627 } 13628 13629 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 13630 sizeof (ns_resp_gan_t), 0, (FCTL_NS_CREATE_DEVICE | 13631 FCTL_NS_NO_DATA_BUF), sleep); 13632 if (ns_cmd == NULL) { 13633 return (NULL); 13634 } 13635 13636 job->job_result = FC_SUCCESS; 13637 ns_cmd->ns_gan_max = 1; 13638 ns_cmd->ns_cmd_code = NS_GA_NXT; 13639 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 13640 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 13641 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 13642 13643 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 13644 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 13645 fctl_free_ns_cmd(ns_cmd); 13646 13647 if (rval != FC_SUCCESS || job->job_result != FC_SUCCESS) { 13648 fctl_dealloc_job(job); 13649 return (NULL); 13650 } 13651 fctl_dealloc_job(job); 13652 13653 pd = fctl_get_remote_port_by_did(port, d_id); 13654 13655 FP_TRACE(FP_NHEAD1(1, 0), "PD creation end; port=%p, d_id=%x, pd=%p", 13656 port, d_id, pd); 13657 13658 return (pd); 13659 } 13660 13661 13662 /* 13663 * Check for the permissions on an ioctl command. If it is required to have an 13664 * EXCLUSIVE open performed, return a FAILURE to just shut the door on it. If 13665 * the ioctl command isn't in one of the list built, shut the door on that too. 13666 * 13667 * Certain ioctls perform hardware accesses in FCA drivers, and it needs 13668 * to be made sure that users open the port for an exclusive access while 13669 * performing those operations. 13670 * 13671 * This can prevent a casual user from inflicting damage on the port by 13672 * sending these ioctls from multiple processes/threads (there is no good 13673 * reason why one would need to do that) without actually realizing how 13674 * expensive such commands could turn out to be. 13675 * 13676 * It is also important to note that, even with an exclusive access, 13677 * multiple threads can share the same file descriptor and fire down 13678 * commands in parallel. To prevent that the driver needs to make sure 13679 * that such commands aren't in progress already. This is taken care of 13680 * in the FP_EXCL_BUSY bit of fp_flag. 13681 */ 13682 static int 13683 fp_check_perms(uchar_t open_flag, uint16_t ioctl_cmd) 13684 { 13685 int ret = FC_FAILURE; 13686 int count; 13687 13688 for (count = 0; 13689 count < sizeof (fp_perm_list) / sizeof (fp_perm_list[0]); 13690 count++) { 13691 if (fp_perm_list[count].fp_ioctl_cmd == ioctl_cmd) { 13692 if (fp_perm_list[count].fp_open_flag & open_flag) { 13693 ret = FC_SUCCESS; 13694 } 13695 break; 13696 } 13697 } 13698 13699 return (ret); 13700 } 13701 13702 13703 /* 13704 * Bind Port driver's unsolicited, state change callbacks 13705 */ 13706 static int 13707 fp_bind_callbacks(fc_local_port_t *port) 13708 { 13709 fc_fca_bind_info_t bind_info = {0}; 13710 fc_fca_port_info_t *port_info; 13711 int rval = DDI_SUCCESS; 13712 uint16_t class; 13713 int node_namelen, port_namelen; 13714 char *nname = NULL, *pname = NULL; 13715 13716 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13717 13718 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13719 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13720 "node-name", &nname) != DDI_PROP_SUCCESS) { 13721 FP_TRACE(FP_NHEAD1(1, 0), 13722 "fp_bind_callback fail to get node-name"); 13723 } 13724 if (nname) { 13725 fc_str_to_wwn(nname, &(bind_info.port_nwwn)); 13726 } 13727 13728 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, port->fp_port_dip, 13729 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 13730 "port-name", &pname) != DDI_PROP_SUCCESS) { 13731 FP_TRACE(FP_NHEAD1(1, 0), 13732 "fp_bind_callback fail to get port-name"); 13733 } 13734 if (pname) { 13735 fc_str_to_wwn(pname, &(bind_info.port_pwwn)); 13736 } 13737 13738 if (port->fp_npiv_type == FC_NPIV_PORT) { 13739 bind_info.port_npiv = 1; 13740 } 13741 13742 /* 13743 * fca_bind_port returns the FCA driver's handle for the local 13744 * port instance. If the port number isn't supported it returns NULL. 13745 * It also sets up callback in the FCA for various 13746 * things like state change, ELS etc.. 13747 */ 13748 bind_info.port_statec_cb = fp_statec_cb; 13749 bind_info.port_unsol_cb = fp_unsol_cb; 13750 bind_info.port_num = port->fp_port_num; 13751 bind_info.port_handle = (opaque_t)port; 13752 13753 port_info = kmem_zalloc(sizeof (*port_info), KM_SLEEP); 13754 13755 /* 13756 * Hold the port driver mutex as the callbacks are bound until the 13757 * service parameters are properly filled in (in order to be able to 13758 * properly respond to unsolicited ELS requests) 13759 */ 13760 mutex_enter(&port->fp_mutex); 13761 13762 port->fp_fca_handle = port->fp_fca_tran->fca_bind_port( 13763 port->fp_fca_dip, port_info, &bind_info); 13764 13765 if (port->fp_fca_handle == NULL) { 13766 rval = DDI_FAILURE; 13767 goto exit; 13768 } 13769 13770 /* 13771 * Only fcoei will set this bit 13772 */ 13773 if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) { 13774 port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA; 13775 port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA); 13776 } 13777 13778 port->fp_bind_state = port->fp_state = port_info->pi_port_state; 13779 port->fp_service_params = port_info->pi_login_params; 13780 port->fp_hard_addr = port_info->pi_hard_addr; 13781 13782 /* Copy from the FCA structure to the FP structure */ 13783 port->fp_hba_port_attrs = port_info->pi_attrs; 13784 13785 if (port_info->pi_rnid_params.status == FC_SUCCESS) { 13786 port->fp_rnid_init = 1; 13787 bcopy(&port_info->pi_rnid_params.params, 13788 &port->fp_rnid_params, 13789 sizeof (port->fp_rnid_params)); 13790 } else { 13791 port->fp_rnid_init = 0; 13792 } 13793 13794 node_namelen = strlen((char *)&port_info->pi_attrs.sym_node_name); 13795 if (node_namelen) { 13796 bcopy(&port_info->pi_attrs.sym_node_name, 13797 &port->fp_sym_node_name, 13798 node_namelen); 13799 port->fp_sym_node_namelen = node_namelen; 13800 } 13801 port_namelen = strlen((char *)&port_info->pi_attrs.sym_port_name); 13802 if (port_namelen) { 13803 bcopy(&port_info->pi_attrs.sym_port_name, 13804 &port->fp_sym_port_name, 13805 port_namelen); 13806 port->fp_sym_port_namelen = port_namelen; 13807 } 13808 13809 /* zero out the normally unused fields right away */ 13810 port->fp_service_params.ls_code.mbz = 0; 13811 port->fp_service_params.ls_code.ls_code = 0; 13812 bzero(&port->fp_service_params.reserved, 13813 sizeof (port->fp_service_params.reserved)); 13814 13815 class = port_info->pi_login_params.class_1.class_opt; 13816 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS1 : 0; 13817 13818 class = port_info->pi_login_params.class_2.class_opt; 13819 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS2 : 0; 13820 13821 class = port_info->pi_login_params.class_3.class_opt; 13822 port->fp_cos |= (class & 0x8000) ? FC_NS_CLASS3 : 0; 13823 13824 exit: 13825 if (nname) { 13826 ddi_prop_free(nname); 13827 } 13828 if (pname) { 13829 ddi_prop_free(pname); 13830 } 13831 mutex_exit(&port->fp_mutex); 13832 kmem_free(port_info, sizeof (*port_info)); 13833 13834 return (rval); 13835 } 13836 13837 13838 /* 13839 * Retrieve FCA capabilities 13840 */ 13841 static void 13842 fp_retrieve_caps(fc_local_port_t *port) 13843 { 13844 int rval; 13845 int ub_count; 13846 fc_fcp_dma_t fcp_dma; 13847 fc_reset_action_t action; 13848 fc_dma_behavior_t dma_behavior; 13849 13850 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 13851 13852 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13853 FC_CAP_UNSOL_BUF, &ub_count); 13854 13855 switch (rval) { 13856 case FC_CAP_FOUND: 13857 case FC_CAP_SETTABLE: 13858 switch (ub_count) { 13859 case 0: 13860 break; 13861 13862 case -1: 13863 ub_count = fp_unsol_buf_count; 13864 break; 13865 13866 default: 13867 /* 1/4th of total buffers is my share */ 13868 ub_count = 13869 (ub_count / port->fp_fca_tran->fca_numports) >> 2; 13870 break; 13871 } 13872 break; 13873 13874 default: 13875 ub_count = 0; 13876 break; 13877 } 13878 13879 mutex_enter(&port->fp_mutex); 13880 port->fp_ub_count = ub_count; 13881 mutex_exit(&port->fp_mutex); 13882 13883 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13884 FC_CAP_POST_RESET_BEHAVIOR, &action); 13885 13886 switch (rval) { 13887 case FC_CAP_FOUND: 13888 case FC_CAP_SETTABLE: 13889 switch (action) { 13890 case FC_RESET_RETURN_NONE: 13891 case FC_RESET_RETURN_ALL: 13892 case FC_RESET_RETURN_OUTSTANDING: 13893 break; 13894 13895 default: 13896 action = FC_RESET_RETURN_NONE; 13897 break; 13898 } 13899 break; 13900 13901 default: 13902 action = FC_RESET_RETURN_NONE; 13903 break; 13904 } 13905 mutex_enter(&port->fp_mutex); 13906 port->fp_reset_action = action; 13907 mutex_exit(&port->fp_mutex); 13908 13909 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13910 FC_CAP_NOSTREAM_ON_UNALIGN_BUF, &dma_behavior); 13911 13912 switch (rval) { 13913 case FC_CAP_FOUND: 13914 switch (dma_behavior) { 13915 case FC_ALLOW_STREAMING: 13916 /* FALLTHROUGH */ 13917 case FC_NO_STREAMING: 13918 break; 13919 13920 default: 13921 /* 13922 * If capability was found and the value 13923 * was incorrect assume the worst 13924 */ 13925 dma_behavior = FC_NO_STREAMING; 13926 break; 13927 } 13928 break; 13929 13930 default: 13931 /* 13932 * If capability was not defined - allow streaming; existing 13933 * FCAs should not be affected. 13934 */ 13935 dma_behavior = FC_ALLOW_STREAMING; 13936 break; 13937 } 13938 mutex_enter(&port->fp_mutex); 13939 port->fp_dma_behavior = dma_behavior; 13940 mutex_exit(&port->fp_mutex); 13941 13942 rval = port->fp_fca_tran->fca_get_cap(port->fp_fca_handle, 13943 FC_CAP_FCP_DMA, &fcp_dma); 13944 13945 if (rval != FC_CAP_FOUND || (fcp_dma != FC_NO_DVMA_SPACE && 13946 fcp_dma != FC_DVMA_SPACE)) { 13947 fcp_dma = FC_DVMA_SPACE; 13948 } 13949 13950 mutex_enter(&port->fp_mutex); 13951 port->fp_fcp_dma = fcp_dma; 13952 mutex_exit(&port->fp_mutex); 13953 } 13954 13955 13956 /* 13957 * Handle Domain, Area changes in the Fabric. 13958 */ 13959 static void 13960 fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask, 13961 job_request_t *job, int sleep) 13962 { 13963 #ifdef DEBUG 13964 uint32_t dcnt; 13965 #endif 13966 int rval; 13967 int send; 13968 int index; 13969 int listindex; 13970 int login; 13971 int job_flags; 13972 char ww_name[17]; 13973 uint32_t d_id; 13974 uint32_t count; 13975 fctl_ns_req_t *ns_cmd; 13976 fc_portmap_t *list; 13977 fc_orphan_t *orp; 13978 fc_orphan_t *norp; 13979 fc_orphan_t *prev; 13980 fc_remote_port_t *pd; 13981 fc_remote_port_t *npd; 13982 struct pwwn_hash *head; 13983 13984 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 13985 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 13986 0, sleep); 13987 if (ns_cmd == NULL) { 13988 mutex_enter(&port->fp_mutex); 13989 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 13990 --port->fp_rscn_count; 13991 } 13992 mutex_exit(&port->fp_mutex); 13993 13994 return; 13995 } 13996 ns_cmd->ns_cmd_code = NS_GID_PN; 13997 13998 /* 13999 * We need to get a new count of devices from the 14000 * name server, which will also create any new devices 14001 * as needed. 14002 */ 14003 14004 (void) fp_ns_get_devcount(port, job, 1, sleep); 14005 14006 FP_TRACE(FP_NHEAD1(3, 0), 14007 "fp_validate_area_domain: get_devcount found %d devices", 14008 port->fp_total_devices); 14009 14010 mutex_enter(&port->fp_mutex); 14011 14012 for (count = index = 0; index < pwwn_table_size; index++) { 14013 head = &port->fp_pwwn_table[index]; 14014 pd = head->pwwn_head; 14015 while (pd != NULL) { 14016 mutex_enter(&pd->pd_mutex); 14017 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14018 if ((pd->pd_port_id.port_id & mask) == id && 14019 pd->pd_recepient == PD_PLOGI_INITIATOR) { 14020 count++; 14021 pd->pd_type = PORT_DEVICE_OLD; 14022 pd->pd_flags = PD_ELS_MARK; 14023 } 14024 } 14025 mutex_exit(&pd->pd_mutex); 14026 pd = pd->pd_wwn_hnext; 14027 } 14028 } 14029 14030 #ifdef DEBUG 14031 dcnt = count; 14032 #endif /* DEBUG */ 14033 14034 /* 14035 * Since port->fp_orphan_count is declared an 'int' it is 14036 * theoretically possible that the count could go negative. 14037 * 14038 * This would be bad and if that happens we really do want 14039 * to know. 14040 */ 14041 14042 ASSERT(port->fp_orphan_count >= 0); 14043 14044 count += port->fp_orphan_count; 14045 14046 /* 14047 * We add the port->fp_total_devices value to the count 14048 * in the case where our port is newly attached. This is 14049 * because we haven't done any discovery and we don't have 14050 * any orphans in the port's orphan list. If we do not do 14051 * this addition to count then we won't alloc enough kmem 14052 * to do discovery with. 14053 */ 14054 14055 if (count == 0) { 14056 count += port->fp_total_devices; 14057 FP_TRACE(FP_NHEAD1(3, 0), "fp_validate_area_domain: " 14058 "0x%x orphans found, using 0x%x", 14059 port->fp_orphan_count, count); 14060 } 14061 14062 mutex_exit(&port->fp_mutex); 14063 14064 /* 14065 * Allocate the change list 14066 */ 14067 14068 list = kmem_zalloc(sizeof (fc_portmap_t) * count, sleep); 14069 if (list == NULL) { 14070 fp_printf(port, CE_NOTE, FP_LOG_ONLY, 0, NULL, 14071 " Not enough memory to service RSCNs" 14072 " for %d ports, continuing...", count); 14073 14074 fctl_free_ns_cmd(ns_cmd); 14075 14076 mutex_enter(&port->fp_mutex); 14077 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14078 --port->fp_rscn_count; 14079 } 14080 mutex_exit(&port->fp_mutex); 14081 14082 return; 14083 } 14084 14085 /* 14086 * Attempt to validate or invalidate the devices that were 14087 * already in the pwwn hash table. 14088 */ 14089 14090 mutex_enter(&port->fp_mutex); 14091 for (listindex = 0, index = 0; index < pwwn_table_size; index++) { 14092 head = &port->fp_pwwn_table[index]; 14093 npd = head->pwwn_head; 14094 14095 while ((pd = npd) != NULL) { 14096 npd = pd->pd_wwn_hnext; 14097 14098 mutex_enter(&pd->pd_mutex); 14099 if ((pd->pd_port_id.port_id & mask) == id && 14100 pd->pd_flags == PD_ELS_MARK) { 14101 la_wwn_t *pwwn; 14102 14103 job->job_result = FC_SUCCESS; 14104 14105 ((ns_req_gid_pn_t *) 14106 (ns_cmd->ns_cmd_buf))->pwwn = 14107 pd->pd_port_name; 14108 14109 pwwn = &pd->pd_port_name; 14110 d_id = pd->pd_port_id.port_id; 14111 14112 mutex_exit(&pd->pd_mutex); 14113 mutex_exit(&port->fp_mutex); 14114 14115 rval = fp_ns_query(port, ns_cmd, job, 1, 14116 sleep); 14117 if (rval != FC_SUCCESS) { 14118 fc_wwn_to_str(pwwn, ww_name); 14119 14120 FP_TRACE(FP_NHEAD1(3, 0), 14121 "AREA RSCN: PD disappeared; " 14122 "d_id=%x, PWWN=%s", d_id, ww_name); 14123 14124 FP_TRACE(FP_NHEAD2(9, 0), 14125 "N_x Port with D_ID=%x," 14126 " PWWN=%s disappeared from fabric", 14127 d_id, ww_name); 14128 14129 fp_fillout_old_map(list + listindex++, 14130 pd, 1); 14131 } else { 14132 fctl_copy_portmap(list + listindex++, 14133 pd); 14134 14135 mutex_enter(&pd->pd_mutex); 14136 pd->pd_flags = PD_ELS_IN_PROGRESS; 14137 mutex_exit(&pd->pd_mutex); 14138 } 14139 14140 mutex_enter(&port->fp_mutex); 14141 } else { 14142 mutex_exit(&pd->pd_mutex); 14143 } 14144 } 14145 } 14146 14147 mutex_exit(&port->fp_mutex); 14148 14149 ASSERT(listindex == dcnt); 14150 14151 job->job_counter = listindex; 14152 job_flags = job->job_flags; 14153 job->job_flags |= JOB_TYPE_FP_ASYNC; 14154 14155 /* 14156 * Login (if we were the initiator) or validate devices in the 14157 * port map. 14158 */ 14159 14160 for (index = 0; index < listindex; index++) { 14161 pd = list[index].map_pd; 14162 14163 mutex_enter(&pd->pd_mutex); 14164 ASSERT((pd->pd_port_id.port_id & mask) == id); 14165 14166 if (pd->pd_flags != PD_ELS_IN_PROGRESS) { 14167 ASSERT(pd->pd_type == PORT_DEVICE_OLD); 14168 mutex_exit(&pd->pd_mutex); 14169 fp_jobdone(job); 14170 continue; 14171 } 14172 14173 login = (pd->pd_state == PORT_DEVICE_LOGGED_IN) ? 1 : 0; 14174 send = (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0; 14175 d_id = pd->pd_port_id.port_id; 14176 mutex_exit(&pd->pd_mutex); 14177 14178 if ((d_id & mask) == id && send) { 14179 if (login) { 14180 FP_TRACE(FP_NHEAD1(6, 0), 14181 "RSCN and PLOGI request;" 14182 " pd=%p, job=%p d_id=%x, index=%d", pd, 14183 job, d_id, index); 14184 14185 rval = fp_port_login(port, d_id, job, 14186 FP_CMD_PLOGI_RETAIN, sleep, pd, NULL); 14187 if (rval != FC_SUCCESS) { 14188 mutex_enter(&pd->pd_mutex); 14189 pd->pd_flags = PD_IDLE; 14190 mutex_exit(&pd->pd_mutex); 14191 14192 job->job_result = rval; 14193 fp_jobdone(job); 14194 } 14195 FP_TRACE(FP_NHEAD1(1, 0), 14196 "PLOGI succeeded:no skip(1) for " 14197 "D_ID %x", d_id); 14198 list[index].map_flags |= 14199 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14200 } else { 14201 FP_TRACE(FP_NHEAD1(6, 0), "RSCN and NS request;" 14202 " pd=%p, job=%p d_id=%x, index=%d", pd, 14203 job, d_id, index); 14204 14205 rval = fp_ns_validate_device(port, pd, job, 14206 0, sleep); 14207 if (rval != FC_SUCCESS) { 14208 fp_jobdone(job); 14209 } 14210 mutex_enter(&pd->pd_mutex); 14211 pd->pd_flags = PD_IDLE; 14212 mutex_exit(&pd->pd_mutex); 14213 } 14214 } else { 14215 FP_TRACE(FP_NHEAD1(6, 0), 14216 "RSCN and NO request sent; pd=%p," 14217 " d_id=%x, index=%d", pd, d_id, index); 14218 14219 mutex_enter(&pd->pd_mutex); 14220 pd->pd_flags = PD_IDLE; 14221 mutex_exit(&pd->pd_mutex); 14222 14223 fp_jobdone(job); 14224 } 14225 } 14226 14227 if (listindex) { 14228 fctl_jobwait(job); 14229 } 14230 job->job_flags = job_flags; 14231 14232 /* 14233 * Orphan list validation. 14234 */ 14235 mutex_enter(&port->fp_mutex); 14236 for (prev = NULL, orp = port->fp_orphan_list; port->fp_orphan_count && 14237 orp != NULL; orp = norp) { 14238 norp = orp->orp_next; 14239 mutex_exit(&port->fp_mutex); 14240 14241 job->job_counter = 1; 14242 job->job_result = FC_SUCCESS; 14243 ASSERT((job->job_flags & JOB_TYPE_FP_ASYNC) == 0); 14244 14245 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = orp->orp_pwwn; 14246 14247 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14248 ((ns_resp_gid_pn_t *) 14249 ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14250 14251 rval = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 14252 if (rval == FC_SUCCESS) { 14253 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 14254 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 14255 if (pd != NULL) { 14256 fc_wwn_to_str(&orp->orp_pwwn, ww_name); 14257 14258 FP_TRACE(FP_NHEAD1(6, 0), 14259 "RSCN and ORPHAN list " 14260 "success; d_id=%x, PWWN=%s", d_id, ww_name); 14261 14262 FP_TRACE(FP_NHEAD2(6, 0), 14263 "N_x Port with D_ID=%x, PWWN=%s reappeared" 14264 " in fabric", d_id, ww_name); 14265 14266 mutex_enter(&port->fp_mutex); 14267 if (prev) { 14268 prev->orp_next = orp->orp_next; 14269 } else { 14270 ASSERT(orp == port->fp_orphan_list); 14271 port->fp_orphan_list = orp->orp_next; 14272 } 14273 port->fp_orphan_count--; 14274 mutex_exit(&port->fp_mutex); 14275 14276 kmem_free(orp, sizeof (*orp)); 14277 fctl_copy_portmap(list + listindex++, pd); 14278 } else { 14279 prev = orp; 14280 } 14281 } else { 14282 prev = orp; 14283 } 14284 mutex_enter(&port->fp_mutex); 14285 } 14286 mutex_exit(&port->fp_mutex); 14287 14288 /* 14289 * One more pass through the list to delist old devices from 14290 * the d_id and pwwn tables and possibly add to the orphan list. 14291 */ 14292 14293 for (index = 0; index < listindex; index++) { 14294 pd = list[index].map_pd; 14295 ASSERT(pd != NULL); 14296 14297 /* 14298 * Update PLOGI results; For NS validation 14299 * of orphan list, it is redundant 14300 * 14301 * Take care to preserve PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY if 14302 * appropriate as fctl_copy_portmap() will clear map_flags. 14303 */ 14304 if (list[index].map_flags & 14305 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY) { 14306 fctl_copy_portmap(list + index, pd); 14307 list[index].map_flags |= 14308 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14309 } else { 14310 fctl_copy_portmap(list + index, pd); 14311 } 14312 14313 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14314 "results; pd=%p, d_id=%x pwwn=%x %x %x %x %x %x %x %x", 14315 pd, pd->pd_port_id.port_id, 14316 pd->pd_port_name.raw_wwn[0], 14317 pd->pd_port_name.raw_wwn[1], 14318 pd->pd_port_name.raw_wwn[2], 14319 pd->pd_port_name.raw_wwn[3], 14320 pd->pd_port_name.raw_wwn[4], 14321 pd->pd_port_name.raw_wwn[5], 14322 pd->pd_port_name.raw_wwn[6], 14323 pd->pd_port_name.raw_wwn[7]); 14324 14325 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with Area DOMAIN " 14326 "results continued, pd=%p type=%x, flags=%x, state=%x", 14327 pd, pd->pd_type, pd->pd_flags, pd->pd_state); 14328 14329 mutex_enter(&pd->pd_mutex); 14330 if (pd->pd_type == PORT_DEVICE_OLD) { 14331 int initiator; 14332 14333 pd->pd_flags = PD_IDLE; 14334 initiator = (pd->pd_recepient == 14335 PD_PLOGI_INITIATOR) ? 1 : 0; 14336 14337 mutex_exit(&pd->pd_mutex); 14338 14339 mutex_enter(&port->fp_mutex); 14340 mutex_enter(&pd->pd_mutex); 14341 14342 pd->pd_state = PORT_DEVICE_INVALID; 14343 fctl_delist_did_table(port, pd); 14344 fctl_delist_pwwn_table(port, pd); 14345 14346 mutex_exit(&pd->pd_mutex); 14347 mutex_exit(&port->fp_mutex); 14348 14349 if (initiator) { 14350 (void) fctl_add_orphan(port, pd, sleep); 14351 } 14352 list[index].map_pd = pd; 14353 } else { 14354 ASSERT(pd->pd_flags == PD_IDLE); 14355 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 14356 /* 14357 * Reset LOGO tolerance to zero 14358 */ 14359 fctl_tc_reset(&pd->pd_logo_tc); 14360 } 14361 mutex_exit(&pd->pd_mutex); 14362 } 14363 } 14364 14365 if (ns_cmd) { 14366 fctl_free_ns_cmd(ns_cmd); 14367 } 14368 if (listindex) { 14369 (void) fp_ulp_devc_cb(port, list, listindex, count, 14370 sleep, 0); 14371 } else { 14372 kmem_free(list, sizeof (*list) * count); 14373 14374 mutex_enter(&port->fp_mutex); 14375 if (--port->fp_rscn_count == FC_INVALID_RSCN_COUNT) { 14376 --port->fp_rscn_count; 14377 } 14378 mutex_exit(&port->fp_mutex); 14379 } 14380 } 14381 14382 14383 /* 14384 * Work hard to make sense out of an RSCN page. 14385 */ 14386 static void 14387 fp_validate_rscn_page(fc_local_port_t *port, fc_affected_id_t *page, 14388 job_request_t *job, fctl_ns_req_t *ns_cmd, fc_portmap_t *listptr, 14389 int *listindex, int sleep) 14390 { 14391 int rval; 14392 char ww_name[17]; 14393 la_wwn_t *pwwn; 14394 fc_remote_port_t *pwwn_pd; 14395 fc_remote_port_t *did_pd; 14396 14397 did_pd = fctl_get_remote_port_by_did(port, page->aff_d_id); 14398 14399 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; " 14400 "port=%p, d_id=%x, pd=%p, rscn_count:0x%x", port, page->aff_d_id, 14401 did_pd, (uint32_t)(uintptr_t)job->job_cb_arg); 14402 14403 if (did_pd != NULL) { 14404 mutex_enter(&did_pd->pd_mutex); 14405 if (did_pd->pd_flags != PD_IDLE) { 14406 mutex_exit(&did_pd->pd_mutex); 14407 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page: " 14408 "PD is BUSY; port=%p, d_id=%x, pd=%p", 14409 port, page->aff_d_id, did_pd); 14410 return; 14411 } 14412 did_pd->pd_flags = PD_ELS_IN_PROGRESS; 14413 mutex_exit(&did_pd->pd_mutex); 14414 } 14415 14416 job->job_counter = 1; 14417 14418 pwwn = &((ns_resp_gpn_id_t *)ns_cmd->ns_data_buf)->pwwn; 14419 14420 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.port_id = page->aff_d_id; 14421 ((ns_req_gpn_id_t *)ns_cmd->ns_cmd_buf)->pid.priv_lilp_posit = 0; 14422 14423 bzero(ns_cmd->ns_data_buf, sizeof (la_wwn_t)); 14424 rval = fp_ns_query(port, ns_cmd, job, 1, sleep); 14425 14426 FP_TRACE(FP_NHEAD1(1, 0), "NS Query Response for D_ID page; rev=%x," 14427 " in_id=%x, cmdrsp=%x, reason=%x, expln=%x", 14428 ns_cmd->ns_resp_hdr.ct_rev, ns_cmd->ns_resp_hdr.ct_inid, 14429 ns_cmd->ns_resp_hdr.ct_cmdrsp, ns_cmd->ns_resp_hdr.ct_reason, 14430 ns_cmd->ns_resp_hdr.ct_expln); 14431 14432 job->job_counter = 1; 14433 14434 if (rval != FC_SUCCESS || fctl_is_wwn_zero(pwwn) == FC_SUCCESS) { 14435 /* 14436 * What this means is that the D_ID 14437 * disappeared from the Fabric. 14438 */ 14439 if (did_pd == NULL) { 14440 FP_TRACE(FP_NHEAD1(1, 0), "RSCN with D_ID page;" 14441 " NULL PD disappeared, rval=%x", rval); 14442 return; 14443 } 14444 14445 fc_wwn_to_str(&did_pd->pd_port_name, ww_name); 14446 14447 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14448 (uint32_t)(uintptr_t)job->job_cb_arg; 14449 14450 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14451 14452 FP_TRACE(FP_NHEAD1(3, 0), "RSCN: PD disappeared; " 14453 "d_id=%x, PWWN=%s", page->aff_d_id, ww_name); 14454 14455 FP_TRACE(FP_NHEAD2(9, 0), 14456 "GPN_ID for D_ID=%x failed", page->aff_d_id); 14457 14458 FP_TRACE(FP_NHEAD2(9, 0), 14459 "N_x Port with D_ID=%x, PWWN=%s disappeared from" 14460 " fabric", page->aff_d_id, ww_name); 14461 14462 mutex_enter(&did_pd->pd_mutex); 14463 did_pd->pd_flags = PD_IDLE; 14464 mutex_exit(&did_pd->pd_mutex); 14465 14466 FP_TRACE(FP_NHEAD1(3, 0), "RSCN with D_ID (%x) page; " 14467 "PD disappeared, pd=%p", page->aff_d_id, did_pd); 14468 14469 return; 14470 } 14471 14472 pwwn_pd = fctl_get_remote_port_by_pwwn(port, pwwn); 14473 14474 if (did_pd != NULL && pwwn_pd != NULL && did_pd == pwwn_pd) { 14475 /* 14476 * There is no change. Do PLOGI again and add it to 14477 * ULP portmap baggage and return. Note: When RSCNs 14478 * arrive with per page states, the need for PLOGI 14479 * can be determined correctly. 14480 */ 14481 mutex_enter(&pwwn_pd->pd_mutex); 14482 pwwn_pd->pd_type = PORT_DEVICE_NOCHANGE; 14483 mutex_exit(&pwwn_pd->pd_mutex); 14484 14485 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14486 (uint32_t)(uintptr_t)job->job_cb_arg; 14487 14488 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14489 14490 mutex_enter(&pwwn_pd->pd_mutex); 14491 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14492 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14493 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14494 mutex_exit(&pwwn_pd->pd_mutex); 14495 14496 rval = fp_port_login(port, page->aff_d_id, job, 14497 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14498 if (rval == FC_SUCCESS) { 14499 fp_jobwait(job); 14500 rval = job->job_result; 14501 14502 /* 14503 * Reset LOGO tolerance to zero 14504 * Also we are the PLOGI initiator now. 14505 */ 14506 mutex_enter(&pwwn_pd->pd_mutex); 14507 fctl_tc_reset(&pwwn_pd->pd_logo_tc); 14508 pwwn_pd->pd_recepient = PD_PLOGI_INITIATOR; 14509 mutex_exit(&pwwn_pd->pd_mutex); 14510 } 14511 14512 if (rval == FC_SUCCESS) { 14513 struct fc_portmap *map = 14514 listptr + *listindex - 1; 14515 14516 FP_TRACE(FP_NHEAD1(1, 0), 14517 "PLOGI succeeded: no skip(2)" 14518 " for D_ID %x", page->aff_d_id); 14519 map->map_flags |= 14520 PORT_DEVICE_NO_SKIP_DEVICE_DISCOVERY; 14521 } else { 14522 FP_TRACE(FP_NHEAD2(9, rval), 14523 "PLOGI to D_ID=%x failed", page->aff_d_id); 14524 14525 FP_TRACE(FP_NHEAD2(9, 0), 14526 "N_x Port with D_ID=%x, PWWN=%s" 14527 " disappeared from fabric", 14528 page->aff_d_id, ww_name); 14529 14530 fp_fillout_old_map(listptr + 14531 *listindex - 1, pwwn_pd, 0); 14532 } 14533 } else { 14534 mutex_exit(&pwwn_pd->pd_mutex); 14535 } 14536 14537 mutex_enter(&did_pd->pd_mutex); 14538 did_pd->pd_flags = PD_IDLE; 14539 mutex_exit(&did_pd->pd_mutex); 14540 14541 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14542 "Case ONE, rval=%x, result=%x pd=%p", page->aff_d_id, rval, 14543 job->job_result, pwwn_pd); 14544 14545 return; 14546 } 14547 14548 if (did_pd == NULL && pwwn_pd == NULL) { 14549 14550 fc_orphan_t *orp = NULL; 14551 fc_orphan_t *norp = NULL; 14552 fc_orphan_t *prev = NULL; 14553 14554 /* 14555 * Hunt down the orphan list before giving up. 14556 */ 14557 14558 mutex_enter(&port->fp_mutex); 14559 if (port->fp_orphan_count) { 14560 14561 for (orp = port->fp_orphan_list; orp; orp = norp) { 14562 norp = orp->orp_next; 14563 14564 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) != 0) { 14565 prev = orp; 14566 continue; 14567 } 14568 14569 if (prev) { 14570 prev->orp_next = orp->orp_next; 14571 } else { 14572 ASSERT(orp == 14573 port->fp_orphan_list); 14574 port->fp_orphan_list = 14575 orp->orp_next; 14576 } 14577 port->fp_orphan_count--; 14578 break; 14579 } 14580 } 14581 14582 mutex_exit(&port->fp_mutex); 14583 pwwn_pd = fp_create_remote_port_by_ns(port, 14584 page->aff_d_id, sleep); 14585 14586 if (pwwn_pd != NULL) { 14587 14588 if (orp) { 14589 fc_wwn_to_str(&orp->orp_pwwn, 14590 ww_name); 14591 14592 FP_TRACE(FP_NHEAD2(9, 0), 14593 "N_x Port with D_ID=%x," 14594 " PWWN=%s reappeared in fabric", 14595 page->aff_d_id, ww_name); 14596 14597 kmem_free(orp, sizeof (*orp)); 14598 } 14599 14600 (listptr + *listindex)-> 14601 map_rscn_info.ulp_rscn_count = 14602 (uint32_t)(uintptr_t)job->job_cb_arg; 14603 14604 fctl_copy_portmap(listptr + 14605 (*listindex)++, pwwn_pd); 14606 } 14607 14608 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID (0x%x) page; " 14609 "Case TWO", page->aff_d_id); 14610 14611 return; 14612 } 14613 14614 if (pwwn_pd != NULL && did_pd == NULL) { 14615 uint32_t old_d_id; 14616 uint32_t d_id = page->aff_d_id; 14617 14618 /* 14619 * What this means is there is a new D_ID for this 14620 * Port WWN. Take out the port device off D_ID 14621 * list and put it back with a new D_ID. Perform 14622 * PLOGI if already logged in. 14623 */ 14624 mutex_enter(&port->fp_mutex); 14625 mutex_enter(&pwwn_pd->pd_mutex); 14626 14627 old_d_id = pwwn_pd->pd_port_id.port_id; 14628 14629 fctl_delist_did_table(port, pwwn_pd); 14630 14631 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14632 (uint32_t)(uintptr_t)job->job_cb_arg; 14633 14634 fp_fillout_changed_map(listptr + (*listindex)++, pwwn_pd, 14635 &d_id, NULL); 14636 fctl_enlist_did_table(port, pwwn_pd); 14637 14638 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page;" 14639 " Case THREE, pd=%p," 14640 " state=%x", pwwn_pd, pwwn_pd->pd_state); 14641 14642 if ((pwwn_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14643 (pwwn_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14644 fc_wwn_to_str(&pwwn_pd->pd_port_name, ww_name); 14645 14646 mutex_exit(&pwwn_pd->pd_mutex); 14647 mutex_exit(&port->fp_mutex); 14648 14649 FP_TRACE(FP_NHEAD2(9, 0), 14650 "N_x Port with D_ID=%x, PWWN=%s has a new" 14651 " D_ID=%x now", old_d_id, ww_name, d_id); 14652 14653 rval = fp_port_login(port, page->aff_d_id, job, 14654 FP_CMD_PLOGI_RETAIN, sleep, pwwn_pd, NULL); 14655 if (rval == FC_SUCCESS) { 14656 fp_jobwait(job); 14657 rval = job->job_result; 14658 } 14659 14660 if (rval != FC_SUCCESS) { 14661 fp_fillout_old_map(listptr + 14662 *listindex - 1, pwwn_pd, 0); 14663 } 14664 } else { 14665 mutex_exit(&pwwn_pd->pd_mutex); 14666 mutex_exit(&port->fp_mutex); 14667 } 14668 14669 return; 14670 } 14671 14672 if (pwwn_pd == NULL && did_pd != NULL) { 14673 fc_portmap_t *ptr; 14674 uint32_t len = 1; 14675 char old_ww_name[17]; 14676 14677 mutex_enter(&did_pd->pd_mutex); 14678 fc_wwn_to_str(&did_pd->pd_port_name, old_ww_name); 14679 mutex_exit(&did_pd->pd_mutex); 14680 14681 fc_wwn_to_str(pwwn, ww_name); 14682 14683 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14684 (uint32_t)(uintptr_t)job->job_cb_arg; 14685 14686 /* 14687 * What this means is that there is a new Port WWN for 14688 * this D_ID; Mark the Port device as old and provide 14689 * the new PWWN and D_ID combination as new. 14690 */ 14691 fp_fillout_old_map(listptr + (*listindex)++, did_pd, 0); 14692 14693 FP_TRACE(FP_NHEAD2(9, 0), 14694 "N_x Port with D_ID=%x, PWWN=%s has a new PWWN=%s now", 14695 page->aff_d_id, old_ww_name, ww_name); 14696 14697 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14698 (uint32_t)(uintptr_t)job->job_cb_arg; 14699 14700 ptr = listptr + (*listindex)++; 14701 14702 job->job_counter = 1; 14703 14704 if (fp_ns_getmap(port, job, &ptr, &len, 14705 page->aff_d_id - 1) != FC_SUCCESS) { 14706 (*listindex)--; 14707 } 14708 14709 mutex_enter(&did_pd->pd_mutex); 14710 did_pd->pd_flags = PD_IDLE; 14711 mutex_exit(&did_pd->pd_mutex); 14712 14713 return; 14714 } 14715 14716 /* 14717 * A weird case of Port WWN and D_ID existence but not matching up 14718 * between them. Trust your instincts - Take the port device handle 14719 * off Port WWN list, fix it with new Port WWN and put it back, In 14720 * the mean time mark the port device corresponding to the old port 14721 * WWN as OLD. 14722 */ 14723 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; Case WEIRD, pwwn_pd=%p," 14724 " did_pd=%p", pwwn_pd, did_pd); 14725 14726 mutex_enter(&port->fp_mutex); 14727 mutex_enter(&pwwn_pd->pd_mutex); 14728 14729 pwwn_pd->pd_type = PORT_DEVICE_OLD; 14730 pwwn_pd->pd_state = PORT_DEVICE_INVALID; 14731 fctl_delist_did_table(port, pwwn_pd); 14732 fctl_delist_pwwn_table(port, pwwn_pd); 14733 14734 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14735 " pwwn-d_id=%x pwwn-wwn=%x %x %x %x %x %x %x %x", 14736 pwwn_pd->pd_port_id.port_id, 14737 14738 pwwn_pd->pd_port_name.raw_wwn[0], 14739 pwwn_pd->pd_port_name.raw_wwn[1], 14740 pwwn_pd->pd_port_name.raw_wwn[2], 14741 pwwn_pd->pd_port_name.raw_wwn[3], 14742 pwwn_pd->pd_port_name.raw_wwn[4], 14743 pwwn_pd->pd_port_name.raw_wwn[5], 14744 pwwn_pd->pd_port_name.raw_wwn[6], 14745 pwwn_pd->pd_port_name.raw_wwn[7]); 14746 14747 mutex_exit(&pwwn_pd->pd_mutex); 14748 mutex_exit(&port->fp_mutex); 14749 14750 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14751 (uint32_t)(uintptr_t)job->job_cb_arg; 14752 14753 fctl_copy_portmap(listptr + (*listindex)++, pwwn_pd); 14754 14755 mutex_enter(&port->fp_mutex); 14756 mutex_enter(&did_pd->pd_mutex); 14757 14758 fctl_delist_pwwn_table(port, did_pd); 14759 14760 (listptr + *listindex)->map_rscn_info.ulp_rscn_count = 14761 (uint32_t)(uintptr_t)job->job_cb_arg; 14762 14763 fp_fillout_changed_map(listptr + (*listindex)++, did_pd, NULL, pwwn); 14764 fctl_enlist_pwwn_table(port, did_pd); 14765 14766 FP_TRACE(FP_NHEAD1(6, 0), "RSCN with D_ID page; case WEIRD continued," 14767 " d_id=%x, state=%x, did-wwn=%x %x %x %x %x %x %x %x", 14768 did_pd->pd_port_id.port_id, did_pd->pd_state, 14769 14770 did_pd->pd_port_name.raw_wwn[0], 14771 did_pd->pd_port_name.raw_wwn[1], 14772 did_pd->pd_port_name.raw_wwn[2], 14773 did_pd->pd_port_name.raw_wwn[3], 14774 did_pd->pd_port_name.raw_wwn[4], 14775 did_pd->pd_port_name.raw_wwn[5], 14776 did_pd->pd_port_name.raw_wwn[6], 14777 did_pd->pd_port_name.raw_wwn[7]); 14778 14779 if ((did_pd->pd_state == PORT_DEVICE_LOGGED_IN) || 14780 (did_pd->pd_aux_flags & PD_LOGGED_OUT)) { 14781 mutex_exit(&did_pd->pd_mutex); 14782 mutex_exit(&port->fp_mutex); 14783 14784 rval = fp_port_login(port, page->aff_d_id, job, 14785 FP_CMD_PLOGI_RETAIN, sleep, did_pd, NULL); 14786 if (rval == FC_SUCCESS) { 14787 fp_jobwait(job); 14788 if (job->job_result != FC_SUCCESS) { 14789 fp_fillout_old_map(listptr + 14790 *listindex - 1, did_pd, 0); 14791 } 14792 } else { 14793 fp_fillout_old_map(listptr + *listindex - 1, did_pd, 0); 14794 } 14795 } else { 14796 mutex_exit(&did_pd->pd_mutex); 14797 mutex_exit(&port->fp_mutex); 14798 } 14799 14800 mutex_enter(&did_pd->pd_mutex); 14801 did_pd->pd_flags = PD_IDLE; 14802 mutex_exit(&did_pd->pd_mutex); 14803 } 14804 14805 14806 /* 14807 * Check with NS for the presence of this port WWN 14808 */ 14809 static int 14810 fp_ns_validate_device(fc_local_port_t *port, fc_remote_port_t *pd, 14811 job_request_t *job, int polled, int sleep) 14812 { 14813 la_wwn_t pwwn; 14814 uint32_t flags; 14815 fctl_ns_req_t *ns_cmd; 14816 14817 flags = FCTL_NS_VALIDATE_PD | ((polled) ? 0: FCTL_NS_ASYNC_REQUEST); 14818 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14819 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14820 flags, sleep); 14821 if (ns_cmd == NULL) { 14822 return (FC_NOMEM); 14823 } 14824 14825 mutex_enter(&pd->pd_mutex); 14826 pwwn = pd->pd_port_name; 14827 mutex_exit(&pd->pd_mutex); 14828 14829 ns_cmd->ns_cmd_code = NS_GID_PN; 14830 ns_cmd->ns_pd = pd; 14831 ((ns_req_gid_pn_t *)ns_cmd->ns_cmd_buf)->pwwn = pwwn; 14832 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id = 0; 14833 ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.priv_lilp_posit = 0; 14834 14835 return (fp_ns_query(port, ns_cmd, job, polled, sleep)); 14836 } 14837 14838 14839 /* 14840 * Sanity check the LILP map returned by FCA 14841 */ 14842 static int 14843 fp_validate_lilp_map(fc_lilpmap_t *lilp_map) 14844 { 14845 int count; 14846 14847 if (lilp_map->lilp_length == 0) { 14848 return (FC_FAILURE); 14849 } 14850 14851 for (count = 0; count < lilp_map->lilp_length; count++) { 14852 if (fp_is_valid_alpa(lilp_map->lilp_alpalist[count]) != 14853 FC_SUCCESS) { 14854 return (FC_FAILURE); 14855 } 14856 } 14857 14858 return (FC_SUCCESS); 14859 } 14860 14861 14862 /* 14863 * Sanity check if the AL_PA is a valid address 14864 */ 14865 static int 14866 fp_is_valid_alpa(uchar_t al_pa) 14867 { 14868 int count; 14869 14870 for (count = 0; count < sizeof (fp_valid_alpas); count++) { 14871 if (al_pa == fp_valid_alpas[count] || al_pa == 0) { 14872 return (FC_SUCCESS); 14873 } 14874 } 14875 14876 return (FC_FAILURE); 14877 } 14878 14879 14880 /* 14881 * Post unsolicited callbacks to ULPs 14882 */ 14883 static void 14884 fp_ulp_unsol_cb(void *arg) 14885 { 14886 fp_unsol_spec_t *ub_spec = (fp_unsol_spec_t *)arg; 14887 14888 fctl_ulp_unsol_cb(ub_spec->port, ub_spec->buf, 14889 ub_spec->buf->ub_frame.type); 14890 kmem_free(ub_spec, sizeof (*ub_spec)); 14891 } 14892 14893 14894 /* 14895 * Perform message reporting in a consistent manner. Unless there is 14896 * a strong reason NOT to use this function (which is very very rare) 14897 * all message reporting should go through this. 14898 */ 14899 static void 14900 fp_printf(fc_local_port_t *port, int level, fp_mesg_dest_t dest, int fc_errno, 14901 fc_packet_t *pkt, const char *fmt, ...) 14902 { 14903 caddr_t buf; 14904 va_list ap; 14905 14906 switch (level) { 14907 case CE_NOTE: 14908 if ((port->fp_verbose & FP_WARNING_MESSAGES) == 0) { 14909 return; 14910 } 14911 break; 14912 14913 case CE_WARN: 14914 if ((port->fp_verbose & FP_FATAL_MESSAGES) == 0) { 14915 return; 14916 } 14917 break; 14918 } 14919 14920 buf = kmem_zalloc(256, KM_NOSLEEP); 14921 if (buf == NULL) { 14922 return; 14923 } 14924 14925 (void) sprintf(buf, "fp(%d): ", port->fp_instance); 14926 14927 va_start(ap, fmt); 14928 (void) vsprintf(buf + strlen(buf), fmt, ap); 14929 va_end(ap); 14930 14931 if (fc_errno) { 14932 char *errmsg; 14933 14934 (void) fc_ulp_error(fc_errno, &errmsg); 14935 (void) sprintf(buf + strlen(buf), " FC Error=%s", errmsg); 14936 } else { 14937 if (pkt) { 14938 caddr_t state, reason, action, expln; 14939 14940 (void) fc_ulp_pkt_error(pkt, &state, &reason, 14941 &action, &expln); 14942 14943 (void) sprintf(buf + strlen(buf), 14944 " state=%s, reason=%s", state, reason); 14945 14946 if (pkt->pkt_resp_resid) { 14947 (void) sprintf(buf + strlen(buf), 14948 " resp resid=%x\n", pkt->pkt_resp_resid); 14949 } 14950 } 14951 } 14952 14953 switch (dest) { 14954 case FP_CONSOLE_ONLY: 14955 cmn_err(level, "^%s", buf); 14956 break; 14957 14958 case FP_LOG_ONLY: 14959 cmn_err(level, "!%s", buf); 14960 break; 14961 14962 default: 14963 cmn_err(level, "%s", buf); 14964 break; 14965 } 14966 14967 kmem_free(buf, 256); 14968 } 14969 14970 static int 14971 fp_fcio_login(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 14972 { 14973 int ret; 14974 uint32_t d_id; 14975 la_wwn_t pwwn; 14976 fc_remote_port_t *pd = NULL; 14977 fc_remote_port_t *held_pd = NULL; 14978 fctl_ns_req_t *ns_cmd; 14979 fc_portmap_t *changelist; 14980 14981 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 14982 14983 mutex_enter(&port->fp_mutex); 14984 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 14985 mutex_exit(&port->fp_mutex); 14986 job->job_counter = 1; 14987 14988 job->job_result = FC_SUCCESS; 14989 14990 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 14991 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 14992 FCTL_NS_BUF_IS_USERLAND, KM_SLEEP); 14993 14994 ASSERT(ns_cmd != NULL); 14995 14996 ns_cmd->ns_cmd_code = NS_GID_PN; 14997 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = pwwn; 14998 14999 ret = fp_ns_query(port, ns_cmd, job, 1, KM_SLEEP); 15000 15001 if (ret != FC_SUCCESS || job->job_result != FC_SUCCESS) { 15002 if (ret != FC_SUCCESS) { 15003 fcio->fcio_errno = ret; 15004 } else { 15005 fcio->fcio_errno = job->job_result; 15006 } 15007 fctl_free_ns_cmd(ns_cmd); 15008 return (EIO); 15009 } 15010 d_id = BE_32(*((uint32_t *)ns_cmd->ns_data_buf)); 15011 fctl_free_ns_cmd(ns_cmd); 15012 } else { 15013 mutex_exit(&port->fp_mutex); 15014 15015 held_pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15016 if (held_pd == NULL) { 15017 fcio->fcio_errno = FC_BADWWN; 15018 return (EIO); 15019 } 15020 pd = held_pd; 15021 15022 mutex_enter(&pd->pd_mutex); 15023 d_id = pd->pd_port_id.port_id; 15024 mutex_exit(&pd->pd_mutex); 15025 } 15026 15027 job->job_counter = 1; 15028 15029 pd = fctl_get_remote_port_by_did(port, d_id); 15030 15031 if (pd) { 15032 mutex_enter(&pd->pd_mutex); 15033 if (pd->pd_state == PORT_DEVICE_LOGGED_IN) { 15034 pd->pd_login_count++; 15035 mutex_exit(&pd->pd_mutex); 15036 15037 fcio->fcio_errno = FC_SUCCESS; 15038 if (held_pd) { 15039 fctl_release_remote_port(held_pd); 15040 } 15041 15042 return (0); 15043 } 15044 mutex_exit(&pd->pd_mutex); 15045 } else { 15046 mutex_enter(&port->fp_mutex); 15047 if (FC_IS_TOP_SWITCH(port->fp_topology)) { 15048 mutex_exit(&port->fp_mutex); 15049 pd = fp_create_remote_port_by_ns(port, d_id, KM_SLEEP); 15050 if (pd == NULL) { 15051 fcio->fcio_errno = FC_FAILURE; 15052 if (held_pd) { 15053 fctl_release_remote_port(held_pd); 15054 } 15055 return (EIO); 15056 } 15057 } else { 15058 mutex_exit(&port->fp_mutex); 15059 } 15060 } 15061 15062 job->job_flags &= ~JOB_TYPE_FP_ASYNC; 15063 job->job_counter = 1; 15064 15065 ret = fp_port_login(port, d_id, job, FP_CMD_PLOGI_RETAIN, 15066 KM_SLEEP, pd, NULL); 15067 15068 if (ret != FC_SUCCESS) { 15069 fcio->fcio_errno = ret; 15070 if (held_pd) { 15071 fctl_release_remote_port(held_pd); 15072 } 15073 return (EIO); 15074 } 15075 fp_jobwait(job); 15076 15077 fcio->fcio_errno = job->job_result; 15078 15079 if (held_pd) { 15080 fctl_release_remote_port(held_pd); 15081 } 15082 15083 if (job->job_result != FC_SUCCESS) { 15084 return (EIO); 15085 } 15086 15087 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15088 if (pd == NULL) { 15089 fcio->fcio_errno = FC_BADDEV; 15090 return (ENODEV); 15091 } 15092 15093 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15094 15095 fctl_copy_portmap(changelist, pd); 15096 changelist->map_type = PORT_DEVICE_USER_LOGIN; 15097 15098 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15099 15100 mutex_enter(&pd->pd_mutex); 15101 pd->pd_type = PORT_DEVICE_NOCHANGE; 15102 mutex_exit(&pd->pd_mutex); 15103 15104 fctl_release_remote_port(pd); 15105 15106 return (0); 15107 } 15108 15109 15110 static int 15111 fp_fcio_logout(fc_local_port_t *port, fcio_t *fcio, job_request_t *job) 15112 { 15113 la_wwn_t pwwn; 15114 fp_cmd_t *cmd; 15115 fc_portmap_t *changelist; 15116 fc_remote_port_t *pd; 15117 15118 bcopy(fcio->fcio_ibuf, &pwwn, sizeof (pwwn)); 15119 15120 pd = fctl_hold_remote_port_by_pwwn(port, &pwwn); 15121 if (pd == NULL) { 15122 fcio->fcio_errno = FC_BADWWN; 15123 return (ENXIO); 15124 } 15125 15126 mutex_enter(&pd->pd_mutex); 15127 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 15128 fcio->fcio_errno = FC_LOGINREQ; 15129 mutex_exit(&pd->pd_mutex); 15130 15131 fctl_release_remote_port(pd); 15132 15133 return (EINVAL); 15134 } 15135 15136 ASSERT(pd->pd_login_count >= 1); 15137 15138 if (pd->pd_flags == PD_ELS_IN_PROGRESS) { 15139 fcio->fcio_errno = FC_FAILURE; 15140 mutex_exit(&pd->pd_mutex); 15141 15142 fctl_release_remote_port(pd); 15143 15144 return (EBUSY); 15145 } 15146 15147 if (pd->pd_login_count > 1) { 15148 pd->pd_login_count--; 15149 fcio->fcio_errno = FC_SUCCESS; 15150 mutex_exit(&pd->pd_mutex); 15151 15152 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15153 15154 fctl_copy_portmap(changelist, pd); 15155 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15156 15157 fctl_release_remote_port(pd); 15158 15159 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15160 15161 return (0); 15162 } 15163 15164 pd->pd_flags = PD_ELS_IN_PROGRESS; 15165 mutex_exit(&pd->pd_mutex); 15166 15167 job->job_counter = 1; 15168 15169 cmd = fp_alloc_pkt(port, sizeof (la_els_logo_t), 15170 FP_PORT_IDENTIFIER_LEN, KM_SLEEP, pd); 15171 if (cmd == NULL) { 15172 fcio->fcio_errno = FC_NOMEM; 15173 fctl_release_remote_port(pd); 15174 15175 mutex_enter(&pd->pd_mutex); 15176 pd->pd_flags = PD_IDLE; 15177 mutex_exit(&pd->pd_mutex); 15178 15179 return (ENOMEM); 15180 } 15181 15182 mutex_enter(&port->fp_mutex); 15183 mutex_enter(&pd->pd_mutex); 15184 15185 cmd->cmd_pkt.pkt_tran_flags = FC_TRAN_INTR | pd->pd_login_class; 15186 cmd->cmd_pkt.pkt_tran_type = FC_PKT_EXCHANGE; 15187 cmd->cmd_flags = FP_CMD_PLOGI_DONT_CARE; 15188 cmd->cmd_retry_count = 1; 15189 cmd->cmd_ulp_pkt = NULL; 15190 15191 fp_logo_init(pd, cmd, job); 15192 15193 mutex_exit(&pd->pd_mutex); 15194 mutex_exit(&port->fp_mutex); 15195 15196 if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) { 15197 mutex_enter(&pd->pd_mutex); 15198 pd->pd_flags = PD_IDLE; 15199 mutex_exit(&pd->pd_mutex); 15200 15201 fp_free_pkt(cmd); 15202 fctl_release_remote_port(pd); 15203 15204 return (EIO); 15205 } 15206 15207 fp_jobwait(job); 15208 15209 fcio->fcio_errno = job->job_result; 15210 if (job->job_result != FC_SUCCESS) { 15211 mutex_enter(&pd->pd_mutex); 15212 pd->pd_flags = PD_IDLE; 15213 mutex_exit(&pd->pd_mutex); 15214 15215 fctl_release_remote_port(pd); 15216 15217 return (EIO); 15218 } 15219 15220 ASSERT(pd != NULL); 15221 15222 changelist = kmem_zalloc(sizeof (*changelist), KM_SLEEP); 15223 15224 fctl_copy_portmap(changelist, pd); 15225 changelist->map_type = PORT_DEVICE_USER_LOGOUT; 15226 changelist->map_state = PORT_DEVICE_INVALID; 15227 15228 mutex_enter(&port->fp_mutex); 15229 mutex_enter(&pd->pd_mutex); 15230 15231 fctl_delist_did_table(port, pd); 15232 fctl_delist_pwwn_table(port, pd); 15233 pd->pd_flags = PD_IDLE; 15234 15235 mutex_exit(&pd->pd_mutex); 15236 mutex_exit(&port->fp_mutex); 15237 15238 (void) fp_ulp_devc_cb(port, changelist, 1, 1, KM_SLEEP, 1); 15239 15240 fctl_release_remote_port(pd); 15241 15242 return (0); 15243 } 15244 15245 15246 15247 /* 15248 * Send a syslog event for adapter port level events. 15249 */ 15250 static void 15251 fp_log_port_event(fc_local_port_t *port, char *subclass) 15252 { 15253 nvlist_t *attr_list; 15254 15255 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15256 KM_SLEEP) != DDI_SUCCESS) { 15257 goto alloc_failed; 15258 } 15259 15260 if (nvlist_add_uint32(attr_list, "instance", 15261 port->fp_instance) != DDI_SUCCESS) { 15262 goto error; 15263 } 15264 15265 if (nvlist_add_byte_array(attr_list, "port-wwn", 15266 port->fp_service_params.nport_ww_name.raw_wwn, 15267 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15268 goto error; 15269 } 15270 15271 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15272 subclass, attr_list, NULL, DDI_SLEEP); 15273 15274 nvlist_free(attr_list); 15275 return; 15276 15277 error: 15278 nvlist_free(attr_list); 15279 alloc_failed: 15280 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15281 } 15282 15283 15284 static void 15285 fp_log_target_event(fc_local_port_t *port, char *subclass, la_wwn_t tgt_pwwn, 15286 uint32_t port_id) 15287 { 15288 nvlist_t *attr_list; 15289 15290 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 15291 KM_SLEEP) != DDI_SUCCESS) { 15292 goto alloc_failed; 15293 } 15294 15295 if (nvlist_add_uint32(attr_list, "instance", 15296 port->fp_instance) != DDI_SUCCESS) { 15297 goto error; 15298 } 15299 15300 if (nvlist_add_byte_array(attr_list, "port-wwn", 15301 port->fp_service_params.nport_ww_name.raw_wwn, 15302 sizeof (la_wwn_t)) != DDI_SUCCESS) { 15303 goto error; 15304 } 15305 15306 if (nvlist_add_byte_array(attr_list, "target-port-wwn", 15307 tgt_pwwn.raw_wwn, sizeof (la_wwn_t)) != DDI_SUCCESS) { 15308 goto error; 15309 } 15310 15311 if (nvlist_add_uint32(attr_list, "target-port-id", 15312 port_id) != DDI_SUCCESS) { 15313 goto error; 15314 } 15315 15316 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 15317 subclass, attr_list, NULL, DDI_SLEEP); 15318 15319 nvlist_free(attr_list); 15320 return; 15321 15322 error: 15323 nvlist_free(attr_list); 15324 alloc_failed: 15325 FP_TRACE(FP_NHEAD1(9, 0), "Unable to send %s event", subclass); 15326 } 15327 15328 static uint32_t 15329 fp_map_remote_port_state(uint32_t rm_state) 15330 { 15331 switch (rm_state) { 15332 case PORT_DEVICE_LOGGED_IN: 15333 return (FC_HBA_PORTSTATE_ONLINE); 15334 case PORT_DEVICE_VALID: 15335 case PORT_DEVICE_INVALID: 15336 default: 15337 return (FC_HBA_PORTSTATE_UNKNOWN); 15338 } 15339 } 15340