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