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