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