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