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