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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27 */ 28 /* 29 * Fibre channel Transport Library (fctl) 30 * 31 * Function naming conventions: 32 * Functions called from ULPs begin with fc_ulp_ 33 * Functions called from FCAs begin with fc_fca_ 34 * Internal functions begin with fctl_ 35 * 36 * Fibre channel packet layout: 37 * +---------------------+<--------+ 38 * | | | 39 * | ULP Packet private | | 40 * | | | 41 * +---------------------+ | 42 * | |---------+ 43 * | struct fc_packet |---------+ 44 * | | | 45 * +---------------------+<--------+ 46 * | | 47 * | FCA Packet private | 48 * | | 49 * +---------------------+ 50 * 51 * So you loved the ascii art ? It's strongly desirable to cache 52 * allocate the entire packet in one common place. So we define a set a 53 * of rules. In a contiguous block of memory, the top portion of the 54 * block points to ulp packet private area, next follows the fc_packet 55 * structure used extensively by all the consumers and what follows this 56 * is the FCA packet private. Note that given a packet structure, it is 57 * possible to get to the ULP and FCA Packet private fields using 58 * ulp_private and fca_private fields (which hold pointers) respectively. 59 * 60 * It should be noted with a grain of salt that ULP Packet private size 61 * varies between two different ULP types, So this poses a challenge to 62 * compute the correct size of the whole block on a per port basis. The 63 * transport layer doesn't have a problem in dealing with FCA packet 64 * private sizes as it is the sole manager of ports underneath. Since 65 * it's not a good idea to cache allocate different sizes of memory for 66 * different ULPs and have the ability to choose from one of these caches 67 * based on ULP type during every packet allocation, the transport some 68 * what wisely (?) hands off this job of cache allocation to the ULPs 69 * themselves. 70 * 71 * That means FCAs need to make their packet private size known to the 72 * transport to pass it up to the ULPs. This is done during 73 * fc_fca_attach(). And the transport passes this size up to ULPs during 74 * fc_ulp_port_attach() of each ULP. 75 * 76 * This leaves us with another possible question; How are packets 77 * allocated for ELS's started by the transport itself ? Well, the port 78 * driver during attach time, cache allocates on a per port basis to 79 * handle ELSs too. 80 */ 81 82 #include <sys/note.h> 83 #include <sys/types.h> 84 #include <sys/varargs.h> 85 #include <sys/param.h> 86 #include <sys/errno.h> 87 #include <sys/uio.h> 88 #include <sys/buf.h> 89 #include <sys/modctl.h> 90 #include <sys/open.h> 91 #include <sys/kmem.h> 92 #include <sys/poll.h> 93 #include <sys/conf.h> 94 #include <sys/cmn_err.h> 95 #include <sys/stat.h> 96 #include <sys/ddi.h> 97 #include <sys/sunddi.h> 98 #include <sys/promif.h> 99 #include <sys/byteorder.h> 100 #include <sys/fibre-channel/fc.h> 101 #include <sys/fibre-channel/impl/fc_ulpif.h> 102 #include <sys/fibre-channel/impl/fc_fcaif.h> 103 #include <sys/fibre-channel/impl/fctl_private.h> 104 #include <sys/fibre-channel/impl/fc_portif.h> 105 106 /* These are referenced by fp.c! */ 107 int did_table_size = D_ID_HASH_TABLE_SIZE; 108 int pwwn_table_size = PWWN_HASH_TABLE_SIZE; 109 110 static fc_ulp_module_t *fctl_ulp_modules; 111 static fc_fca_port_t *fctl_fca_portlist; 112 static fc_ulp_list_t *fctl_ulp_list; 113 114 static char fctl_greeting[] = 115 "fctl: %s ULP same type (0x%x) as existing module.\n"; 116 117 static char *fctl_undefined = "Undefined"; 118 119 /* 120 * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field) 121 */ 122 123 static krwlock_t fctl_ulp_lock; 124 125 /* 126 * The fctl_mod_ports_lock protects the mod_ports element in the 127 * fc_ulp_ports_t structure 128 */ 129 130 static krwlock_t fctl_mod_ports_lock; 131 132 /* 133 * fctl_port_lock protects the linked list of local port structures 134 * (fctl_fca_portlist). When walking the list, this lock must be obtained 135 * prior to any local port locks. 136 */ 137 138 static kmutex_t fctl_port_lock; 139 static kmutex_t fctl_ulp_list_mutex; 140 141 static fctl_nwwn_list_t *fctl_nwwn_hash_table; 142 static kmutex_t fctl_nwwn_hash_mutex; 143 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE; 144 145 #define FCTL_VERSION "20090729-1.70" 146 #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION 147 148 char *fctl_version = FCTL_NAME_VERSION; 149 150 extern struct mod_ops mod_miscops; 151 152 static struct modlmisc modlmisc = { 153 &mod_miscops, /* type of module */ 154 FCTL_NAME_VERSION /* Module name */ 155 }; 156 157 static struct modlinkage modlinkage = { 158 MODREV_1, (void *)&modlmisc, NULL 159 }; 160 161 static struct bus_ops fctl_fca_busops = { 162 BUSO_REV, 163 nullbusmap, /* bus_map */ 164 NULL, /* bus_get_intrspec */ 165 NULL, /* bus_add_intrspec */ 166 NULL, /* bus_remove_intrspec */ 167 i_ddi_map_fault, /* bus_map_fault */ 168 NULL, /* bus_dma_map */ 169 ddi_dma_allochdl, /* bus_dma_allochdl */ 170 ddi_dma_freehdl, /* bus_dma_freehdl */ 171 ddi_dma_bindhdl, /* bus_dma_bindhdl */ 172 ddi_dma_unbindhdl, /* bus_unbindhdl */ 173 ddi_dma_flush, /* bus_dma_flush */ 174 ddi_dma_win, /* bus_dma_win */ 175 ddi_dma_mctl, /* bus_dma_ctl */ 176 fctl_fca_bus_ctl, /* bus_ctl */ 177 ddi_bus_prop_op, /* bus_prop_op */ 178 NULL, /* bus_get_eventcookie */ 179 NULL, /* bus_add_eventcall */ 180 NULL, /* bus_remove_event */ 181 NULL, /* bus_post_event */ 182 NULL, /* bus_intr_ctl */ 183 NULL, /* bus_config */ 184 NULL, /* bus_unconfig */ 185 NULL, /* bus_fm_init */ 186 NULL, /* bus_fm_fini */ 187 NULL, /* bus_fm_access_enter */ 188 NULL, /* bus_fm_access_exit */ 189 NULL, /* bus_power */ 190 NULL 191 }; 192 193 struct kmem_cache *fctl_job_cache; 194 195 static fc_errmap_t fc_errlist [] = { 196 { FC_FAILURE, "Operation failed" }, 197 { FC_SUCCESS, "Operation success" }, 198 { FC_CAP_ERROR, "Capability error" }, 199 { FC_CAP_FOUND, "Capability found" }, 200 { FC_CAP_SETTABLE, "Capability settable" }, 201 { FC_UNBOUND, "Port not bound" }, 202 { FC_NOMEM, "No memory" }, 203 { FC_BADPACKET, "Bad packet" }, 204 { FC_OFFLINE, "Port offline" }, 205 { FC_OLDPORT, "Old Port" }, 206 { FC_NO_MAP, "No map available" }, 207 { FC_TRANSPORT_ERROR, "Transport error" }, 208 { FC_ELS_FREJECT, "ELS Frejected" }, 209 { FC_ELS_PREJECT, "ELS PRejected" }, 210 { FC_ELS_BAD, "Bad ELS request" }, 211 { FC_ELS_MALFORMED, "Malformed ELS request" }, 212 { FC_TOOMANY, "Too many commands" }, 213 { FC_UB_BADTOKEN, "Bad Unsolicited buffer token" }, 214 { FC_UB_ERROR, "Unsolicited buffer error" }, 215 { FC_UB_BUSY, "Unsolicited buffer busy" }, 216 { FC_BADULP, "Bad ULP" }, 217 { FC_BADTYPE, "Bad Type" }, 218 { FC_UNCLAIMED, "Not Claimed" }, 219 { FC_ULP_SAMEMODULE, "Same ULP Module" }, 220 { FC_ULP_SAMETYPE, "Same ULP Type" }, 221 { FC_ABORTED, "Command Aborted" }, 222 { FC_ABORT_FAILED, "Abort Failed" }, 223 { FC_BADEXCHANGE, "Bad Exchange" }, 224 { FC_BADWWN, "Bad World Wide Name" }, 225 { FC_BADDEV, "Bad Device" }, 226 { FC_BADCMD, "Bad Command" }, 227 { FC_BADOBJECT, "Bad Object" }, 228 { FC_BADPORT, "Bad Port" }, 229 { FC_NOTTHISPORT, "Not on this Port" }, 230 { FC_PREJECT, "Operation Prejected" }, 231 { FC_FREJECT, "Operation Frejected" }, 232 { FC_PBUSY, "Operation Pbusyed" }, 233 { FC_FBUSY, "Operation Fbusyed" }, 234 { FC_ALREADY, "Already done" }, 235 { FC_LOGINREQ, "PLOGI Required" }, 236 { FC_RESETFAIL, "Reset operation failed" }, 237 { FC_INVALID_REQUEST, "Invalid Request" }, 238 { FC_OUTOFBOUNDS, "Out of Bounds" }, 239 { FC_TRAN_BUSY, "Command transport Busy" }, 240 { FC_STATEC_BUSY, "State change Busy" }, 241 { FC_DEVICE_BUSY, "Port driver is working on this device" } 242 }; 243 244 fc_pkt_reason_t remote_stop_reasons [] = { 245 { FC_REASON_ABTS, "Abort Sequence" }, 246 { FC_REASON_ABTX, "Abort Exchange" }, 247 { FC_REASON_INVALID, NULL } 248 }; 249 250 fc_pkt_reason_t general_reasons [] = { 251 { FC_REASON_HW_ERROR, "Hardware Error" }, 252 { FC_REASON_SEQ_TIMEOUT, "Sequence Timeout" }, 253 { FC_REASON_ABORTED, "Aborted" }, 254 { FC_REASON_ABORT_FAILED, "Abort Failed" }, 255 { FC_REASON_NO_CONNECTION, "No Connection" }, 256 { FC_REASON_XCHG_DROPPED, "Exchange Dropped" }, 257 { FC_REASON_ILLEGAL_FRAME, "Illegal Frame" }, 258 { FC_REASON_ILLEGAL_LENGTH, "Illegal Length" }, 259 { FC_REASON_UNSUPPORTED, "Unsuported" }, 260 { FC_REASON_RX_BUF_TIMEOUT, "Receive Buffer Timeout" }, 261 { FC_REASON_FCAL_OPN_FAIL, "FC AL Open Failed" }, 262 { FC_REASON_OVERRUN, "Over run" }, 263 { FC_REASON_QFULL, "Queue Full" }, 264 { FC_REASON_ILLEGAL_REQ, "Illegal Request", }, 265 { FC_REASON_PKT_BUSY, "Busy" }, 266 { FC_REASON_OFFLINE, "Offline" }, 267 { FC_REASON_BAD_XID, "Bad Exchange Id" }, 268 { FC_REASON_XCHG_BSY, "Exchange Busy" }, 269 { FC_REASON_NOMEM, "No Memory" }, 270 { FC_REASON_BAD_SID, "Bad S_ID" }, 271 { FC_REASON_NO_SEQ_INIT, "No Sequence Initiative" }, 272 { FC_REASON_DIAG_BUSY, "Diagnostic Busy" }, 273 { FC_REASON_DMA_ERROR, "DMA Error" }, 274 { FC_REASON_CRC_ERROR, "CRC Error" }, 275 { FC_REASON_ABORT_TIMEOUT, "Abort Timeout" }, 276 { FC_REASON_FCA_UNIQUE, "FCA Unique" }, 277 { FC_REASON_INVALID, NULL } 278 }; 279 280 fc_pkt_reason_t rjt_reasons [] = { 281 { FC_REASON_INVALID_D_ID, "Invalid D_ID" }, 282 { FC_REASON_INVALID_S_ID, "Invalid S_ID" }, 283 { FC_REASON_TEMP_UNAVAILABLE, "Temporarily Unavailable" }, 284 { FC_REASON_PERM_UNAVAILABLE, "Permamnently Unavailable" }, 285 { FC_REASON_CLASS_NOT_SUPP, "Class Not Supported", }, 286 { FC_REASON_DELIMTER_USAGE_ERROR, 287 "Delimeter Usage Error" }, 288 { FC_REASON_TYPE_NOT_SUPP, "Type Not Supported" }, 289 { FC_REASON_INVALID_LINK_CTRL, "Invalid Link Control" }, 290 { FC_REASON_INVALID_R_CTL, "Invalid R_CTL" }, 291 { FC_REASON_INVALID_F_CTL, "Invalid F_CTL" }, 292 { FC_REASON_INVALID_OX_ID, "Invalid OX_ID" }, 293 { FC_REASON_INVALID_RX_ID, "Invalid RX_ID" }, 294 { FC_REASON_INVALID_SEQ_ID, "Invalid Sequence ID" }, 295 { FC_REASON_INVALID_DF_CTL, "Invalid DF_CTL" }, 296 { FC_REASON_INVALID_SEQ_CNT, "Invalid Sequence count" }, 297 { FC_REASON_INVALID_PARAM, "Invalid Parameter" }, 298 { FC_REASON_EXCH_ERROR, "Exchange Error" }, 299 { FC_REASON_PROTOCOL_ERROR, "Protocol Error" }, 300 { FC_REASON_INCORRECT_LENGTH, "Incorrect Length" }, 301 { FC_REASON_UNEXPECTED_ACK, "Unexpected Ack" }, 302 { FC_REASON_UNEXPECTED_LR, "Unexpected Link reset" }, 303 { FC_REASON_LOGIN_REQUIRED, "Login Required" }, 304 { FC_REASON_EXCESSIVE_SEQS, "Excessive Sequences" 305 " Attempted" }, 306 { FC_REASON_EXCH_UNABLE, "Exchange incapable" }, 307 { FC_REASON_ESH_NOT_SUPP, "Expiration Security Header " 308 "Not Supported" }, 309 { FC_REASON_NO_FABRIC_PATH, "No Fabric Path" }, 310 { FC_REASON_VENDOR_UNIQUE, "Vendor Unique" }, 311 { FC_REASON_INVALID, NULL } 312 }; 313 314 fc_pkt_reason_t n_port_busy_reasons [] = { 315 { FC_REASON_PHYSICAL_BUSY, "Physical Busy" }, 316 { FC_REASON_N_PORT_RESOURCE_BSY, "Resource Busy" }, 317 { FC_REASON_N_PORT_VENDOR_UNIQUE, "Vendor Unique" }, 318 { FC_REASON_INVALID, NULL } 319 }; 320 321 fc_pkt_reason_t f_busy_reasons [] = { 322 { FC_REASON_FABRIC_BSY, "Fabric Busy" }, 323 { FC_REASON_N_PORT_BSY, "N_Port Busy" }, 324 { FC_REASON_INVALID, NULL } 325 }; 326 327 fc_pkt_reason_t ls_ba_rjt_reasons [] = { 328 { FC_REASON_INVALID_LA_CODE, "Invalid Link Application Code" }, 329 { FC_REASON_LOGICAL_ERROR, "Logical Error" }, 330 { FC_REASON_LOGICAL_BSY, "Logical Busy" }, 331 { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject" }, 332 { FC_REASON_CMD_UNABLE, "Unable to Perform Command" }, 333 { FC_REASON_CMD_UNSUPPORTED, "Unsupported Command" }, 334 { FC_REASON_VU_RJT, "Vendor Unique" }, 335 { FC_REASON_INVALID, NULL } 336 }; 337 338 fc_pkt_reason_t fs_rjt_reasons [] = { 339 { FC_REASON_FS_INVALID_CMD, "Invalid Command" }, 340 { FC_REASON_FS_INVALID_VER, "Invalid Version" }, 341 { FC_REASON_FS_LOGICAL_ERR, "Logical Error" }, 342 { FC_REASON_FS_INVALID_IUSIZE, "Invalid IU Size" }, 343 { FC_REASON_FS_LOGICAL_BUSY, "Logical Busy" }, 344 { FC_REASON_FS_PROTOCOL_ERR, "Protocol Error" }, 345 { FC_REASON_FS_CMD_UNABLE, "Unable to Perform Command" }, 346 { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command" }, 347 { FC_REASON_FS_VENDOR_UNIQUE, "Vendor Unique" }, 348 { FC_REASON_INVALID, NULL } 349 }; 350 351 fc_pkt_action_t n_port_busy_actions [] = { 352 { FC_ACTION_SEQ_TERM_RETRY, "Retry terminated Sequence" }, 353 { FC_ACTION_SEQ_ACTIVE_RETRY, "Retry Active Sequence" }, 354 { FC_REASON_INVALID, NULL } 355 }; 356 357 fc_pkt_action_t rjt_timeout_actions [] = { 358 { FC_ACTION_RETRYABLE, "Retryable" }, 359 { FC_ACTION_NON_RETRYABLE, "Non Retryable" }, 360 { FC_REASON_INVALID, NULL } 361 }; 362 363 fc_pkt_expln_t ba_rjt_explns [] = { 364 { FC_EXPLN_NONE, "No Explanation" }, 365 { FC_EXPLN_INVALID_OX_RX_ID, "Invalid X_ID" }, 366 { FC_EXPLN_SEQ_ABORTED, "Sequence Aborted" }, 367 { FC_EXPLN_INVALID, NULL } 368 }; 369 370 fc_pkt_error_t fc_pkt_errlist[] = { 371 { 372 FC_PKT_SUCCESS, 373 "Operation Success", 374 NULL, 375 NULL, 376 NULL 377 }, 378 { FC_PKT_REMOTE_STOP, 379 "Remote Stop", 380 remote_stop_reasons, 381 NULL, 382 NULL 383 }, 384 { 385 FC_PKT_LOCAL_RJT, 386 "Local Reject", 387 general_reasons, 388 rjt_timeout_actions, 389 NULL 390 }, 391 { 392 FC_PKT_NPORT_RJT, 393 "N_Port Reject", 394 rjt_reasons, 395 rjt_timeout_actions, 396 NULL 397 }, 398 { 399 FC_PKT_FABRIC_RJT, 400 "Fabric Reject", 401 rjt_reasons, 402 rjt_timeout_actions, 403 NULL 404 }, 405 { 406 FC_PKT_LOCAL_BSY, 407 "Local Busy", 408 general_reasons, 409 NULL, 410 NULL, 411 }, 412 { 413 FC_PKT_TRAN_BSY, 414 "Transport Busy", 415 general_reasons, 416 NULL, 417 NULL, 418 }, 419 { 420 FC_PKT_NPORT_BSY, 421 "N_Port Busy", 422 n_port_busy_reasons, 423 n_port_busy_actions, 424 NULL 425 }, 426 { 427 FC_PKT_FABRIC_BSY, 428 "Fabric Busy", 429 f_busy_reasons, 430 NULL, 431 NULL, 432 }, 433 { 434 FC_PKT_LS_RJT, 435 "Link Service Reject", 436 ls_ba_rjt_reasons, 437 NULL, 438 NULL, 439 }, 440 { 441 FC_PKT_BA_RJT, 442 "Basic Reject", 443 ls_ba_rjt_reasons, 444 NULL, 445 ba_rjt_explns, 446 }, 447 { 448 FC_PKT_TIMEOUT, 449 "Timeout", 450 general_reasons, 451 rjt_timeout_actions, 452 NULL 453 }, 454 { 455 FC_PKT_FS_RJT, 456 "Fabric Switch Reject", 457 fs_rjt_reasons, 458 NULL, 459 NULL 460 }, 461 { 462 FC_PKT_TRAN_ERROR, 463 "Packet Transport error", 464 general_reasons, 465 NULL, 466 NULL 467 }, 468 { 469 FC_PKT_FAILURE, 470 "Packet Failure", 471 general_reasons, 472 NULL, 473 NULL 474 }, 475 { 476 FC_PKT_PORT_OFFLINE, 477 "Port Offline", 478 NULL, 479 NULL, 480 NULL 481 }, 482 { 483 FC_PKT_ELS_IN_PROGRESS, 484 "ELS is in Progress", 485 NULL, 486 NULL, 487 NULL 488 } 489 }; 490 491 int 492 _init() 493 { 494 int rval; 495 496 rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL); 497 rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL); 498 mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL); 499 mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL); 500 501 fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) * 502 fctl_nwwn_table_size, KM_SLEEP); 503 504 fctl_ulp_modules = NULL; 505 fctl_fca_portlist = NULL; 506 507 fctl_job_cache = kmem_cache_create("fctl_cache", 508 sizeof (job_request_t), 8, fctl_cache_constructor, 509 fctl_cache_destructor, NULL, NULL, NULL, 0); 510 511 if (fctl_job_cache == NULL) { 512 kmem_free(fctl_nwwn_hash_table, 513 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 514 mutex_destroy(&fctl_nwwn_hash_mutex); 515 mutex_destroy(&fctl_port_lock); 516 rw_destroy(&fctl_ulp_lock); 517 rw_destroy(&fctl_mod_ports_lock); 518 return (ENOMEM); 519 } 520 521 if ((rval = mod_install(&modlinkage)) != 0) { 522 kmem_cache_destroy(fctl_job_cache); 523 kmem_free(fctl_nwwn_hash_table, 524 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 525 mutex_destroy(&fctl_nwwn_hash_mutex); 526 mutex_destroy(&fctl_port_lock); 527 rw_destroy(&fctl_ulp_lock); 528 rw_destroy(&fctl_mod_ports_lock); 529 } 530 531 return (rval); 532 } 533 534 535 /* 536 * The mod_uninstall code doesn't call _fini when 537 * there is living dependent module on fctl. So 538 * there is no need to be extra careful here ? 539 */ 540 int 541 _fini() 542 { 543 int rval; 544 545 if ((rval = mod_remove(&modlinkage)) != 0) { 546 return (rval); 547 } 548 549 kmem_cache_destroy(fctl_job_cache); 550 kmem_free(fctl_nwwn_hash_table, 551 sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 552 mutex_destroy(&fctl_nwwn_hash_mutex); 553 mutex_destroy(&fctl_port_lock); 554 rw_destroy(&fctl_ulp_lock); 555 rw_destroy(&fctl_mod_ports_lock); 556 557 return (rval); 558 } 559 560 561 int 562 _info(struct modinfo *modinfo_p) 563 { 564 return (mod_info(&modlinkage, modinfo_p)); 565 } 566 567 568 /* ARGSUSED */ 569 static int 570 fctl_cache_constructor(void *buf, void *cdarg, int kmflag) 571 { 572 job_request_t *job = (job_request_t *)buf; 573 574 mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL); 575 sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL); 576 sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL); 577 578 return (0); 579 } 580 581 582 /* ARGSUSED */ 583 static void 584 fctl_cache_destructor(void *buf, void *cdarg) 585 { 586 job_request_t *job = (job_request_t *)buf; 587 588 sema_destroy(&job->job_fctl_sema); 589 sema_destroy(&job->job_port_sema); 590 mutex_destroy(&job->job_mutex); 591 } 592 593 594 /* 595 * fc_ulp_add: 596 * Add a ULP module 597 * 598 * Return Codes: 599 * FC_ULP_SAMEMODULE 600 * FC_SUCCESS 601 * FC_FAILURE 602 * 603 * fc_ulp_add prints a warning message if there is already a 604 * similar ULP type attached and this is unlikely to change as 605 * we trudge along. Further, this function returns a failure 606 * code if the same module attempts to add more than once for 607 * the same FC-4 type. 608 */ 609 int 610 fc_ulp_add(fc_ulp_modinfo_t *ulp_info) 611 { 612 fc_ulp_module_t *mod; 613 fc_ulp_module_t *prev; 614 job_request_t *job; 615 fc_ulp_list_t *new; 616 fc_fca_port_t *fca_port; 617 int ntry = 0; 618 619 ASSERT(ulp_info != NULL); 620 621 /* 622 * Make sure ulp_rev matches fctl version. 623 * Whenever non-private data structure or non-static interface changes, 624 * we should use an increased FCTL_ULP_MODREV_# number here and in all 625 * ulps to prevent version mismatch. 626 */ 627 if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) { 628 cmn_err(CE_WARN, "fctl: ULP %s version mismatch;" 629 " ULP %s would not be loaded", ulp_info->ulp_name, 630 ulp_info->ulp_name); 631 return (FC_BADULP); 632 } 633 634 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 635 ASSERT(new != NULL); 636 637 mutex_enter(&fctl_ulp_list_mutex); 638 new->ulp_info = ulp_info; 639 if (fctl_ulp_list != NULL) { 640 new->ulp_next = fctl_ulp_list; 641 } 642 fctl_ulp_list = new; 643 mutex_exit(&fctl_ulp_list_mutex); 644 645 while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) { 646 delay(drv_usectohz(1000000)); 647 if (ntry++ > FC_ULP_ADD_RETRY_COUNT) { 648 fc_ulp_list_t *list; 649 fc_ulp_list_t *last; 650 mutex_enter(&fctl_ulp_list_mutex); 651 for (last = NULL, list = fctl_ulp_list; list != NULL; 652 list = list->ulp_next) { 653 if (list->ulp_info == ulp_info) { 654 break; 655 } 656 last = list; 657 } 658 659 if (list) { 660 if (last) { 661 last->ulp_next = list->ulp_next; 662 } else { 663 fctl_ulp_list = list->ulp_next; 664 } 665 kmem_free(list, sizeof (*list)); 666 } 667 mutex_exit(&fctl_ulp_list_mutex); 668 cmn_err(CE_WARN, "fctl: ULP %s unable to load", 669 ulp_info->ulp_name); 670 return (FC_FAILURE); 671 } 672 } 673 674 for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) { 675 ASSERT(mod->mod_info != NULL); 676 677 if (ulp_info == mod->mod_info && 678 ulp_info->ulp_type == mod->mod_info->ulp_type) { 679 rw_exit(&fctl_ulp_lock); 680 return (FC_ULP_SAMEMODULE); 681 } 682 683 if (ulp_info->ulp_type == mod->mod_info->ulp_type) { 684 cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name, 685 ulp_info->ulp_type); 686 } 687 prev = mod; 688 } 689 690 mod = kmem_zalloc(sizeof (*mod), KM_SLEEP); 691 mod->mod_info = ulp_info; 692 mod->mod_next = NULL; 693 694 if (prev) { 695 prev->mod_next = mod; 696 } else { 697 fctl_ulp_modules = mod; 698 } 699 700 /* 701 * Schedule a job to each port's job_handler 702 * thread to attach their ports with this ULP. 703 */ 704 mutex_enter(&fctl_port_lock); 705 for (fca_port = fctl_fca_portlist; fca_port != NULL; 706 fca_port = fca_port->port_next) { 707 job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC, 708 NULL, NULL, KM_SLEEP); 709 710 fctl_enque_job(fca_port->port_handle, job); 711 } 712 mutex_exit(&fctl_port_lock); 713 714 rw_exit(&fctl_ulp_lock); 715 716 return (FC_SUCCESS); 717 } 718 719 720 /* 721 * fc_ulp_remove 722 * Remove a ULP module 723 * 724 * A misbehaving ULP may call this routine while I/Os are in progress. 725 * Currently there is no mechanism to detect it to fail such a request. 726 * 727 * Return Codes: 728 * FC_SUCCESS 729 * FC_FAILURE 730 */ 731 int 732 fc_ulp_remove(fc_ulp_modinfo_t *ulp_info) 733 { 734 fc_ulp_module_t *mod; 735 fc_ulp_list_t *list; 736 fc_ulp_list_t *last; 737 fc_ulp_module_t *prev; 738 739 mutex_enter(&fctl_ulp_list_mutex); 740 741 for (last = NULL, list = fctl_ulp_list; list != NULL; 742 list = list->ulp_next) { 743 if (list->ulp_info == ulp_info) { 744 break; 745 } 746 last = list; 747 } 748 749 if (list) { 750 if (last) { 751 last->ulp_next = list->ulp_next; 752 } else { 753 fctl_ulp_list = list->ulp_next; 754 } 755 kmem_free(list, sizeof (*list)); 756 } 757 758 mutex_exit(&fctl_ulp_list_mutex); 759 760 rw_enter(&fctl_ulp_lock, RW_WRITER); 761 762 for (mod = fctl_ulp_modules, prev = NULL; mod != NULL; 763 mod = mod->mod_next) { 764 if (mod->mod_info == ulp_info) { 765 break; 766 } 767 prev = mod; 768 } 769 770 if (mod) { 771 fc_ulp_ports_t *next; 772 773 if (prev) { 774 prev->mod_next = mod->mod_next; 775 } else { 776 fctl_ulp_modules = mod->mod_next; 777 } 778 779 rw_enter(&fctl_mod_ports_lock, RW_WRITER); 780 781 while ((next = mod->mod_ports) != NULL) { 782 mod->mod_ports = next->port_next; 783 fctl_dealloc_ulp_port(next); 784 } 785 786 rw_exit(&fctl_mod_ports_lock); 787 rw_exit(&fctl_ulp_lock); 788 789 kmem_free(mod, sizeof (*mod)); 790 791 return (FC_SUCCESS); 792 } 793 rw_exit(&fctl_ulp_lock); 794 795 return (FC_FAILURE); 796 } 797 798 799 /* 800 * The callers typically cache allocate the packet, complete the 801 * DMA setup for pkt_cmd and pkt_resp fields of the packet and 802 * call this function to see if the FCA is interested in doing 803 * its own intialization. For example, socal may like to initialize 804 * the soc_hdr which is pointed to by the pkt_fca_private field 805 * and sitting right below fc_packet_t in memory. 806 * 807 * The caller is required to ensure that pkt_pd is populated with the 808 * handle that it was given when the transport notified it about the 809 * device this packet is associated with. If there is no associated 810 * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an 811 * increment of the reference count for said pd. When the packet is freed, 812 * the reference count will be decremented. This reference count, in 813 * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd 814 * will not wink out of existence while there is a packet outstanding. 815 * 816 * This function and fca_init_pkt must not perform any operations that 817 * would result in a call back to the ULP, as the ULP may be required 818 * to hold a mutex across this call to ensure that the pd in question 819 * won't go away prior the call to fc_ulp_transport. 820 * 821 * ULPs are responsible for using the handles they are given during state 822 * change callback processing in a manner that ensures consistency. That 823 * is, they must be aware that they could be processing a state change 824 * notification that tells them the device associated with a particular 825 * handle has gone away at the same time they are being asked to 826 * initialize a packet using that handle. ULPs must therefore ensure 827 * that their state change processing and packet initialization code 828 * paths are sufficiently synchronized to avoid the use of an 829 * invalidated handle in any fc_packet_t struct that is passed to the 830 * fc_ulp_init_packet() function. 831 */ 832 int 833 fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep) 834 { 835 int rval; 836 fc_local_port_t *port = port_handle; 837 fc_remote_port_t *pd; 838 839 ASSERT(pkt != NULL); 840 841 pd = pkt->pkt_pd; 842 843 /* Call the FCA driver's fca_init_pkt entry point function. */ 844 rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep); 845 846 if ((rval == FC_SUCCESS) && (pd != NULL)) { 847 /* 848 * A !NULL pd here must still be a valid 849 * reference to the fc_remote_port_t. 850 */ 851 mutex_enter(&pd->pd_mutex); 852 ASSERT(pd->pd_ref_count >= 0); 853 pd->pd_ref_count++; 854 mutex_exit(&pd->pd_mutex); 855 } 856 857 return (rval); 858 } 859 860 861 /* 862 * This function is called before destroying the cache allocated 863 * fc_packet to free up (and uninitialize) any resource specially 864 * allocated by the FCA driver during tran_init_pkt(). 865 * 866 * If the pkt_pd field in the given fc_packet_t struct is not NULL, then 867 * the pd_ref_count reference count is decremented for the indicated 868 * fc_remote_port_t struct. 869 */ 870 int 871 fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt) 872 { 873 int rval; 874 fc_local_port_t *port = port_handle; 875 fc_remote_port_t *pd; 876 877 ASSERT(pkt != NULL); 878 879 pd = pkt->pkt_pd; 880 881 /* Call the FCA driver's fca_un_init_pkt entry point function */ 882 rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt); 883 884 if ((rval == FC_SUCCESS) && (pd != NULL)) { 885 mutex_enter(&pd->pd_mutex); 886 887 ASSERT(pd->pd_ref_count > 0); 888 pd->pd_ref_count--; 889 890 /* 891 * If at this point the state of this fc_remote_port_t 892 * struct is PORT_DEVICE_INVALID, it probably means somebody 893 * is cleaning up old (e.g. retried) packets. If the 894 * pd_ref_count has also dropped to zero, it's time to 895 * deallocate this fc_remote_port_t struct. 896 */ 897 if (pd->pd_state == PORT_DEVICE_INVALID && 898 pd->pd_ref_count == 0) { 899 fc_remote_node_t *node = pd->pd_remote_nodep; 900 901 mutex_exit(&pd->pd_mutex); 902 903 /* 904 * Also deallocate the associated fc_remote_node_t 905 * struct if it has no other associated 906 * fc_remote_port_t structs. 907 */ 908 if ((fctl_destroy_remote_port(port, pd) == 0) && 909 (node != NULL)) { 910 fctl_destroy_remote_node(node); 911 } 912 return (rval); 913 } 914 915 mutex_exit(&pd->pd_mutex); 916 } 917 918 return (rval); 919 } 920 921 922 int 923 fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len, 924 int flag) 925 { 926 int job_code; 927 fc_local_port_t *port; 928 job_request_t *job; 929 fc_portmap_t *tmp_map; 930 uint32_t tmp_len; 931 fc_portmap_t *change_list = NULL; 932 uint32_t listlen = 0; 933 934 port = port_handle; 935 936 mutex_enter(&port->fp_mutex); 937 if (port->fp_statec_busy) { 938 mutex_exit(&port->fp_mutex); 939 return (FC_STATEC_BUSY); 940 } 941 942 if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 943 mutex_exit(&port->fp_mutex); 944 return (FC_OFFLINE); 945 } 946 947 if (port->fp_dev_count && (port->fp_dev_count == 948 port->fp_total_devices)) { 949 mutex_exit(&port->fp_mutex); 950 fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0); 951 if (listlen > *len) { 952 tmp_map = (fc_portmap_t *)kmem_zalloc( 953 listlen * sizeof (fc_portmap_t), KM_NOSLEEP); 954 if (tmp_map == NULL) { 955 return (FC_NOMEM); 956 } 957 if (*map) { 958 kmem_free(*map, (*len) * sizeof (fc_portmap_t)); 959 } 960 *map = tmp_map; 961 } 962 if (change_list) { 963 bcopy(change_list, *map, 964 listlen * sizeof (fc_portmap_t)); 965 kmem_free(change_list, listlen * sizeof (fc_portmap_t)); 966 } 967 *len = listlen; 968 } else { 969 mutex_exit(&port->fp_mutex); 970 971 switch (flag) { 972 case FC_ULP_PLOGI_DONTCARE: 973 job_code = JOB_PORT_GETMAP; 974 break; 975 976 case FC_ULP_PLOGI_PRESERVE: 977 job_code = JOB_PORT_GETMAP_PLOGI_ALL; 978 break; 979 980 default: 981 return (FC_INVALID_REQUEST); 982 } 983 /* 984 * Submit a job request to the job handler 985 * thread to get the map and wait 986 */ 987 job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP); 988 job->job_private = (opaque_t)map; 989 job->job_arg = (opaque_t)len; 990 fctl_enque_job(port, job); 991 992 fctl_jobwait(job); 993 /* 994 * The result of the last I/O operation is 995 * in job_code. We don't care to look at it 996 * Rather we look at the number of devices 997 * that are found to fill out the map for 998 * ULPs. 999 */ 1000 fctl_dealloc_job(job); 1001 } 1002 1003 /* 1004 * If we're here, we're returning a map to the caller, which means 1005 * we'd better make sure every pd in that map has the 1006 * PD_GIVEN_TO_ULPS flag set. 1007 */ 1008 1009 tmp_len = *len; 1010 tmp_map = *map; 1011 1012 while (tmp_len-- != 0) { 1013 if (tmp_map->map_state != PORT_DEVICE_INVALID) { 1014 fc_remote_port_t *pd = 1015 (fc_remote_port_t *)tmp_map->map_pd; 1016 mutex_enter(&pd->pd_mutex); 1017 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1018 mutex_exit(&pd->pd_mutex); 1019 } 1020 tmp_map++; 1021 } 1022 1023 return (FC_SUCCESS); 1024 } 1025 1026 1027 int 1028 fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen) 1029 { 1030 int rval = FC_SUCCESS; 1031 int job_flags; 1032 uint32_t count; 1033 fc_packet_t **tmp_array; 1034 job_request_t *job; 1035 fc_local_port_t *port = port_handle; 1036 fc_ulp_rscn_info_t *rscnp = 1037 (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop; 1038 1039 /* 1040 * If the port is OFFLINE, or if the port driver is 1041 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 1042 * PLOGI operations 1043 */ 1044 mutex_enter(&port->fp_mutex); 1045 if (port->fp_statec_busy) { 1046 mutex_exit(&port->fp_mutex); 1047 return (FC_STATEC_BUSY); 1048 } 1049 1050 if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 1051 (port->fp_soft_state & 1052 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1053 mutex_exit(&port->fp_mutex); 1054 return (FC_OFFLINE); 1055 } 1056 1057 /* 1058 * If the rscn count in the packet is not the same as the rscn count 1059 * in the fc_local_port_t, then one or more new RSCNs has occurred. 1060 */ 1061 if ((rscnp != NULL) && 1062 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1063 (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1064 mutex_exit(&port->fp_mutex); 1065 return (FC_DEVICE_BUSY_NEW_RSCN); 1066 } 1067 1068 mutex_exit(&port->fp_mutex); 1069 1070 tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP); 1071 for (count = 0; count < listlen; count++) { 1072 tmp_array[count] = ulp_pkt[count]; 1073 } 1074 1075 job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR) 1076 ? 0 : JOB_TYPE_FCTL_ASYNC; 1077 1078 #ifdef DEBUG 1079 { 1080 int next; 1081 int count; 1082 int polled; 1083 1084 polled = ((ulp_pkt[0]->pkt_tran_flags) & 1085 FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 1086 1087 for (count = 0; count < listlen; count++) { 1088 next = ((ulp_pkt[count]->pkt_tran_flags) 1089 & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 1090 ASSERT(next == polled); 1091 } 1092 } 1093 #endif 1094 1095 job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP); 1096 job->job_ulp_pkts = tmp_array; 1097 job->job_ulp_listlen = listlen; 1098 1099 while (listlen--) { 1100 fc_packet_t *pkt; 1101 1102 pkt = tmp_array[listlen]; 1103 if (pkt->pkt_pd == NULL) { 1104 pkt->pkt_state = FC_PKT_SUCCESS; 1105 continue; 1106 } 1107 1108 mutex_enter(&pkt->pkt_pd->pd_mutex); 1109 if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS || 1110 pkt->pkt_pd->pd_flags == PD_ELS_MARK) { 1111 /* 1112 * Set the packet state and let the port 1113 * driver call the completion routine 1114 * from its thread 1115 */ 1116 mutex_exit(&pkt->pkt_pd->pd_mutex); 1117 pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 1118 continue; 1119 } 1120 1121 if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID || 1122 pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) { 1123 mutex_exit(&pkt->pkt_pd->pd_mutex); 1124 pkt->pkt_state = FC_PKT_LOCAL_RJT; 1125 continue; 1126 } 1127 mutex_exit(&pkt->pkt_pd->pd_mutex); 1128 pkt->pkt_state = FC_PKT_SUCCESS; 1129 } 1130 1131 fctl_enque_job(port, job); 1132 1133 if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) { 1134 fctl_jobwait(job); 1135 rval = job->job_result; 1136 fctl_dealloc_job(job); 1137 } 1138 1139 return (rval); 1140 } 1141 1142 1143 opaque_t 1144 fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error, 1145 int create) 1146 { 1147 fc_local_port_t *port; 1148 job_request_t *job; 1149 fc_remote_port_t *pd; 1150 1151 port = port_handle; 1152 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 1153 1154 if (pd != NULL) { 1155 *error = FC_SUCCESS; 1156 /* 1157 * A ULP now knows about this pd, so mark it 1158 */ 1159 mutex_enter(&pd->pd_mutex); 1160 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1161 mutex_exit(&pd->pd_mutex); 1162 return (pd); 1163 } 1164 1165 mutex_enter(&port->fp_mutex); 1166 if (FC_IS_TOP_SWITCH(port->fp_topology) && create) { 1167 uint32_t d_id; 1168 fctl_ns_req_t *ns_cmd; 1169 1170 mutex_exit(&port->fp_mutex); 1171 1172 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 1173 1174 if (job == NULL) { 1175 *error = FC_NOMEM; 1176 return (pd); 1177 } 1178 1179 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 1180 sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 1181 0, KM_SLEEP); 1182 1183 if (ns_cmd == NULL) { 1184 fctl_dealloc_job(job); 1185 *error = FC_NOMEM; 1186 return (pd); 1187 } 1188 ns_cmd->ns_cmd_code = NS_GID_PN; 1189 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 1190 1191 job->job_result = FC_SUCCESS; 1192 job->job_private = (void *)ns_cmd; 1193 job->job_counter = 1; 1194 fctl_enque_job(port, job); 1195 fctl_jobwait(job); 1196 1197 if (job->job_result != FC_SUCCESS) { 1198 *error = job->job_result; 1199 fctl_free_ns_cmd(ns_cmd); 1200 fctl_dealloc_job(job); 1201 return (pd); 1202 } 1203 d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id; 1204 fctl_free_ns_cmd(ns_cmd); 1205 1206 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 1207 sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE, 1208 KM_SLEEP); 1209 ASSERT(ns_cmd != NULL); 1210 1211 ns_cmd->ns_gan_max = 1; 1212 ns_cmd->ns_cmd_code = NS_GA_NXT; 1213 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 1214 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 1215 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 1216 1217 job->job_result = FC_SUCCESS; 1218 job->job_private = (void *)ns_cmd; 1219 job->job_counter = 1; 1220 fctl_enque_job(port, job); 1221 fctl_jobwait(job); 1222 1223 fctl_free_ns_cmd(ns_cmd); 1224 if (job->job_result != FC_SUCCESS) { 1225 *error = job->job_result; 1226 fctl_dealloc_job(job); 1227 return (pd); 1228 } 1229 fctl_dealloc_job(job); 1230 1231 /* 1232 * Check if the port device is created now. 1233 */ 1234 pd = fctl_get_remote_port_by_pwwn(port, pwwn); 1235 1236 if (pd == NULL) { 1237 *error = FC_FAILURE; 1238 } else { 1239 *error = FC_SUCCESS; 1240 1241 /* 1242 * A ULP now knows about this pd, so mark it 1243 */ 1244 mutex_enter(&pd->pd_mutex); 1245 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1246 mutex_exit(&pd->pd_mutex); 1247 } 1248 } else { 1249 mutex_exit(&port->fp_mutex); 1250 *error = FC_FAILURE; 1251 } 1252 1253 return (pd); 1254 } 1255 1256 1257 /* 1258 * If a NS object exists in the host and query is performed 1259 * on that object, we should retrieve it from our basket 1260 * and return it right here, there by saving a request going 1261 * all the up to the Name Server. 1262 */ 1263 int 1264 fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req) 1265 { 1266 int rval; 1267 int fabric; 1268 job_request_t *job; 1269 fctl_ns_req_t *ns_cmd; 1270 fc_local_port_t *port = port_handle; 1271 1272 mutex_enter(&port->fp_mutex); 1273 fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0; 1274 mutex_exit(&port->fp_mutex); 1275 1276 /* 1277 * Name server query can't be performed for devices not in Fabric 1278 */ 1279 if (!fabric && pd) { 1280 return (FC_BADOBJECT); 1281 } 1282 1283 if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) { 1284 if (pd == NULL) { 1285 rval = fctl_update_host_ns_values(port, ns_req); 1286 if (rval != FC_SUCCESS) { 1287 return (rval); 1288 } 1289 } else { 1290 /* 1291 * Guess what, FC-GS-2 currently prohibits (not 1292 * in the strongest language though) setting of 1293 * NS object values by other ports. But we might 1294 * get that changed to at least accommodate setting 1295 * symbolic node/port names - But if disks/tapes 1296 * were going to provide a method to set these 1297 * values directly (which in turn might register 1298 * with the NS when they come up; yep, for that 1299 * to happen the disks will have to be very well 1300 * behaved Fabric citizen) we won't need to 1301 * register the symbolic port/node names for 1302 * other ports too (rather send down SCSI commands 1303 * to the devices to set the names) 1304 * 1305 * Be that as it may, let's continue to fail 1306 * registration requests for other ports. period. 1307 */ 1308 return (FC_BADOBJECT); 1309 } 1310 1311 if (!fabric) { 1312 return (FC_SUCCESS); 1313 } 1314 } else if (!fabric) { 1315 return (fctl_retrieve_host_ns_values(port, ns_req)); 1316 } 1317 1318 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 1319 ASSERT(job != NULL); 1320 1321 ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 1322 ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP); 1323 ASSERT(ns_cmd != NULL); 1324 ns_cmd->ns_cmd_code = ns_req->ns_cmd; 1325 bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf, 1326 ns_req->ns_req_len); 1327 1328 job->job_private = (void *)ns_cmd; 1329 fctl_enque_job(port, job); 1330 fctl_jobwait(job); 1331 rval = job->job_result; 1332 1333 if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) { 1334 bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload, 1335 ns_cmd->ns_data_len); 1336 } 1337 bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr, 1338 sizeof (fc_ct_header_t)); 1339 1340 fctl_free_ns_cmd(ns_cmd); 1341 fctl_dealloc_job(job); 1342 1343 return (rval); 1344 } 1345 1346 1347 int 1348 fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt) 1349 { 1350 int rval; 1351 fc_local_port_t *port; 1352 fc_remote_port_t *pd, *newpd; 1353 fc_ulp_rscn_info_t *rscnp = 1354 (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 1355 1356 port = port_handle; 1357 1358 if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) { 1359 return (port->fp_fca_tran->fca_transport( 1360 port->fp_fca_handle, pkt)); 1361 } 1362 1363 mutex_enter(&port->fp_mutex); 1364 if (port->fp_statec_busy) { 1365 mutex_exit(&port->fp_mutex); 1366 return (FC_STATEC_BUSY); 1367 } 1368 1369 /* A locus of race conditions */ 1370 if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) || 1371 (port->fp_soft_state & 1372 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1373 mutex_exit(&port->fp_mutex); 1374 return (FC_OFFLINE); 1375 } 1376 1377 /* 1378 * If the rscn count in the packet is not the same as the rscn count 1379 * in the fc_local_port_t, then one or more new RSCNs has occurred. 1380 */ 1381 if ((rscnp != NULL) && 1382 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1383 (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1384 mutex_exit(&port->fp_mutex); 1385 return (FC_DEVICE_BUSY_NEW_RSCN); 1386 } 1387 1388 pd = pkt->pkt_pd; 1389 if (pd) { 1390 if (pd->pd_type == PORT_DEVICE_OLD || 1391 pd->pd_state == PORT_DEVICE_INVALID) { 1392 1393 newpd = fctl_get_remote_port_by_pwwn_mutex_held(port, 1394 &pd->pd_port_name); 1395 1396 /* 1397 * The remote port (pd) in the packet is no longer 1398 * usable, as the old pd still exists we can use the 1399 * WWN to check if we have a current pd for the device 1400 * we want. Either way we continue with the old logic 1401 * whether we have a new pd or not, as the new pd 1402 * could be bad, or have become unusable. 1403 */ 1404 if ((newpd) && (newpd != pd)) { 1405 1406 /* 1407 * There is a better remote port (pd) to try, 1408 * so we need to fix the reference counts, etc. 1409 */ 1410 mutex_enter(&newpd->pd_mutex); 1411 newpd->pd_ref_count++; 1412 pkt->pkt_pd = newpd; 1413 mutex_exit(&newpd->pd_mutex); 1414 1415 mutex_enter(&pd->pd_mutex); 1416 pd->pd_ref_count--; 1417 if ((pd->pd_state == PORT_DEVICE_INVALID) && 1418 (pd->pd_ref_count == 0)) { 1419 fc_remote_node_t *node = 1420 pd->pd_remote_nodep; 1421 1422 mutex_exit(&pd->pd_mutex); 1423 mutex_exit(&port->fp_mutex); 1424 1425 /* 1426 * This will create another PD hole 1427 * where we have a reference to a pd, 1428 * but someone else could remove it. 1429 */ 1430 if ((fctl_destroy_remote_port(port, pd) 1431 == 0) && (node != NULL)) { 1432 fctl_destroy_remote_node(node); 1433 } 1434 mutex_enter(&port->fp_mutex); 1435 } else { 1436 mutex_exit(&pd->pd_mutex); 1437 } 1438 pd = newpd; 1439 } 1440 } 1441 1442 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 1443 rval = (pd->pd_state == PORT_DEVICE_VALID) ? 1444 FC_LOGINREQ : FC_BADDEV; 1445 mutex_exit(&port->fp_mutex); 1446 return (rval); 1447 } 1448 1449 if (pd->pd_flags != PD_IDLE) { 1450 mutex_exit(&port->fp_mutex); 1451 return (FC_DEVICE_BUSY); 1452 } 1453 1454 if (pd->pd_type == PORT_DEVICE_OLD || 1455 pd->pd_state == PORT_DEVICE_INVALID) { 1456 mutex_exit(&port->fp_mutex); 1457 return (FC_BADDEV); 1458 } 1459 1460 } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) { 1461 mutex_exit(&port->fp_mutex); 1462 return (FC_BADPACKET); 1463 } 1464 mutex_exit(&port->fp_mutex); 1465 1466 return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt)); 1467 } 1468 1469 1470 int 1471 fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt) 1472 { 1473 int rval; 1474 fc_local_port_t *port = port_handle; 1475 fc_remote_port_t *pd; 1476 fc_ulp_rscn_info_t *rscnp = 1477 (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 1478 1479 /* 1480 * If the port is OFFLINE, or if the port driver is 1481 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 1482 * ELS operations 1483 */ 1484 mutex_enter(&port->fp_mutex); 1485 if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 1486 (port->fp_soft_state & 1487 (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1488 mutex_exit(&port->fp_mutex); 1489 return (FC_OFFLINE); 1490 } 1491 1492 if (port->fp_statec_busy) { 1493 mutex_exit(&port->fp_mutex); 1494 return (FC_STATEC_BUSY); 1495 } 1496 1497 /* 1498 * If the rscn count in the packet is not the same as the rscn count 1499 * in the fc_local_port_t, then one or more new RSCNs has occurred. 1500 */ 1501 if ((rscnp != NULL) && 1502 (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1503 (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1504 mutex_exit(&port->fp_mutex); 1505 return (FC_DEVICE_BUSY_NEW_RSCN); 1506 } 1507 1508 mutex_exit(&port->fp_mutex); 1509 1510 if ((pd = pkt->pkt_pd) != NULL) { 1511 mutex_enter(&pd->pd_mutex); 1512 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 1513 rval = (pd->pd_state == PORT_DEVICE_VALID) ? 1514 FC_LOGINREQ : FC_BADDEV; 1515 mutex_exit(&pd->pd_mutex); 1516 return (rval); 1517 } 1518 1519 if (pd->pd_flags != PD_IDLE) { 1520 mutex_exit(&pd->pd_mutex); 1521 return (FC_DEVICE_BUSY); 1522 } 1523 if (pd->pd_type == PORT_DEVICE_OLD || 1524 pd->pd_state == PORT_DEVICE_INVALID) { 1525 mutex_exit(&pd->pd_mutex); 1526 return (FC_BADDEV); 1527 } 1528 mutex_exit(&pd->pd_mutex); 1529 } 1530 1531 return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt)); 1532 } 1533 1534 1535 int 1536 fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size, 1537 uint32_t type, uint64_t *tokens) 1538 { 1539 fc_local_port_t *port = port_handle; 1540 1541 return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle, 1542 tokens, size, count, type)); 1543 } 1544 1545 1546 int 1547 fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens) 1548 { 1549 fc_local_port_t *port = port_handle; 1550 1551 return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle, 1552 count, tokens)); 1553 } 1554 1555 1556 int 1557 fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens) 1558 { 1559 fc_local_port_t *port = port_handle; 1560 1561 return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 1562 count, tokens)); 1563 } 1564 1565 1566 int 1567 fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags) 1568 { 1569 fc_local_port_t *port = port_handle; 1570 1571 return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags)); 1572 } 1573 1574 1575 /* 1576 * Submit an asynchronous request to the job handler if the sleep 1577 * flag is set to KM_NOSLEEP, as such calls could have been made 1578 * in interrupt contexts, and the goal is to avoid busy waiting, 1579 * blocking on a conditional variable, a semaphore or any of the 1580 * synchronization primitives. A noticeable draw back with this 1581 * asynchronous request is that an FC_SUCCESS is returned long 1582 * before the reset is complete (successful or not). 1583 */ 1584 int 1585 fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep) 1586 { 1587 int rval; 1588 fc_local_port_t *port; 1589 job_request_t *job; 1590 1591 port = port_handle; 1592 /* 1593 * Many a times, this function is called from interrupt 1594 * contexts and there have been several dead locks and 1595 * hangs - One of the simplest work arounds is to fib 1596 * if a RESET is in progress. 1597 */ 1598 mutex_enter(&port->fp_mutex); 1599 if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 1600 mutex_exit(&port->fp_mutex); 1601 return (FC_SUCCESS); 1602 } 1603 1604 /* 1605 * Ward off this reset if a state change is in progress. 1606 */ 1607 if (port->fp_statec_busy) { 1608 mutex_exit(&port->fp_mutex); 1609 return (FC_STATEC_BUSY); 1610 } 1611 port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 1612 mutex_exit(&port->fp_mutex); 1613 1614 if (fctl_busy_port(port) != 0) { 1615 mutex_enter(&port->fp_mutex); 1616 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1617 mutex_exit(&port->fp_mutex); 1618 return (FC_FAILURE); 1619 } 1620 1621 if (sleep == KM_SLEEP) { 1622 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep); 1623 ASSERT(job != NULL); 1624 1625 job->job_private = (void *)pwwn; 1626 job->job_counter = 1; 1627 fctl_enque_job(port, job); 1628 fctl_jobwait(job); 1629 1630 mutex_enter(&port->fp_mutex); 1631 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1632 mutex_exit(&port->fp_mutex); 1633 1634 fctl_idle_port(port); 1635 1636 rval = job->job_result; 1637 fctl_dealloc_job(job); 1638 } else { 1639 job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC, 1640 fctl_link_reset_done, port, sleep); 1641 if (job == NULL) { 1642 mutex_enter(&port->fp_mutex); 1643 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1644 mutex_exit(&port->fp_mutex); 1645 fctl_idle_port(port); 1646 return (FC_NOMEM); 1647 } 1648 job->job_private = (void *)pwwn; 1649 job->job_counter = 1; 1650 fctl_priority_enque_job(port, job); 1651 rval = FC_SUCCESS; 1652 } 1653 1654 return (rval); 1655 } 1656 1657 1658 int 1659 fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd) 1660 { 1661 int rval = FC_SUCCESS; 1662 fc_local_port_t *port = port_handle; 1663 1664 switch (cmd) { 1665 case FC_RESET_PORT: 1666 rval = port->fp_fca_tran->fca_reset( 1667 port->fp_fca_handle, FC_FCA_LINK_RESET); 1668 break; 1669 1670 case FC_RESET_ADAPTER: 1671 rval = port->fp_fca_tran->fca_reset( 1672 port->fp_fca_handle, FC_FCA_RESET); 1673 break; 1674 1675 case FC_RESET_DUMP: 1676 rval = port->fp_fca_tran->fca_reset( 1677 port->fp_fca_handle, FC_FCA_CORE); 1678 break; 1679 1680 case FC_RESET_CRASH: 1681 rval = port->fp_fca_tran->fca_reset( 1682 port->fp_fca_handle, FC_FCA_RESET_CORE); 1683 break; 1684 1685 default: 1686 rval = FC_FAILURE; 1687 } 1688 1689 return (rval); 1690 } 1691 1692 1693 int 1694 fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params) 1695 { 1696 fc_local_port_t *port = port_handle; 1697 1698 /* Copy the login parameters */ 1699 *login_params = port->fp_service_params; 1700 return (FC_SUCCESS); 1701 } 1702 1703 1704 int 1705 fc_ulp_get_port_instance(opaque_t port_handle) 1706 { 1707 fc_local_port_t *port = port_handle; 1708 1709 return (port->fp_instance); 1710 } 1711 1712 1713 opaque_t 1714 fc_ulp_get_port_handle(int port_instance) 1715 { 1716 opaque_t port_handle = NULL; 1717 fc_fca_port_t *cur; 1718 1719 mutex_enter(&fctl_port_lock); 1720 for (cur = fctl_fca_portlist; cur; cur = cur->port_next) { 1721 if (cur->port_handle->fp_instance == port_instance) { 1722 port_handle = (opaque_t)cur->port_handle; 1723 break; 1724 } 1725 } 1726 mutex_exit(&fctl_port_lock); 1727 1728 return (port_handle); 1729 } 1730 1731 1732 int 1733 fc_ulp_error(int fc_errno, char **errmsg) 1734 { 1735 return (fctl_error(fc_errno, errmsg)); 1736 } 1737 1738 1739 int 1740 fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason, 1741 char **action, char **expln) 1742 { 1743 return (fctl_pkt_error(pkt, state, reason, action, expln)); 1744 } 1745 1746 1747 /* 1748 * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE 1749 */ 1750 int 1751 fc_ulp_is_name_present(caddr_t ulp_name) 1752 { 1753 int rval = FC_FAILURE; 1754 fc_ulp_list_t *list; 1755 1756 mutex_enter(&fctl_ulp_list_mutex); 1757 for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) { 1758 if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) { 1759 rval = FC_SUCCESS; 1760 break; 1761 } 1762 } 1763 mutex_exit(&fctl_ulp_list_mutex); 1764 1765 return (rval); 1766 } 1767 1768 1769 /* 1770 * Return port WWN for a port Identifier 1771 */ 1772 int 1773 fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn) 1774 { 1775 int rval = FC_FAILURE; 1776 fc_remote_port_t *pd; 1777 fc_local_port_t *port = port_handle; 1778 1779 pd = fctl_get_remote_port_by_did(port, d_id.port_id); 1780 if (pd != NULL) { 1781 mutex_enter(&pd->pd_mutex); 1782 *pwwn = pd->pd_port_name; 1783 mutex_exit(&pd->pd_mutex); 1784 rval = FC_SUCCESS; 1785 } 1786 1787 return (rval); 1788 } 1789 1790 1791 /* 1792 * Return a port map for a port WWN 1793 */ 1794 int 1795 fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map) 1796 { 1797 fc_local_port_t *port = port_handle; 1798 fc_remote_node_t *node; 1799 fc_remote_port_t *pd; 1800 1801 pd = fctl_get_remote_port_by_pwwn(port, bytes); 1802 if (pd == NULL) { 1803 return (FC_FAILURE); 1804 } 1805 1806 mutex_enter(&pd->pd_mutex); 1807 map->map_pwwn = pd->pd_port_name; 1808 map->map_did = pd->pd_port_id; 1809 map->map_hard_addr = pd->pd_hard_addr; 1810 map->map_state = pd->pd_state; 1811 map->map_type = pd->pd_type; 1812 map->map_flags = 0; 1813 1814 ASSERT(map->map_type <= PORT_DEVICE_DELETE); 1815 1816 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 1817 1818 node = pd->pd_remote_nodep; 1819 mutex_exit(&pd->pd_mutex); 1820 1821 if (node) { 1822 mutex_enter(&node->fd_mutex); 1823 map->map_nwwn = node->fd_node_name; 1824 mutex_exit(&node->fd_mutex); 1825 } 1826 map->map_pd = pd; 1827 1828 return (FC_SUCCESS); 1829 } 1830 1831 1832 opaque_t 1833 fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id) 1834 { 1835 fc_local_port_t *port = port_handle; 1836 1837 if (port->fp_fca_tran->fca_get_device == NULL) { 1838 return (NULL); 1839 } 1840 1841 return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id)); 1842 } 1843 1844 1845 int 1846 fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd) 1847 { 1848 int rval = FC_SUCCESS; 1849 fc_local_port_t *port = port_handle; 1850 1851 if (port->fp_fca_tran->fca_notify) { 1852 mutex_enter(&port->fp_mutex); 1853 switch (cmd) { 1854 case FC_NOTIFY_TARGET_MODE: 1855 port->fp_options |= FP_TARGET_MODE; 1856 break; 1857 case FC_NOTIFY_NO_TARGET_MODE: 1858 port->fp_options &= ~FP_TARGET_MODE; 1859 break; 1860 } 1861 mutex_exit(&port->fp_mutex); 1862 rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd); 1863 } 1864 1865 return (rval); 1866 } 1867 1868 1869 void 1870 fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 1871 { 1872 fc_remote_port_t *pd = 1873 fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 1874 1875 if (pd) { 1876 mutex_enter(&pd->pd_mutex); 1877 pd->pd_aux_flags |= PD_DISABLE_RELOGIN; 1878 mutex_exit(&pd->pd_mutex); 1879 } 1880 } 1881 1882 1883 void 1884 fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 1885 { 1886 fc_remote_port_t *pd = 1887 fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 1888 1889 if (pd) { 1890 mutex_enter(&pd->pd_mutex); 1891 pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN; 1892 mutex_exit(&pd->pd_mutex); 1893 } 1894 } 1895 1896 1897 /* 1898 * fc_fca_init 1899 * Overload the FCA bus_ops vector in its dev_ops with 1900 * fctl_fca_busops to handle all the INITchilds for "sf" 1901 * in one common place. 1902 * 1903 * Should be called from FCA _init routine. 1904 */ 1905 void 1906 fc_fca_init(struct dev_ops *fca_devops_p) 1907 { 1908 fca_devops_p->devo_bus_ops = &fctl_fca_busops; 1909 } 1910 1911 1912 /* 1913 * fc_fca_attach 1914 */ 1915 int 1916 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran) 1917 { 1918 /* 1919 * When we are in a position to offer downward compatibility 1920 * we should change the following check to allow lower revision 1921 * of FCAs; But we aren't there right now. 1922 */ 1923 if (tran->fca_version != FCTL_FCA_MODREV_5) { 1924 const char *name = ddi_driver_name(fca_dip); 1925 1926 ASSERT(name != NULL); 1927 1928 cmn_err(CE_WARN, "fctl: FCA %s version mismatch" 1929 " please upgrade %s", name, name); 1930 return (DDI_FAILURE); 1931 } 1932 1933 ddi_set_driver_private(fca_dip, (caddr_t)tran); 1934 return (DDI_SUCCESS); 1935 } 1936 1937 1938 /* 1939 * fc_fca_detach 1940 */ 1941 int 1942 fc_fca_detach(dev_info_t *fca_dip) 1943 { 1944 ddi_set_driver_private(fca_dip, NULL); 1945 return (DDI_SUCCESS); 1946 } 1947 1948 1949 /* 1950 * Check if the frame is a Link response Frame; Handle all cases (P_RJT, 1951 * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic 1952 * Link Service responses such as BA_RJT and Extended Link Service response 1953 * such as LS_RJT. If the response is a Link_Data Frame or something that 1954 * this function doesn't understand return FC_FAILURE; Otherwise, fill out 1955 * various fields (state, action, reason, expln) from the response gotten 1956 * in the packet and return FC_SUCCESS. 1957 */ 1958 int 1959 fc_fca_update_errors(fc_packet_t *pkt) 1960 { 1961 int ret = FC_SUCCESS; 1962 1963 switch (pkt->pkt_resp_fhdr.r_ctl) { 1964 case R_CTL_P_RJT: { 1965 uint32_t prjt; 1966 1967 prjt = pkt->pkt_resp_fhdr.ro; 1968 pkt->pkt_state = FC_PKT_NPORT_RJT; 1969 pkt->pkt_action = (prjt & 0xFF000000) >> 24; 1970 pkt->pkt_reason = (prjt & 0xFF0000) >> 16; 1971 break; 1972 } 1973 1974 case R_CTL_F_RJT: { 1975 uint32_t frjt; 1976 1977 frjt = pkt->pkt_resp_fhdr.ro; 1978 pkt->pkt_state = FC_PKT_FABRIC_RJT; 1979 pkt->pkt_action = (frjt & 0xFF000000) >> 24; 1980 pkt->pkt_reason = (frjt & 0xFF0000) >> 16; 1981 break; 1982 } 1983 1984 case R_CTL_P_BSY: { 1985 uint32_t pbsy; 1986 1987 pbsy = pkt->pkt_resp_fhdr.ro; 1988 pkt->pkt_state = FC_PKT_NPORT_BSY; 1989 pkt->pkt_action = (pbsy & 0xFF000000) >> 24; 1990 pkt->pkt_reason = (pbsy & 0xFF0000) >> 16; 1991 break; 1992 } 1993 1994 case R_CTL_F_BSY_LC: 1995 case R_CTL_F_BSY_DF: { 1996 uchar_t fbsy; 1997 1998 fbsy = pkt->pkt_resp_fhdr.type; 1999 pkt->pkt_state = FC_PKT_FABRIC_BSY; 2000 pkt->pkt_reason = (fbsy & 0xF0) >> 4; 2001 break; 2002 } 2003 2004 case R_CTL_LS_BA_RJT: { 2005 uint32_t brjt; 2006 2007 brjt = *(uint32_t *)pkt->pkt_resp; 2008 pkt->pkt_state = FC_PKT_BA_RJT; 2009 pkt->pkt_reason = (brjt & 0xFF0000) >> 16; 2010 pkt->pkt_expln = (brjt & 0xFF00) >> 8; 2011 break; 2012 } 2013 2014 case R_CTL_ELS_RSP: { 2015 la_els_rjt_t *lsrjt; 2016 2017 lsrjt = (la_els_rjt_t *)pkt->pkt_resp; 2018 if (lsrjt->ls_code.ls_code == LA_ELS_RJT) { 2019 pkt->pkt_state = FC_PKT_LS_RJT; 2020 pkt->pkt_reason = lsrjt->reason; 2021 pkt->pkt_action = lsrjt->action; 2022 break; 2023 } 2024 /* FALLTHROUGH */ 2025 } 2026 2027 default: 2028 ret = FC_FAILURE; 2029 break; 2030 } 2031 2032 return (ret); 2033 } 2034 2035 2036 int 2037 fc_fca_error(int fc_errno, char **errmsg) 2038 { 2039 return (fctl_error(fc_errno, errmsg)); 2040 } 2041 2042 2043 int 2044 fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason, 2045 char **action, char **expln) 2046 { 2047 return (fctl_pkt_error(pkt, state, reason, action, expln)); 2048 } 2049 2050 2051 /* 2052 * WWN to string goodie. Unpredictable results will happen 2053 * if enough memory isn't supplied in str argument. If you 2054 * are wondering how much does this routine need, it is just 2055 * (2 * WWN size + 1). So for a WWN size of 8 bytes the str 2056 * argument should have atleast 17 bytes allocated. 2057 */ 2058 void 2059 fc_wwn_to_str(la_wwn_t *wwn, caddr_t str) 2060 { 2061 int count; 2062 2063 for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) { 2064 (void) sprintf(str, "%02x", wwn->raw_wwn[count]); 2065 } 2066 *str = '\0'; 2067 } 2068 2069 #define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : \ 2070 ((x) >= 'a' && (x) <= 'f') ? \ 2071 ((x) - 'a' + 10) : ((x) - 'A' + 10)) 2072 2073 void 2074 fc_str_to_wwn(caddr_t str, la_wwn_t *wwn) 2075 { 2076 int count = 0; 2077 uchar_t byte; 2078 2079 while (*str) { 2080 byte = FC_ATOB(*str); 2081 str++; 2082 byte = byte << 4 | FC_ATOB(*str); 2083 str++; 2084 wwn->raw_wwn[count++] = byte; 2085 } 2086 } 2087 2088 /* 2089 * FCA driver's intercepted bus control operations. 2090 */ 2091 static int 2092 fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 2093 ddi_ctl_enum_t op, void *arg, void *result) 2094 { 2095 switch (op) { 2096 case DDI_CTLOPS_REPORTDEV: 2097 break; 2098 2099 case DDI_CTLOPS_IOMIN: 2100 break; 2101 2102 case DDI_CTLOPS_INITCHILD: 2103 return (fctl_initchild(fca_dip, (dev_info_t *)arg)); 2104 2105 case DDI_CTLOPS_UNINITCHILD: 2106 return (fctl_uninitchild(fca_dip, (dev_info_t *)arg)); 2107 2108 default: 2109 return (ddi_ctlops(fca_dip, rip, op, arg, result)); 2110 } 2111 2112 return (DDI_SUCCESS); 2113 } 2114 2115 2116 /* 2117 * FCAs indicate the maximum number of ports supported in their 2118 * tran structure. Fail the INITCHILD if the child port number 2119 * is any greater than the maximum number of ports supported 2120 * by the FCA. 2121 */ 2122 static int 2123 fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip) 2124 { 2125 int rval; 2126 int port_no; 2127 int port_len; 2128 char name[20]; 2129 fc_fca_tran_t *tran; 2130 dev_info_t *dip; 2131 int portprop; 2132 2133 port_len = sizeof (port_no); 2134 2135 /* physical port do not has this property */ 2136 portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip, 2137 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 2138 "phyport-instance", -1); 2139 2140 if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) { 2141 /* 2142 * Clear any addr bindings created by fcode interpreter 2143 * in devi_last_addr so that a ndi_devi_find should never 2144 * return this fcode node. 2145 */ 2146 ddi_set_name_addr(port_dip, NULL); 2147 return (DDI_FAILURE); 2148 } 2149 2150 rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF, 2151 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 2152 (caddr_t)&port_no, &port_len); 2153 2154 if (rval != DDI_SUCCESS) { 2155 return (DDI_FAILURE); 2156 } 2157 2158 tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip); 2159 ASSERT(tran != NULL); 2160 2161 (void) sprintf((char *)name, "%x,0", port_no); 2162 ddi_set_name_addr(port_dip, name); 2163 2164 dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 2165 2166 /* 2167 * Even though we never initialize FCode nodes of fp, such a node 2168 * could still be there after a DR operation. There will only be 2169 * one FCode node, so if this is the one, clear it and issue a 2170 * ndi_devi_find again. 2171 */ 2172 if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) { 2173 ddi_set_name_addr(dip, NULL); 2174 dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 2175 } 2176 2177 if ((portprop == -1) && dip && (dip != port_dip)) { 2178 /* 2179 * Here we have a duplicate .conf entry. Clear the addr 2180 * set previously and return failure. 2181 */ 2182 ddi_set_name_addr(port_dip, NULL); 2183 return (DDI_FAILURE); 2184 } 2185 2186 return (DDI_SUCCESS); 2187 } 2188 2189 2190 /* ARGSUSED */ 2191 static int 2192 fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip) 2193 { 2194 ddi_set_name_addr(port_dip, NULL); 2195 return (DDI_SUCCESS); 2196 } 2197 2198 2199 static dev_info_t * 2200 fctl_findchild(dev_info_t *pdip, char *cname, char *caddr) 2201 { 2202 dev_info_t *dip; 2203 char *addr; 2204 2205 ASSERT(cname != NULL && caddr != NULL); 2206 /* ASSERT(DEVI_BUSY_OWNED(pdip)); */ 2207 2208 for (dip = ddi_get_child(pdip); dip != NULL; 2209 dip = ddi_get_next_sibling(dip)) { 2210 if (strcmp(cname, ddi_node_name(dip)) != 0) { 2211 continue; 2212 } 2213 2214 if ((addr = ddi_get_name_addr(dip)) == NULL) { 2215 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 2216 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 2217 "bus-addr", &addr) == DDI_PROP_SUCCESS) { 2218 if (strcmp(caddr, addr) == 0) { 2219 ddi_prop_free(addr); 2220 return (dip); 2221 } 2222 ddi_prop_free(addr); 2223 } 2224 } else { 2225 if (strcmp(caddr, addr) == 0) { 2226 return (dip); 2227 } 2228 } 2229 } 2230 2231 return (NULL); 2232 } 2233 2234 int 2235 fctl_check_npiv_portindex(dev_info_t *dip, int vindex) 2236 { 2237 int i, instance; 2238 fc_local_port_t *port; 2239 2240 instance = ddi_get_instance(dip); 2241 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2242 if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) { 2243 return (0); 2244 } 2245 2246 i = vindex-1; 2247 mutex_enter(&port->fp_mutex); 2248 if (port->fp_npiv_portindex[i] == 0) { 2249 mutex_exit(&port->fp_mutex); 2250 return (vindex); 2251 } 2252 mutex_exit(&port->fp_mutex); 2253 return (0); 2254 } 2255 2256 int 2257 fctl_get_npiv_portindex(dev_info_t *dip) 2258 { 2259 int i, instance; 2260 fc_local_port_t *port; 2261 2262 instance = ddi_get_instance(dip); 2263 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2264 if (!port) { 2265 return (0); 2266 } 2267 2268 mutex_enter(&port->fp_mutex); 2269 for (i = 0; i < FC_NPIV_MAX_PORT; i++) { 2270 if (port->fp_npiv_portindex[i] == 0) { 2271 mutex_exit(&port->fp_mutex); 2272 return (i+1); 2273 } 2274 } 2275 mutex_exit(&port->fp_mutex); 2276 return (0); 2277 } 2278 2279 2280 void 2281 fctl_set_npiv_portindex(dev_info_t *dip, int index) 2282 { 2283 int instance; 2284 fc_local_port_t *port; 2285 2286 instance = ddi_get_instance(dip); 2287 port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2288 if (!port) { 2289 return; 2290 } 2291 mutex_enter(&port->fp_mutex); 2292 port->fp_npiv_portindex[index - 1] = 1; 2293 mutex_exit(&port->fp_mutex); 2294 } 2295 2296 2297 int 2298 fctl_fca_create_npivport(dev_info_t *parent, 2299 dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex) 2300 { 2301 int rval = 0, devstrlen; 2302 char *devname, *cname, *caddr, *devstr; 2303 dev_info_t *child = NULL; 2304 int portnum; 2305 2306 if (*vindex == 0) { 2307 portnum = fctl_get_npiv_portindex(phydip); 2308 *vindex = portnum; 2309 } else { 2310 portnum = fctl_check_npiv_portindex(phydip, *vindex); 2311 } 2312 2313 if (portnum == 0) { 2314 cmn_err(CE_WARN, 2315 "Cann't find valid port index, fail to create devnode"); 2316 return (NDI_FAILURE); 2317 } 2318 2319 devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 2320 (void) sprintf(devname, "fp@%x,0", portnum); 2321 devstrlen = strlen(devname) + 1; 2322 devstr = i_ddi_strdup(devname, KM_SLEEP); 2323 i_ddi_parse_name(devstr, &cname, &caddr, NULL); 2324 2325 if (fctl_findchild(parent, cname, caddr) != NULL) { 2326 rval = NDI_FAILURE; 2327 goto freememory; 2328 } 2329 2330 ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child); 2331 if (child == NULL) { 2332 cmn_err(CE_WARN, 2333 "fctl_create_npiv_port fail to create new devinfo"); 2334 rval = NDI_FAILURE; 2335 goto freememory; 2336 } 2337 2338 if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2339 "bus-addr", caddr) != DDI_PROP_SUCCESS) { 2340 cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed", 2341 ddi_get_instance(parent), cname, caddr); 2342 (void) ndi_devi_free(child); 2343 rval = NDI_FAILURE; 2344 goto freememory; 2345 } 2346 2347 if (strlen(nname) != 0) { 2348 if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2349 "node-name", nname) != DDI_PROP_SUCCESS) { 2350 (void) ndi_devi_free(child); 2351 rval = NDI_FAILURE; 2352 goto freememory; 2353 } 2354 } 2355 2356 if (strlen(pname) != 0) { 2357 if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2358 "port-name", pname) != DDI_PROP_SUCCESS) { 2359 (void) ndi_devi_free(child); 2360 rval = NDI_FAILURE; 2361 goto freememory; 2362 } 2363 } 2364 2365 if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 2366 "port", portnum) != DDI_PROP_SUCCESS) { 2367 cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed", 2368 ddi_get_instance(parent), cname, caddr); 2369 (void) ndi_devi_free(child); 2370 rval = NDI_FAILURE; 2371 goto freememory; 2372 } 2373 2374 if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 2375 "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) { 2376 cmn_err(CE_WARN, 2377 "fp%d: prop_update phyport-instance %s@%s failed", 2378 ddi_get_instance(parent), cname, caddr); 2379 (void) ndi_devi_free(child); 2380 rval = NDI_FAILURE; 2381 goto freememory; 2382 } 2383 2384 rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); 2385 if (rval != NDI_SUCCESS) { 2386 cmn_err(CE_WARN, "fp%d: online_driver %s failed", 2387 ddi_get_instance(parent), cname); 2388 rval = NDI_FAILURE; 2389 goto freememory; 2390 } 2391 2392 fctl_set_npiv_portindex(phydip, portnum); 2393 freememory: 2394 kmem_free(devstr, devstrlen); 2395 kmem_free(devname, MAXNAMELEN); 2396 2397 return (rval); 2398 } 2399 2400 2401 void 2402 fctl_add_port(fc_local_port_t *port) 2403 { 2404 fc_fca_port_t *new; 2405 2406 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 2407 2408 mutex_enter(&fctl_port_lock); 2409 new->port_handle = port; 2410 new->port_next = fctl_fca_portlist; 2411 fctl_fca_portlist = new; 2412 mutex_exit(&fctl_port_lock); 2413 } 2414 2415 2416 void 2417 fctl_remove_port(fc_local_port_t *port) 2418 { 2419 fc_ulp_module_t *mod; 2420 fc_fca_port_t *prev; 2421 fc_fca_port_t *list; 2422 fc_ulp_ports_t *ulp_port; 2423 2424 rw_enter(&fctl_ulp_lock, RW_WRITER); 2425 rw_enter(&fctl_mod_ports_lock, RW_WRITER); 2426 2427 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2428 ulp_port = fctl_get_ulp_port(mod, port); 2429 if (ulp_port == NULL) { 2430 continue; 2431 } 2432 2433 ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0); 2434 2435 (void) fctl_remove_ulp_port(mod, port); 2436 } 2437 2438 rw_exit(&fctl_mod_ports_lock); 2439 rw_exit(&fctl_ulp_lock); 2440 2441 mutex_enter(&fctl_port_lock); 2442 2443 list = fctl_fca_portlist; 2444 prev = NULL; 2445 while (list != NULL) { 2446 if (list->port_handle == port) { 2447 if (prev == NULL) { 2448 fctl_fca_portlist = list->port_next; 2449 } else { 2450 prev->port_next = list->port_next; 2451 } 2452 kmem_free(list, sizeof (*list)); 2453 break; 2454 } 2455 prev = list; 2456 list = list->port_next; 2457 } 2458 mutex_exit(&fctl_port_lock); 2459 } 2460 2461 2462 void 2463 fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd, 2464 struct modlinkage *linkage) 2465 { 2466 int rval; 2467 uint32_t s_id; 2468 uint32_t state; 2469 fc_ulp_module_t *mod; 2470 fc_ulp_port_info_t info; 2471 fc_ulp_ports_t *ulp_port; 2472 2473 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 2474 2475 info.port_linkage = linkage; 2476 info.port_dip = port->fp_port_dip; 2477 info.port_handle = (opaque_t)port; 2478 info.port_dma_behavior = port->fp_dma_behavior; 2479 info.port_fcp_dma = port->fp_fcp_dma; 2480 info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 2481 info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 2482 info.port_reset_action = port->fp_reset_action; 2483 2484 mutex_enter(&port->fp_mutex); 2485 2486 /* 2487 * It is still possible that another thread could have gotten 2488 * into the detach process before we got here. 2489 */ 2490 if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 2491 mutex_exit(&port->fp_mutex); 2492 return; 2493 } 2494 2495 s_id = port->fp_port_id.port_id; 2496 if (port->fp_statec_busy) { 2497 info.port_state = port->fp_bind_state; 2498 } else { 2499 info.port_state = port->fp_state; 2500 } 2501 2502 switch (state = FC_PORT_STATE_MASK(info.port_state)) { 2503 case FC_STATE_LOOP: 2504 case FC_STATE_NAMESERVICE: 2505 info.port_state &= ~state; 2506 info.port_state |= FC_STATE_ONLINE; 2507 break; 2508 2509 default: 2510 break; 2511 } 2512 ASSERT((info.port_state & FC_STATE_LOOP) == 0); 2513 2514 info.port_flags = port->fp_topology; 2515 info.port_pwwn = port->fp_service_params.nport_ww_name; 2516 info.port_nwwn = port->fp_service_params.node_ww_name; 2517 mutex_exit(&port->fp_mutex); 2518 2519 rw_enter(&fctl_ulp_lock, RW_READER); 2520 rw_enter(&fctl_mod_ports_lock, RW_WRITER); 2521 2522 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2523 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) && 2524 (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) { 2525 /* 2526 * We don't support IP over FC on FCOE HBA 2527 */ 2528 continue; 2529 } 2530 2531 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 2532 ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP); 2533 ASSERT(ulp_port != NULL); 2534 2535 mutex_enter(&ulp_port->port_mutex); 2536 ulp_port->port_statec = ((info.port_state & 2537 FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE : 2538 FC_ULP_STATEC_OFFLINE); 2539 mutex_exit(&ulp_port->port_mutex); 2540 } 2541 } 2542 2543 rw_downgrade(&fctl_mod_ports_lock); 2544 2545 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2546 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) && 2547 (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) { 2548 /* 2549 * We don't support IP over FC on FCOE HBA 2550 */ 2551 continue; 2552 } 2553 2554 ulp_port = fctl_get_ulp_port(mod, port); 2555 ASSERT(ulp_port != NULL); 2556 2557 if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) { 2558 continue; 2559 } 2560 2561 fctl_init_dma_attr(port, mod, &info); 2562 2563 rval = mod->mod_info->ulp_port_attach( 2564 mod->mod_info->ulp_handle, &info, cmd, s_id); 2565 2566 fctl_post_attach(mod, ulp_port, cmd, rval); 2567 2568 if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH && 2569 strcmp(mod->mod_info->ulp_name, "fcp") == 0) { 2570 ASSERT(ddi_get_driver_private(info.port_dip) != NULL); 2571 } 2572 } 2573 2574 rw_exit(&fctl_mod_ports_lock); 2575 rw_exit(&fctl_ulp_lock); 2576 } 2577 2578 2579 static int 2580 fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd) 2581 { 2582 int rval = FC_SUCCESS; 2583 2584 mutex_enter(&ulp_port->port_mutex); 2585 2586 switch (cmd) { 2587 case FC_CMD_ATTACH: 2588 if (ulp_port->port_dstate & ULP_PORT_ATTACH) { 2589 rval = FC_FAILURE; 2590 } 2591 break; 2592 2593 case FC_CMD_RESUME: 2594 ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0); 2595 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2596 !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) { 2597 rval = FC_FAILURE; 2598 } 2599 break; 2600 2601 case FC_CMD_POWER_UP: 2602 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2603 !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) { 2604 rval = FC_FAILURE; 2605 } 2606 break; 2607 } 2608 2609 if (rval == FC_SUCCESS) { 2610 ulp_port->port_dstate |= ULP_PORT_BUSY; 2611 } 2612 mutex_exit(&ulp_port->port_mutex); 2613 2614 return (rval); 2615 } 2616 2617 2618 static void 2619 fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 2620 fc_attach_cmd_t cmd, int rval) 2621 { 2622 int be_chatty; 2623 2624 ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME || 2625 cmd == FC_CMD_POWER_UP); 2626 2627 mutex_enter(&ulp_port->port_mutex); 2628 ulp_port->port_dstate &= ~ULP_PORT_BUSY; 2629 2630 be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1; 2631 2632 if (rval != FC_SUCCESS) { 2633 caddr_t op; 2634 fc_local_port_t *port = ulp_port->port_handle; 2635 2636 mutex_exit(&ulp_port->port_mutex); 2637 2638 switch (cmd) { 2639 case FC_CMD_ATTACH: 2640 op = "attach"; 2641 break; 2642 2643 case FC_CMD_RESUME: 2644 op = "resume"; 2645 break; 2646 2647 case FC_CMD_POWER_UP: 2648 op = "power up"; 2649 break; 2650 } 2651 2652 if (be_chatty) { 2653 cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 2654 port->fp_instance, op, mod->mod_info->ulp_name); 2655 } 2656 2657 return; 2658 } 2659 2660 switch (cmd) { 2661 case FC_CMD_ATTACH: 2662 ulp_port->port_dstate |= ULP_PORT_ATTACH; 2663 break; 2664 2665 case FC_CMD_RESUME: 2666 ulp_port->port_dstate &= ~ULP_PORT_SUSPEND; 2667 break; 2668 2669 case FC_CMD_POWER_UP: 2670 ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN; 2671 break; 2672 } 2673 mutex_exit(&ulp_port->port_mutex); 2674 } 2675 2676 2677 int 2678 fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd, 2679 struct modlinkage *linkage) 2680 { 2681 int rval = FC_SUCCESS; 2682 fc_ulp_module_t *mod; 2683 fc_ulp_port_info_t info; 2684 fc_ulp_ports_t *ulp_port; 2685 2686 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 2687 2688 info.port_linkage = linkage; 2689 info.port_dip = port->fp_port_dip; 2690 info.port_handle = (opaque_t)port; 2691 info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 2692 info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 2693 2694 rw_enter(&fctl_ulp_lock, RW_READER); 2695 rw_enter(&fctl_mod_ports_lock, RW_READER); 2696 2697 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2698 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 2699 continue; 2700 } 2701 2702 if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) { 2703 continue; 2704 } 2705 2706 fctl_init_dma_attr(port, mod, &info); 2707 2708 rval = mod->mod_info->ulp_port_detach( 2709 mod->mod_info->ulp_handle, &info, cmd); 2710 2711 fctl_post_detach(mod, ulp_port, cmd, rval); 2712 2713 if (rval != FC_SUCCESS) { 2714 break; 2715 } 2716 2717 if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name, 2718 "fcp") == 0) { 2719 ASSERT(ddi_get_driver_private(info.port_dip) == NULL); 2720 } 2721 2722 mutex_enter(&ulp_port->port_mutex); 2723 ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE; 2724 mutex_exit(&ulp_port->port_mutex); 2725 } 2726 2727 rw_exit(&fctl_mod_ports_lock); 2728 rw_exit(&fctl_ulp_lock); 2729 2730 return (rval); 2731 } 2732 2733 static void 2734 fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod, 2735 fc_ulp_port_info_t *info) 2736 { 2737 2738 if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) || 2739 (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) { 2740 info->port_cmd_dma_attr = 2741 port->fp_fca_tran->fca_dma_fcp_cmd_attr; 2742 info->port_data_dma_attr = 2743 port->fp_fca_tran->fca_dma_fcp_data_attr; 2744 info->port_resp_dma_attr = 2745 port->fp_fca_tran->fca_dma_fcp_rsp_attr; 2746 } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) { 2747 info->port_cmd_dma_attr = 2748 port->fp_fca_tran->fca_dma_fcsm_cmd_attr; 2749 info->port_data_dma_attr = 2750 port->fp_fca_tran->fca_dma_attr; 2751 info->port_resp_dma_attr = 2752 port->fp_fca_tran->fca_dma_fcsm_rsp_attr; 2753 } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) { 2754 info->port_cmd_dma_attr = 2755 port->fp_fca_tran->fca_dma_fcip_cmd_attr; 2756 info->port_data_dma_attr = 2757 port->fp_fca_tran->fca_dma_attr; 2758 info->port_resp_dma_attr = 2759 port->fp_fca_tran->fca_dma_fcip_rsp_attr; 2760 } else { 2761 info->port_cmd_dma_attr = info->port_data_dma_attr = 2762 info->port_resp_dma_attr = 2763 port->fp_fca_tran->fca_dma_attr; /* default */ 2764 } 2765 } 2766 2767 static int 2768 fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd) 2769 { 2770 int rval = FC_SUCCESS; 2771 2772 mutex_enter(&ulp_port->port_mutex); 2773 2774 switch (cmd) { 2775 case FC_CMD_DETACH: 2776 if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) { 2777 rval = FC_FAILURE; 2778 } 2779 break; 2780 2781 case FC_CMD_SUSPEND: 2782 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2783 ulp_port->port_dstate & ULP_PORT_SUSPEND) { 2784 rval = FC_FAILURE; 2785 } 2786 break; 2787 2788 case FC_CMD_POWER_DOWN: 2789 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2790 ulp_port->port_dstate & ULP_PORT_POWER_DOWN) { 2791 rval = FC_FAILURE; 2792 } 2793 break; 2794 } 2795 2796 if (rval == FC_SUCCESS) { 2797 ulp_port->port_dstate |= ULP_PORT_BUSY; 2798 } 2799 mutex_exit(&ulp_port->port_mutex); 2800 2801 return (rval); 2802 } 2803 2804 2805 static void 2806 fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 2807 fc_detach_cmd_t cmd, int rval) 2808 { 2809 ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND || 2810 cmd == FC_CMD_POWER_DOWN); 2811 2812 mutex_enter(&ulp_port->port_mutex); 2813 ulp_port->port_dstate &= ~ULP_PORT_BUSY; 2814 2815 if (rval != FC_SUCCESS) { 2816 caddr_t op; 2817 fc_local_port_t *port = ulp_port->port_handle; 2818 2819 mutex_exit(&ulp_port->port_mutex); 2820 2821 switch (cmd) { 2822 case FC_CMD_DETACH: 2823 op = "detach"; 2824 break; 2825 2826 case FC_CMD_SUSPEND: 2827 op = "suspend"; 2828 break; 2829 2830 case FC_CMD_POWER_DOWN: 2831 op = "power down"; 2832 break; 2833 } 2834 2835 cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 2836 port->fp_instance, op, mod->mod_info->ulp_name); 2837 2838 return; 2839 } 2840 2841 switch (cmd) { 2842 case FC_CMD_DETACH: 2843 ulp_port->port_dstate &= ~ULP_PORT_ATTACH; 2844 break; 2845 2846 case FC_CMD_SUSPEND: 2847 ulp_port->port_dstate |= ULP_PORT_SUSPEND; 2848 break; 2849 2850 case FC_CMD_POWER_DOWN: 2851 ulp_port->port_dstate |= ULP_PORT_POWER_DOWN; 2852 break; 2853 } 2854 mutex_exit(&ulp_port->port_mutex); 2855 } 2856 2857 2858 static fc_ulp_ports_t * 2859 fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle, 2860 int sleep) 2861 { 2862 fc_ulp_ports_t *last; 2863 fc_ulp_ports_t *next; 2864 fc_ulp_ports_t *new; 2865 2866 ASSERT(RW_READ_HELD(&fctl_ulp_lock)); 2867 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 2868 2869 last = NULL; 2870 next = ulp_module->mod_ports; 2871 2872 while (next != NULL) { 2873 last = next; 2874 next = next->port_next; 2875 } 2876 2877 new = fctl_alloc_ulp_port(sleep); 2878 if (new == NULL) { 2879 return (new); 2880 } 2881 2882 new->port_handle = port_handle; 2883 if (last == NULL) { 2884 ulp_module->mod_ports = new; 2885 } else { 2886 last->port_next = new; 2887 } 2888 2889 return (new); 2890 } 2891 2892 2893 static fc_ulp_ports_t * 2894 fctl_alloc_ulp_port(int sleep) 2895 { 2896 fc_ulp_ports_t *new; 2897 2898 new = kmem_zalloc(sizeof (*new), sleep); 2899 if (new == NULL) { 2900 return (new); 2901 } 2902 mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL); 2903 2904 return (new); 2905 } 2906 2907 2908 static int 2909 fctl_remove_ulp_port(struct ulp_module *ulp_module, 2910 fc_local_port_t *port_handle) 2911 { 2912 fc_ulp_ports_t *last; 2913 fc_ulp_ports_t *next; 2914 2915 ASSERT(RW_WRITE_HELD(&fctl_ulp_lock)); 2916 ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 2917 2918 last = NULL; 2919 next = ulp_module->mod_ports; 2920 2921 while (next != NULL) { 2922 if (next->port_handle == port_handle) { 2923 if (next->port_dstate & ULP_PORT_ATTACH) { 2924 return (FC_FAILURE); 2925 } 2926 break; 2927 } 2928 last = next; 2929 next = next->port_next; 2930 } 2931 2932 if (next != NULL) { 2933 ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0); 2934 2935 if (last == NULL) { 2936 ulp_module->mod_ports = next->port_next; 2937 } else { 2938 last->port_next = next->port_next; 2939 } 2940 fctl_dealloc_ulp_port(next); 2941 2942 return (FC_SUCCESS); 2943 } else { 2944 return (FC_FAILURE); 2945 } 2946 } 2947 2948 2949 static void 2950 fctl_dealloc_ulp_port(fc_ulp_ports_t *next) 2951 { 2952 mutex_destroy(&next->port_mutex); 2953 kmem_free(next, sizeof (*next)); 2954 } 2955 2956 2957 static fc_ulp_ports_t * 2958 fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle) 2959 { 2960 fc_ulp_ports_t *next; 2961 2962 ASSERT(RW_LOCK_HELD(&fctl_ulp_lock)); 2963 ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock)); 2964 2965 for (next = ulp_module->mod_ports; next != NULL; 2966 next = next->port_next) { 2967 if (next->port_handle == port_handle) { 2968 return (next); 2969 } 2970 } 2971 2972 return (NULL); 2973 } 2974 2975 2976 /* 2977 * Pass state change notfications on to registered ULPs. 2978 * 2979 * Can issue wakeups to client callers who might be waiting for completions 2980 * on other threads. 2981 * 2982 * Caution: will silently deallocate any fc_remote_port_t and/or 2983 * fc_remote_node_t structs it finds that are not in use. 2984 */ 2985 void 2986 fctl_ulp_statec_cb(void *arg) 2987 { 2988 uint32_t s_id; 2989 uint32_t new_state; 2990 fc_local_port_t *port; 2991 fc_ulp_ports_t *ulp_port; 2992 fc_ulp_module_t *mod; 2993 fc_port_clist_t *clist = (fc_port_clist_t *)arg; 2994 2995 ASSERT(clist != NULL); 2996 2997 port = clist->clist_port; 2998 2999 mutex_enter(&port->fp_mutex); 3000 s_id = port->fp_port_id.port_id; 3001 mutex_exit(&port->fp_mutex); 3002 3003 switch (clist->clist_state) { 3004 case FC_STATE_ONLINE: 3005 new_state = FC_ULP_STATEC_ONLINE; 3006 break; 3007 3008 case FC_STATE_OFFLINE: 3009 if (clist->clist_len) { 3010 new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT; 3011 } else { 3012 new_state = FC_ULP_STATEC_OFFLINE; 3013 } 3014 break; 3015 3016 default: 3017 new_state = FC_ULP_STATEC_DONT_CARE; 3018 break; 3019 } 3020 3021 #ifdef DEBUG 3022 /* 3023 * sanity check for presence of OLD devices in the hash lists 3024 */ 3025 if (clist->clist_size) { 3026 int count; 3027 fc_remote_port_t *pd; 3028 3029 ASSERT(clist->clist_map != NULL); 3030 for (count = 0; count < clist->clist_len; count++) { 3031 if (clist->clist_map[count].map_state == 3032 PORT_DEVICE_INVALID) { 3033 la_wwn_t pwwn; 3034 fc_portid_t d_id; 3035 3036 pd = clist->clist_map[count].map_pd; 3037 if (pd != NULL) { 3038 mutex_enter(&pd->pd_mutex); 3039 pwwn = pd->pd_port_name; 3040 d_id = pd->pd_port_id; 3041 mutex_exit(&pd->pd_mutex); 3042 3043 pd = fctl_get_remote_port_by_pwwn(port, 3044 &pwwn); 3045 3046 ASSERT(pd != clist->clist_map[count]. 3047 map_pd); 3048 3049 pd = fctl_get_remote_port_by_did(port, 3050 d_id.port_id); 3051 ASSERT(pd != clist->clist_map[count]. 3052 map_pd); 3053 } 3054 } 3055 } 3056 } 3057 #endif 3058 3059 /* 3060 * Check for duplicate map entries 3061 */ 3062 if (clist->clist_size) { 3063 int count; 3064 fc_remote_port_t *pd1, *pd2; 3065 3066 ASSERT(clist->clist_map != NULL); 3067 for (count = 0; count < clist->clist_len-1; count++) { 3068 int count2; 3069 3070 pd1 = clist->clist_map[count].map_pd; 3071 if (pd1 == NULL) { 3072 continue; 3073 } 3074 3075 for (count2 = count+1; 3076 count2 < clist->clist_len; 3077 count2++) { 3078 3079 pd2 = clist->clist_map[count2].map_pd; 3080 if (pd2 == NULL) { 3081 continue; 3082 } 3083 3084 if (pd1 == pd2) { 3085 clist->clist_map[count].map_flags |= 3086 PORT_DEVICE_DUPLICATE_MAP_ENTRY; 3087 break; 3088 } 3089 } 3090 } 3091 } 3092 3093 3094 rw_enter(&fctl_ulp_lock, RW_READER); 3095 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 3096 rw_enter(&fctl_mod_ports_lock, RW_READER); 3097 ulp_port = fctl_get_ulp_port(mod, port); 3098 rw_exit(&fctl_mod_ports_lock); 3099 3100 if (ulp_port == NULL) { 3101 continue; 3102 } 3103 3104 mutex_enter(&ulp_port->port_mutex); 3105 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 3106 mutex_exit(&ulp_port->port_mutex); 3107 continue; 3108 } 3109 3110 switch (ulp_port->port_statec) { 3111 case FC_ULP_STATEC_DONT_CARE: 3112 if (ulp_port->port_statec != new_state) { 3113 ulp_port->port_statec = new_state; 3114 } 3115 break; 3116 3117 case FC_ULP_STATEC_ONLINE: 3118 case FC_ULP_STATEC_OFFLINE: 3119 if (ulp_port->port_statec == new_state) { 3120 mutex_exit(&ulp_port->port_mutex); 3121 continue; 3122 } 3123 ulp_port->port_statec = new_state; 3124 break; 3125 3126 case FC_ULP_STATEC_OFFLINE_TIMEOUT: 3127 if (ulp_port->port_statec == new_state || 3128 new_state == FC_ULP_STATEC_OFFLINE) { 3129 mutex_exit(&ulp_port->port_mutex); 3130 continue; 3131 } 3132 ulp_port->port_statec = new_state; 3133 break; 3134 3135 default: 3136 ASSERT(0); 3137 break; 3138 } 3139 3140 mod->mod_info->ulp_statec_callback( 3141 mod->mod_info->ulp_handle, (opaque_t)port, 3142 clist->clist_state, clist->clist_flags, 3143 clist->clist_map, clist->clist_len, s_id); 3144 3145 mutex_exit(&ulp_port->port_mutex); 3146 } 3147 rw_exit(&fctl_ulp_lock); 3148 3149 if (clist->clist_size) { 3150 int count; 3151 fc_remote_node_t *node; 3152 fc_remote_port_t *pd; 3153 3154 ASSERT(clist->clist_map != NULL); 3155 for (count = 0; count < clist->clist_len; count++) { 3156 3157 if ((pd = clist->clist_map[count].map_pd) == NULL) { 3158 continue; 3159 } 3160 3161 mutex_enter(&pd->pd_mutex); 3162 3163 pd->pd_ref_count--; 3164 ASSERT(pd->pd_ref_count >= 0); 3165 3166 if (clist->clist_map[count].map_state != 3167 PORT_DEVICE_INVALID) { 3168 mutex_exit(&pd->pd_mutex); 3169 continue; 3170 } 3171 3172 node = pd->pd_remote_nodep; 3173 pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS; 3174 3175 mutex_exit(&pd->pd_mutex); 3176 3177 /* 3178 * This fc_remote_port_t is no longer referenced 3179 * by any ULPs. Deallocate it if its pd_ref_count 3180 * has reached zero. 3181 */ 3182 if ((fctl_destroy_remote_port(port, pd) == 0) && 3183 (node != NULL)) { 3184 fctl_destroy_remote_node(node); 3185 } 3186 } 3187 3188 kmem_free(clist->clist_map, 3189 sizeof (*(clist->clist_map)) * clist->clist_size); 3190 } 3191 3192 if (clist->clist_wait) { 3193 mutex_enter(&clist->clist_mutex); 3194 clist->clist_wait = 0; 3195 cv_signal(&clist->clist_cv); 3196 mutex_exit(&clist->clist_mutex); 3197 } else { 3198 kmem_free(clist, sizeof (*clist)); 3199 } 3200 } 3201 3202 3203 /* 3204 * Allocate an fc_remote_node_t struct to represent a remote node for the 3205 * given nwwn. This will also add the nwwn to the global nwwn table. 3206 * 3207 * Returns a pointer to the newly-allocated struct. Returns NULL if 3208 * the kmem_zalloc fails or if the enlist_wwn attempt fails. 3209 */ 3210 fc_remote_node_t * 3211 fctl_create_remote_node(la_wwn_t *nwwn, int sleep) 3212 { 3213 fc_remote_node_t *rnodep; 3214 3215 if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) { 3216 return (NULL); 3217 } 3218 3219 mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL); 3220 3221 rnodep->fd_node_name = *nwwn; 3222 rnodep->fd_flags = FC_REMOTE_NODE_VALID; 3223 rnodep->fd_numports = 1; 3224 3225 if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) { 3226 mutex_destroy(&rnodep->fd_mutex); 3227 kmem_free(rnodep, sizeof (*rnodep)); 3228 return (NULL); 3229 } 3230 3231 return (rnodep); 3232 } 3233 3234 /* 3235 * Deconstruct and free the given fc_remote_node_t struct (remote node struct). 3236 * Silently skips the deconstruct/free if there are any fc_remote_port_t 3237 * (remote port device) structs still referenced by the given 3238 * fc_remote_node_t struct. 3239 */ 3240 void 3241 fctl_destroy_remote_node(fc_remote_node_t *rnodep) 3242 { 3243 mutex_enter(&rnodep->fd_mutex); 3244 3245 /* 3246 * Look at the count and linked list of of remote ports 3247 * (fc_remote_port_t structs); bail if these indicate that 3248 * given fc_remote_node_t may be in use. 3249 */ 3250 if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) { 3251 mutex_exit(&rnodep->fd_mutex); 3252 return; 3253 } 3254 3255 mutex_exit(&rnodep->fd_mutex); 3256 3257 mutex_destroy(&rnodep->fd_mutex); 3258 kmem_free(rnodep, sizeof (*rnodep)); 3259 } 3260 3261 3262 /* 3263 * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This 3264 * uses the nwwn in the fd_node_name.raw_wwn of the given struct. 3265 * This only fails if the kmem_zalloc fails. This does not check for a 3266 * unique or pre-existing nwwn in the fctl_nwwn_hash_table[]. 3267 * This is only called from fctl_create_remote_node(). 3268 */ 3269 int 3270 fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep) 3271 { 3272 int index; 3273 fctl_nwwn_elem_t *new; 3274 fctl_nwwn_list_t *head; 3275 3276 ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 3277 3278 if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) { 3279 return (FC_FAILURE); 3280 } 3281 3282 mutex_enter(&fctl_nwwn_hash_mutex); 3283 new->fne_nodep = rnodep; 3284 3285 mutex_enter(&rnodep->fd_mutex); 3286 ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE); 3287 index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 3288 fctl_nwwn_table_size); 3289 mutex_exit(&rnodep->fd_mutex); 3290 3291 head = &fctl_nwwn_hash_table[index]; 3292 3293 /* Link it in at the head of the hash list */ 3294 new->fne_nextp = head->fnl_headp; 3295 head->fnl_headp = new; 3296 3297 mutex_exit(&fctl_nwwn_hash_mutex); 3298 3299 return (FC_SUCCESS); 3300 } 3301 3302 3303 /* 3304 * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[]. 3305 * This uses the nwwn in the fd_node_name.raw_wwn of the given struct. 3306 */ 3307 void 3308 fctl_delist_nwwn_table(fc_remote_node_t *rnodep) 3309 { 3310 int index; 3311 fctl_nwwn_list_t *head; 3312 fctl_nwwn_elem_t *elem; 3313 fctl_nwwn_elem_t *prev; 3314 3315 ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex)); 3316 ASSERT(MUTEX_HELD(&rnodep->fd_mutex)); 3317 3318 index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 3319 fctl_nwwn_table_size); 3320 3321 head = &fctl_nwwn_hash_table[index]; 3322 elem = head->fnl_headp; 3323 prev = NULL; 3324 3325 while (elem != NULL) { 3326 if (elem->fne_nodep == rnodep) { 3327 /* 3328 * Found it -- unlink it from the list & decrement 3329 * the count for the hash chain. 3330 */ 3331 if (prev == NULL) { 3332 head->fnl_headp = elem->fne_nextp; 3333 } else { 3334 prev->fne_nextp = elem->fne_nextp; 3335 } 3336 break; 3337 } 3338 prev = elem; 3339 elem = elem->fne_nextp; 3340 } 3341 3342 if (elem != NULL) { 3343 kmem_free(elem, sizeof (*elem)); 3344 } 3345 } 3346 3347 3348 /* 3349 * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 3350 * Looks in the global fctl_nwwn_hash_table[]. Identical to the 3351 * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment 3352 * the fc_count reference count in the f_device_t before returning. 3353 * 3354 * This function is called by: fctl_create_remote_port_t(). 3355 * 3356 * OLD COMMENT: 3357 * Note: The calling thread needs to make sure it isn't holding any device 3358 * mutex (more so the fc_remote_node_t that could potentially have this wwn). 3359 */ 3360 fc_remote_node_t * 3361 fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn) 3362 { 3363 int index; 3364 fctl_nwwn_elem_t *elem; 3365 fc_remote_node_t *next; 3366 fc_remote_node_t *rnodep = NULL; 3367 3368 index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 3369 fctl_nwwn_table_size); 3370 ASSERT(index >= 0 && index < fctl_nwwn_table_size); 3371 3372 mutex_enter(&fctl_nwwn_hash_mutex); 3373 elem = fctl_nwwn_hash_table[index].fnl_headp; 3374 while (elem != NULL) { 3375 next = elem->fne_nodep; 3376 if (next != NULL) { 3377 mutex_enter(&next->fd_mutex); 3378 if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 3379 rnodep = next; 3380 mutex_exit(&next->fd_mutex); 3381 break; 3382 } 3383 mutex_exit(&next->fd_mutex); 3384 } 3385 elem = elem->fne_nextp; 3386 } 3387 mutex_exit(&fctl_nwwn_hash_mutex); 3388 3389 return (rnodep); 3390 } 3391 3392 3393 /* 3394 * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 3395 * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports 3396 * reference count in the f_device_t before returning. 3397 * 3398 * This function is only called by fctl_create_remote_port_t(). 3399 */ 3400 fc_remote_node_t * 3401 fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn) 3402 { 3403 int index; 3404 fctl_nwwn_elem_t *elem; 3405 fc_remote_node_t *next; 3406 fc_remote_node_t *rnodep = NULL; 3407 3408 index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 3409 fctl_nwwn_table_size); 3410 ASSERT(index >= 0 && index < fctl_nwwn_table_size); 3411 3412 mutex_enter(&fctl_nwwn_hash_mutex); 3413 elem = fctl_nwwn_hash_table[index].fnl_headp; 3414 while (elem != NULL) { 3415 next = elem->fne_nodep; 3416 if (next != NULL) { 3417 mutex_enter(&next->fd_mutex); 3418 if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 3419 rnodep = next; 3420 rnodep->fd_numports++; 3421 mutex_exit(&next->fd_mutex); 3422 break; 3423 } 3424 mutex_exit(&next->fd_mutex); 3425 } 3426 elem = elem->fne_nextp; 3427 } 3428 mutex_exit(&fctl_nwwn_hash_mutex); 3429 3430 return (rnodep); 3431 } 3432 3433 3434 /* 3435 * Allocate and initialize an fc_remote_port_t struct & returns a pointer to 3436 * the newly allocated struct. Only fails if the kmem_zalloc() fails. 3437 */ 3438 fc_remote_port_t * 3439 fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn, 3440 uint32_t d_id, uchar_t recepient, int sleep) 3441 { 3442 fc_remote_port_t *pd; 3443 3444 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3445 ASSERT(FC_IS_REAL_DEVICE(d_id)); 3446 3447 if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) { 3448 return (NULL); 3449 } 3450 fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT, 3451 FC_LOGO_TOLERANCE_TIME_LIMIT); 3452 3453 mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL); 3454 3455 pd->pd_port_id.port_id = d_id; 3456 pd->pd_port_name = *port_wwn; 3457 pd->pd_port = port; 3458 pd->pd_state = PORT_DEVICE_VALID; 3459 pd->pd_type = PORT_DEVICE_NEW; 3460 pd->pd_recepient = recepient; 3461 3462 return (pd); 3463 } 3464 3465 3466 /* 3467 * Deconstruct and free the given fc_remote_port_t struct (unconditionally). 3468 */ 3469 void 3470 fctl_dealloc_remote_port(fc_remote_port_t *pd) 3471 { 3472 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 3473 3474 fctl_tc_destructor(&pd->pd_logo_tc); 3475 mutex_destroy(&pd->pd_mutex); 3476 kmem_free(pd, sizeof (*pd)); 3477 } 3478 3479 /* 3480 * Add the given fc_remote_port_t onto the linked list of remote port 3481 * devices associated with the given fc_remote_node_t. Does NOT add the 3482 * fc_remote_port_t to the list if already exists on the list. 3483 */ 3484 void 3485 fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep, 3486 fc_remote_port_t *pd) 3487 { 3488 fc_remote_port_t *last; 3489 fc_remote_port_t *ports; 3490 3491 mutex_enter(&rnodep->fd_mutex); 3492 3493 last = NULL; 3494 for (ports = rnodep->fd_portlistp; ports != NULL; 3495 ports = ports->pd_port_next) { 3496 if (ports == pd) { 3497 /* 3498 * The given fc_remote_port_t is already on the linked 3499 * list chain for the given remote node, so bail now. 3500 */ 3501 mutex_exit(&rnodep->fd_mutex); 3502 return; 3503 } 3504 last = ports; 3505 } 3506 3507 /* Add the fc_remote_port_t to the tail of the linked list */ 3508 if (last != NULL) { 3509 last->pd_port_next = pd; 3510 } else { 3511 rnodep->fd_portlistp = pd; 3512 } 3513 pd->pd_port_next = NULL; 3514 3515 /* 3516 * Link the fc_remote_port_t back to the associated fc_remote_node_t. 3517 */ 3518 mutex_enter(&pd->pd_mutex); 3519 pd->pd_remote_nodep = rnodep; 3520 mutex_exit(&pd->pd_mutex); 3521 3522 mutex_exit(&rnodep->fd_mutex); 3523 } 3524 3525 3526 /* 3527 * Remove the specified fc_remote_port_t from the linked list of remote ports 3528 * for the given fc_remote_node_t. 3529 * 3530 * Returns a count of the _remaining_ fc_remote_port_t structs on the linked 3531 * list of the fc_remote_node_t. 3532 * 3533 * The fd_numports on the given fc_remote_node_t is decremented, and if 3534 * it hits zero then this function also removes the fc_remote_node_t from the 3535 * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries 3536 * are removed from the fctl_nwwn_hash_table[]. 3537 */ 3538 int 3539 fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep, 3540 fc_remote_port_t *pd) 3541 { 3542 int rcount = 0; 3543 fc_remote_port_t *last; 3544 fc_remote_port_t *ports; 3545 3546 ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 3547 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 3548 3549 last = NULL; 3550 3551 mutex_enter(&fctl_nwwn_hash_mutex); 3552 3553 mutex_enter(&rnodep->fd_mutex); 3554 3555 /* 3556 * Go thru the linked list of fc_remote_port_t structs for the given 3557 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd). 3558 */ 3559 ports = rnodep->fd_portlistp; 3560 while (ports != NULL) { 3561 if (ports == pd) { 3562 break; /* Found the requested fc_remote_port_t */ 3563 } 3564 last = ports; 3565 ports = ports->pd_port_next; 3566 } 3567 3568 if (ports) { 3569 rcount = --rnodep->fd_numports; 3570 if (rcount == 0) { 3571 /* Note: this is only ever called from here */ 3572 fctl_delist_nwwn_table(rnodep); 3573 } 3574 if (last) { 3575 last->pd_port_next = pd->pd_port_next; 3576 } else { 3577 rnodep->fd_portlistp = pd->pd_port_next; 3578 } 3579 mutex_enter(&pd->pd_mutex); 3580 pd->pd_remote_nodep = NULL; 3581 mutex_exit(&pd->pd_mutex); 3582 } 3583 3584 pd->pd_port_next = NULL; 3585 3586 mutex_exit(&rnodep->fd_mutex); 3587 mutex_exit(&fctl_nwwn_hash_mutex); 3588 3589 return (rcount); 3590 } 3591 3592 3593 /* 3594 * Add the given fc_remote_port_t struct to the d_id table in the given 3595 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 3596 * fc_remote_port_t. 3597 * 3598 * No memory allocs are required, so this never fails, but it does use the 3599 * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list. 3600 * (There does not seem to be a way to tell the caller that a duplicate 3601 * exists.) 3602 */ 3603 void 3604 fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 3605 { 3606 struct d_id_hash *head; 3607 3608 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3609 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3610 3611 if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 3612 return; 3613 } 3614 3615 head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id, 3616 did_table_size)]; 3617 3618 #ifdef DEBUG 3619 { 3620 int index; 3621 fc_remote_port_t *tmp_pd; 3622 struct d_id_hash *tmp_head; 3623 3624 /* 3625 * Search down in each bucket for a duplicate pd 3626 * Also search for duplicate D_IDs 3627 * This DEBUG code will force an ASSERT if a duplicate 3628 * is ever found. 3629 */ 3630 for (index = 0; index < did_table_size; index++) { 3631 tmp_head = &port->fp_did_table[index]; 3632 3633 tmp_pd = tmp_head->d_id_head; 3634 while (tmp_pd != NULL) { 3635 ASSERT(tmp_pd != pd); 3636 3637 if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 3638 tmp_pd->pd_type != PORT_DEVICE_OLD) { 3639 ASSERT(tmp_pd->pd_port_id.port_id != 3640 pd->pd_port_id.port_id); 3641 } 3642 3643 tmp_pd = tmp_pd->pd_did_hnext; 3644 } 3645 } 3646 } 3647 3648 bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack)); 3649 pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH); 3650 #endif 3651 3652 pd->pd_did_hnext = head->d_id_head; 3653 head->d_id_head = pd; 3654 3655 pd->pd_aux_flags |= PD_IN_DID_QUEUE; 3656 head->d_id_count++; 3657 } 3658 3659 3660 /* 3661 * Remove the given fc_remote_port_t struct from the d_id table in the given 3662 * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 3663 * fc_remote_port_t. 3664 * 3665 * Does nothing if the requested fc_remote_port_t was not found. 3666 */ 3667 void 3668 fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 3669 { 3670 uint32_t d_id; 3671 struct d_id_hash *head; 3672 fc_remote_port_t *pd_next; 3673 fc_remote_port_t *last; 3674 3675 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3676 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3677 3678 d_id = pd->pd_port_id.port_id; 3679 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3680 3681 pd_next = head->d_id_head; 3682 last = NULL; 3683 while (pd_next != NULL) { 3684 if (pd == pd_next) { 3685 break; /* Found the given fc_remote_port_t */ 3686 } 3687 last = pd_next; 3688 pd_next = pd_next->pd_did_hnext; 3689 } 3690 3691 if (pd_next) { 3692 /* 3693 * Found the given fc_remote_port_t; now remove it from the 3694 * d_id list. 3695 */ 3696 head->d_id_count--; 3697 if (last == NULL) { 3698 head->d_id_head = pd->pd_did_hnext; 3699 } else { 3700 last->pd_did_hnext = pd->pd_did_hnext; 3701 } 3702 pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 3703 pd->pd_did_hnext = NULL; 3704 } 3705 } 3706 3707 3708 /* 3709 * Add the given fc_remote_port_t struct to the pwwn table in the given 3710 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 3711 * in the fc_remote_port_t. 3712 * 3713 * No memory allocs are required, so this never fails. 3714 */ 3715 void 3716 fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 3717 { 3718 int index; 3719 struct pwwn_hash *head; 3720 3721 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3722 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3723 3724 ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE); 3725 3726 index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn), 3727 pwwn_table_size); 3728 3729 head = &port->fp_pwwn_table[index]; 3730 3731 #ifdef DEBUG 3732 { 3733 int index; 3734 fc_remote_port_t *tmp_pd; 3735 struct pwwn_hash *tmp_head; 3736 3737 /* 3738 * Search down in each bucket for a duplicate pd 3739 * Search also for a duplicate WWN 3740 * Throw an ASSERT if any duplicate is found. 3741 */ 3742 for (index = 0; index < pwwn_table_size; index++) { 3743 tmp_head = &port->fp_pwwn_table[index]; 3744 3745 tmp_pd = tmp_head->pwwn_head; 3746 while (tmp_pd != NULL) { 3747 ASSERT(tmp_pd != pd); 3748 3749 if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 3750 tmp_pd->pd_type != PORT_DEVICE_OLD) { 3751 ASSERT(fctl_wwn_cmp( 3752 &tmp_pd->pd_port_name, 3753 &pd->pd_port_name) != 0); 3754 } 3755 3756 tmp_pd = tmp_pd->pd_wwn_hnext; 3757 } 3758 } 3759 } 3760 3761 bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack)); 3762 pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH); 3763 #endif /* DEBUG */ 3764 3765 pd->pd_wwn_hnext = head->pwwn_head; 3766 head->pwwn_head = pd; 3767 3768 head->pwwn_count++; 3769 /* 3770 * Make sure we tie fp_dev_count to the size of the 3771 * pwwn_table 3772 */ 3773 port->fp_dev_count++; 3774 } 3775 3776 3777 /* 3778 * Remove the given fc_remote_port_t struct from the pwwn table in the given 3779 * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 3780 * in the fc_remote_port_t. 3781 * 3782 * Does nothing if the requested fc_remote_port_t was not found. 3783 */ 3784 void 3785 fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 3786 { 3787 int index; 3788 la_wwn_t pwwn; 3789 struct pwwn_hash *head; 3790 fc_remote_port_t *pd_next; 3791 fc_remote_port_t *last; 3792 3793 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3794 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3795 3796 pwwn = pd->pd_port_name; 3797 index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size); 3798 3799 head = &port->fp_pwwn_table[index]; 3800 3801 last = NULL; 3802 pd_next = head->pwwn_head; 3803 while (pd_next != NULL) { 3804 if (pd_next == pd) { 3805 break; /* Found the given fc_remote_port_t */ 3806 } 3807 last = pd_next; 3808 pd_next = pd_next->pd_wwn_hnext; 3809 } 3810 3811 if (pd_next) { 3812 /* 3813 * Found the given fc_remote_port_t; now remove it from the 3814 * pwwn list. 3815 */ 3816 head->pwwn_count--; 3817 /* 3818 * Make sure we tie fp_dev_count to the size of the 3819 * pwwn_table 3820 */ 3821 port->fp_dev_count--; 3822 if (last == NULL) { 3823 head->pwwn_head = pd->pd_wwn_hnext; 3824 } else { 3825 last->pd_wwn_hnext = pd->pd_wwn_hnext; 3826 } 3827 pd->pd_wwn_hnext = NULL; 3828 } 3829 } 3830 3831 3832 /* 3833 * Looks in the d_id table of the specified fc_local_port_t for the 3834 * fc_remote_port_t that matches the given d_id. Hashes based upon 3835 * the given d_id. 3836 * Returns a pointer to the fc_remote_port_t struct, but does not update any 3837 * reference counts or otherwise indicate that the fc_remote_port_t is in 3838 * use. 3839 */ 3840 fc_remote_port_t * 3841 fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 3842 { 3843 struct d_id_hash *head; 3844 fc_remote_port_t *pd; 3845 3846 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3847 3848 mutex_enter(&port->fp_mutex); 3849 3850 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3851 3852 pd = head->d_id_head; 3853 while (pd != NULL) { 3854 mutex_enter(&pd->pd_mutex); 3855 if (pd->pd_port_id.port_id == d_id) { 3856 /* Match found -- break out of the loop */ 3857 mutex_exit(&pd->pd_mutex); 3858 break; 3859 } 3860 mutex_exit(&pd->pd_mutex); 3861 pd = pd->pd_did_hnext; 3862 } 3863 3864 mutex_exit(&port->fp_mutex); 3865 3866 return (pd); 3867 } 3868 3869 3870 void 3871 fc_ulp_hold_remote_port(opaque_t port_handle) 3872 { 3873 fc_remote_port_t *pd = port_handle; 3874 3875 mutex_enter(&pd->pd_mutex); 3876 pd->pd_ref_count++; 3877 mutex_exit(&pd->pd_mutex); 3878 } 3879 3880 /* 3881 * Looks in the d_id table of the specified fc_local_port_t for the 3882 * fc_remote_port_t that matches the given d_id. Hashes based upon 3883 * the given d_id. Returns a pointer to the fc_remote_port_t struct. 3884 * 3885 * Increments pd_ref_count in the fc_remote_port_t if the 3886 * fc_remote_port_t is found at the given d_id. 3887 * 3888 * The fc_remote_port_t is ignored (treated as non-existent) if either 3889 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 3890 */ 3891 fc_remote_port_t * 3892 fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 3893 { 3894 struct d_id_hash *head; 3895 fc_remote_port_t *pd; 3896 3897 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3898 3899 mutex_enter(&port->fp_mutex); 3900 3901 head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3902 3903 pd = head->d_id_head; 3904 while (pd != NULL) { 3905 mutex_enter(&pd->pd_mutex); 3906 if (pd->pd_port_id.port_id == d_id && pd->pd_state != 3907 PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) { 3908 ASSERT(pd->pd_ref_count >= 0); 3909 pd->pd_ref_count++; 3910 mutex_exit(&pd->pd_mutex); 3911 break; 3912 } 3913 mutex_exit(&pd->pd_mutex); 3914 pd = pd->pd_did_hnext; 3915 } 3916 3917 mutex_exit(&port->fp_mutex); 3918 3919 return (pd); 3920 } 3921 3922 /* 3923 * Looks in the pwwn table of the specified fc_local_port_t for the 3924 * fc_remote_port_t that matches the given pwwn. Hashes based upon the 3925 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct, 3926 * but does not update any reference counts or otherwise indicate that 3927 * the fc_remote_port_t is in use. 3928 */ 3929 fc_remote_port_t * 3930 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 3931 { 3932 int index; 3933 struct pwwn_hash *head; 3934 fc_remote_port_t *pd; 3935 3936 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3937 3938 mutex_enter(&port->fp_mutex); 3939 3940 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 3941 head = &port->fp_pwwn_table[index]; 3942 3943 pd = head->pwwn_head; 3944 while (pd != NULL) { 3945 mutex_enter(&pd->pd_mutex); 3946 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 3947 mutex_exit(&pd->pd_mutex); 3948 break; 3949 } 3950 mutex_exit(&pd->pd_mutex); 3951 pd = pd->pd_wwn_hnext; 3952 } 3953 3954 mutex_exit(&port->fp_mutex); 3955 3956 return (pd); 3957 } 3958 3959 3960 /* 3961 * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that 3962 * the caller already hold the fp_mutex in the fc_local_port_t struct. 3963 */ 3964 fc_remote_port_t * 3965 fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn) 3966 { 3967 int index; 3968 struct pwwn_hash *head; 3969 fc_remote_port_t *pd; 3970 3971 ASSERT(MUTEX_HELD(&port->fp_mutex)); 3972 3973 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 3974 head = &port->fp_pwwn_table[index]; 3975 3976 pd = head->pwwn_head; 3977 while (pd != NULL) { 3978 mutex_enter(&pd->pd_mutex); 3979 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 3980 mutex_exit(&pd->pd_mutex); 3981 break; 3982 } 3983 mutex_exit(&pd->pd_mutex); 3984 pd = pd->pd_wwn_hnext; 3985 } 3986 3987 return (pd); 3988 } 3989 3990 3991 /* 3992 * Looks in the pwwn table of the specified fc_local_port_t for the 3993 * fc_remote_port_t that matches the given d_id. Hashes based upon the 3994 * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct. 3995 * 3996 * Increments pd_ref_count in the fc_remote_port_t if the 3997 * fc_remote_port_t is found at the given pwwn. 3998 * 3999 * The fc_remote_port_t is ignored (treated as non-existent) if either 4000 * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 4001 */ 4002 fc_remote_port_t * 4003 fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 4004 { 4005 int index; 4006 struct pwwn_hash *head; 4007 fc_remote_port_t *pd; 4008 4009 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4010 4011 mutex_enter(&port->fp_mutex); 4012 4013 index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 4014 head = &port->fp_pwwn_table[index]; 4015 4016 pd = head->pwwn_head; 4017 while (pd != NULL) { 4018 mutex_enter(&pd->pd_mutex); 4019 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 && 4020 pd->pd_state != PORT_DEVICE_INVALID && 4021 pd->pd_type != PORT_DEVICE_OLD) { 4022 ASSERT(pd->pd_ref_count >= 0); 4023 pd->pd_ref_count++; 4024 mutex_exit(&pd->pd_mutex); 4025 break; 4026 } 4027 mutex_exit(&pd->pd_mutex); 4028 pd = pd->pd_wwn_hnext; 4029 } 4030 4031 mutex_exit(&port->fp_mutex); 4032 4033 return (pd); 4034 } 4035 4036 4037 /* 4038 * Unconditionally decrement pd_ref_count in the given fc_remote_port_t 4039 * struct. 4040 * 4041 * If pd_ref_count reaches zero, then this function will see if the 4042 * fc_remote_port_t has been marked for deallocation. If so (and also if there 4043 * are no other potential operations in progress, as indicated by the 4044 * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then 4045 * fctl_destroy_remote_port_t() is called to deconstruct/free the given 4046 * fc_remote_port_t (which will also remove it from the d_id and pwwn tables 4047 * on the associated fc_local_port_t). If the associated fc_remote_node_t is no 4048 * longer in use, then it too is deconstructed/freed. 4049 */ 4050 void 4051 fctl_release_remote_port(fc_remote_port_t *pd) 4052 { 4053 int remove = 0; 4054 fc_remote_node_t *node; 4055 fc_local_port_t *port; 4056 4057 mutex_enter(&pd->pd_mutex); 4058 port = pd->pd_port; 4059 4060 ASSERT(pd->pd_ref_count > 0); 4061 pd->pd_ref_count--; 4062 if (pd->pd_ref_count == 0 && 4063 (pd->pd_aux_flags & PD_NEEDS_REMOVAL) && 4064 (pd->pd_flags != PD_ELS_IN_PROGRESS) && 4065 (pd->pd_flags != PD_ELS_MARK)) { 4066 remove = 1; 4067 pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL; 4068 } 4069 node = pd->pd_remote_nodep; 4070 ASSERT(node != NULL); 4071 4072 mutex_exit(&pd->pd_mutex); 4073 4074 if (remove) { 4075 /* 4076 * The fc_remote_port_t struct has to go away now, so call the 4077 * cleanup function to get it off the various lists and remove 4078 * references to it in any other associated structs. 4079 */ 4080 if (fctl_destroy_remote_port(port, pd) == 0) { 4081 /* 4082 * No more fc_remote_port_t references found in the 4083 * associated fc_remote_node_t, so deallocate the 4084 * fc_remote_node_t (if it even exists). 4085 */ 4086 if (node) { 4087 fctl_destroy_remote_node(node); 4088 } 4089 } 4090 } 4091 } 4092 4093 4094 void 4095 fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len, 4096 int whole_map, int justcopy, int orphan) 4097 { 4098 int index; 4099 int listlen; 4100 int full_list; 4101 int initiator; 4102 uint32_t topology; 4103 struct pwwn_hash *head; 4104 fc_remote_port_t *pd; 4105 fc_remote_port_t *old_pd; 4106 fc_remote_port_t *last_pd; 4107 fc_portmap_t *listptr; 4108 4109 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4110 4111 mutex_enter(&port->fp_mutex); 4112 4113 topology = port->fp_topology; 4114 4115 if (orphan) { 4116 ASSERT(!FC_IS_TOP_SWITCH(topology)); 4117 } 4118 4119 for (full_list = listlen = index = 0; 4120 index < pwwn_table_size; index++) { 4121 head = &port->fp_pwwn_table[index]; 4122 pd = head->pwwn_head; 4123 while (pd != NULL) { 4124 full_list++; 4125 mutex_enter(&pd->pd_mutex); 4126 if (pd->pd_type != PORT_DEVICE_NOCHANGE) { 4127 listlen++; 4128 } 4129 mutex_exit(&pd->pd_mutex); 4130 pd = pd->pd_wwn_hnext; 4131 } 4132 } 4133 4134 if (whole_map == 0) { 4135 if (listlen == 0 && *len == 0) { 4136 *map = NULL; 4137 *len = listlen; 4138 mutex_exit(&port->fp_mutex); 4139 return; 4140 } 4141 } else { 4142 if (full_list == 0 && *len == 0) { 4143 *map = NULL; 4144 *len = full_list; 4145 mutex_exit(&port->fp_mutex); 4146 return; 4147 } 4148 } 4149 4150 if (*len == 0) { 4151 ASSERT(*map == NULL); 4152 if (whole_map == 0) { 4153 listptr = *map = kmem_zalloc( 4154 sizeof (*listptr) * listlen, KM_SLEEP); 4155 *len = listlen; 4156 } else { 4157 listptr = *map = kmem_zalloc( 4158 sizeof (*listptr) * full_list, KM_SLEEP); 4159 *len = full_list; 4160 } 4161 } else { 4162 /* 4163 * By design this routine mandates the callers to 4164 * ask for a whole map when they specify the length 4165 * and the listptr. 4166 */ 4167 ASSERT(whole_map == 1); 4168 if (*len < full_list) { 4169 *len = full_list; 4170 mutex_exit(&port->fp_mutex); 4171 return; 4172 } 4173 listptr = *map; 4174 *len = full_list; 4175 } 4176 4177 for (index = 0; index < pwwn_table_size; index++) { 4178 head = &port->fp_pwwn_table[index]; 4179 last_pd = NULL; 4180 pd = head->pwwn_head; 4181 while (pd != NULL) { 4182 mutex_enter(&pd->pd_mutex); 4183 if ((whole_map == 0 && 4184 pd->pd_type == PORT_DEVICE_NOCHANGE) || 4185 pd->pd_state == PORT_DEVICE_INVALID) { 4186 mutex_exit(&pd->pd_mutex); 4187 last_pd = pd; 4188 pd = pd->pd_wwn_hnext; 4189 continue; 4190 } 4191 mutex_exit(&pd->pd_mutex); 4192 4193 fctl_copy_portmap(listptr, pd); 4194 4195 if (justcopy) { 4196 last_pd = pd; 4197 pd = pd->pd_wwn_hnext; 4198 listptr++; 4199 continue; 4200 } 4201 4202 mutex_enter(&pd->pd_mutex); 4203 ASSERT(pd->pd_state != PORT_DEVICE_INVALID); 4204 if (pd->pd_type == PORT_DEVICE_OLD) { 4205 listptr->map_pd = pd; 4206 listptr->map_state = pd->pd_state = 4207 PORT_DEVICE_INVALID; 4208 /* 4209 * Remove this from the PWWN hash table. 4210 */ 4211 old_pd = pd; 4212 pd = old_pd->pd_wwn_hnext; 4213 4214 if (last_pd == NULL) { 4215 ASSERT(old_pd == head->pwwn_head); 4216 4217 head->pwwn_head = pd; 4218 } else { 4219 last_pd->pd_wwn_hnext = pd; 4220 } 4221 head->pwwn_count--; 4222 /* 4223 * Make sure we tie fp_dev_count to the size 4224 * of the pwwn_table 4225 */ 4226 port->fp_dev_count--; 4227 old_pd->pd_wwn_hnext = NULL; 4228 4229 if (port->fp_topology == FC_TOP_PRIVATE_LOOP && 4230 port->fp_statec_busy && !orphan) { 4231 fctl_check_alpa_list(port, old_pd); 4232 } 4233 4234 /* 4235 * Remove if the port device has stealthily 4236 * present in the D_ID hash table 4237 */ 4238 fctl_delist_did_table(port, old_pd); 4239 4240 ASSERT(old_pd->pd_remote_nodep != NULL); 4241 4242 initiator = (old_pd->pd_recepient == 4243 PD_PLOGI_INITIATOR) ? 1 : 0; 4244 4245 mutex_exit(&old_pd->pd_mutex); 4246 mutex_exit(&port->fp_mutex); 4247 4248 if (orphan) { 4249 fctl_print_if_not_orphan(port, old_pd); 4250 4251 (void) fctl_add_orphan(port, old_pd, 4252 KM_NOSLEEP); 4253 } 4254 4255 if (FC_IS_TOP_SWITCH(topology) && initiator) { 4256 (void) fctl_add_orphan(port, old_pd, 4257 KM_NOSLEEP); 4258 } 4259 mutex_enter(&port->fp_mutex); 4260 } else { 4261 listptr->map_pd = pd; 4262 pd->pd_type = PORT_DEVICE_NOCHANGE; 4263 mutex_exit(&pd->pd_mutex); 4264 last_pd = pd; 4265 pd = pd->pd_wwn_hnext; 4266 } 4267 listptr++; 4268 } 4269 } 4270 mutex_exit(&port->fp_mutex); 4271 } 4272 4273 4274 job_request_t * 4275 fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t), 4276 opaque_t arg, int sleep) 4277 { 4278 job_request_t *job; 4279 4280 job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep); 4281 if (job != NULL) { 4282 job->job_result = FC_SUCCESS; 4283 job->job_code = job_code; 4284 job->job_flags = job_flags; 4285 job->job_cb_arg = arg; 4286 job->job_comp = comp; 4287 job->job_private = NULL; 4288 job->job_ulp_pkts = NULL; 4289 job->job_ulp_listlen = 0; 4290 job->job_counter = 0; 4291 job->job_next = NULL; 4292 } 4293 4294 return (job); 4295 } 4296 4297 4298 void 4299 fctl_dealloc_job(job_request_t *job) 4300 { 4301 kmem_cache_free(fctl_job_cache, (void *)job); 4302 } 4303 4304 4305 void 4306 fctl_enque_job(fc_local_port_t *port, job_request_t *job) 4307 { 4308 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4309 4310 mutex_enter(&port->fp_mutex); 4311 4312 if (port->fp_job_tail == NULL) { 4313 ASSERT(port->fp_job_head == NULL); 4314 port->fp_job_head = port->fp_job_tail = job; 4315 } else { 4316 port->fp_job_tail->job_next = job; 4317 port->fp_job_tail = job; 4318 } 4319 job->job_next = NULL; 4320 4321 cv_signal(&port->fp_cv); 4322 mutex_exit(&port->fp_mutex); 4323 } 4324 4325 4326 job_request_t * 4327 fctl_deque_job(fc_local_port_t *port) 4328 { 4329 job_request_t *job; 4330 4331 ASSERT(MUTEX_HELD(&port->fp_mutex)); 4332 4333 if (port->fp_job_head == NULL) { 4334 ASSERT(port->fp_job_tail == NULL); 4335 job = NULL; 4336 } else { 4337 job = port->fp_job_head; 4338 if (job->job_next == NULL) { 4339 ASSERT(job == port->fp_job_tail); 4340 port->fp_job_tail = NULL; 4341 } 4342 port->fp_job_head = job->job_next; 4343 } 4344 4345 return (job); 4346 } 4347 4348 4349 void 4350 fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job) 4351 { 4352 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4353 4354 mutex_enter(&port->fp_mutex); 4355 if (port->fp_job_tail == NULL) { 4356 ASSERT(port->fp_job_head == NULL); 4357 port->fp_job_head = port->fp_job_tail = job; 4358 job->job_next = NULL; 4359 } else { 4360 job->job_next = port->fp_job_head; 4361 port->fp_job_head = job; 4362 } 4363 cv_signal(&port->fp_cv); 4364 mutex_exit(&port->fp_mutex); 4365 } 4366 4367 4368 void 4369 fctl_jobwait(job_request_t *job) 4370 { 4371 ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC)); 4372 sema_p(&job->job_fctl_sema); 4373 ASSERT(!MUTEX_HELD(&job->job_mutex)); 4374 } 4375 4376 4377 void 4378 fctl_jobdone(job_request_t *job) 4379 { 4380 if (job->job_flags & JOB_TYPE_FCTL_ASYNC) { 4381 if (job->job_comp) { 4382 job->job_comp(job->job_cb_arg, job->job_result); 4383 } 4384 fctl_dealloc_job(job); 4385 } else { 4386 sema_v(&job->job_fctl_sema); 4387 } 4388 } 4389 4390 4391 /* 4392 * Compare two WWNs. 4393 * The NAA can't be omitted for comparison. 4394 * 4395 * Return Values: 4396 * if src == dst return 0 4397 * if src > dst return 1 4398 * if src < dst return -1 4399 */ 4400 int 4401 fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst) 4402 { 4403 uint8_t *l, *r; 4404 int i; 4405 uint64_t wl, wr; 4406 4407 l = (uint8_t *)src; 4408 r = (uint8_t *)dst; 4409 4410 for (i = 0, wl = 0; i < 8; i++) { 4411 wl <<= 8; 4412 wl |= l[i]; 4413 } 4414 for (i = 0, wr = 0; i < 8; i++) { 4415 wr <<= 8; 4416 wr |= r[i]; 4417 } 4418 4419 if (wl > wr) { 4420 return (1); 4421 } else if (wl == wr) { 4422 return (0); 4423 } else { 4424 return (-1); 4425 } 4426 } 4427 4428 4429 /* 4430 * ASCII to Integer goodie with support for base 16, 10, 2 and 8 4431 */ 4432 int 4433 fctl_atoi(char *s, int base) 4434 { 4435 int val; 4436 int ch; 4437 4438 for (val = 0; *s != '\0'; s++) { 4439 switch (base) { 4440 case 16: 4441 if (*s >= '0' && *s <= '9') { 4442 ch = *s - '0'; 4443 } else if (*s >= 'a' && *s <= 'f') { 4444 ch = *s - 'a' + 10; 4445 } else if (*s >= 'A' && *s <= 'F') { 4446 ch = *s - 'A' + 10; 4447 } else { 4448 return (-1); 4449 } 4450 break; 4451 4452 case 10: 4453 if (*s < '0' || *s > '9') { 4454 return (-1); 4455 } 4456 ch = *s - '0'; 4457 break; 4458 4459 case 2: 4460 if (*s < '0' || *s > '1') { 4461 return (-1); 4462 } 4463 ch = *s - '0'; 4464 break; 4465 4466 case 8: 4467 if (*s < '0' || *s > '7') { 4468 return (-1); 4469 } 4470 ch = *s - '0'; 4471 break; 4472 4473 default: 4474 return (-1); 4475 } 4476 val = (val * base) + ch; 4477 } 4478 return (val); 4479 } 4480 4481 4482 /* 4483 * Create the fc_remote_port_t struct for the given port_wwn and d_id. 4484 * 4485 * If the struct already exists (and is "valid"), then use it. Before using 4486 * it, the code below also checks: (a) if the d_id has changed, and (b) if 4487 * the device is maked as PORT_DEVICE_OLD. 4488 * 4489 * If no fc_remote_node_t struct exists for the given node_wwn, then that 4490 * struct is also created (and linked with the fc_remote_port_t). 4491 * 4492 * The given fc_local_port_t struct is updated with the info on the new 4493 * struct(s). The d_id and pwwn hash tables in the port_wwn are updated. 4494 * The global node_hash_table[] is updated (if necessary). 4495 */ 4496 fc_remote_port_t * 4497 fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn, 4498 la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep) 4499 { 4500 int invalid = 0; 4501 fc_remote_node_t *rnodep; 4502 fc_remote_port_t *pd; 4503 4504 rnodep = fctl_get_remote_node_by_nwwn(node_wwn); 4505 if (rnodep) { 4506 /* 4507 * We found an fc_remote_node_t for the remote node -- see if 4508 * anyone has marked it as going away or gone. 4509 */ 4510 mutex_enter(&rnodep->fd_mutex); 4511 invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0; 4512 mutex_exit(&rnodep->fd_mutex); 4513 } 4514 if (rnodep == NULL || invalid) { 4515 /* 4516 * No valid remote node struct found -- create it. 4517 * Note: this is the only place that this func is called. 4518 */ 4519 rnodep = fctl_create_remote_node(node_wwn, sleep); 4520 if (rnodep == NULL) { 4521 return (NULL); 4522 } 4523 } 4524 4525 mutex_enter(&port->fp_mutex); 4526 4527 /* 4528 * See if there already is an fc_remote_port_t struct in existence 4529 * on the specified fc_local_port_t for the given pwwn. If so, then 4530 * grab a reference to it. The 'held' here just means that fp_mutex 4531 * is held by the caller -- no reference counts are updated. 4532 */ 4533 pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn); 4534 if (pd) { 4535 /* 4536 * An fc_remote_port_t struct was found -- see if anyone has 4537 * marked it as "invalid", which means that it is in the 4538 * process of going away & we don't want to use it. 4539 */ 4540 mutex_enter(&pd->pd_mutex); 4541 invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0; 4542 mutex_exit(&pd->pd_mutex); 4543 } 4544 4545 if (pd == NULL || invalid) { 4546 /* 4547 * No fc_remote_port_t was found (or the existing one is 4548 * marked as "invalid".) Allocate a new one and use that. 4549 * This call will also update the d_id and pwwn hash tables 4550 * in the given fc_local_port_t struct with the newly allocated 4551 * fc_remote_port_t. 4552 */ 4553 if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id, 4554 recepient, sleep)) == NULL) { 4555 /* Just give up if the allocation fails. */ 4556 mutex_exit(&port->fp_mutex); 4557 fctl_destroy_remote_node(rnodep); 4558 return (pd); 4559 } 4560 4561 /* 4562 * Add the new fc_remote_port_t struct to the d_id and pwwn 4563 * hash tables on the associated fc_local_port_t struct. 4564 */ 4565 mutex_enter(&pd->pd_mutex); 4566 pd->pd_remote_nodep = rnodep; 4567 fctl_enlist_did_table(port, pd); 4568 fctl_enlist_pwwn_table(port, pd); 4569 mutex_exit(&pd->pd_mutex); 4570 mutex_exit(&port->fp_mutex); 4571 4572 /* 4573 * Retrieve a pointer to the fc_remote_node_t (i.e., remote 4574 * node) specified by the given node_wwn. This looks in the 4575 * global fctl_nwwn_hash_table[]. The fd_numports reference 4576 * count in the fc_remote_node_t struct is incremented. 4577 */ 4578 rnodep = fctl_lock_remote_node_by_nwwn(node_wwn); 4579 4580 } else { 4581 /* 4582 * An existing and valid fc_remote_port_t struct already 4583 * exists on the fc_local_port_t for the given pwwn. 4584 */ 4585 4586 mutex_enter(&pd->pd_mutex); 4587 ASSERT(pd->pd_remote_nodep != NULL); 4588 4589 if (pd->pd_port_id.port_id != d_id) { 4590 /* 4591 * A very unlikely occurance in a well 4592 * behaved environment. 4593 */ 4594 4595 /* 4596 * The existing fc_remote_port_t has a different 4597 * d_id than what we were given. This code will 4598 * update the existing one with the one that was 4599 * just given. 4600 */ 4601 char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1]; 4602 uint32_t old_id; 4603 4604 fc_wwn_to_str(port_wwn, string); 4605 4606 old_id = pd->pd_port_id.port_id; 4607 4608 fctl_delist_did_table(port, pd); 4609 4610 cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device" 4611 " with PWWN %s changed. New D_ID = %x," 4612 " OLD D_ID = %x", port->fp_instance, string, 4613 d_id, old_id); 4614 4615 pd->pd_port_id.port_id = d_id; 4616 4617 /* 4618 * Looks like we have to presume here that the 4619 * remote port could be something entirely different 4620 * from what was previously existing & valid at this 4621 * pwwn. 4622 */ 4623 pd->pd_type = PORT_DEVICE_CHANGED; 4624 4625 /* Record (update) the new d_id for the remote port */ 4626 fctl_enlist_did_table(port, pd); 4627 4628 } else if (pd->pd_type == PORT_DEVICE_OLD) { 4629 /* 4630 * OK at least the old & new d_id's match. So for 4631 * PORT_DEVICE_OLD, this assumes that the remote 4632 * port had disappeared but now has come back. 4633 * Update the pd_type and pd_state to put the 4634 * remote port back into service. 4635 */ 4636 pd->pd_type = PORT_DEVICE_NOCHANGE; 4637 pd->pd_state = PORT_DEVICE_VALID; 4638 4639 fctl_enlist_did_table(port, pd); 4640 4641 } else { 4642 /* 4643 * OK the old & new d_id's match, and the remote 4644 * port struct is not marked as PORT_DEVICE_OLD, so 4645 * presume that it's still the same device and is 4646 * still in good shape. Also this presumes that we 4647 * do not need to update d_id or pwwn hash tables. 4648 */ 4649 /* sanitize device values */ 4650 pd->pd_type = PORT_DEVICE_NOCHANGE; 4651 pd->pd_state = PORT_DEVICE_VALID; 4652 } 4653 4654 mutex_exit(&pd->pd_mutex); 4655 mutex_exit(&port->fp_mutex); 4656 4657 if (rnodep != pd->pd_remote_nodep) { 4658 if ((rnodep != NULL) && 4659 (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name, 4660 node_wwn) != 0)) { 4661 /* 4662 * Rut-roh, there is an fc_remote_node_t remote 4663 * node struct for the given node_wwn, but the 4664 * fc_remote_port_t remote port struct doesn't 4665 * know about it. This just prints a warning 4666 * message & fails the fc_remote_port_t 4667 * allocation (possible leak here?). 4668 */ 4669 char ww1_name[17]; 4670 char ww2_name[17]; 4671 4672 fc_wwn_to_str( 4673 &pd->pd_remote_nodep->fd_node_name, 4674 ww1_name); 4675 fc_wwn_to_str(node_wwn, ww2_name); 4676 4677 cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: " 4678 "Expected %s Got %s", port->fp_instance, 4679 ww1_name, ww2_name); 4680 } 4681 4682 return (NULL); 4683 } 4684 } 4685 4686 /* 4687 * Add the fc_remote_port_t onto the linked list of remote port 4688 * devices associated with the given fc_remote_node_t (remote node). 4689 */ 4690 fctl_link_remote_port_to_remote_node(rnodep, pd); 4691 4692 return (pd); 4693 } 4694 4695 4696 /* 4697 * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes 4698 * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any 4699 * references to the fc_remote_port_t from the d_id and pwwn tables in the 4700 * given fc_local_port_t. Deallocates the given fc_remote_port_t. 4701 * 4702 * Returns a count of the number of remaining fc_remote_port_t structs 4703 * associated with the fc_remote_node_t struct. 4704 * 4705 * If pd_ref_count in the given fc_remote_port_t is nonzero, then this 4706 * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the 4707 * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about 4708 * the cleanup. The function then also returns '1' 4709 * instead of the actual number of remaining fc_remote_port_t structs 4710 * 4711 * If there are no more remote ports on the remote node, return 0. 4712 * Otherwise, return non-zero. 4713 */ 4714 int 4715 fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd) 4716 { 4717 fc_remote_node_t *rnodep; 4718 int rcount = 0; 4719 4720 mutex_enter(&pd->pd_mutex); 4721 4722 /* 4723 * If pd_ref_count > 0, we can't pull the rug out from any 4724 * current users of this fc_remote_port_t. We'll mark it as old 4725 * and in need of removal. The same goes for any fc_remote_port_t 4726 * that has a reference handle(s) in a ULP(s) but for which the ULP(s) 4727 * have not yet been notified that the handle is no longer valid 4728 * (i.e., PD_GIVEN_TO_ULPS is set). 4729 */ 4730 if ((pd->pd_ref_count > 0) || 4731 (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) { 4732 pd->pd_aux_flags |= PD_NEEDS_REMOVAL; 4733 pd->pd_type = PORT_DEVICE_OLD; 4734 mutex_exit(&pd->pd_mutex); 4735 return (1); 4736 } 4737 4738 pd->pd_type = PORT_DEVICE_OLD; 4739 4740 rnodep = pd->pd_remote_nodep; 4741 4742 mutex_exit(&pd->pd_mutex); 4743 4744 if (rnodep != NULL) { 4745 /* 4746 * Remove the fc_remote_port_t from the linked list of remote 4747 * ports for the given fc_remote_node_t. This is only called 4748 * here and in fctl_destroy_all_remote_ports(). 4749 */ 4750 rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd); 4751 } 4752 4753 mutex_enter(&port->fp_mutex); 4754 mutex_enter(&pd->pd_mutex); 4755 4756 fctl_delist_did_table(port, pd); 4757 fctl_delist_pwwn_table(port, pd); 4758 4759 mutex_exit(&pd->pd_mutex); 4760 4761 /* 4762 * Deconstruct & free the fc_remote_port_t. This is only called 4763 * here and in fctl_destroy_all_remote_ports(). 4764 */ 4765 fctl_dealloc_remote_port(pd); 4766 4767 mutex_exit(&port->fp_mutex); 4768 4769 return (rcount); 4770 } 4771 4772 4773 /* 4774 * This goes thru the d_id table on the given fc_local_port_t. 4775 * For each fc_remote_port_t found, this will: 4776 * 4777 * - Remove the fc_remote_port_t from the linked list of remote ports for 4778 * the associated fc_remote_node_t. If the linked list goes empty, then this 4779 * tries to deconstruct & free the fc_remote_node_t (that also removes the 4780 * fc_remote_node_t from the global fctl_nwwn_hash_table[]). 4781 * 4782 * - Remove the fc_remote_port_t from the pwwn list on the given 4783 * fc_local_port_t. 4784 * 4785 * - Deconstruct and free the fc_remote_port_t. 4786 * 4787 * - Removes the link to the fc_remote_port_t in the d_id table. Note, this 4788 * does not appear to correctle decrement the d_id_count tho. 4789 */ 4790 void 4791 fctl_destroy_all_remote_ports(fc_local_port_t *port) 4792 { 4793 int index; 4794 fc_remote_port_t *pd; 4795 fc_remote_node_t *rnodep; 4796 struct d_id_hash *head; 4797 4798 mutex_enter(&port->fp_mutex); 4799 4800 for (index = 0; index < did_table_size; index++) { 4801 4802 head = &port->fp_did_table[index]; 4803 4804 while (head->d_id_head != NULL) { 4805 pd = head->d_id_head; 4806 4807 /* 4808 * See if this remote port (fc_remote_port_t) has a 4809 * reference to a remote node (fc_remote_node_t) in its 4810 * pd->pd_remote_nodep pointer. 4811 */ 4812 mutex_enter(&pd->pd_mutex); 4813 rnodep = pd->pd_remote_nodep; 4814 mutex_exit(&pd->pd_mutex); 4815 4816 if (rnodep != NULL) { 4817 /* 4818 * An fc_remote_node_t reference exists. Remove 4819 * the fc_remote_port_t from the linked list of 4820 * remote ports for fc_remote_node_t. 4821 */ 4822 if (fctl_unlink_remote_port_from_remote_node( 4823 rnodep, pd) == 0) { 4824 /* 4825 * The fd_numports reference count 4826 * in the fc_remote_node_t has come 4827 * back as zero, so we can free the 4828 * fc_remote_node_t. This also means 4829 * that the fc_remote_node_t was 4830 * removed from the 4831 * fctl_nwwn_hash_table[]. 4832 * 4833 * This will silently skip the 4834 * kmem_free() if either the 4835 * fd_numports is nonzero or 4836 * the fd_port is not NULL in 4837 * the fc_remote_node_t. 4838 */ 4839 fctl_destroy_remote_node(rnodep); 4840 } 4841 } 4842 4843 /* 4844 * Clean up the entry in the fc_local_port_t's pwwn 4845 * table for the given fc_remote_port_t (i.e., the pd). 4846 */ 4847 mutex_enter(&pd->pd_mutex); 4848 fctl_delist_pwwn_table(port, pd); 4849 pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 4850 mutex_exit(&pd->pd_mutex); 4851 4852 /* 4853 * Remove the current entry from the d_id list. 4854 */ 4855 head->d_id_head = pd->pd_did_hnext; 4856 4857 /* 4858 * Deconstruct & free the fc_remote_port_t (pd) 4859 * Note: this is only called here and in 4860 * fctl_destroy_remote_port_t(). 4861 */ 4862 fctl_dealloc_remote_port(pd); 4863 } 4864 } 4865 4866 mutex_exit(&port->fp_mutex); 4867 } 4868 4869 4870 int 4871 fctl_is_wwn_zero(la_wwn_t *wwn) 4872 { 4873 int count; 4874 4875 for (count = 0; count < sizeof (la_wwn_t); count++) { 4876 if (wwn->raw_wwn[count] != 0) { 4877 return (FC_FAILURE); 4878 } 4879 } 4880 4881 return (FC_SUCCESS); 4882 } 4883 4884 4885 void 4886 fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type) 4887 { 4888 int data_cb; 4889 int check_type; 4890 int rval; 4891 uint32_t claimed; 4892 fc_ulp_module_t *mod; 4893 fc_ulp_ports_t *ulp_port; 4894 4895 claimed = 0; 4896 check_type = 1; 4897 4898 switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) { 4899 case R_CTL_DEVICE_DATA: 4900 data_cb = 1; 4901 break; 4902 4903 case R_CTL_EXTENDED_SVC: 4904 check_type = 0; 4905 /* FALLTHROUGH */ 4906 4907 case R_CTL_FC4_SVC: 4908 data_cb = 0; 4909 break; 4910 4911 default: 4912 mutex_enter(&port->fp_mutex); 4913 ASSERT(port->fp_active_ubs > 0); 4914 if (--(port->fp_active_ubs) == 0) { 4915 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4916 } 4917 mutex_exit(&port->fp_mutex); 4918 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 4919 1, &buf->ub_token); 4920 return; 4921 } 4922 4923 rw_enter(&fctl_ulp_lock, RW_READER); 4924 for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 4925 if (check_type && mod->mod_info->ulp_type != type) { 4926 continue; 4927 } 4928 4929 rw_enter(&fctl_mod_ports_lock, RW_READER); 4930 ulp_port = fctl_get_ulp_port(mod, port); 4931 rw_exit(&fctl_mod_ports_lock); 4932 4933 if (ulp_port == NULL) { 4934 continue; 4935 } 4936 4937 mutex_enter(&ulp_port->port_mutex); 4938 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 4939 mutex_exit(&ulp_port->port_mutex); 4940 continue; 4941 } 4942 mutex_exit(&ulp_port->port_mutex); 4943 4944 if (data_cb == 1) { 4945 rval = mod->mod_info->ulp_data_callback( 4946 mod->mod_info->ulp_handle, 4947 (opaque_t)port, buf, claimed); 4948 } else { 4949 rval = mod->mod_info->ulp_els_callback( 4950 mod->mod_info->ulp_handle, 4951 (opaque_t)port, buf, claimed); 4952 } 4953 4954 if (rval == FC_SUCCESS && claimed == 0) { 4955 claimed = 1; 4956 } 4957 } 4958 rw_exit(&fctl_ulp_lock); 4959 4960 if (claimed == 0) { 4961 /* 4962 * We should actually RJT since nobody claimed it. 4963 */ 4964 mutex_enter(&port->fp_mutex); 4965 ASSERT(port->fp_active_ubs > 0); 4966 if (--(port->fp_active_ubs) == 0) { 4967 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4968 } 4969 mutex_exit(&port->fp_mutex); 4970 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 4971 1, &buf->ub_token); 4972 4973 } else { 4974 mutex_enter(&port->fp_mutex); 4975 if (--port->fp_active_ubs == 0) { 4976 port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4977 } 4978 mutex_exit(&port->fp_mutex); 4979 } 4980 } 4981 4982 4983 /* 4984 * Both fd_mutex and pd_mutex are held (in that order) coming in to this func 4985 * 4986 * With all these mutexes held, we should make sure this function does not eat 4987 * up much time. 4988 */ 4989 void 4990 fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd) 4991 { 4992 fc_remote_node_t *node; 4993 4994 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4995 4996 map->map_pwwn = pd->pd_port_name; 4997 map->map_did = pd->pd_port_id; 4998 map->map_hard_addr = pd->pd_hard_addr; 4999 map->map_state = pd->pd_state; 5000 map->map_type = pd->pd_type; 5001 map->map_flags = 0; 5002 5003 ASSERT(map->map_type <= PORT_DEVICE_DELETE); 5004 5005 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 5006 5007 node = pd->pd_remote_nodep; 5008 5009 ASSERT(MUTEX_HELD(&node->fd_mutex)); 5010 5011 if (node) { 5012 map->map_nwwn = node->fd_node_name; 5013 } 5014 map->map_pd = pd; 5015 } 5016 5017 void 5018 fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd) 5019 { 5020 fc_remote_node_t *node; 5021 5022 ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 5023 5024 mutex_enter(&pd->pd_mutex); 5025 map->map_pwwn = pd->pd_port_name; 5026 map->map_did = pd->pd_port_id; 5027 map->map_hard_addr = pd->pd_hard_addr; 5028 map->map_state = pd->pd_state; 5029 map->map_type = pd->pd_type; 5030 map->map_flags = 0; 5031 5032 ASSERT(map->map_type <= PORT_DEVICE_DELETE); 5033 5034 bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 5035 5036 node = pd->pd_remote_nodep; 5037 mutex_exit(&pd->pd_mutex); 5038 5039 if (node) { 5040 mutex_enter(&node->fd_mutex); 5041 map->map_nwwn = node->fd_node_name; 5042 mutex_exit(&node->fd_mutex); 5043 } 5044 map->map_pd = pd; 5045 } 5046 5047 5048 static int 5049 fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 5050 { 5051 int rval = FC_SUCCESS; 5052 5053 switch (ns_req->ns_cmd) { 5054 case NS_RFT_ID: { 5055 int count; 5056 uint32_t *src; 5057 uint32_t *dst; 5058 ns_rfc_type_t *rfc; 5059 5060 rfc = (ns_rfc_type_t *)ns_req->ns_req_payload; 5061 5062 mutex_enter(&port->fp_mutex); 5063 src = (uint32_t *)port->fp_fc4_types; 5064 dst = (uint32_t *)rfc->rfc_types; 5065 5066 for (count = 0; count < 8; count++) { 5067 *src++ |= *dst++; 5068 } 5069 mutex_exit(&port->fp_mutex); 5070 5071 break; 5072 } 5073 5074 case NS_RSPN_ID: { 5075 ns_spn_t *spn; 5076 5077 spn = (ns_spn_t *)ns_req->ns_req_payload; 5078 5079 mutex_enter(&port->fp_mutex); 5080 port->fp_sym_port_namelen = spn->spn_len; 5081 if (spn->spn_len) { 5082 bcopy((caddr_t)spn + sizeof (ns_spn_t), 5083 port->fp_sym_port_name, spn->spn_len); 5084 } 5085 mutex_exit(&port->fp_mutex); 5086 5087 break; 5088 } 5089 5090 case NS_RSNN_NN: { 5091 ns_snn_t *snn; 5092 5093 snn = (ns_snn_t *)ns_req->ns_req_payload; 5094 5095 mutex_enter(&port->fp_mutex); 5096 port->fp_sym_node_namelen = snn->snn_len; 5097 if (snn->snn_len) { 5098 bcopy((caddr_t)snn + sizeof (ns_snn_t), 5099 port->fp_sym_node_name, snn->snn_len); 5100 } 5101 mutex_exit(&port->fp_mutex); 5102 5103 break; 5104 } 5105 5106 case NS_RIP_NN: { 5107 ns_rip_t *rip; 5108 5109 rip = (ns_rip_t *)ns_req->ns_req_payload; 5110 5111 mutex_enter(&port->fp_mutex); 5112 bcopy(rip->rip_ip_addr, port->fp_ip_addr, 5113 sizeof (rip->rip_ip_addr)); 5114 mutex_exit(&port->fp_mutex); 5115 5116 break; 5117 } 5118 5119 case NS_RIPA_NN: { 5120 ns_ipa_t *ipa; 5121 5122 ipa = (ns_ipa_t *)ns_req->ns_req_payload; 5123 5124 mutex_enter(&port->fp_mutex); 5125 bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value)); 5126 mutex_exit(&port->fp_mutex); 5127 5128 break; 5129 } 5130 5131 default: 5132 rval = FC_BADOBJECT; 5133 break; 5134 } 5135 5136 return (rval); 5137 } 5138 5139 5140 static int 5141 fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 5142 { 5143 int rval = FC_SUCCESS; 5144 5145 switch (ns_req->ns_cmd) { 5146 case NS_GFT_ID: { 5147 ns_rfc_type_t *rfc; 5148 5149 rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload; 5150 5151 mutex_enter(&port->fp_mutex); 5152 bcopy(port->fp_fc4_types, rfc->rfc_types, 5153 sizeof (rfc->rfc_types)); 5154 mutex_exit(&port->fp_mutex); 5155 break; 5156 } 5157 5158 case NS_GSPN_ID: { 5159 ns_spn_t *spn; 5160 5161 spn = (ns_spn_t *)ns_req->ns_resp_payload; 5162 5163 mutex_enter(&port->fp_mutex); 5164 spn->spn_len = port->fp_sym_port_namelen; 5165 if (spn->spn_len) { 5166 bcopy(port->fp_sym_port_name, (caddr_t)spn + 5167 sizeof (ns_spn_t), spn->spn_len); 5168 } 5169 mutex_exit(&port->fp_mutex); 5170 5171 break; 5172 } 5173 5174 case NS_GSNN_NN: { 5175 ns_snn_t *snn; 5176 5177 snn = (ns_snn_t *)ns_req->ns_resp_payload; 5178 5179 mutex_enter(&port->fp_mutex); 5180 snn->snn_len = port->fp_sym_node_namelen; 5181 if (snn->snn_len) { 5182 bcopy(port->fp_sym_node_name, (caddr_t)snn + 5183 sizeof (ns_snn_t), snn->snn_len); 5184 } 5185 mutex_exit(&port->fp_mutex); 5186 5187 break; 5188 } 5189 5190 case NS_GIP_NN: { 5191 ns_rip_t *rip; 5192 5193 rip = (ns_rip_t *)ns_req->ns_resp_payload; 5194 5195 mutex_enter(&port->fp_mutex); 5196 bcopy(port->fp_ip_addr, rip->rip_ip_addr, 5197 sizeof (rip->rip_ip_addr)); 5198 mutex_exit(&port->fp_mutex); 5199 5200 break; 5201 } 5202 5203 case NS_GIPA_NN: { 5204 ns_ipa_t *ipa; 5205 5206 ipa = (ns_ipa_t *)ns_req->ns_resp_payload; 5207 5208 mutex_enter(&port->fp_mutex); 5209 bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value)); 5210 mutex_exit(&port->fp_mutex); 5211 5212 break; 5213 } 5214 5215 default: 5216 rval = FC_BADOBJECT; 5217 break; 5218 } 5219 5220 return (rval); 5221 } 5222 5223 5224 fctl_ns_req_t * 5225 fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len, 5226 uint32_t ns_flags, int sleep) 5227 { 5228 fctl_ns_req_t *ns_cmd; 5229 5230 ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep); 5231 if (ns_cmd == NULL) { 5232 return (NULL); 5233 } 5234 5235 if (cmd_len) { 5236 ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep); 5237 if (ns_cmd->ns_cmd_buf == NULL) { 5238 kmem_free(ns_cmd, sizeof (*ns_cmd)); 5239 return (NULL); 5240 } 5241 ns_cmd->ns_cmd_size = cmd_len; 5242 } 5243 5244 ns_cmd->ns_resp_size = resp_len; 5245 5246 if (data_len) { 5247 ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep); 5248 if (ns_cmd->ns_data_buf == NULL) { 5249 if (ns_cmd->ns_cmd_buf && cmd_len) { 5250 kmem_free(ns_cmd->ns_cmd_buf, cmd_len); 5251 } 5252 kmem_free(ns_cmd, sizeof (*ns_cmd)); 5253 return (NULL); 5254 } 5255 ns_cmd->ns_data_len = data_len; 5256 } 5257 ns_cmd->ns_flags = ns_flags; 5258 5259 return (ns_cmd); 5260 } 5261 5262 5263 void 5264 fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd) 5265 { 5266 if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) { 5267 kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size); 5268 } 5269 if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) { 5270 kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len); 5271 } 5272 kmem_free(ns_cmd, sizeof (*ns_cmd)); 5273 } 5274 5275 5276 int 5277 fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd, 5278 intptr_t data, int mode, cred_t *credp, int *rval) 5279 { 5280 int ret; 5281 int save; 5282 uint32_t claimed; 5283 fc_ulp_module_t *mod; 5284 fc_ulp_ports_t *ulp_port; 5285 5286 save = *rval; 5287 *rval = ENOTTY; 5288 5289 rw_enter(&fctl_ulp_lock, RW_READER); 5290 for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 5291 rw_enter(&fctl_mod_ports_lock, RW_READER); 5292 ulp_port = fctl_get_ulp_port(mod, port); 5293 rw_exit(&fctl_mod_ports_lock); 5294 5295 if (ulp_port == NULL) { 5296 continue; 5297 } 5298 5299 mutex_enter(&ulp_port->port_mutex); 5300 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) || 5301 mod->mod_info->ulp_port_ioctl == NULL) { 5302 mutex_exit(&ulp_port->port_mutex); 5303 continue; 5304 } 5305 mutex_exit(&ulp_port->port_mutex); 5306 5307 ret = mod->mod_info->ulp_port_ioctl( 5308 mod->mod_info->ulp_handle, (opaque_t)port, 5309 dev, cmd, data, mode, credp, rval, claimed); 5310 5311 if (ret == FC_SUCCESS && claimed == 0) { 5312 claimed = 1; 5313 } 5314 } 5315 rw_exit(&fctl_ulp_lock); 5316 5317 ret = *rval; 5318 *rval = save; 5319 5320 return (ret); 5321 } 5322 5323 /* 5324 * raise power if necessary, and set the port busy 5325 * 5326 * this may cause power to be raised, so no power related locks should 5327 * be held 5328 */ 5329 int 5330 fc_ulp_busy_port(opaque_t port_handle) 5331 { 5332 fc_local_port_t *port = port_handle; 5333 5334 return (fctl_busy_port(port)); 5335 } 5336 5337 void 5338 fc_ulp_idle_port(opaque_t port_handle) 5339 { 5340 fc_local_port_t *port = port_handle; 5341 fctl_idle_port(port); 5342 } 5343 5344 void 5345 fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd) 5346 { 5347 fctl_copy_portmap(map, (fc_remote_port_t *)pd); 5348 } 5349 5350 5351 int 5352 fc_ulp_get_npiv_port_num(opaque_t port_handle) 5353 { 5354 int portsnum = 0; 5355 fc_local_port_t *port = port_handle; 5356 fc_local_port_t *tmpport; 5357 5358 mutex_enter(&port->fp_mutex); 5359 tmpport = port->fp_port_next; 5360 if (!tmpport) { 5361 mutex_exit(&port->fp_mutex); 5362 return (portsnum); 5363 } 5364 while (tmpport != port) { 5365 portsnum ++; 5366 tmpport = tmpport->fp_port_next; 5367 } 5368 mutex_exit(&port->fp_mutex); 5369 return (portsnum); 5370 } 5371 5372 fc_local_port_t * 5373 fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn) 5374 { 5375 fc_fca_port_t *fca_port; 5376 fc_local_port_t *tmpPort = phyport; 5377 5378 mutex_enter(&fctl_port_lock); 5379 5380 for (fca_port = fctl_fca_portlist; fca_port != NULL; 5381 fca_port = fca_port->port_next) { 5382 tmpPort = fca_port->port_handle; 5383 if (tmpPort == NULL) { 5384 continue; 5385 } 5386 mutex_enter(&tmpPort->fp_mutex); 5387 if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn, 5388 pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) { 5389 mutex_exit(&tmpPort->fp_mutex); 5390 mutex_exit(&fctl_port_lock); 5391 return (tmpPort); 5392 } 5393 mutex_exit(&tmpPort->fp_mutex); 5394 } 5395 5396 mutex_exit(&fctl_port_lock); 5397 5398 return (NULL); 5399 } 5400 5401 int 5402 fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList) 5403 { 5404 int portsnum = 0; 5405 fc_local_port_t *port = port_handle; 5406 fc_local_port_t *tmpport; 5407 5408 mutex_enter(&port->fp_mutex); 5409 tmpport = port->fp_port_next; 5410 if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 5411 mutex_exit(&port->fp_mutex); 5412 return (portsnum); 5413 } 5414 5415 while (tmpport != port) { 5416 (void) ddi_pathname(tmpport->fp_port_dip, 5417 &pathList[MAXPATHLEN * portsnum]); 5418 portsnum ++; 5419 tmpport = tmpport->fp_port_next; 5420 } 5421 mutex_exit(&port->fp_mutex); 5422 5423 return (portsnum); 5424 } 5425 5426 5427 fc_local_port_t * 5428 fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn) 5429 { 5430 fc_local_port_t *tmpport; 5431 5432 mutex_enter(&port->fp_mutex); 5433 tmpport = port->fp_port_next; 5434 if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 5435 mutex_exit(&port->fp_mutex); 5436 return (NULL); 5437 } 5438 5439 while (tmpport != port) { 5440 if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn, 5441 pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) && 5442 (tmpport->fp_npiv_state == 0)) { 5443 tmpport->fp_npiv_state = FC_NPIV_DELETING; 5444 mutex_exit(&port->fp_mutex); 5445 return (tmpport); 5446 } 5447 tmpport = tmpport->fp_port_next; 5448 } 5449 5450 mutex_exit(&port->fp_mutex); 5451 return (NULL); 5452 } 5453 5454 /* 5455 * Get the list of Adapters. On multi-ported adapters, 5456 * only ONE port on the adapter will be returned. 5457 * pathList should be (count * MAXPATHLEN) long. 5458 * The return value will be set to the number of 5459 * HBAs that were found on the system. If the value 5460 * is greater than count, the routine should be retried 5461 * with a larger buffer. 5462 */ 5463 int 5464 fc_ulp_get_adapter_paths(char *pathList, int count) 5465 { 5466 fc_fca_port_t *fca_port; 5467 int in = 0, out = 0, check, skip, maxPorts = 0; 5468 fc_local_port_t **portList; 5469 fc_local_port_t *new_port, *stored_port; 5470 fca_hba_fru_details_t *new_fru, *stored_fru; 5471 5472 ASSERT(pathList != NULL); 5473 5474 /* First figure out how many ports we have */ 5475 mutex_enter(&fctl_port_lock); 5476 5477 for (fca_port = fctl_fca_portlist; fca_port != NULL; 5478 fca_port = fca_port->port_next) { 5479 maxPorts ++; 5480 } 5481 5482 /* Now allocate a buffer to store all the pointers for comparisons */ 5483 portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP); 5484 5485 for (fca_port = fctl_fca_portlist; fca_port != NULL; 5486 fca_port = fca_port->port_next) { 5487 skip = 0; 5488 5489 /* Lock the new port for subsequent comparisons */ 5490 new_port = fca_port->port_handle; 5491 mutex_enter(&new_port->fp_mutex); 5492 new_fru = &new_port->fp_hba_port_attrs.hba_fru_details; 5493 5494 /* Filter out secondary ports from the list */ 5495 for (check = 0; check < out; check++) { 5496 if (portList[check] == NULL) { 5497 continue; 5498 } 5499 /* Guard against duplicates (should never happen) */ 5500 if (portList[check] == fca_port->port_handle) { 5501 /* Same port */ 5502 skip = 1; 5503 break; 5504 } 5505 5506 /* Lock the already stored port for comparison */ 5507 stored_port = portList[check]; 5508 mutex_enter(&stored_port->fp_mutex); 5509 stored_fru = 5510 &stored_port->fp_hba_port_attrs.hba_fru_details; 5511 5512 /* Are these ports on the same HBA? */ 5513 if (new_fru->high == stored_fru->high && 5514 new_fru->low == stored_fru->low) { 5515 /* Now double check driver */ 5516 if (strncmp( 5517 new_port->fp_hba_port_attrs.driver_name, 5518 stored_port->fp_hba_port_attrs.driver_name, 5519 FCHBA_DRIVER_NAME_LEN) == 0) { 5520 /* we don't need to grow the list */ 5521 skip = 1; 5522 /* looking at a lower port index? */ 5523 if (new_fru->port_index < 5524 stored_fru->port_index) { 5525 /* Replace the port in list */ 5526 mutex_exit( 5527 &stored_port->fp_mutex); 5528 if (new_port->fp_npiv_type == 5529 FC_NPIV_PORT) { 5530 break; 5531 } 5532 portList[check] = new_port; 5533 break; 5534 } /* Else, just skip this port */ 5535 } 5536 } 5537 5538 mutex_exit(&stored_port->fp_mutex); 5539 } 5540 mutex_exit(&new_port->fp_mutex); 5541 5542 if (!skip) { 5543 /* 5544 * Either this is the first port for this HBA, or 5545 * it's a secondary port and we haven't stored the 5546 * primary/first port for that HBA. In the latter case, 5547 * will just filter it out as we proceed to loop. 5548 */ 5549 if (fca_port->port_handle->fp_npiv_type == 5550 FC_NPIV_PORT) { 5551 continue; 5552 } else { 5553 portList[out++] = fca_port->port_handle; 5554 } 5555 } 5556 } 5557 5558 if (out <= count) { 5559 for (in = 0; in < out; in++) { 5560 (void) ddi_pathname(portList[in]->fp_port_dip, 5561 &pathList[MAXPATHLEN * in]); 5562 } 5563 } 5564 mutex_exit(&fctl_port_lock); 5565 kmem_free(portList, sizeof (*portList) * maxPorts); 5566 return (out); 5567 } 5568 5569 uint32_t 5570 fc_ulp_get_rscn_count(opaque_t port_handle) 5571 { 5572 uint32_t count; 5573 fc_local_port_t *port; 5574 5575 port = (fc_local_port_t *)port_handle; 5576 mutex_enter(&port->fp_mutex); 5577 count = port->fp_rscn_count; 5578 mutex_exit(&port->fp_mutex); 5579 5580 return (count); 5581 } 5582 5583 5584 /* 5585 * This function is a very similar to fctl_add_orphan except that it expects 5586 * that the fp_mutex and pd_mutex of the pd passed in are held coming in. 5587 * 5588 * Note that there is a lock hierarchy here (fp_mutex should be held first) but 5589 * since this function could be called with a different pd's pd_mutex held, we 5590 * should take care not to release fp_mutex in this function. 5591 */ 5592 int 5593 fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd) 5594 { 5595 int rval = FC_FAILURE; 5596 la_wwn_t pwwn; 5597 fc_orphan_t *orp; 5598 fc_orphan_t *orphan; 5599 5600 ASSERT(MUTEX_HELD(&port->fp_mutex)); 5601 ASSERT(MUTEX_HELD(&pd->pd_mutex)); 5602 5603 pwwn = pd->pd_port_name; 5604 5605 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5606 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5607 return (FC_SUCCESS); 5608 } 5609 } 5610 5611 orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP); 5612 if (orphan) { 5613 orphan->orp_pwwn = pwwn; 5614 orphan->orp_tstamp = ddi_get_lbolt(); 5615 5616 if (port->fp_orphan_list) { 5617 ASSERT(port->fp_orphan_count > 0); 5618 orphan->orp_next = port->fp_orphan_list; 5619 } 5620 port->fp_orphan_list = orphan; 5621 port->fp_orphan_count++; 5622 5623 rval = FC_SUCCESS; 5624 } 5625 5626 return (rval); 5627 } 5628 5629 int 5630 fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep) 5631 { 5632 int rval = FC_FAILURE; 5633 la_wwn_t pwwn; 5634 fc_orphan_t *orp; 5635 fc_orphan_t *orphan; 5636 5637 mutex_enter(&port->fp_mutex); 5638 5639 mutex_enter(&pd->pd_mutex); 5640 pwwn = pd->pd_port_name; 5641 mutex_exit(&pd->pd_mutex); 5642 5643 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5644 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5645 mutex_exit(&port->fp_mutex); 5646 return (FC_SUCCESS); 5647 } 5648 } 5649 mutex_exit(&port->fp_mutex); 5650 5651 orphan = kmem_zalloc(sizeof (*orphan), sleep); 5652 if (orphan != NULL) { 5653 mutex_enter(&port->fp_mutex); 5654 5655 orphan->orp_pwwn = pwwn; 5656 orphan->orp_tstamp = ddi_get_lbolt(); 5657 5658 if (port->fp_orphan_list) { 5659 ASSERT(port->fp_orphan_count > 0); 5660 orphan->orp_next = port->fp_orphan_list; 5661 } 5662 port->fp_orphan_list = orphan; 5663 port->fp_orphan_count++; 5664 mutex_exit(&port->fp_mutex); 5665 5666 rval = FC_SUCCESS; 5667 } 5668 5669 return (rval); 5670 } 5671 5672 5673 int 5674 fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn) 5675 { 5676 int rval = FC_FAILURE; 5677 fc_orphan_t *prev = NULL; 5678 fc_orphan_t *orp; 5679 5680 mutex_enter(&port->fp_mutex); 5681 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5682 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) { 5683 if (prev) { 5684 prev->orp_next = orp->orp_next; 5685 } else { 5686 ASSERT(port->fp_orphan_list == orp); 5687 port->fp_orphan_list = orp->orp_next; 5688 } 5689 port->fp_orphan_count--; 5690 rval = FC_SUCCESS; 5691 break; 5692 } 5693 prev = orp; 5694 } 5695 mutex_exit(&port->fp_mutex); 5696 5697 if (rval == FC_SUCCESS) { 5698 kmem_free(orp, sizeof (*orp)); 5699 } 5700 5701 return (rval); 5702 } 5703 5704 5705 static void 5706 fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd) 5707 { 5708 char ww_name[17]; 5709 la_wwn_t pwwn; 5710 fc_orphan_t *orp; 5711 5712 mutex_enter(&port->fp_mutex); 5713 5714 mutex_enter(&pd->pd_mutex); 5715 pwwn = pd->pd_port_name; 5716 mutex_exit(&pd->pd_mutex); 5717 5718 for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5719 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5720 mutex_exit(&port->fp_mutex); 5721 return; 5722 } 5723 } 5724 mutex_exit(&port->fp_mutex); 5725 5726 fc_wwn_to_str(&pwwn, ww_name); 5727 5728 cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s" 5729 " disappeared from fabric", port->fp_instance, 5730 pd->pd_port_id.port_id, ww_name); 5731 } 5732 5733 5734 /* ARGSUSED */ 5735 static void 5736 fctl_link_reset_done(opaque_t port_handle, uchar_t result) 5737 { 5738 fc_local_port_t *port = port_handle; 5739 5740 mutex_enter(&port->fp_mutex); 5741 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 5742 mutex_exit(&port->fp_mutex); 5743 5744 fctl_idle_port(port); 5745 } 5746 5747 5748 static int 5749 fctl_error(int fc_errno, char **errmsg) 5750 { 5751 int count; 5752 5753 for (count = 0; count < sizeof (fc_errlist) / 5754 sizeof (fc_errlist[0]); count++) { 5755 if (fc_errlist[count].fc_errno == fc_errno) { 5756 *errmsg = fc_errlist[count].fc_errname; 5757 return (FC_SUCCESS); 5758 } 5759 } 5760 *errmsg = fctl_undefined; 5761 5762 return (FC_FAILURE); 5763 } 5764 5765 5766 /* 5767 * Return number of successful translations. 5768 * Anybody with some userland programming experience would have 5769 * figured it by now that the return value exactly resembles that 5770 * of scanf(3c). This function returns a count of successful 5771 * translations. It could range from 0 (no match for state, reason, 5772 * action, expln) to 4 (successful matches for all state, reason, 5773 * action, expln) and where translation isn't successful into a 5774 * friendlier message the relevent field is set to "Undefined" 5775 */ 5776 static int 5777 fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason, 5778 char **action, char **expln) 5779 { 5780 int ret; 5781 int len; 5782 int index; 5783 fc_pkt_error_t *error; 5784 fc_pkt_reason_t *reason_b; /* Base pointer */ 5785 fc_pkt_action_t *action_b; /* Base pointer */ 5786 fc_pkt_expln_t *expln_b; /* Base pointer */ 5787 5788 ret = 0; 5789 *state = *reason = *action = *expln = fctl_undefined; 5790 5791 len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0]; 5792 for (index = 0; index < len; index++) { 5793 error = fc_pkt_errlist + index; 5794 if (pkt->pkt_state == error->pkt_state) { 5795 *state = error->pkt_msg; 5796 ret++; 5797 5798 reason_b = error->pkt_reason; 5799 action_b = error->pkt_action; 5800 expln_b = error->pkt_expln; 5801 5802 while (reason_b != NULL && 5803 reason_b->reason_val != FC_REASON_INVALID) { 5804 if (reason_b->reason_val == pkt->pkt_reason) { 5805 *reason = reason_b->reason_msg; 5806 ret++; 5807 break; 5808 } 5809 reason_b++; 5810 } 5811 5812 while (action_b != NULL && 5813 action_b->action_val != FC_ACTION_INVALID) { 5814 if (action_b->action_val == pkt->pkt_action) { 5815 *action = action_b->action_msg; 5816 ret++; 5817 break; 5818 } 5819 action_b++; 5820 } 5821 5822 while (expln_b != NULL && 5823 expln_b->expln_val != FC_EXPLN_INVALID) { 5824 if (expln_b->expln_val == pkt->pkt_expln) { 5825 *expln = expln_b->expln_msg; 5826 ret++; 5827 break; 5828 } 5829 expln_b++; 5830 } 5831 break; 5832 } 5833 } 5834 5835 return (ret); 5836 } 5837 5838 5839 /* 5840 * Remove all port devices that are marked OLD, remove 5841 * corresponding node devices (fc_remote_node_t) 5842 */ 5843 void 5844 fctl_remove_oldies(fc_local_port_t *port) 5845 { 5846 int index; 5847 int initiator; 5848 fc_remote_node_t *node; 5849 struct pwwn_hash *head; 5850 fc_remote_port_t *pd; 5851 fc_remote_port_t *old_pd; 5852 fc_remote_port_t *last_pd; 5853 5854 /* 5855 * Nuke all OLD devices 5856 */ 5857 mutex_enter(&port->fp_mutex); 5858 5859 for (index = 0; index < pwwn_table_size; index++) { 5860 head = &port->fp_pwwn_table[index]; 5861 last_pd = NULL; 5862 pd = head->pwwn_head; 5863 5864 while (pd != NULL) { 5865 mutex_enter(&pd->pd_mutex); 5866 if (pd->pd_type != PORT_DEVICE_OLD) { 5867 mutex_exit(&pd->pd_mutex); 5868 last_pd = pd; 5869 pd = pd->pd_wwn_hnext; 5870 continue; 5871 } 5872 5873 /* 5874 * Remove this from the PWWN hash table 5875 */ 5876 old_pd = pd; 5877 pd = old_pd->pd_wwn_hnext; 5878 5879 if (last_pd == NULL) { 5880 ASSERT(old_pd == head->pwwn_head); 5881 head->pwwn_head = pd; 5882 } else { 5883 last_pd->pd_wwn_hnext = pd; 5884 } 5885 head->pwwn_count--; 5886 /* 5887 * Make sure we tie fp_dev_count to the size of the 5888 * pwwn_table 5889 */ 5890 port->fp_dev_count--; 5891 old_pd->pd_wwn_hnext = NULL; 5892 5893 fctl_delist_did_table(port, old_pd); 5894 node = old_pd->pd_remote_nodep; 5895 ASSERT(node != NULL); 5896 5897 initiator = (old_pd->pd_recepient == 5898 PD_PLOGI_INITIATOR) ? 1 : 0; 5899 5900 mutex_exit(&old_pd->pd_mutex); 5901 5902 if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) { 5903 mutex_exit(&port->fp_mutex); 5904 5905 (void) fctl_add_orphan(port, old_pd, 5906 KM_NOSLEEP); 5907 } else { 5908 mutex_exit(&port->fp_mutex); 5909 } 5910 5911 if (fctl_destroy_remote_port(port, old_pd) == 0) { 5912 if (node) { 5913 fctl_destroy_remote_node(node); 5914 } 5915 } 5916 5917 mutex_enter(&port->fp_mutex); 5918 } 5919 } 5920 5921 mutex_exit(&port->fp_mutex); 5922 } 5923 5924 5925 static void 5926 fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd) 5927 { 5928 ASSERT(MUTEX_HELD(&port->fp_mutex)); 5929 ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 5930 5931 if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) { 5932 return; 5933 } 5934 5935 cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map", 5936 port->fp_instance, pd->pd_port_id.port_id); 5937 } 5938 5939 5940 static int 5941 fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa) 5942 { 5943 int index; 5944 5945 ASSERT(MUTEX_HELD(&port->fp_mutex)); 5946 ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 5947 5948 for (index = 0; index < port->fp_lilp_map.lilp_length; index++) { 5949 if (port->fp_lilp_map.lilp_alpalist[index] == alpa) { 5950 return (FC_SUCCESS); 5951 } 5952 } 5953 5954 return (FC_FAILURE); 5955 } 5956 5957 5958 fc_remote_port_t * 5959 fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id) 5960 { 5961 int index; 5962 struct pwwn_hash *head; 5963 fc_remote_port_t *pd; 5964 5965 ASSERT(MUTEX_HELD(&port->fp_mutex)); 5966 5967 for (index = 0; index < pwwn_table_size; index++) { 5968 head = &port->fp_pwwn_table[index]; 5969 pd = head->pwwn_head; 5970 5971 while (pd != NULL) { 5972 mutex_enter(&pd->pd_mutex); 5973 if (pd->pd_port_id.port_id == d_id) { 5974 mutex_exit(&pd->pd_mutex); 5975 return (pd); 5976 } 5977 mutex_exit(&pd->pd_mutex); 5978 pd = pd->pd_wwn_hnext; 5979 } 5980 } 5981 5982 return (pd); 5983 } 5984 5985 5986 /* 5987 * trace debugging 5988 */ 5989 void 5990 fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel, 5991 int errno, const char *fmt, ...) 5992 { 5993 char buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */ 5994 char *bufptr = buf; 5995 va_list ap; 5996 int cnt = 0; 5997 5998 if ((dlevel & dflag) == 0) { 5999 return; 6000 } 6001 6002 if (name) { 6003 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::", 6004 logq->il_id++, name); 6005 } else { 6006 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::", 6007 logq->il_id++); 6008 } 6009 6010 if (cnt < FC_MAX_TRACE_BUF_LEN) { 6011 va_start(ap, fmt); 6012 cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 6013 fmt, ap); 6014 va_end(ap); 6015 } 6016 6017 if (cnt > FC_MAX_TRACE_BUF_LEN) { 6018 cnt = FC_MAX_TRACE_BUF_LEN; 6019 } 6020 if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) { 6021 cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 6022 "error=0x%x\n", errno); 6023 } 6024 (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n"); 6025 6026 if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) { 6027 fc_trace_logmsg(logq, buf, dlevel); 6028 } 6029 6030 /* 6031 * We do not want to print the log numbers that appear as 6032 * random numbers at the console and messages files, to 6033 * the user. 6034 */ 6035 if ((bufptr = strchr(buf, '>')) == NULL) { 6036 /* 6037 * We would have added the a string with "=>" above and so, 6038 * ideally, we should not get here at all. But, if we do, 6039 * we'll just use the full buf. 6040 */ 6041 bufptr = buf; 6042 } else { 6043 bufptr++; 6044 } 6045 6046 switch (dlevel & FC_TRACE_LOG_MASK) { 6047 case FC_TRACE_LOG_CONSOLE: 6048 cmn_err(CE_WARN, "%s", bufptr); 6049 break; 6050 6051 case FC_TRACE_LOG_CONSOLE_MSG: 6052 cmn_err(CE_WARN, "%s", bufptr); 6053 break; 6054 6055 case FC_TRACE_LOG_MSG: 6056 cmn_err(CE_WARN, "!%s", bufptr); 6057 break; 6058 6059 default: 6060 break; 6061 } 6062 } 6063 6064 6065 /* 6066 * This function can block 6067 */ 6068 fc_trace_logq_t * 6069 fc_trace_alloc_logq(int maxsize) 6070 { 6071 fc_trace_logq_t *logq; 6072 6073 logq = kmem_zalloc(sizeof (*logq), KM_SLEEP); 6074 6075 mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL); 6076 logq->il_hiwat = maxsize; 6077 logq->il_flags |= FC_TRACE_LOGQ_V2; 6078 6079 return (logq); 6080 } 6081 6082 6083 void 6084 fc_trace_free_logq(fc_trace_logq_t *logq) 6085 { 6086 mutex_enter(&logq->il_lock); 6087 while (logq->il_msgh) { 6088 fc_trace_freemsg(logq); 6089 } 6090 mutex_exit(&logq->il_lock); 6091 6092 mutex_destroy(&logq->il_lock); 6093 kmem_free(logq, sizeof (*logq)); 6094 } 6095 6096 6097 /* ARGSUSED */ 6098 void 6099 fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level) 6100 { 6101 int qfull = 0; 6102 fc_trace_dmsg_t *dmsg; 6103 6104 dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP); 6105 if (dmsg == NULL) { 6106 mutex_enter(&logq->il_lock); 6107 logq->il_afail++; 6108 mutex_exit(&logq->il_lock); 6109 6110 return; 6111 } 6112 6113 gethrestime(&dmsg->id_time); 6114 6115 dmsg->id_size = strlen(buf) + 1; 6116 dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP); 6117 if (dmsg->id_buf == NULL) { 6118 kmem_free(dmsg, sizeof (*dmsg)); 6119 6120 mutex_enter(&logq->il_lock); 6121 logq->il_afail++; 6122 mutex_exit(&logq->il_lock); 6123 6124 return; 6125 } 6126 bcopy(buf, dmsg->id_buf, strlen(buf)); 6127 dmsg->id_buf[strlen(buf)] = '\0'; 6128 6129 mutex_enter(&logq->il_lock); 6130 6131 logq->il_size += dmsg->id_size; 6132 if (logq->il_size >= logq->il_hiwat) { 6133 qfull = 1; 6134 } 6135 6136 if (qfull) { 6137 fc_trace_freemsg(logq); 6138 } 6139 6140 dmsg->id_next = NULL; 6141 if (logq->il_msgt) { 6142 logq->il_msgt->id_next = dmsg; 6143 } else { 6144 ASSERT(logq->il_msgh == NULL); 6145 logq->il_msgh = dmsg; 6146 } 6147 logq->il_msgt = dmsg; 6148 6149 mutex_exit(&logq->il_lock); 6150 } 6151 6152 6153 static void 6154 fc_trace_freemsg(fc_trace_logq_t *logq) 6155 { 6156 fc_trace_dmsg_t *dmsg; 6157 6158 ASSERT(MUTEX_HELD(&logq->il_lock)); 6159 6160 if ((dmsg = logq->il_msgh) != NULL) { 6161 logq->il_msgh = dmsg->id_next; 6162 if (logq->il_msgh == NULL) { 6163 logq->il_msgt = NULL; 6164 } 6165 6166 logq->il_size -= dmsg->id_size; 6167 kmem_free(dmsg->id_buf, dmsg->id_size); 6168 kmem_free(dmsg, sizeof (*dmsg)); 6169 } else { 6170 ASSERT(logq->il_msgt == NULL); 6171 } 6172 } 6173 6174 /* 6175 * Used by T11 FC-HBA to fetch discovered ports by index. 6176 * Returns NULL if the index isn't valid. 6177 */ 6178 fc_remote_port_t * 6179 fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index) 6180 { 6181 int outer; 6182 int match = 0; 6183 struct pwwn_hash *head; 6184 fc_remote_port_t *pd; 6185 6186 ASSERT(MUTEX_HELD(&port->fp_mutex)); 6187 6188 for (outer = 0; 6189 outer < pwwn_table_size && match <= index; 6190 outer++) { 6191 head = &port->fp_pwwn_table[outer]; 6192 pd = head->pwwn_head; 6193 if (pd != NULL) match ++; 6194 6195 while (pd != NULL && match <= index) { 6196 pd = pd->pd_wwn_hnext; 6197 if (pd != NULL) match ++; 6198 } 6199 } 6200 6201 return (pd); 6202 } 6203 6204 /* 6205 * Search for a matching Node or Port WWN in the discovered port list 6206 */ 6207 fc_remote_port_t * 6208 fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn) 6209 { 6210 int index; 6211 struct pwwn_hash *head; 6212 fc_remote_port_t *pd; 6213 6214 ASSERT(MUTEX_HELD(&port->fp_mutex)); 6215 6216 for (index = 0; index < pwwn_table_size; index++) { 6217 head = &port->fp_pwwn_table[index]; 6218 pd = head->pwwn_head; 6219 6220 while (pd != NULL) { 6221 mutex_enter(&pd->pd_mutex); 6222 if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn, 6223 sizeof (la_wwn_t)) == 0) { 6224 mutex_exit(&pd->pd_mutex); 6225 return (pd); 6226 } 6227 if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn, 6228 wwn.raw_wwn, sizeof (la_wwn_t)) == 0) { 6229 mutex_exit(&pd->pd_mutex); 6230 return (pd); 6231 } 6232 mutex_exit(&pd->pd_mutex); 6233 pd = pd->pd_wwn_hnext; 6234 } 6235 } 6236 /* No match */ 6237 return (NULL); 6238 } 6239 6240 6241 /* 6242 * Count the number of ports on this adapter. 6243 * This routine will walk the port list and count up the number of adapters 6244 * with matching fp_hba_port_attrs.hba_fru_details.high and 6245 * fp_hba_port_attrs.hba_fru_details.low. 6246 * 6247 * port->fp_mutex must not be held. 6248 */ 6249 int 6250 fctl_count_fru_ports(fc_local_port_t *port, int npivflag) 6251 { 6252 fca_hba_fru_details_t *fru; 6253 fc_fca_port_t *fca_port; 6254 fc_local_port_t *tmpPort = NULL; 6255 uint32_t count = 1; 6256 6257 mutex_enter(&fctl_port_lock); 6258 6259 mutex_enter(&port->fp_mutex); 6260 fru = &port->fp_hba_port_attrs.hba_fru_details; 6261 6262 /* Detect FCA drivers that don't support linking HBA ports */ 6263 if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 6264 mutex_exit(&port->fp_mutex); 6265 mutex_exit(&fctl_port_lock); 6266 return (1); 6267 } 6268 6269 for (fca_port = fctl_fca_portlist; fca_port != NULL; 6270 fca_port = fca_port->port_next) { 6271 tmpPort = fca_port->port_handle; 6272 if (tmpPort == port) { 6273 continue; 6274 } 6275 mutex_enter(&tmpPort->fp_mutex); 6276 6277 /* 6278 * If an FCA driver returns unique fru->high and fru->low for 6279 * ports on the same card, there is no way for the transport 6280 * layer to determine that the two ports on the same FRU. So, 6281 * the discovery of the ports on a same FRU is limited to what 6282 * the FCA driver can report back. 6283 */ 6284 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 6285 fru->high && 6286 tmpPort->fp_hba_port_attrs.hba_fru_details.low == 6287 fru->low) { 6288 /* Now double check driver */ 6289 if (strncmp(port->fp_hba_port_attrs.driver_name, 6290 tmpPort->fp_hba_port_attrs.driver_name, 6291 FCHBA_DRIVER_NAME_LEN) == 0) { 6292 if (!npivflag || 6293 (tmpPort->fp_npiv_type != FC_NPIV_PORT)) { 6294 count++; 6295 } 6296 } /* Else, different FCA driver */ 6297 } /* Else not the same HBA FRU */ 6298 mutex_exit(&tmpPort->fp_mutex); 6299 } 6300 6301 mutex_exit(&port->fp_mutex); 6302 mutex_exit(&fctl_port_lock); 6303 6304 return (count); 6305 } 6306 6307 fc_fca_port_t * 6308 fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port) 6309 { 6310 fc_fca_port_t *tmp = list, *newentry = NULL; 6311 6312 newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP); 6313 if (newentry == NULL) { 6314 return (list); 6315 } 6316 newentry->port_handle = port; 6317 6318 if (tmp == NULL) { 6319 return (newentry); 6320 } 6321 while (tmp->port_next != NULL) tmp = tmp->port_next; 6322 tmp->port_next = newentry; 6323 6324 return (list); 6325 } 6326 6327 void 6328 fctl_local_port_list_free(fc_fca_port_t *list) 6329 { 6330 fc_fca_port_t *tmp = list, *nextentry; 6331 6332 if (tmp == NULL) { 6333 return; 6334 } 6335 6336 while (tmp != NULL) { 6337 nextentry = tmp->port_next; 6338 kmem_free(tmp, sizeof (*tmp)); 6339 tmp = nextentry; 6340 } 6341 } 6342 6343 /* 6344 * Fetch another port on the HBA FRU based on index. 6345 * Returns NULL if index not found. 6346 * 6347 * port->fp_mutex must not be held. 6348 */ 6349 fc_local_port_t * 6350 fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index) 6351 { 6352 fca_hba_fru_details_t *fru; 6353 fc_fca_port_t *fca_port; 6354 fc_local_port_t *tmpPort = NULL; 6355 fc_fca_port_t *list = NULL, *tmpEntry; 6356 fc_local_port_t *phyPort, *virPort = NULL; 6357 int index, phyPortNum = 0; 6358 6359 mutex_enter(&fctl_port_lock); 6360 6361 mutex_enter(&port->fp_mutex); 6362 fru = &port->fp_hba_port_attrs.hba_fru_details; 6363 6364 /* Are we looking for this port? */ 6365 if (fru->port_index == port_index) { 6366 mutex_exit(&port->fp_mutex); 6367 mutex_exit(&fctl_port_lock); 6368 return (port); 6369 } 6370 6371 /* Detect FCA drivers that don't support linking HBA ports */ 6372 if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 6373 mutex_exit(&port->fp_mutex); 6374 mutex_exit(&fctl_port_lock); 6375 return (NULL); 6376 } 6377 6378 list = fctl_local_port_list_add(list, port); 6379 phyPortNum++; 6380 /* Loop through all known ports */ 6381 for (fca_port = fctl_fca_portlist; fca_port != NULL; 6382 fca_port = fca_port->port_next) { 6383 tmpPort = fca_port->port_handle; 6384 if (tmpPort == port) { 6385 /* Skip the port that was passed in as the argument */ 6386 continue; 6387 } 6388 mutex_enter(&tmpPort->fp_mutex); 6389 6390 /* See if this port is on the same HBA FRU (fast check) */ 6391 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 6392 fru->high && 6393 tmpPort->fp_hba_port_attrs.hba_fru_details.low == 6394 fru->low) { 6395 /* Now double check driver (slower check) */ 6396 if (strncmp(port->fp_hba_port_attrs.driver_name, 6397 tmpPort->fp_hba_port_attrs.driver_name, 6398 FCHBA_DRIVER_NAME_LEN) == 0) { 6399 6400 fru = 6401 &tmpPort->fp_hba_port_attrs.hba_fru_details; 6402 /* Check for the matching port_index */ 6403 if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) && 6404 (fru->port_index == port_index)) { 6405 /* Found it! */ 6406 mutex_exit(&tmpPort->fp_mutex); 6407 mutex_exit(&port->fp_mutex); 6408 mutex_exit(&fctl_port_lock); 6409 fctl_local_port_list_free(list); 6410 return (tmpPort); 6411 } 6412 if (tmpPort->fp_npiv_type != FC_NPIV_PORT) { 6413 (void) fctl_local_port_list_add(list, 6414 tmpPort); 6415 phyPortNum++; 6416 } 6417 } /* Else, different FCA driver */ 6418 } /* Else not the same HBA FRU */ 6419 mutex_exit(&tmpPort->fp_mutex); 6420 6421 } 6422 6423 /* scan all physical port on same chip to find virtual port */ 6424 tmpEntry = list; 6425 index = phyPortNum - 1; 6426 virPort = NULL; 6427 while (index < port_index) { 6428 if (tmpEntry == NULL) { 6429 break; 6430 } 6431 if (virPort == NULL) { 6432 phyPort = tmpEntry->port_handle; 6433 virPort = phyPort->fp_port_next; 6434 if (virPort == NULL) { 6435 tmpEntry = tmpEntry->port_next; 6436 continue; 6437 } 6438 } else { 6439 virPort = virPort->fp_port_next; 6440 } 6441 if (virPort == phyPort) { 6442 tmpEntry = tmpEntry->port_next; 6443 virPort = NULL; 6444 } else { 6445 index++; 6446 } 6447 } 6448 mutex_exit(&port->fp_mutex); 6449 mutex_exit(&fctl_port_lock); 6450 6451 fctl_local_port_list_free(list); 6452 if (virPort) { 6453 return (virPort); 6454 } 6455 return (NULL); 6456 } 6457 6458 int 6459 fctl_busy_port(fc_local_port_t *port) 6460 { 6461 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 6462 6463 mutex_enter(&port->fp_mutex); 6464 if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 6465 /* 6466 * If fctl_busy_port() is called before we've registered our 6467 * PM components, we return success. We need to be aware of 6468 * this because the caller will eventually call fctl_idle_port. 6469 * This wouldn't be a problem except that if we have 6470 * registered our PM components in the meantime, we will 6471 * then be idling a component that was never busied. PM 6472 * will be very unhappy if we do this. Thus, we keep 6473 * track of this with port->fp_pm_busy_nocomp. 6474 */ 6475 port->fp_pm_busy_nocomp++; 6476 mutex_exit(&port->fp_mutex); 6477 return (0); 6478 } 6479 port->fp_pm_busy++; 6480 mutex_exit(&port->fp_mutex); 6481 6482 if (pm_busy_component(port->fp_port_dip, 6483 FP_PM_COMPONENT) != DDI_SUCCESS) { 6484 mutex_enter(&port->fp_mutex); 6485 port->fp_pm_busy--; 6486 mutex_exit(&port->fp_mutex); 6487 return (ENXIO); 6488 } 6489 6490 mutex_enter(&port->fp_mutex); 6491 if (port->fp_pm_level == FP_PM_PORT_DOWN) { 6492 mutex_exit(&port->fp_mutex); 6493 if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT, 6494 FP_PM_PORT_UP) != DDI_SUCCESS) { 6495 6496 mutex_enter(&port->fp_mutex); 6497 port->fp_pm_busy--; 6498 mutex_exit(&port->fp_mutex); 6499 6500 (void) pm_idle_component(port->fp_port_dip, 6501 FP_PM_COMPONENT); 6502 return (EIO); 6503 } 6504 return (0); 6505 } 6506 mutex_exit(&port->fp_mutex); 6507 return (0); 6508 } 6509 6510 void 6511 fctl_idle_port(fc_local_port_t *port) 6512 { 6513 ASSERT(!MUTEX_HELD(&port->fp_mutex)); 6514 6515 mutex_enter(&port->fp_mutex); 6516 6517 /* 6518 * If port->fp_pm_busy_nocomp is > 0, that means somebody had 6519 * called fctl_busy_port prior to us registering our PM components. 6520 * In that case, we just decrement fp_pm_busy_nocomp and return. 6521 */ 6522 6523 if (port->fp_pm_busy_nocomp > 0) { 6524 port->fp_pm_busy_nocomp--; 6525 mutex_exit(&port->fp_mutex); 6526 return; 6527 } 6528 6529 port->fp_pm_busy--; 6530 mutex_exit(&port->fp_mutex); 6531 6532 (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT); 6533 } 6534 6535 /* 6536 * Function: fctl_tc_timer 6537 * 6538 * Description: Resets the value of the timed counter. 6539 * 6540 * Arguments: *tc Timed counter 6541 * 6542 * Return Value: Nothing 6543 * 6544 * Context: Kernel context. 6545 */ 6546 static void 6547 fctl_tc_timer(void *arg) 6548 { 6549 timed_counter_t *tc = (timed_counter_t *)arg; 6550 6551 ASSERT(tc != NULL); 6552 ASSERT(tc->sig == tc); 6553 6554 mutex_enter(&tc->mutex); 6555 if (tc->active) { 6556 tc->active = B_FALSE; 6557 tc->counter = 0; 6558 } 6559 mutex_exit(&tc->mutex); 6560 } 6561 6562 /* 6563 * Function: fctl_tc_constructor 6564 * 6565 * Description: Constructs a timed counter. 6566 * 6567 * Arguments: *tc Address where the timed counter will reside. 6568 * max_value Maximum value the counter is allowed to take. 6569 * timer Number of microseconds after which the counter 6570 * will be reset. The timer is started when the 6571 * value of the counter goes from 0 to 1. 6572 * 6573 * Return Value: Nothing 6574 * 6575 * Context: Kernel context. 6576 */ 6577 void 6578 fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer) 6579 { 6580 ASSERT(tc != NULL); 6581 ASSERT(tc->sig != tc); 6582 6583 bzero(tc, sizeof (*tc)); 6584 mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL); 6585 tc->timer = drv_usectohz(timer); 6586 tc->active = B_FALSE; 6587 tc->maxed_out = B_FALSE; 6588 tc->max_value = max_value; 6589 tc->sig = tc; 6590 } 6591 6592 /* 6593 * Function: fctl_tc_destructor 6594 * 6595 * Description: Destroyes a timed counter. 6596 * 6597 * Arguments: *tc Timed counter to destroy. 6598 * 6599 * Return Value: Nothing 6600 * 6601 * Context: Kernel context. 6602 */ 6603 void 6604 fctl_tc_destructor(timed_counter_t *tc) 6605 { 6606 ASSERT(tc != NULL); 6607 ASSERT(tc->sig == tc); 6608 ASSERT(!mutex_owned(&tc->mutex)); 6609 6610 mutex_enter(&tc->mutex); 6611 if (tc->active) { 6612 tc->active = B_FALSE; 6613 mutex_exit(&tc->mutex); 6614 (void) untimeout(tc->tid); 6615 mutex_enter(&tc->mutex); 6616 tc->sig = NULL; 6617 } 6618 mutex_exit(&tc->mutex); 6619 mutex_destroy(&tc->mutex); 6620 } 6621 6622 /* 6623 * Function: fctl_tc_increment 6624 * 6625 * Description: Increments a timed counter 6626 * 6627 * Arguments: *tc Timed counter to increment. 6628 * 6629 * Return Value: B_TRUE Counter reached the max value. 6630 * B_FALSE Counter hasn't reached the max value. 6631 * 6632 * Context: Kernel or interrupt context. 6633 */ 6634 boolean_t 6635 fctl_tc_increment(timed_counter_t *tc) 6636 { 6637 ASSERT(tc != NULL); 6638 ASSERT(tc->sig == tc); 6639 6640 mutex_enter(&tc->mutex); 6641 if (!tc->maxed_out) { 6642 /* Hasn't maxed out yet. */ 6643 ++tc->counter; 6644 if (tc->counter >= tc->max_value) { 6645 /* Just maxed out. */ 6646 tc->maxed_out = B_TRUE; 6647 } 6648 if (!tc->active) { 6649 tc->tid = timeout(fctl_tc_timer, tc, tc->timer); 6650 tc->active = B_TRUE; 6651 } 6652 } 6653 mutex_exit(&tc->mutex); 6654 6655 return (tc->maxed_out); 6656 } 6657 6658 /* 6659 * Function: fctl_tc_reset 6660 * 6661 * Description: Resets a timed counter. The caller of this function has to 6662 * to make sure that while in fctl_tc_reset() fctl_tc_increment() 6663 * is not called. 6664 * 6665 * Arguments: *tc Timed counter to reset. 6666 * 6667 * Return Value: 0 Counter reached the max value. 6668 * Not 0 Counter hasn't reached the max value. 6669 * 6670 * Context: Kernel or interrupt context. 6671 */ 6672 void 6673 fctl_tc_reset(timed_counter_t *tc) 6674 { 6675 ASSERT(tc != NULL); 6676 ASSERT(tc->sig == tc); 6677 6678 mutex_enter(&tc->mutex); 6679 tc->counter = 0; 6680 tc->maxed_out = B_FALSE; 6681 if (tc->active) { 6682 tc->active = B_FALSE; 6683 (void) untimeout(tc->tid); 6684 } 6685 mutex_exit(&tc->mutex); 6686 } 6687 6688 void 6689 fc_ulp_log_device_event(opaque_t port_handle, int type) 6690 { 6691 fc_local_port_t *port = port_handle; 6692 nvlist_t *attr_list; 6693 6694 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 6695 KM_SLEEP) != DDI_SUCCESS) { 6696 return; 6697 } 6698 6699 if (nvlist_add_uint32(attr_list, "instance", 6700 port->fp_instance) != DDI_SUCCESS) { 6701 goto error; 6702 } 6703 6704 if (nvlist_add_byte_array(attr_list, "port-wwn", 6705 port->fp_service_params.nport_ww_name.raw_wwn, 6706 sizeof (la_wwn_t)) != DDI_SUCCESS) { 6707 goto error; 6708 } 6709 6710 (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 6711 (type == FC_ULP_DEVICE_ONLINE) ? 6712 ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE, 6713 attr_list, NULL, DDI_SLEEP); 6714 nvlist_free(attr_list); 6715 return; 6716 6717 error: 6718 nvlist_free(attr_list); 6719 }