1*7836SJohn.Forte@Sun.COM /* 2*7836SJohn.Forte@Sun.COM * CDDL HEADER START 3*7836SJohn.Forte@Sun.COM * 4*7836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the 5*7836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License"). 6*7836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License. 7*7836SJohn.Forte@Sun.COM * 8*7836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions 11*7836SJohn.Forte@Sun.COM * and limitations under the License. 12*7836SJohn.Forte@Sun.COM * 13*7836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7836SJohn.Forte@Sun.COM * 19*7836SJohn.Forte@Sun.COM * CDDL HEADER END 20*7836SJohn.Forte@Sun.COM */ 21*7836SJohn.Forte@Sun.COM /* 22*7836SJohn.Forte@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*7836SJohn.Forte@Sun.COM * Use is subject to license terms. 24*7836SJohn.Forte@Sun.COM * 25*7836SJohn.Forte@Sun.COM * Fibre channel Transport Library (fctl) 26*7836SJohn.Forte@Sun.COM * 27*7836SJohn.Forte@Sun.COM * Function naming conventions: 28*7836SJohn.Forte@Sun.COM * Functions called from ULPs begin with fc_ulp_ 29*7836SJohn.Forte@Sun.COM * Functions called from FCAs begin with fc_fca_ 30*7836SJohn.Forte@Sun.COM * Internal functions begin with fctl_ 31*7836SJohn.Forte@Sun.COM * 32*7836SJohn.Forte@Sun.COM * Fibre channel packet layout: 33*7836SJohn.Forte@Sun.COM * +---------------------+<--------+ 34*7836SJohn.Forte@Sun.COM * | | | 35*7836SJohn.Forte@Sun.COM * | ULP Packet private | | 36*7836SJohn.Forte@Sun.COM * | | | 37*7836SJohn.Forte@Sun.COM * +---------------------+ | 38*7836SJohn.Forte@Sun.COM * | |---------+ 39*7836SJohn.Forte@Sun.COM * | struct fc_packet |---------+ 40*7836SJohn.Forte@Sun.COM * | | | 41*7836SJohn.Forte@Sun.COM * +---------------------+<--------+ 42*7836SJohn.Forte@Sun.COM * | | 43*7836SJohn.Forte@Sun.COM * | FCA Packet private | 44*7836SJohn.Forte@Sun.COM * | | 45*7836SJohn.Forte@Sun.COM * +---------------------+ 46*7836SJohn.Forte@Sun.COM * 47*7836SJohn.Forte@Sun.COM * So you loved the ascii art ? It's strongly desirable to cache 48*7836SJohn.Forte@Sun.COM * allocate the entire packet in one common place. So we define a set a 49*7836SJohn.Forte@Sun.COM * of rules. In a contiguous block of memory, the top portion of the 50*7836SJohn.Forte@Sun.COM * block points to ulp packet private area, next follows the fc_packet 51*7836SJohn.Forte@Sun.COM * structure used extensively by all the consumers and what follows this 52*7836SJohn.Forte@Sun.COM * is the FCA packet private. Note that given a packet structure, it is 53*7836SJohn.Forte@Sun.COM * possible to get to the ULP and FCA Packet private fields using 54*7836SJohn.Forte@Sun.COM * ulp_private and fca_private fields (which hold pointers) respectively. 55*7836SJohn.Forte@Sun.COM * 56*7836SJohn.Forte@Sun.COM * It should be noted with a grain of salt that ULP Packet private size 57*7836SJohn.Forte@Sun.COM * varies between two different ULP types, So this poses a challenge to 58*7836SJohn.Forte@Sun.COM * compute the correct size of the whole block on a per port basis. The 59*7836SJohn.Forte@Sun.COM * transport layer doesn't have a problem in dealing with FCA packet 60*7836SJohn.Forte@Sun.COM * private sizes as it is the sole manager of ports underneath. Since 61*7836SJohn.Forte@Sun.COM * it's not a good idea to cache allocate different sizes of memory for 62*7836SJohn.Forte@Sun.COM * different ULPs and have the ability to choose from one of these caches 63*7836SJohn.Forte@Sun.COM * based on ULP type during every packet allocation, the transport some 64*7836SJohn.Forte@Sun.COM * what wisely (?) hands off this job of cache allocation to the ULPs 65*7836SJohn.Forte@Sun.COM * themselves. 66*7836SJohn.Forte@Sun.COM * 67*7836SJohn.Forte@Sun.COM * That means FCAs need to make their packet private size known to the 68*7836SJohn.Forte@Sun.COM * transport to pass it up to the ULPs. This is done during 69*7836SJohn.Forte@Sun.COM * fc_fca_attach(). And the transport passes this size up to ULPs during 70*7836SJohn.Forte@Sun.COM * fc_ulp_port_attach() of each ULP. 71*7836SJohn.Forte@Sun.COM * 72*7836SJohn.Forte@Sun.COM * This leaves us with another possible question; How are packets 73*7836SJohn.Forte@Sun.COM * allocated for ELS's started by the transport itself ? Well, the port 74*7836SJohn.Forte@Sun.COM * driver during attach time, cache allocates on a per port basis to 75*7836SJohn.Forte@Sun.COM * handle ELSs too. 76*7836SJohn.Forte@Sun.COM */ 77*7836SJohn.Forte@Sun.COM 78*7836SJohn.Forte@Sun.COM #include <sys/note.h> 79*7836SJohn.Forte@Sun.COM #include <sys/types.h> 80*7836SJohn.Forte@Sun.COM #include <sys/varargs.h> 81*7836SJohn.Forte@Sun.COM #include <sys/param.h> 82*7836SJohn.Forte@Sun.COM #include <sys/errno.h> 83*7836SJohn.Forte@Sun.COM #include <sys/uio.h> 84*7836SJohn.Forte@Sun.COM #include <sys/buf.h> 85*7836SJohn.Forte@Sun.COM #include <sys/modctl.h> 86*7836SJohn.Forte@Sun.COM #include <sys/open.h> 87*7836SJohn.Forte@Sun.COM #include <sys/kmem.h> 88*7836SJohn.Forte@Sun.COM #include <sys/poll.h> 89*7836SJohn.Forte@Sun.COM #include <sys/conf.h> 90*7836SJohn.Forte@Sun.COM #include <sys/cmn_err.h> 91*7836SJohn.Forte@Sun.COM #include <sys/stat.h> 92*7836SJohn.Forte@Sun.COM #include <sys/ddi.h> 93*7836SJohn.Forte@Sun.COM #include <sys/sunddi.h> 94*7836SJohn.Forte@Sun.COM #include <sys/promif.h> 95*7836SJohn.Forte@Sun.COM #include <sys/byteorder.h> 96*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fc.h> 97*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_ulpif.h> 98*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_fcaif.h> 99*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fctl_private.h> 100*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_portif.h> 101*7836SJohn.Forte@Sun.COM 102*7836SJohn.Forte@Sun.COM /* These are referenced by fp.c! */ 103*7836SJohn.Forte@Sun.COM int did_table_size = D_ID_HASH_TABLE_SIZE; 104*7836SJohn.Forte@Sun.COM int pwwn_table_size = PWWN_HASH_TABLE_SIZE; 105*7836SJohn.Forte@Sun.COM 106*7836SJohn.Forte@Sun.COM static fc_ulp_module_t *fctl_ulp_modules; 107*7836SJohn.Forte@Sun.COM static fc_fca_port_t *fctl_fca_portlist; 108*7836SJohn.Forte@Sun.COM static fc_ulp_list_t *fctl_ulp_list; 109*7836SJohn.Forte@Sun.COM 110*7836SJohn.Forte@Sun.COM static char fctl_greeting[] = 111*7836SJohn.Forte@Sun.COM "fctl: %s ULP same type (0x%x) as existing module.\n"; 112*7836SJohn.Forte@Sun.COM 113*7836SJohn.Forte@Sun.COM static char *fctl_undefined = "Undefined"; 114*7836SJohn.Forte@Sun.COM 115*7836SJohn.Forte@Sun.COM /* 116*7836SJohn.Forte@Sun.COM * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field) 117*7836SJohn.Forte@Sun.COM */ 118*7836SJohn.Forte@Sun.COM 119*7836SJohn.Forte@Sun.COM static krwlock_t fctl_ulp_lock; 120*7836SJohn.Forte@Sun.COM 121*7836SJohn.Forte@Sun.COM /* 122*7836SJohn.Forte@Sun.COM * The fctl_mod_ports_lock protects the mod_ports element in the 123*7836SJohn.Forte@Sun.COM * fc_ulp_ports_t structure 124*7836SJohn.Forte@Sun.COM */ 125*7836SJohn.Forte@Sun.COM 126*7836SJohn.Forte@Sun.COM static krwlock_t fctl_mod_ports_lock; 127*7836SJohn.Forte@Sun.COM 128*7836SJohn.Forte@Sun.COM /* 129*7836SJohn.Forte@Sun.COM * fctl_port_lock protects the linked list of local port structures 130*7836SJohn.Forte@Sun.COM * (fctl_fca_portlist). When walking the list, this lock must be obtained 131*7836SJohn.Forte@Sun.COM * prior to any local port locks. 132*7836SJohn.Forte@Sun.COM */ 133*7836SJohn.Forte@Sun.COM 134*7836SJohn.Forte@Sun.COM static kmutex_t fctl_port_lock; 135*7836SJohn.Forte@Sun.COM static kmutex_t fctl_ulp_list_mutex; 136*7836SJohn.Forte@Sun.COM 137*7836SJohn.Forte@Sun.COM static fctl_nwwn_list_t *fctl_nwwn_hash_table; 138*7836SJohn.Forte@Sun.COM static kmutex_t fctl_nwwn_hash_mutex; 139*7836SJohn.Forte@Sun.COM int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE; 140*7836SJohn.Forte@Sun.COM 141*7836SJohn.Forte@Sun.COM #if !defined(lint) 142*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table)) 143*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list)) 144*7836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next)) 145*7836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports 146*7836SJohn.Forte@Sun.COM ulp_ports::port_handle)) 147*7836SJohn.Forte@Sun.COM _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info)) 148*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec 149*7836SJohn.Forte@Sun.COM ulp_ports::port_dstate)) 150*7836SJohn.Forte@Sun.COM #endif /* lint */ 151*7836SJohn.Forte@Sun.COM 152*7836SJohn.Forte@Sun.COM #define FCTL_VERSION "1.69" 153*7836SJohn.Forte@Sun.COM #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION 154*7836SJohn.Forte@Sun.COM 155*7836SJohn.Forte@Sun.COM 156*7836SJohn.Forte@Sun.COM char *fctl_version = FCTL_NAME_VERSION; 157*7836SJohn.Forte@Sun.COM 158*7836SJohn.Forte@Sun.COM extern struct mod_ops mod_miscops; 159*7836SJohn.Forte@Sun.COM 160*7836SJohn.Forte@Sun.COM static struct modlmisc modlmisc = { 161*7836SJohn.Forte@Sun.COM &mod_miscops, /* type of module */ 162*7836SJohn.Forte@Sun.COM FCTL_NAME_VERSION /* Module name */ 163*7836SJohn.Forte@Sun.COM }; 164*7836SJohn.Forte@Sun.COM 165*7836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = { 166*7836SJohn.Forte@Sun.COM MODREV_1, (void *)&modlmisc, NULL 167*7836SJohn.Forte@Sun.COM }; 168*7836SJohn.Forte@Sun.COM 169*7836SJohn.Forte@Sun.COM static struct bus_ops fctl_fca_busops = { 170*7836SJohn.Forte@Sun.COM BUSO_REV, 171*7836SJohn.Forte@Sun.COM nullbusmap, /* bus_map */ 172*7836SJohn.Forte@Sun.COM NULL, /* bus_get_intrspec */ 173*7836SJohn.Forte@Sun.COM NULL, /* bus_add_intrspec */ 174*7836SJohn.Forte@Sun.COM NULL, /* bus_remove_intrspec */ 175*7836SJohn.Forte@Sun.COM i_ddi_map_fault, /* bus_map_fault */ 176*7836SJohn.Forte@Sun.COM ddi_dma_map, /* bus_dma_map */ 177*7836SJohn.Forte@Sun.COM ddi_dma_allochdl, /* bus_dma_allochdl */ 178*7836SJohn.Forte@Sun.COM ddi_dma_freehdl, /* bus_dma_freehdl */ 179*7836SJohn.Forte@Sun.COM ddi_dma_bindhdl, /* bus_dma_bindhdl */ 180*7836SJohn.Forte@Sun.COM ddi_dma_unbindhdl, /* bus_unbindhdl */ 181*7836SJohn.Forte@Sun.COM ddi_dma_flush, /* bus_dma_flush */ 182*7836SJohn.Forte@Sun.COM ddi_dma_win, /* bus_dma_win */ 183*7836SJohn.Forte@Sun.COM ddi_dma_mctl, /* bus_dma_ctl */ 184*7836SJohn.Forte@Sun.COM fctl_fca_bus_ctl, /* bus_ctl */ 185*7836SJohn.Forte@Sun.COM ddi_bus_prop_op, /* bus_prop_op */ 186*7836SJohn.Forte@Sun.COM NULL, /* bus_get_eventcookie */ 187*7836SJohn.Forte@Sun.COM NULL, /* bus_add_eventcall */ 188*7836SJohn.Forte@Sun.COM NULL, /* bus_remove_event */ 189*7836SJohn.Forte@Sun.COM NULL, /* bus_post_event */ 190*7836SJohn.Forte@Sun.COM NULL, /* bus_intr_ctl */ 191*7836SJohn.Forte@Sun.COM NULL, /* bus_config */ 192*7836SJohn.Forte@Sun.COM NULL, /* bus_unconfig */ 193*7836SJohn.Forte@Sun.COM NULL, /* bus_fm_init */ 194*7836SJohn.Forte@Sun.COM NULL, /* bus_fm_fini */ 195*7836SJohn.Forte@Sun.COM NULL, /* bus_fm_access_enter */ 196*7836SJohn.Forte@Sun.COM NULL, /* bus_fm_access_exit */ 197*7836SJohn.Forte@Sun.COM NULL, /* bus_power */ 198*7836SJohn.Forte@Sun.COM NULL 199*7836SJohn.Forte@Sun.COM }; 200*7836SJohn.Forte@Sun.COM 201*7836SJohn.Forte@Sun.COM struct kmem_cache *fctl_job_cache; 202*7836SJohn.Forte@Sun.COM 203*7836SJohn.Forte@Sun.COM static fc_errmap_t fc_errlist [] = { 204*7836SJohn.Forte@Sun.COM { FC_FAILURE, "Operation failed" }, 205*7836SJohn.Forte@Sun.COM { FC_SUCCESS, "Operation success" }, 206*7836SJohn.Forte@Sun.COM { FC_CAP_ERROR, "Capability error" }, 207*7836SJohn.Forte@Sun.COM { FC_CAP_FOUND, "Capability found" }, 208*7836SJohn.Forte@Sun.COM { FC_CAP_SETTABLE, "Capability settable" }, 209*7836SJohn.Forte@Sun.COM { FC_UNBOUND, "Port not bound" }, 210*7836SJohn.Forte@Sun.COM { FC_NOMEM, "No memory" }, 211*7836SJohn.Forte@Sun.COM { FC_BADPACKET, "Bad packet" }, 212*7836SJohn.Forte@Sun.COM { FC_OFFLINE, "Port offline" }, 213*7836SJohn.Forte@Sun.COM { FC_OLDPORT, "Old Port" }, 214*7836SJohn.Forte@Sun.COM { FC_NO_MAP, "No map available" }, 215*7836SJohn.Forte@Sun.COM { FC_TRANSPORT_ERROR, "Transport error" }, 216*7836SJohn.Forte@Sun.COM { FC_ELS_FREJECT, "ELS Frejected" }, 217*7836SJohn.Forte@Sun.COM { FC_ELS_PREJECT, "ELS PRejected" }, 218*7836SJohn.Forte@Sun.COM { FC_ELS_BAD, "Bad ELS request" }, 219*7836SJohn.Forte@Sun.COM { FC_ELS_MALFORMED, "Malformed ELS request" }, 220*7836SJohn.Forte@Sun.COM { FC_TOOMANY, "Too many commands" }, 221*7836SJohn.Forte@Sun.COM { FC_UB_BADTOKEN, "Bad Unsolicited buffer token" }, 222*7836SJohn.Forte@Sun.COM { FC_UB_ERROR, "Unsolicited buffer error" }, 223*7836SJohn.Forte@Sun.COM { FC_UB_BUSY, "Unsolicited buffer busy" }, 224*7836SJohn.Forte@Sun.COM { FC_BADULP, "Bad ULP" }, 225*7836SJohn.Forte@Sun.COM { FC_BADTYPE, "Bad Type" }, 226*7836SJohn.Forte@Sun.COM { FC_UNCLAIMED, "Not Claimed" }, 227*7836SJohn.Forte@Sun.COM { FC_ULP_SAMEMODULE, "Same ULP Module" }, 228*7836SJohn.Forte@Sun.COM { FC_ULP_SAMETYPE, "Same ULP Type" }, 229*7836SJohn.Forte@Sun.COM { FC_ABORTED, "Command Aborted" }, 230*7836SJohn.Forte@Sun.COM { FC_ABORT_FAILED, "Abort Failed" }, 231*7836SJohn.Forte@Sun.COM { FC_BADEXCHANGE, "Bad Exchange" }, 232*7836SJohn.Forte@Sun.COM { FC_BADWWN, "Bad World Wide Name" }, 233*7836SJohn.Forte@Sun.COM { FC_BADDEV, "Bad Device" }, 234*7836SJohn.Forte@Sun.COM { FC_BADCMD, "Bad Command" }, 235*7836SJohn.Forte@Sun.COM { FC_BADOBJECT, "Bad Object" }, 236*7836SJohn.Forte@Sun.COM { FC_BADPORT, "Bad Port" }, 237*7836SJohn.Forte@Sun.COM { FC_NOTTHISPORT, "Not on this Port" }, 238*7836SJohn.Forte@Sun.COM { FC_PREJECT, "Operation Prejected" }, 239*7836SJohn.Forte@Sun.COM { FC_FREJECT, "Operation Frejected" }, 240*7836SJohn.Forte@Sun.COM { FC_PBUSY, "Operation Pbusyed" }, 241*7836SJohn.Forte@Sun.COM { FC_FBUSY, "Operation Fbusyed" }, 242*7836SJohn.Forte@Sun.COM { FC_ALREADY, "Already done" }, 243*7836SJohn.Forte@Sun.COM { FC_LOGINREQ, "PLOGI Required" }, 244*7836SJohn.Forte@Sun.COM { FC_RESETFAIL, "Reset operation failed" }, 245*7836SJohn.Forte@Sun.COM { FC_INVALID_REQUEST, "Invalid Request" }, 246*7836SJohn.Forte@Sun.COM { FC_OUTOFBOUNDS, "Out of Bounds" }, 247*7836SJohn.Forte@Sun.COM { FC_TRAN_BUSY, "Command transport Busy" }, 248*7836SJohn.Forte@Sun.COM { FC_STATEC_BUSY, "State change Busy" }, 249*7836SJohn.Forte@Sun.COM { FC_DEVICE_BUSY, "Port driver is working on this device" } 250*7836SJohn.Forte@Sun.COM }; 251*7836SJohn.Forte@Sun.COM 252*7836SJohn.Forte@Sun.COM fc_pkt_reason_t remote_stop_reasons [] = { 253*7836SJohn.Forte@Sun.COM { FC_REASON_ABTS, "Abort Sequence" }, 254*7836SJohn.Forte@Sun.COM { FC_REASON_ABTX, "Abort Exchange" }, 255*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 256*7836SJohn.Forte@Sun.COM }; 257*7836SJohn.Forte@Sun.COM 258*7836SJohn.Forte@Sun.COM fc_pkt_reason_t general_reasons [] = { 259*7836SJohn.Forte@Sun.COM { FC_REASON_HW_ERROR, "Hardware Error" }, 260*7836SJohn.Forte@Sun.COM { FC_REASON_SEQ_TIMEOUT, "Sequence Timeout" }, 261*7836SJohn.Forte@Sun.COM { FC_REASON_ABORTED, "Aborted" }, 262*7836SJohn.Forte@Sun.COM { FC_REASON_ABORT_FAILED, "Abort Failed" }, 263*7836SJohn.Forte@Sun.COM { FC_REASON_NO_CONNECTION, "No Connection" }, 264*7836SJohn.Forte@Sun.COM { FC_REASON_XCHG_DROPPED, "Exchange Dropped" }, 265*7836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_FRAME, "Illegal Frame" }, 266*7836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_LENGTH, "Illegal Length" }, 267*7836SJohn.Forte@Sun.COM { FC_REASON_UNSUPPORTED, "Unsuported" }, 268*7836SJohn.Forte@Sun.COM { FC_REASON_RX_BUF_TIMEOUT, "Receive Buffer Timeout" }, 269*7836SJohn.Forte@Sun.COM { FC_REASON_FCAL_OPN_FAIL, "FC AL Open Failed" }, 270*7836SJohn.Forte@Sun.COM { FC_REASON_OVERRUN, "Over run" }, 271*7836SJohn.Forte@Sun.COM { FC_REASON_QFULL, "Queue Full" }, 272*7836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_REQ, "Illegal Request", }, 273*7836SJohn.Forte@Sun.COM { FC_REASON_PKT_BUSY, "Busy" }, 274*7836SJohn.Forte@Sun.COM { FC_REASON_OFFLINE, "Offline" }, 275*7836SJohn.Forte@Sun.COM { FC_REASON_BAD_XID, "Bad Exchange Id" }, 276*7836SJohn.Forte@Sun.COM { FC_REASON_XCHG_BSY, "Exchange Busy" }, 277*7836SJohn.Forte@Sun.COM { FC_REASON_NOMEM, "No Memory" }, 278*7836SJohn.Forte@Sun.COM { FC_REASON_BAD_SID, "Bad S_ID" }, 279*7836SJohn.Forte@Sun.COM { FC_REASON_NO_SEQ_INIT, "No Sequence Initiative" }, 280*7836SJohn.Forte@Sun.COM { FC_REASON_DIAG_BUSY, "Diagnostic Busy" }, 281*7836SJohn.Forte@Sun.COM { FC_REASON_DMA_ERROR, "DMA Error" }, 282*7836SJohn.Forte@Sun.COM { FC_REASON_CRC_ERROR, "CRC Error" }, 283*7836SJohn.Forte@Sun.COM { FC_REASON_ABORT_TIMEOUT, "Abort Timeout" }, 284*7836SJohn.Forte@Sun.COM { FC_REASON_FCA_UNIQUE, "FCA Unique" }, 285*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 286*7836SJohn.Forte@Sun.COM }; 287*7836SJohn.Forte@Sun.COM 288*7836SJohn.Forte@Sun.COM fc_pkt_reason_t rjt_reasons [] = { 289*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_D_ID, "Invalid D_ID" }, 290*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_S_ID, "Invalid S_ID" }, 291*7836SJohn.Forte@Sun.COM { FC_REASON_TEMP_UNAVAILABLE, "Temporarily Unavailable" }, 292*7836SJohn.Forte@Sun.COM { FC_REASON_PERM_UNAVAILABLE, "Permamnently Unavailable" }, 293*7836SJohn.Forte@Sun.COM { FC_REASON_CLASS_NOT_SUPP, "Class Not Supported", }, 294*7836SJohn.Forte@Sun.COM { FC_REASON_DELIMTER_USAGE_ERROR, 295*7836SJohn.Forte@Sun.COM "Delimeter Usage Error" }, 296*7836SJohn.Forte@Sun.COM { FC_REASON_TYPE_NOT_SUPP, "Type Not Supported" }, 297*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_LINK_CTRL, "Invalid Link Control" }, 298*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_R_CTL, "Invalid R_CTL" }, 299*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_F_CTL, "Invalid F_CTL" }, 300*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_OX_ID, "Invalid OX_ID" }, 301*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_RX_ID, "Invalid RX_ID" }, 302*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_SEQ_ID, "Invalid Sequence ID" }, 303*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_DF_CTL, "Invalid DF_CTL" }, 304*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_SEQ_CNT, "Invalid Sequence count" }, 305*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_PARAM, "Invalid Parameter" }, 306*7836SJohn.Forte@Sun.COM { FC_REASON_EXCH_ERROR, "Exchange Error" }, 307*7836SJohn.Forte@Sun.COM { FC_REASON_PROTOCOL_ERROR, "Protocol Error" }, 308*7836SJohn.Forte@Sun.COM { FC_REASON_INCORRECT_LENGTH, "Incorrect Length" }, 309*7836SJohn.Forte@Sun.COM { FC_REASON_UNEXPECTED_ACK, "Unexpected Ack" }, 310*7836SJohn.Forte@Sun.COM { FC_REASON_UNEXPECTED_LR, "Unexpected Link reset" }, 311*7836SJohn.Forte@Sun.COM { FC_REASON_LOGIN_REQUIRED, "Login Required" }, 312*7836SJohn.Forte@Sun.COM { FC_REASON_EXCESSIVE_SEQS, "Excessive Sequences" 313*7836SJohn.Forte@Sun.COM " Attempted" }, 314*7836SJohn.Forte@Sun.COM { FC_REASON_EXCH_UNABLE, "Exchange incapable" }, 315*7836SJohn.Forte@Sun.COM { FC_REASON_ESH_NOT_SUPP, "Expiration Security Header " 316*7836SJohn.Forte@Sun.COM "Not Supported" }, 317*7836SJohn.Forte@Sun.COM { FC_REASON_NO_FABRIC_PATH, "No Fabric Path" }, 318*7836SJohn.Forte@Sun.COM { FC_REASON_VENDOR_UNIQUE, "Vendor Unique" }, 319*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 320*7836SJohn.Forte@Sun.COM }; 321*7836SJohn.Forte@Sun.COM 322*7836SJohn.Forte@Sun.COM fc_pkt_reason_t n_port_busy_reasons [] = { 323*7836SJohn.Forte@Sun.COM { FC_REASON_PHYSICAL_BUSY, "Physical Busy" }, 324*7836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_RESOURCE_BSY, "Resource Busy" }, 325*7836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_VENDOR_UNIQUE, "Vendor Unique" }, 326*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 327*7836SJohn.Forte@Sun.COM }; 328*7836SJohn.Forte@Sun.COM 329*7836SJohn.Forte@Sun.COM fc_pkt_reason_t f_busy_reasons [] = { 330*7836SJohn.Forte@Sun.COM { FC_REASON_FABRIC_BSY, "Fabric Busy" }, 331*7836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_BSY, "N_Port Busy" }, 332*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 333*7836SJohn.Forte@Sun.COM }; 334*7836SJohn.Forte@Sun.COM 335*7836SJohn.Forte@Sun.COM fc_pkt_reason_t ls_ba_rjt_reasons [] = { 336*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID_LA_CODE, "Invalid Link Application Code" }, 337*7836SJohn.Forte@Sun.COM { FC_REASON_LOGICAL_ERROR, "Logical Error" }, 338*7836SJohn.Forte@Sun.COM { FC_REASON_LOGICAL_BSY, "Logical Busy" }, 339*7836SJohn.Forte@Sun.COM { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject" }, 340*7836SJohn.Forte@Sun.COM { FC_REASON_CMD_UNABLE, "Unable to Perform Command" }, 341*7836SJohn.Forte@Sun.COM { FC_REASON_CMD_UNSUPPORTED, "Unsupported Command" }, 342*7836SJohn.Forte@Sun.COM { FC_REASON_VU_RJT, "Vendor Unique" }, 343*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 344*7836SJohn.Forte@Sun.COM }; 345*7836SJohn.Forte@Sun.COM 346*7836SJohn.Forte@Sun.COM fc_pkt_reason_t fs_rjt_reasons [] = { 347*7836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_CMD, "Invalid Command" }, 348*7836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_VER, "Invalid Version" }, 349*7836SJohn.Forte@Sun.COM { FC_REASON_FS_LOGICAL_ERR, "Logical Error" }, 350*7836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_IUSIZE, "Invalid IU Size" }, 351*7836SJohn.Forte@Sun.COM { FC_REASON_FS_LOGICAL_BUSY, "Logical Busy" }, 352*7836SJohn.Forte@Sun.COM { FC_REASON_FS_PROTOCOL_ERR, "Protocol Error" }, 353*7836SJohn.Forte@Sun.COM { FC_REASON_FS_CMD_UNABLE, "Unable to Perform Command" }, 354*7836SJohn.Forte@Sun.COM { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command" }, 355*7836SJohn.Forte@Sun.COM { FC_REASON_FS_VENDOR_UNIQUE, "Vendor Unique" }, 356*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 357*7836SJohn.Forte@Sun.COM }; 358*7836SJohn.Forte@Sun.COM 359*7836SJohn.Forte@Sun.COM fc_pkt_action_t n_port_busy_actions [] = { 360*7836SJohn.Forte@Sun.COM { FC_ACTION_SEQ_TERM_RETRY, "Retry terminated Sequence" }, 361*7836SJohn.Forte@Sun.COM { FC_ACTION_SEQ_ACTIVE_RETRY, "Retry Active Sequence" }, 362*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 363*7836SJohn.Forte@Sun.COM }; 364*7836SJohn.Forte@Sun.COM 365*7836SJohn.Forte@Sun.COM fc_pkt_action_t rjt_timeout_actions [] = { 366*7836SJohn.Forte@Sun.COM { FC_ACTION_RETRYABLE, "Retryable" }, 367*7836SJohn.Forte@Sun.COM { FC_ACTION_NON_RETRYABLE, "Non Retryable" }, 368*7836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 369*7836SJohn.Forte@Sun.COM }; 370*7836SJohn.Forte@Sun.COM 371*7836SJohn.Forte@Sun.COM fc_pkt_expln_t ba_rjt_explns [] = { 372*7836SJohn.Forte@Sun.COM { FC_EXPLN_NONE, "No Explanation" }, 373*7836SJohn.Forte@Sun.COM { FC_EXPLN_INVALID_OX_RX_ID, "Invalid X_ID" }, 374*7836SJohn.Forte@Sun.COM { FC_EXPLN_SEQ_ABORTED, "Sequence Aborted" }, 375*7836SJohn.Forte@Sun.COM { FC_EXPLN_INVALID, NULL } 376*7836SJohn.Forte@Sun.COM }; 377*7836SJohn.Forte@Sun.COM 378*7836SJohn.Forte@Sun.COM fc_pkt_error_t fc_pkt_errlist[] = { 379*7836SJohn.Forte@Sun.COM { 380*7836SJohn.Forte@Sun.COM FC_PKT_SUCCESS, 381*7836SJohn.Forte@Sun.COM "Operation Success", 382*7836SJohn.Forte@Sun.COM NULL, 383*7836SJohn.Forte@Sun.COM NULL, 384*7836SJohn.Forte@Sun.COM NULL 385*7836SJohn.Forte@Sun.COM }, 386*7836SJohn.Forte@Sun.COM { FC_PKT_REMOTE_STOP, 387*7836SJohn.Forte@Sun.COM "Remote Stop", 388*7836SJohn.Forte@Sun.COM remote_stop_reasons, 389*7836SJohn.Forte@Sun.COM NULL, 390*7836SJohn.Forte@Sun.COM NULL 391*7836SJohn.Forte@Sun.COM }, 392*7836SJohn.Forte@Sun.COM { 393*7836SJohn.Forte@Sun.COM FC_PKT_LOCAL_RJT, 394*7836SJohn.Forte@Sun.COM "Local Reject", 395*7836SJohn.Forte@Sun.COM general_reasons, 396*7836SJohn.Forte@Sun.COM rjt_timeout_actions, 397*7836SJohn.Forte@Sun.COM NULL 398*7836SJohn.Forte@Sun.COM }, 399*7836SJohn.Forte@Sun.COM { 400*7836SJohn.Forte@Sun.COM FC_PKT_NPORT_RJT, 401*7836SJohn.Forte@Sun.COM "N_Port Reject", 402*7836SJohn.Forte@Sun.COM rjt_reasons, 403*7836SJohn.Forte@Sun.COM rjt_timeout_actions, 404*7836SJohn.Forte@Sun.COM NULL 405*7836SJohn.Forte@Sun.COM }, 406*7836SJohn.Forte@Sun.COM { 407*7836SJohn.Forte@Sun.COM FC_PKT_FABRIC_RJT, 408*7836SJohn.Forte@Sun.COM "Fabric Reject", 409*7836SJohn.Forte@Sun.COM rjt_reasons, 410*7836SJohn.Forte@Sun.COM rjt_timeout_actions, 411*7836SJohn.Forte@Sun.COM NULL 412*7836SJohn.Forte@Sun.COM }, 413*7836SJohn.Forte@Sun.COM { 414*7836SJohn.Forte@Sun.COM FC_PKT_LOCAL_BSY, 415*7836SJohn.Forte@Sun.COM "Local Busy", 416*7836SJohn.Forte@Sun.COM general_reasons, 417*7836SJohn.Forte@Sun.COM NULL, 418*7836SJohn.Forte@Sun.COM NULL, 419*7836SJohn.Forte@Sun.COM }, 420*7836SJohn.Forte@Sun.COM { 421*7836SJohn.Forte@Sun.COM FC_PKT_TRAN_BSY, 422*7836SJohn.Forte@Sun.COM "Transport Busy", 423*7836SJohn.Forte@Sun.COM general_reasons, 424*7836SJohn.Forte@Sun.COM NULL, 425*7836SJohn.Forte@Sun.COM NULL, 426*7836SJohn.Forte@Sun.COM }, 427*7836SJohn.Forte@Sun.COM { 428*7836SJohn.Forte@Sun.COM FC_PKT_NPORT_BSY, 429*7836SJohn.Forte@Sun.COM "N_Port Busy", 430*7836SJohn.Forte@Sun.COM n_port_busy_reasons, 431*7836SJohn.Forte@Sun.COM n_port_busy_actions, 432*7836SJohn.Forte@Sun.COM NULL 433*7836SJohn.Forte@Sun.COM }, 434*7836SJohn.Forte@Sun.COM { 435*7836SJohn.Forte@Sun.COM FC_PKT_FABRIC_BSY, 436*7836SJohn.Forte@Sun.COM "Fabric Busy", 437*7836SJohn.Forte@Sun.COM f_busy_reasons, 438*7836SJohn.Forte@Sun.COM NULL, 439*7836SJohn.Forte@Sun.COM NULL, 440*7836SJohn.Forte@Sun.COM }, 441*7836SJohn.Forte@Sun.COM { 442*7836SJohn.Forte@Sun.COM FC_PKT_LS_RJT, 443*7836SJohn.Forte@Sun.COM "Link Service Reject", 444*7836SJohn.Forte@Sun.COM ls_ba_rjt_reasons, 445*7836SJohn.Forte@Sun.COM NULL, 446*7836SJohn.Forte@Sun.COM NULL, 447*7836SJohn.Forte@Sun.COM }, 448*7836SJohn.Forte@Sun.COM { 449*7836SJohn.Forte@Sun.COM FC_PKT_BA_RJT, 450*7836SJohn.Forte@Sun.COM "Basic Reject", 451*7836SJohn.Forte@Sun.COM ls_ba_rjt_reasons, 452*7836SJohn.Forte@Sun.COM NULL, 453*7836SJohn.Forte@Sun.COM ba_rjt_explns, 454*7836SJohn.Forte@Sun.COM }, 455*7836SJohn.Forte@Sun.COM { 456*7836SJohn.Forte@Sun.COM FC_PKT_TIMEOUT, 457*7836SJohn.Forte@Sun.COM "Timeout", 458*7836SJohn.Forte@Sun.COM general_reasons, 459*7836SJohn.Forte@Sun.COM rjt_timeout_actions, 460*7836SJohn.Forte@Sun.COM NULL 461*7836SJohn.Forte@Sun.COM }, 462*7836SJohn.Forte@Sun.COM { 463*7836SJohn.Forte@Sun.COM FC_PKT_FS_RJT, 464*7836SJohn.Forte@Sun.COM "Fabric Switch Reject", 465*7836SJohn.Forte@Sun.COM fs_rjt_reasons, 466*7836SJohn.Forte@Sun.COM NULL, 467*7836SJohn.Forte@Sun.COM NULL 468*7836SJohn.Forte@Sun.COM }, 469*7836SJohn.Forte@Sun.COM { 470*7836SJohn.Forte@Sun.COM FC_PKT_TRAN_ERROR, 471*7836SJohn.Forte@Sun.COM "Packet Transport error", 472*7836SJohn.Forte@Sun.COM general_reasons, 473*7836SJohn.Forte@Sun.COM NULL, 474*7836SJohn.Forte@Sun.COM NULL 475*7836SJohn.Forte@Sun.COM }, 476*7836SJohn.Forte@Sun.COM { 477*7836SJohn.Forte@Sun.COM FC_PKT_FAILURE, 478*7836SJohn.Forte@Sun.COM "Packet Failure", 479*7836SJohn.Forte@Sun.COM general_reasons, 480*7836SJohn.Forte@Sun.COM NULL, 481*7836SJohn.Forte@Sun.COM NULL 482*7836SJohn.Forte@Sun.COM }, 483*7836SJohn.Forte@Sun.COM { 484*7836SJohn.Forte@Sun.COM FC_PKT_PORT_OFFLINE, 485*7836SJohn.Forte@Sun.COM "Port Offline", 486*7836SJohn.Forte@Sun.COM NULL, 487*7836SJohn.Forte@Sun.COM NULL, 488*7836SJohn.Forte@Sun.COM NULL 489*7836SJohn.Forte@Sun.COM }, 490*7836SJohn.Forte@Sun.COM { 491*7836SJohn.Forte@Sun.COM FC_PKT_ELS_IN_PROGRESS, 492*7836SJohn.Forte@Sun.COM "ELS is in Progress", 493*7836SJohn.Forte@Sun.COM NULL, 494*7836SJohn.Forte@Sun.COM NULL, 495*7836SJohn.Forte@Sun.COM NULL 496*7836SJohn.Forte@Sun.COM } 497*7836SJohn.Forte@Sun.COM }; 498*7836SJohn.Forte@Sun.COM 499*7836SJohn.Forte@Sun.COM int 500*7836SJohn.Forte@Sun.COM _init() 501*7836SJohn.Forte@Sun.COM { 502*7836SJohn.Forte@Sun.COM int rval; 503*7836SJohn.Forte@Sun.COM 504*7836SJohn.Forte@Sun.COM rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL); 505*7836SJohn.Forte@Sun.COM rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL); 506*7836SJohn.Forte@Sun.COM mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL); 507*7836SJohn.Forte@Sun.COM mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL); 508*7836SJohn.Forte@Sun.COM 509*7836SJohn.Forte@Sun.COM fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) * 510*7836SJohn.Forte@Sun.COM fctl_nwwn_table_size, KM_SLEEP); 511*7836SJohn.Forte@Sun.COM 512*7836SJohn.Forte@Sun.COM fctl_ulp_modules = NULL; 513*7836SJohn.Forte@Sun.COM fctl_fca_portlist = NULL; 514*7836SJohn.Forte@Sun.COM 515*7836SJohn.Forte@Sun.COM fctl_job_cache = kmem_cache_create("fctl_cache", 516*7836SJohn.Forte@Sun.COM sizeof (job_request_t), 8, fctl_cache_constructor, 517*7836SJohn.Forte@Sun.COM fctl_cache_destructor, NULL, NULL, NULL, 0); 518*7836SJohn.Forte@Sun.COM 519*7836SJohn.Forte@Sun.COM if (fctl_job_cache == NULL) { 520*7836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 521*7836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 522*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 523*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 524*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 525*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 526*7836SJohn.Forte@Sun.COM return (ENOMEM); 527*7836SJohn.Forte@Sun.COM } 528*7836SJohn.Forte@Sun.COM 529*7836SJohn.Forte@Sun.COM if ((rval = mod_install(&modlinkage)) != 0) { 530*7836SJohn.Forte@Sun.COM kmem_cache_destroy(fctl_job_cache); 531*7836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 532*7836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 533*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 534*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 535*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 536*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 537*7836SJohn.Forte@Sun.COM } 538*7836SJohn.Forte@Sun.COM 539*7836SJohn.Forte@Sun.COM return (rval); 540*7836SJohn.Forte@Sun.COM } 541*7836SJohn.Forte@Sun.COM 542*7836SJohn.Forte@Sun.COM 543*7836SJohn.Forte@Sun.COM /* 544*7836SJohn.Forte@Sun.COM * The mod_uninstall code doesn't call _fini when 545*7836SJohn.Forte@Sun.COM * there is living dependent module on fctl. So 546*7836SJohn.Forte@Sun.COM * there is no need to be extra careful here ? 547*7836SJohn.Forte@Sun.COM */ 548*7836SJohn.Forte@Sun.COM int 549*7836SJohn.Forte@Sun.COM _fini() 550*7836SJohn.Forte@Sun.COM { 551*7836SJohn.Forte@Sun.COM int rval; 552*7836SJohn.Forte@Sun.COM 553*7836SJohn.Forte@Sun.COM if ((rval = mod_remove(&modlinkage)) != 0) { 554*7836SJohn.Forte@Sun.COM return (rval); 555*7836SJohn.Forte@Sun.COM } 556*7836SJohn.Forte@Sun.COM 557*7836SJohn.Forte@Sun.COM kmem_cache_destroy(fctl_job_cache); 558*7836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 559*7836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 560*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 561*7836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 562*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 563*7836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 564*7836SJohn.Forte@Sun.COM 565*7836SJohn.Forte@Sun.COM return (rval); 566*7836SJohn.Forte@Sun.COM } 567*7836SJohn.Forte@Sun.COM 568*7836SJohn.Forte@Sun.COM 569*7836SJohn.Forte@Sun.COM int 570*7836SJohn.Forte@Sun.COM _info(struct modinfo *modinfo_p) 571*7836SJohn.Forte@Sun.COM { 572*7836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfo_p)); 573*7836SJohn.Forte@Sun.COM } 574*7836SJohn.Forte@Sun.COM 575*7836SJohn.Forte@Sun.COM 576*7836SJohn.Forte@Sun.COM /* ARGSUSED */ 577*7836SJohn.Forte@Sun.COM static int 578*7836SJohn.Forte@Sun.COM fctl_cache_constructor(void *buf, void *cdarg, int kmflag) 579*7836SJohn.Forte@Sun.COM { 580*7836SJohn.Forte@Sun.COM job_request_t *job = (job_request_t *)buf; 581*7836SJohn.Forte@Sun.COM 582*7836SJohn.Forte@Sun.COM mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL); 583*7836SJohn.Forte@Sun.COM sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL); 584*7836SJohn.Forte@Sun.COM sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL); 585*7836SJohn.Forte@Sun.COM 586*7836SJohn.Forte@Sun.COM return (0); 587*7836SJohn.Forte@Sun.COM } 588*7836SJohn.Forte@Sun.COM 589*7836SJohn.Forte@Sun.COM 590*7836SJohn.Forte@Sun.COM /* ARGSUSED */ 591*7836SJohn.Forte@Sun.COM static void 592*7836SJohn.Forte@Sun.COM fctl_cache_destructor(void *buf, void *cdarg) 593*7836SJohn.Forte@Sun.COM { 594*7836SJohn.Forte@Sun.COM job_request_t *job = (job_request_t *)buf; 595*7836SJohn.Forte@Sun.COM 596*7836SJohn.Forte@Sun.COM sema_destroy(&job->job_fctl_sema); 597*7836SJohn.Forte@Sun.COM sema_destroy(&job->job_port_sema); 598*7836SJohn.Forte@Sun.COM mutex_destroy(&job->job_mutex); 599*7836SJohn.Forte@Sun.COM } 600*7836SJohn.Forte@Sun.COM 601*7836SJohn.Forte@Sun.COM 602*7836SJohn.Forte@Sun.COM /* 603*7836SJohn.Forte@Sun.COM * fc_ulp_add: 604*7836SJohn.Forte@Sun.COM * Add a ULP module 605*7836SJohn.Forte@Sun.COM * 606*7836SJohn.Forte@Sun.COM * Return Codes: 607*7836SJohn.Forte@Sun.COM * FC_ULP_SAMEMODULE 608*7836SJohn.Forte@Sun.COM * FC_SUCCESS 609*7836SJohn.Forte@Sun.COM * FC_FAILURE 610*7836SJohn.Forte@Sun.COM * 611*7836SJohn.Forte@Sun.COM * fc_ulp_add prints a warning message if there is already a 612*7836SJohn.Forte@Sun.COM * similar ULP type attached and this is unlikely to change as 613*7836SJohn.Forte@Sun.COM * we trudge along. Further, this function returns a failure 614*7836SJohn.Forte@Sun.COM * code if the same module attempts to add more than once for 615*7836SJohn.Forte@Sun.COM * the same FC-4 type. 616*7836SJohn.Forte@Sun.COM */ 617*7836SJohn.Forte@Sun.COM int 618*7836SJohn.Forte@Sun.COM fc_ulp_add(fc_ulp_modinfo_t *ulp_info) 619*7836SJohn.Forte@Sun.COM { 620*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 621*7836SJohn.Forte@Sun.COM fc_ulp_module_t *prev; 622*7836SJohn.Forte@Sun.COM job_request_t *job; 623*7836SJohn.Forte@Sun.COM fc_ulp_list_t *new; 624*7836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 625*7836SJohn.Forte@Sun.COM int ntry = 0; 626*7836SJohn.Forte@Sun.COM 627*7836SJohn.Forte@Sun.COM ASSERT(ulp_info != NULL); 628*7836SJohn.Forte@Sun.COM 629*7836SJohn.Forte@Sun.COM /* 630*7836SJohn.Forte@Sun.COM * Make sure ulp_rev matches fctl version. 631*7836SJohn.Forte@Sun.COM * Whenever non-private data structure or non-static interface changes, 632*7836SJohn.Forte@Sun.COM * we should use an increased FCTL_ULP_MODREV_# number here and in all 633*7836SJohn.Forte@Sun.COM * ulps to prevent version mismatch. 634*7836SJohn.Forte@Sun.COM */ 635*7836SJohn.Forte@Sun.COM if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) { 636*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: ULP %s version mismatch;" 637*7836SJohn.Forte@Sun.COM " ULP %s would not be loaded", ulp_info->ulp_name, 638*7836SJohn.Forte@Sun.COM ulp_info->ulp_name); 639*7836SJohn.Forte@Sun.COM return (FC_BADULP); 640*7836SJohn.Forte@Sun.COM } 641*7836SJohn.Forte@Sun.COM 642*7836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), KM_SLEEP); 643*7836SJohn.Forte@Sun.COM ASSERT(new != NULL); 644*7836SJohn.Forte@Sun.COM 645*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 646*7836SJohn.Forte@Sun.COM new->ulp_info = ulp_info; 647*7836SJohn.Forte@Sun.COM if (fctl_ulp_list != NULL) { 648*7836SJohn.Forte@Sun.COM new->ulp_next = fctl_ulp_list; 649*7836SJohn.Forte@Sun.COM } 650*7836SJohn.Forte@Sun.COM fctl_ulp_list = new; 651*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 652*7836SJohn.Forte@Sun.COM 653*7836SJohn.Forte@Sun.COM while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) { 654*7836SJohn.Forte@Sun.COM delay(drv_usectohz(1000000)); 655*7836SJohn.Forte@Sun.COM if (ntry++ > FC_ULP_ADD_RETRY_COUNT) { 656*7836SJohn.Forte@Sun.COM fc_ulp_list_t *list; 657*7836SJohn.Forte@Sun.COM fc_ulp_list_t *last; 658*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 659*7836SJohn.Forte@Sun.COM for (last = NULL, list = fctl_ulp_list; list != NULL; 660*7836SJohn.Forte@Sun.COM list = list->ulp_next) { 661*7836SJohn.Forte@Sun.COM if (list->ulp_info == ulp_info) { 662*7836SJohn.Forte@Sun.COM break; 663*7836SJohn.Forte@Sun.COM } 664*7836SJohn.Forte@Sun.COM last = list; 665*7836SJohn.Forte@Sun.COM } 666*7836SJohn.Forte@Sun.COM 667*7836SJohn.Forte@Sun.COM if (list) { 668*7836SJohn.Forte@Sun.COM if (last) { 669*7836SJohn.Forte@Sun.COM last->ulp_next = list->ulp_next; 670*7836SJohn.Forte@Sun.COM } else { 671*7836SJohn.Forte@Sun.COM fctl_ulp_list = list->ulp_next; 672*7836SJohn.Forte@Sun.COM } 673*7836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 674*7836SJohn.Forte@Sun.COM } 675*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 676*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: ULP %s unable to load", 677*7836SJohn.Forte@Sun.COM ulp_info->ulp_name); 678*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 679*7836SJohn.Forte@Sun.COM } 680*7836SJohn.Forte@Sun.COM } 681*7836SJohn.Forte@Sun.COM 682*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) { 683*7836SJohn.Forte@Sun.COM ASSERT(mod->mod_info != NULL); 684*7836SJohn.Forte@Sun.COM 685*7836SJohn.Forte@Sun.COM if (ulp_info == mod->mod_info && 686*7836SJohn.Forte@Sun.COM ulp_info->ulp_type == mod->mod_info->ulp_type) { 687*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 688*7836SJohn.Forte@Sun.COM return (FC_ULP_SAMEMODULE); 689*7836SJohn.Forte@Sun.COM } 690*7836SJohn.Forte@Sun.COM 691*7836SJohn.Forte@Sun.COM if (ulp_info->ulp_type == mod->mod_info->ulp_type) { 692*7836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name, 693*7836SJohn.Forte@Sun.COM ulp_info->ulp_type); 694*7836SJohn.Forte@Sun.COM } 695*7836SJohn.Forte@Sun.COM prev = mod; 696*7836SJohn.Forte@Sun.COM } 697*7836SJohn.Forte@Sun.COM 698*7836SJohn.Forte@Sun.COM mod = kmem_zalloc(sizeof (*mod), KM_SLEEP); 699*7836SJohn.Forte@Sun.COM mod->mod_info = ulp_info; 700*7836SJohn.Forte@Sun.COM mod->mod_next = NULL; 701*7836SJohn.Forte@Sun.COM 702*7836SJohn.Forte@Sun.COM if (prev) { 703*7836SJohn.Forte@Sun.COM prev->mod_next = mod; 704*7836SJohn.Forte@Sun.COM } else { 705*7836SJohn.Forte@Sun.COM fctl_ulp_modules = mod; 706*7836SJohn.Forte@Sun.COM } 707*7836SJohn.Forte@Sun.COM 708*7836SJohn.Forte@Sun.COM /* 709*7836SJohn.Forte@Sun.COM * Schedule a job to each port's job_handler 710*7836SJohn.Forte@Sun.COM * thread to attach their ports with this ULP. 711*7836SJohn.Forte@Sun.COM */ 712*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 713*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 714*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 715*7836SJohn.Forte@Sun.COM 716*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC, 717*7836SJohn.Forte@Sun.COM NULL, NULL, KM_SLEEP); 718*7836SJohn.Forte@Sun.COM 719*7836SJohn.Forte@Sun.COM fctl_enque_job(fca_port->port_handle, job); 720*7836SJohn.Forte@Sun.COM } 721*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 722*7836SJohn.Forte@Sun.COM 723*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 724*7836SJohn.Forte@Sun.COM 725*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 726*7836SJohn.Forte@Sun.COM } 727*7836SJohn.Forte@Sun.COM 728*7836SJohn.Forte@Sun.COM 729*7836SJohn.Forte@Sun.COM /* 730*7836SJohn.Forte@Sun.COM * fc_ulp_remove 731*7836SJohn.Forte@Sun.COM * Remove a ULP module 732*7836SJohn.Forte@Sun.COM * 733*7836SJohn.Forte@Sun.COM * A misbehaving ULP may call this routine while I/Os are in progress. 734*7836SJohn.Forte@Sun.COM * Currently there is no mechanism to detect it to fail such a request. 735*7836SJohn.Forte@Sun.COM * 736*7836SJohn.Forte@Sun.COM * Return Codes: 737*7836SJohn.Forte@Sun.COM * FC_SUCCESS 738*7836SJohn.Forte@Sun.COM * FC_FAILURE 739*7836SJohn.Forte@Sun.COM */ 740*7836SJohn.Forte@Sun.COM int 741*7836SJohn.Forte@Sun.COM fc_ulp_remove(fc_ulp_modinfo_t *ulp_info) 742*7836SJohn.Forte@Sun.COM { 743*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 744*7836SJohn.Forte@Sun.COM fc_ulp_list_t *list; 745*7836SJohn.Forte@Sun.COM fc_ulp_list_t *last; 746*7836SJohn.Forte@Sun.COM fc_ulp_module_t *prev; 747*7836SJohn.Forte@Sun.COM 748*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 749*7836SJohn.Forte@Sun.COM 750*7836SJohn.Forte@Sun.COM for (last = NULL, list = fctl_ulp_list; list != NULL; 751*7836SJohn.Forte@Sun.COM list = list->ulp_next) { 752*7836SJohn.Forte@Sun.COM if (list->ulp_info == ulp_info) { 753*7836SJohn.Forte@Sun.COM break; 754*7836SJohn.Forte@Sun.COM } 755*7836SJohn.Forte@Sun.COM last = list; 756*7836SJohn.Forte@Sun.COM } 757*7836SJohn.Forte@Sun.COM 758*7836SJohn.Forte@Sun.COM if (list) { 759*7836SJohn.Forte@Sun.COM if (last) { 760*7836SJohn.Forte@Sun.COM last->ulp_next = list->ulp_next; 761*7836SJohn.Forte@Sun.COM } else { 762*7836SJohn.Forte@Sun.COM fctl_ulp_list = list->ulp_next; 763*7836SJohn.Forte@Sun.COM } 764*7836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 765*7836SJohn.Forte@Sun.COM } 766*7836SJohn.Forte@Sun.COM 767*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 768*7836SJohn.Forte@Sun.COM 769*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_WRITER); 770*7836SJohn.Forte@Sun.COM 771*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules, prev = NULL; mod != NULL; 772*7836SJohn.Forte@Sun.COM mod = mod->mod_next) { 773*7836SJohn.Forte@Sun.COM if (mod->mod_info == ulp_info) { 774*7836SJohn.Forte@Sun.COM break; 775*7836SJohn.Forte@Sun.COM } 776*7836SJohn.Forte@Sun.COM prev = mod; 777*7836SJohn.Forte@Sun.COM } 778*7836SJohn.Forte@Sun.COM 779*7836SJohn.Forte@Sun.COM if (mod) { 780*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 781*7836SJohn.Forte@Sun.COM 782*7836SJohn.Forte@Sun.COM if (prev) { 783*7836SJohn.Forte@Sun.COM prev->mod_next = mod->mod_next; 784*7836SJohn.Forte@Sun.COM } else { 785*7836SJohn.Forte@Sun.COM fctl_ulp_modules = mod->mod_next; 786*7836SJohn.Forte@Sun.COM } 787*7836SJohn.Forte@Sun.COM 788*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 789*7836SJohn.Forte@Sun.COM 790*7836SJohn.Forte@Sun.COM while ((next = mod->mod_ports) != NULL) { 791*7836SJohn.Forte@Sun.COM mod->mod_ports = next->port_next; 792*7836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(next); 793*7836SJohn.Forte@Sun.COM } 794*7836SJohn.Forte@Sun.COM 795*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 796*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 797*7836SJohn.Forte@Sun.COM 798*7836SJohn.Forte@Sun.COM kmem_free(mod, sizeof (*mod)); 799*7836SJohn.Forte@Sun.COM 800*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 801*7836SJohn.Forte@Sun.COM } 802*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 803*7836SJohn.Forte@Sun.COM 804*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 805*7836SJohn.Forte@Sun.COM } 806*7836SJohn.Forte@Sun.COM 807*7836SJohn.Forte@Sun.COM 808*7836SJohn.Forte@Sun.COM /* 809*7836SJohn.Forte@Sun.COM * The callers typically cache allocate the packet, complete the 810*7836SJohn.Forte@Sun.COM * DMA setup for pkt_cmd and pkt_resp fields of the packet and 811*7836SJohn.Forte@Sun.COM * call this function to see if the FCA is interested in doing 812*7836SJohn.Forte@Sun.COM * its own intialization. For example, socal may like to initialize 813*7836SJohn.Forte@Sun.COM * the soc_hdr which is pointed to by the pkt_fca_private field 814*7836SJohn.Forte@Sun.COM * and sitting right below fc_packet_t in memory. 815*7836SJohn.Forte@Sun.COM * 816*7836SJohn.Forte@Sun.COM * The caller is required to ensure that pkt_pd is populated with the 817*7836SJohn.Forte@Sun.COM * handle that it was given when the transport notified it about the 818*7836SJohn.Forte@Sun.COM * device this packet is associated with. If there is no associated 819*7836SJohn.Forte@Sun.COM * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an 820*7836SJohn.Forte@Sun.COM * increment of the reference count for said pd. When the packet is freed, 821*7836SJohn.Forte@Sun.COM * the reference count will be decremented. This reference count, in 822*7836SJohn.Forte@Sun.COM * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd 823*7836SJohn.Forte@Sun.COM * will not wink out of existence while there is a packet outstanding. 824*7836SJohn.Forte@Sun.COM * 825*7836SJohn.Forte@Sun.COM * This function and fca_init_pkt must not perform any operations that 826*7836SJohn.Forte@Sun.COM * would result in a call back to the ULP, as the ULP may be required 827*7836SJohn.Forte@Sun.COM * to hold a mutex across this call to ensure that the pd in question 828*7836SJohn.Forte@Sun.COM * won't go away prior the call to fc_ulp_transport. 829*7836SJohn.Forte@Sun.COM * 830*7836SJohn.Forte@Sun.COM * ULPs are responsible for using the handles they are given during state 831*7836SJohn.Forte@Sun.COM * change callback processing in a manner that ensures consistency. That 832*7836SJohn.Forte@Sun.COM * is, they must be aware that they could be processing a state change 833*7836SJohn.Forte@Sun.COM * notification that tells them the device associated with a particular 834*7836SJohn.Forte@Sun.COM * handle has gone away at the same time they are being asked to 835*7836SJohn.Forte@Sun.COM * initialize a packet using that handle. ULPs must therefore ensure 836*7836SJohn.Forte@Sun.COM * that their state change processing and packet initialization code 837*7836SJohn.Forte@Sun.COM * paths are sufficiently synchronized to avoid the use of an 838*7836SJohn.Forte@Sun.COM * invalidated handle in any fc_packet_t struct that is passed to the 839*7836SJohn.Forte@Sun.COM * fc_ulp_init_packet() function. 840*7836SJohn.Forte@Sun.COM */ 841*7836SJohn.Forte@Sun.COM int 842*7836SJohn.Forte@Sun.COM fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep) 843*7836SJohn.Forte@Sun.COM { 844*7836SJohn.Forte@Sun.COM int rval; 845*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 846*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 847*7836SJohn.Forte@Sun.COM 848*7836SJohn.Forte@Sun.COM ASSERT(pkt != NULL); 849*7836SJohn.Forte@Sun.COM 850*7836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 851*7836SJohn.Forte@Sun.COM 852*7836SJohn.Forte@Sun.COM /* Call the FCA driver's fca_init_pkt entry point function. */ 853*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep); 854*7836SJohn.Forte@Sun.COM 855*7836SJohn.Forte@Sun.COM if ((rval == FC_SUCCESS) && (pd != NULL)) { 856*7836SJohn.Forte@Sun.COM /* 857*7836SJohn.Forte@Sun.COM * A !NULL pd here must still be a valid 858*7836SJohn.Forte@Sun.COM * reference to the fc_remote_port_t. 859*7836SJohn.Forte@Sun.COM */ 860*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 861*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 862*7836SJohn.Forte@Sun.COM pd->pd_ref_count++; 863*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 864*7836SJohn.Forte@Sun.COM } 865*7836SJohn.Forte@Sun.COM 866*7836SJohn.Forte@Sun.COM return (rval); 867*7836SJohn.Forte@Sun.COM } 868*7836SJohn.Forte@Sun.COM 869*7836SJohn.Forte@Sun.COM 870*7836SJohn.Forte@Sun.COM /* 871*7836SJohn.Forte@Sun.COM * This function is called before destroying the cache allocated 872*7836SJohn.Forte@Sun.COM * fc_packet to free up (and uninitialize) any resource specially 873*7836SJohn.Forte@Sun.COM * allocated by the FCA driver during tran_init_pkt(). 874*7836SJohn.Forte@Sun.COM * 875*7836SJohn.Forte@Sun.COM * If the pkt_pd field in the given fc_packet_t struct is not NULL, then 876*7836SJohn.Forte@Sun.COM * the pd_ref_count reference count is decremented for the indicated 877*7836SJohn.Forte@Sun.COM * fc_remote_port_t struct. 878*7836SJohn.Forte@Sun.COM */ 879*7836SJohn.Forte@Sun.COM int 880*7836SJohn.Forte@Sun.COM fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt) 881*7836SJohn.Forte@Sun.COM { 882*7836SJohn.Forte@Sun.COM int rval; 883*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 884*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 885*7836SJohn.Forte@Sun.COM 886*7836SJohn.Forte@Sun.COM ASSERT(pkt != NULL); 887*7836SJohn.Forte@Sun.COM 888*7836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 889*7836SJohn.Forte@Sun.COM 890*7836SJohn.Forte@Sun.COM /* Call the FCA driver's fca_un_init_pkt entry point function */ 891*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt); 892*7836SJohn.Forte@Sun.COM 893*7836SJohn.Forte@Sun.COM if ((rval == FC_SUCCESS) && (pd != NULL)) { 894*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 895*7836SJohn.Forte@Sun.COM 896*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count > 0); 897*7836SJohn.Forte@Sun.COM pd->pd_ref_count--; 898*7836SJohn.Forte@Sun.COM 899*7836SJohn.Forte@Sun.COM /* 900*7836SJohn.Forte@Sun.COM * If at this point the state of this fc_remote_port_t 901*7836SJohn.Forte@Sun.COM * struct is PORT_DEVICE_INVALID, it probably means somebody 902*7836SJohn.Forte@Sun.COM * is cleaning up old (e.g. retried) packets. If the 903*7836SJohn.Forte@Sun.COM * pd_ref_count has also dropped to zero, it's time to 904*7836SJohn.Forte@Sun.COM * deallocate this fc_remote_port_t struct. 905*7836SJohn.Forte@Sun.COM */ 906*7836SJohn.Forte@Sun.COM if (pd->pd_state == PORT_DEVICE_INVALID && 907*7836SJohn.Forte@Sun.COM pd->pd_ref_count == 0) { 908*7836SJohn.Forte@Sun.COM fc_remote_node_t *node = pd->pd_remote_nodep; 909*7836SJohn.Forte@Sun.COM 910*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 911*7836SJohn.Forte@Sun.COM 912*7836SJohn.Forte@Sun.COM /* 913*7836SJohn.Forte@Sun.COM * Also deallocate the associated fc_remote_node_t 914*7836SJohn.Forte@Sun.COM * struct if it has no other associated 915*7836SJohn.Forte@Sun.COM * fc_remote_port_t structs. 916*7836SJohn.Forte@Sun.COM */ 917*7836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) == 0) && 918*7836SJohn.Forte@Sun.COM (node != NULL)) { 919*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 920*7836SJohn.Forte@Sun.COM } 921*7836SJohn.Forte@Sun.COM return (rval); 922*7836SJohn.Forte@Sun.COM } 923*7836SJohn.Forte@Sun.COM 924*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 925*7836SJohn.Forte@Sun.COM } 926*7836SJohn.Forte@Sun.COM 927*7836SJohn.Forte@Sun.COM return (rval); 928*7836SJohn.Forte@Sun.COM } 929*7836SJohn.Forte@Sun.COM 930*7836SJohn.Forte@Sun.COM 931*7836SJohn.Forte@Sun.COM int 932*7836SJohn.Forte@Sun.COM fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len, 933*7836SJohn.Forte@Sun.COM int flag) 934*7836SJohn.Forte@Sun.COM { 935*7836SJohn.Forte@Sun.COM int job_code; 936*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 937*7836SJohn.Forte@Sun.COM job_request_t *job; 938*7836SJohn.Forte@Sun.COM fc_portmap_t *tmp_map; 939*7836SJohn.Forte@Sun.COM uint32_t tmp_len; 940*7836SJohn.Forte@Sun.COM fc_portmap_t *change_list = NULL; 941*7836SJohn.Forte@Sun.COM uint32_t listlen = 0; 942*7836SJohn.Forte@Sun.COM 943*7836SJohn.Forte@Sun.COM port = port_handle; 944*7836SJohn.Forte@Sun.COM 945*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 946*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 947*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 948*7836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 949*7836SJohn.Forte@Sun.COM } 950*7836SJohn.Forte@Sun.COM 951*7836SJohn.Forte@Sun.COM if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 952*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 953*7836SJohn.Forte@Sun.COM return (FC_OFFLINE); 954*7836SJohn.Forte@Sun.COM } 955*7836SJohn.Forte@Sun.COM 956*7836SJohn.Forte@Sun.COM if (port->fp_dev_count && (port->fp_dev_count == 957*7836SJohn.Forte@Sun.COM port->fp_total_devices)) { 958*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 959*7836SJohn.Forte@Sun.COM fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0); 960*7836SJohn.Forte@Sun.COM if (listlen > *len) { 961*7836SJohn.Forte@Sun.COM tmp_map = (fc_portmap_t *)kmem_zalloc( 962*7836SJohn.Forte@Sun.COM listlen * sizeof (fc_portmap_t), KM_NOSLEEP); 963*7836SJohn.Forte@Sun.COM if (tmp_map == NULL) { 964*7836SJohn.Forte@Sun.COM return (FC_NOMEM); 965*7836SJohn.Forte@Sun.COM } 966*7836SJohn.Forte@Sun.COM if (*map) { 967*7836SJohn.Forte@Sun.COM kmem_free(*map, (*len) * sizeof (fc_portmap_t)); 968*7836SJohn.Forte@Sun.COM } 969*7836SJohn.Forte@Sun.COM *map = tmp_map; 970*7836SJohn.Forte@Sun.COM } 971*7836SJohn.Forte@Sun.COM if (change_list) { 972*7836SJohn.Forte@Sun.COM bcopy(change_list, *map, 973*7836SJohn.Forte@Sun.COM listlen * sizeof (fc_portmap_t)); 974*7836SJohn.Forte@Sun.COM kmem_free(change_list, listlen * sizeof (fc_portmap_t)); 975*7836SJohn.Forte@Sun.COM } 976*7836SJohn.Forte@Sun.COM *len = listlen; 977*7836SJohn.Forte@Sun.COM } else { 978*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 979*7836SJohn.Forte@Sun.COM 980*7836SJohn.Forte@Sun.COM switch (flag) { 981*7836SJohn.Forte@Sun.COM case FC_ULP_PLOGI_DONTCARE: 982*7836SJohn.Forte@Sun.COM job_code = JOB_PORT_GETMAP; 983*7836SJohn.Forte@Sun.COM break; 984*7836SJohn.Forte@Sun.COM 985*7836SJohn.Forte@Sun.COM case FC_ULP_PLOGI_PRESERVE: 986*7836SJohn.Forte@Sun.COM job_code = JOB_PORT_GETMAP_PLOGI_ALL; 987*7836SJohn.Forte@Sun.COM break; 988*7836SJohn.Forte@Sun.COM 989*7836SJohn.Forte@Sun.COM default: 990*7836SJohn.Forte@Sun.COM return (FC_INVALID_REQUEST); 991*7836SJohn.Forte@Sun.COM } 992*7836SJohn.Forte@Sun.COM /* 993*7836SJohn.Forte@Sun.COM * Submit a job request to the job handler 994*7836SJohn.Forte@Sun.COM * thread to get the map and wait 995*7836SJohn.Forte@Sun.COM */ 996*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP); 997*7836SJohn.Forte@Sun.COM job->job_private = (opaque_t)map; 998*7836SJohn.Forte@Sun.COM job->job_arg = (opaque_t)len; 999*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1000*7836SJohn.Forte@Sun.COM 1001*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1002*7836SJohn.Forte@Sun.COM /* 1003*7836SJohn.Forte@Sun.COM * The result of the last I/O operation is 1004*7836SJohn.Forte@Sun.COM * in job_code. We don't care to look at it 1005*7836SJohn.Forte@Sun.COM * Rather we look at the number of devices 1006*7836SJohn.Forte@Sun.COM * that are found to fill out the map for 1007*7836SJohn.Forte@Sun.COM * ULPs. 1008*7836SJohn.Forte@Sun.COM */ 1009*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1010*7836SJohn.Forte@Sun.COM } 1011*7836SJohn.Forte@Sun.COM 1012*7836SJohn.Forte@Sun.COM /* 1013*7836SJohn.Forte@Sun.COM * If we're here, we're returning a map to the caller, which means 1014*7836SJohn.Forte@Sun.COM * we'd better make sure every pd in that map has the 1015*7836SJohn.Forte@Sun.COM * PD_GIVEN_TO_ULPS flag set. 1016*7836SJohn.Forte@Sun.COM */ 1017*7836SJohn.Forte@Sun.COM 1018*7836SJohn.Forte@Sun.COM tmp_len = *len; 1019*7836SJohn.Forte@Sun.COM tmp_map = *map; 1020*7836SJohn.Forte@Sun.COM 1021*7836SJohn.Forte@Sun.COM while (tmp_len-- != 0) { 1022*7836SJohn.Forte@Sun.COM if (tmp_map->map_state != PORT_DEVICE_INVALID) { 1023*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 1024*7836SJohn.Forte@Sun.COM (fc_remote_port_t *)tmp_map->map_pd; 1025*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1026*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1027*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1028*7836SJohn.Forte@Sun.COM } 1029*7836SJohn.Forte@Sun.COM tmp_map++; 1030*7836SJohn.Forte@Sun.COM } 1031*7836SJohn.Forte@Sun.COM 1032*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 1033*7836SJohn.Forte@Sun.COM } 1034*7836SJohn.Forte@Sun.COM 1035*7836SJohn.Forte@Sun.COM 1036*7836SJohn.Forte@Sun.COM int 1037*7836SJohn.Forte@Sun.COM fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen) 1038*7836SJohn.Forte@Sun.COM { 1039*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 1040*7836SJohn.Forte@Sun.COM int job_flags; 1041*7836SJohn.Forte@Sun.COM uint32_t count; 1042*7836SJohn.Forte@Sun.COM fc_packet_t **tmp_array; 1043*7836SJohn.Forte@Sun.COM job_request_t *job; 1044*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1045*7836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 1046*7836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop; 1047*7836SJohn.Forte@Sun.COM 1048*7836SJohn.Forte@Sun.COM /* 1049*7836SJohn.Forte@Sun.COM * If the port is OFFLINE, or if the port driver is 1050*7836SJohn.Forte@Sun.COM * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 1051*7836SJohn.Forte@Sun.COM * PLOGI operations 1052*7836SJohn.Forte@Sun.COM */ 1053*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1054*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 1055*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1056*7836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 1057*7836SJohn.Forte@Sun.COM } 1058*7836SJohn.Forte@Sun.COM 1059*7836SJohn.Forte@Sun.COM if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 1060*7836SJohn.Forte@Sun.COM (port->fp_soft_state & 1061*7836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1062*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1063*7836SJohn.Forte@Sun.COM return (FC_OFFLINE); 1064*7836SJohn.Forte@Sun.COM } 1065*7836SJohn.Forte@Sun.COM 1066*7836SJohn.Forte@Sun.COM /* 1067*7836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 1068*7836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 1069*7836SJohn.Forte@Sun.COM */ 1070*7836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 1071*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1072*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1073*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1074*7836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 1075*7836SJohn.Forte@Sun.COM } 1076*7836SJohn.Forte@Sun.COM 1077*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1078*7836SJohn.Forte@Sun.COM 1079*7836SJohn.Forte@Sun.COM tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP); 1080*7836SJohn.Forte@Sun.COM for (count = 0; count < listlen; count++) { 1081*7836SJohn.Forte@Sun.COM tmp_array[count] = ulp_pkt[count]; 1082*7836SJohn.Forte@Sun.COM } 1083*7836SJohn.Forte@Sun.COM 1084*7836SJohn.Forte@Sun.COM job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR) 1085*7836SJohn.Forte@Sun.COM ? 0 : JOB_TYPE_FCTL_ASYNC; 1086*7836SJohn.Forte@Sun.COM 1087*7836SJohn.Forte@Sun.COM #ifdef DEBUG 1088*7836SJohn.Forte@Sun.COM { 1089*7836SJohn.Forte@Sun.COM int next; 1090*7836SJohn.Forte@Sun.COM int count; 1091*7836SJohn.Forte@Sun.COM int polled; 1092*7836SJohn.Forte@Sun.COM 1093*7836SJohn.Forte@Sun.COM polled = ((ulp_pkt[0]->pkt_tran_flags) & 1094*7836SJohn.Forte@Sun.COM FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 1095*7836SJohn.Forte@Sun.COM 1096*7836SJohn.Forte@Sun.COM for (count = 0; count < listlen; count++) { 1097*7836SJohn.Forte@Sun.COM next = ((ulp_pkt[count]->pkt_tran_flags) 1098*7836SJohn.Forte@Sun.COM & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 1099*7836SJohn.Forte@Sun.COM ASSERT(next == polled); 1100*7836SJohn.Forte@Sun.COM } 1101*7836SJohn.Forte@Sun.COM } 1102*7836SJohn.Forte@Sun.COM #endif 1103*7836SJohn.Forte@Sun.COM 1104*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP); 1105*7836SJohn.Forte@Sun.COM job->job_ulp_pkts = tmp_array; 1106*7836SJohn.Forte@Sun.COM job->job_ulp_listlen = listlen; 1107*7836SJohn.Forte@Sun.COM 1108*7836SJohn.Forte@Sun.COM while (listlen--) { 1109*7836SJohn.Forte@Sun.COM fc_packet_t *pkt; 1110*7836SJohn.Forte@Sun.COM 1111*7836SJohn.Forte@Sun.COM pkt = tmp_array[listlen]; 1112*7836SJohn.Forte@Sun.COM if (pkt->pkt_pd == NULL) { 1113*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_SUCCESS; 1114*7836SJohn.Forte@Sun.COM continue; 1115*7836SJohn.Forte@Sun.COM } 1116*7836SJohn.Forte@Sun.COM 1117*7836SJohn.Forte@Sun.COM mutex_enter(&pkt->pkt_pd->pd_mutex); 1118*7836SJohn.Forte@Sun.COM if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS || 1119*7836SJohn.Forte@Sun.COM pkt->pkt_pd->pd_flags == PD_ELS_MARK) { 1120*7836SJohn.Forte@Sun.COM /* 1121*7836SJohn.Forte@Sun.COM * Set the packet state and let the port 1122*7836SJohn.Forte@Sun.COM * driver call the completion routine 1123*7836SJohn.Forte@Sun.COM * from its thread 1124*7836SJohn.Forte@Sun.COM */ 1125*7836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 1126*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 1127*7836SJohn.Forte@Sun.COM continue; 1128*7836SJohn.Forte@Sun.COM } 1129*7836SJohn.Forte@Sun.COM 1130*7836SJohn.Forte@Sun.COM if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID || 1131*7836SJohn.Forte@Sun.COM pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) { 1132*7836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 1133*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_LOCAL_RJT; 1134*7836SJohn.Forte@Sun.COM continue; 1135*7836SJohn.Forte@Sun.COM } 1136*7836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 1137*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_SUCCESS; 1138*7836SJohn.Forte@Sun.COM } 1139*7836SJohn.Forte@Sun.COM 1140*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1141*7836SJohn.Forte@Sun.COM 1142*7836SJohn.Forte@Sun.COM if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) { 1143*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1144*7836SJohn.Forte@Sun.COM rval = job->job_result; 1145*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1146*7836SJohn.Forte@Sun.COM } 1147*7836SJohn.Forte@Sun.COM 1148*7836SJohn.Forte@Sun.COM return (rval); 1149*7836SJohn.Forte@Sun.COM } 1150*7836SJohn.Forte@Sun.COM 1151*7836SJohn.Forte@Sun.COM 1152*7836SJohn.Forte@Sun.COM opaque_t 1153*7836SJohn.Forte@Sun.COM fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error, 1154*7836SJohn.Forte@Sun.COM int create) 1155*7836SJohn.Forte@Sun.COM { 1156*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 1157*7836SJohn.Forte@Sun.COM job_request_t *job; 1158*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 1159*7836SJohn.Forte@Sun.COM 1160*7836SJohn.Forte@Sun.COM port = port_handle; 1161*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, pwwn); 1162*7836SJohn.Forte@Sun.COM 1163*7836SJohn.Forte@Sun.COM if (pd != NULL) { 1164*7836SJohn.Forte@Sun.COM *error = FC_SUCCESS; 1165*7836SJohn.Forte@Sun.COM /* 1166*7836SJohn.Forte@Sun.COM * A ULP now knows about this pd, so mark it 1167*7836SJohn.Forte@Sun.COM */ 1168*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1169*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1170*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1171*7836SJohn.Forte@Sun.COM return (pd); 1172*7836SJohn.Forte@Sun.COM } 1173*7836SJohn.Forte@Sun.COM 1174*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1175*7836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(port->fp_topology) && create) { 1176*7836SJohn.Forte@Sun.COM uint32_t d_id; 1177*7836SJohn.Forte@Sun.COM fctl_ns_req_t *ns_cmd; 1178*7836SJohn.Forte@Sun.COM 1179*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1180*7836SJohn.Forte@Sun.COM 1181*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 1182*7836SJohn.Forte@Sun.COM 1183*7836SJohn.Forte@Sun.COM if (job == NULL) { 1184*7836SJohn.Forte@Sun.COM *error = FC_NOMEM; 1185*7836SJohn.Forte@Sun.COM return (pd); 1186*7836SJohn.Forte@Sun.COM } 1187*7836SJohn.Forte@Sun.COM 1188*7836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 1189*7836SJohn.Forte@Sun.COM sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 1190*7836SJohn.Forte@Sun.COM 0, KM_SLEEP); 1191*7836SJohn.Forte@Sun.COM 1192*7836SJohn.Forte@Sun.COM if (ns_cmd == NULL) { 1193*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1194*7836SJohn.Forte@Sun.COM *error = FC_NOMEM; 1195*7836SJohn.Forte@Sun.COM return (pd); 1196*7836SJohn.Forte@Sun.COM } 1197*7836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = NS_GID_PN; 1198*7836SJohn.Forte@Sun.COM ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 1199*7836SJohn.Forte@Sun.COM 1200*7836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 1201*7836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 1202*7836SJohn.Forte@Sun.COM job->job_counter = 1; 1203*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1204*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1205*7836SJohn.Forte@Sun.COM 1206*7836SJohn.Forte@Sun.COM if (job->job_result != FC_SUCCESS) { 1207*7836SJohn.Forte@Sun.COM *error = job->job_result; 1208*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 1209*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1210*7836SJohn.Forte@Sun.COM return (pd); 1211*7836SJohn.Forte@Sun.COM } 1212*7836SJohn.Forte@Sun.COM d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id; 1213*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 1214*7836SJohn.Forte@Sun.COM 1215*7836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 1216*7836SJohn.Forte@Sun.COM sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE, 1217*7836SJohn.Forte@Sun.COM KM_SLEEP); 1218*7836SJohn.Forte@Sun.COM ASSERT(ns_cmd != NULL); 1219*7836SJohn.Forte@Sun.COM 1220*7836SJohn.Forte@Sun.COM ns_cmd->ns_gan_max = 1; 1221*7836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = NS_GA_NXT; 1222*7836SJohn.Forte@Sun.COM ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 1223*7836SJohn.Forte@Sun.COM ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 1224*7836SJohn.Forte@Sun.COM ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 1225*7836SJohn.Forte@Sun.COM 1226*7836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 1227*7836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 1228*7836SJohn.Forte@Sun.COM job->job_counter = 1; 1229*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1230*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1231*7836SJohn.Forte@Sun.COM 1232*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 1233*7836SJohn.Forte@Sun.COM if (job->job_result != FC_SUCCESS) { 1234*7836SJohn.Forte@Sun.COM *error = job->job_result; 1235*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1236*7836SJohn.Forte@Sun.COM return (pd); 1237*7836SJohn.Forte@Sun.COM } 1238*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1239*7836SJohn.Forte@Sun.COM 1240*7836SJohn.Forte@Sun.COM /* 1241*7836SJohn.Forte@Sun.COM * Check if the port device is created now. 1242*7836SJohn.Forte@Sun.COM */ 1243*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, pwwn); 1244*7836SJohn.Forte@Sun.COM 1245*7836SJohn.Forte@Sun.COM if (pd == NULL) { 1246*7836SJohn.Forte@Sun.COM *error = FC_FAILURE; 1247*7836SJohn.Forte@Sun.COM } else { 1248*7836SJohn.Forte@Sun.COM *error = FC_SUCCESS; 1249*7836SJohn.Forte@Sun.COM 1250*7836SJohn.Forte@Sun.COM /* 1251*7836SJohn.Forte@Sun.COM * A ULP now knows about this pd, so mark it 1252*7836SJohn.Forte@Sun.COM */ 1253*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1254*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 1255*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1256*7836SJohn.Forte@Sun.COM } 1257*7836SJohn.Forte@Sun.COM } else { 1258*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1259*7836SJohn.Forte@Sun.COM *error = FC_FAILURE; 1260*7836SJohn.Forte@Sun.COM } 1261*7836SJohn.Forte@Sun.COM 1262*7836SJohn.Forte@Sun.COM return (pd); 1263*7836SJohn.Forte@Sun.COM } 1264*7836SJohn.Forte@Sun.COM 1265*7836SJohn.Forte@Sun.COM 1266*7836SJohn.Forte@Sun.COM /* 1267*7836SJohn.Forte@Sun.COM * If a NS object exists in the host and query is performed 1268*7836SJohn.Forte@Sun.COM * on that object, we should retrieve it from our basket 1269*7836SJohn.Forte@Sun.COM * and return it right here, there by saving a request going 1270*7836SJohn.Forte@Sun.COM * all the up to the Name Server. 1271*7836SJohn.Forte@Sun.COM */ 1272*7836SJohn.Forte@Sun.COM int 1273*7836SJohn.Forte@Sun.COM fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req) 1274*7836SJohn.Forte@Sun.COM { 1275*7836SJohn.Forte@Sun.COM int rval; 1276*7836SJohn.Forte@Sun.COM int fabric; 1277*7836SJohn.Forte@Sun.COM job_request_t *job; 1278*7836SJohn.Forte@Sun.COM fctl_ns_req_t *ns_cmd; 1279*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1280*7836SJohn.Forte@Sun.COM 1281*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1282*7836SJohn.Forte@Sun.COM fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0; 1283*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1284*7836SJohn.Forte@Sun.COM 1285*7836SJohn.Forte@Sun.COM /* 1286*7836SJohn.Forte@Sun.COM * Name server query can't be performed for devices not in Fabric 1287*7836SJohn.Forte@Sun.COM */ 1288*7836SJohn.Forte@Sun.COM if (!fabric && pd) { 1289*7836SJohn.Forte@Sun.COM return (FC_BADOBJECT); 1290*7836SJohn.Forte@Sun.COM } 1291*7836SJohn.Forte@Sun.COM 1292*7836SJohn.Forte@Sun.COM if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) { 1293*7836SJohn.Forte@Sun.COM if (pd == NULL) { 1294*7836SJohn.Forte@Sun.COM rval = fctl_update_host_ns_values(port, ns_req); 1295*7836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 1296*7836SJohn.Forte@Sun.COM return (rval); 1297*7836SJohn.Forte@Sun.COM } 1298*7836SJohn.Forte@Sun.COM } else { 1299*7836SJohn.Forte@Sun.COM /* 1300*7836SJohn.Forte@Sun.COM * Guess what, FC-GS-2 currently prohibits (not 1301*7836SJohn.Forte@Sun.COM * in the strongest language though) setting of 1302*7836SJohn.Forte@Sun.COM * NS object values by other ports. But we might 1303*7836SJohn.Forte@Sun.COM * get that changed to at least accommodate setting 1304*7836SJohn.Forte@Sun.COM * symbolic node/port names - But if disks/tapes 1305*7836SJohn.Forte@Sun.COM * were going to provide a method to set these 1306*7836SJohn.Forte@Sun.COM * values directly (which in turn might register 1307*7836SJohn.Forte@Sun.COM * with the NS when they come up; yep, for that 1308*7836SJohn.Forte@Sun.COM * to happen the disks will have to be very well 1309*7836SJohn.Forte@Sun.COM * behaved Fabric citizen) we won't need to 1310*7836SJohn.Forte@Sun.COM * register the symbolic port/node names for 1311*7836SJohn.Forte@Sun.COM * other ports too (rather send down SCSI commands 1312*7836SJohn.Forte@Sun.COM * to the devices to set the names) 1313*7836SJohn.Forte@Sun.COM * 1314*7836SJohn.Forte@Sun.COM * Be that as it may, let's continue to fail 1315*7836SJohn.Forte@Sun.COM * registration requests for other ports. period. 1316*7836SJohn.Forte@Sun.COM */ 1317*7836SJohn.Forte@Sun.COM return (FC_BADOBJECT); 1318*7836SJohn.Forte@Sun.COM } 1319*7836SJohn.Forte@Sun.COM 1320*7836SJohn.Forte@Sun.COM if (!fabric) { 1321*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 1322*7836SJohn.Forte@Sun.COM } 1323*7836SJohn.Forte@Sun.COM } else if (!fabric) { 1324*7836SJohn.Forte@Sun.COM return (fctl_retrieve_host_ns_values(port, ns_req)); 1325*7836SJohn.Forte@Sun.COM } 1326*7836SJohn.Forte@Sun.COM 1327*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 1328*7836SJohn.Forte@Sun.COM ASSERT(job != NULL); 1329*7836SJohn.Forte@Sun.COM 1330*7836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 1331*7836SJohn.Forte@Sun.COM ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP); 1332*7836SJohn.Forte@Sun.COM ASSERT(ns_cmd != NULL); 1333*7836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = ns_req->ns_cmd; 1334*7836SJohn.Forte@Sun.COM bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf, 1335*7836SJohn.Forte@Sun.COM ns_req->ns_req_len); 1336*7836SJohn.Forte@Sun.COM 1337*7836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 1338*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1339*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1340*7836SJohn.Forte@Sun.COM rval = job->job_result; 1341*7836SJohn.Forte@Sun.COM 1342*7836SJohn.Forte@Sun.COM if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) { 1343*7836SJohn.Forte@Sun.COM bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload, 1344*7836SJohn.Forte@Sun.COM ns_cmd->ns_data_len); 1345*7836SJohn.Forte@Sun.COM } 1346*7836SJohn.Forte@Sun.COM bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr, 1347*7836SJohn.Forte@Sun.COM sizeof (fc_ct_header_t)); 1348*7836SJohn.Forte@Sun.COM 1349*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 1350*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1351*7836SJohn.Forte@Sun.COM 1352*7836SJohn.Forte@Sun.COM return (rval); 1353*7836SJohn.Forte@Sun.COM } 1354*7836SJohn.Forte@Sun.COM 1355*7836SJohn.Forte@Sun.COM 1356*7836SJohn.Forte@Sun.COM int 1357*7836SJohn.Forte@Sun.COM fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt) 1358*7836SJohn.Forte@Sun.COM { 1359*7836SJohn.Forte@Sun.COM int rval; 1360*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 1361*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd, *newpd; 1362*7836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 1363*7836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 1364*7836SJohn.Forte@Sun.COM 1365*7836SJohn.Forte@Sun.COM port = port_handle; 1366*7836SJohn.Forte@Sun.COM 1367*7836SJohn.Forte@Sun.COM if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) { 1368*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_transport( 1369*7836SJohn.Forte@Sun.COM port->fp_fca_handle, pkt)); 1370*7836SJohn.Forte@Sun.COM } 1371*7836SJohn.Forte@Sun.COM 1372*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1373*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 1374*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1375*7836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 1376*7836SJohn.Forte@Sun.COM } 1377*7836SJohn.Forte@Sun.COM 1378*7836SJohn.Forte@Sun.COM /* A locus of race conditions */ 1379*7836SJohn.Forte@Sun.COM if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) || 1380*7836SJohn.Forte@Sun.COM (port->fp_soft_state & 1381*7836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1382*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1383*7836SJohn.Forte@Sun.COM return (FC_OFFLINE); 1384*7836SJohn.Forte@Sun.COM } 1385*7836SJohn.Forte@Sun.COM 1386*7836SJohn.Forte@Sun.COM /* 1387*7836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 1388*7836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 1389*7836SJohn.Forte@Sun.COM */ 1390*7836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 1391*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1392*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1393*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1394*7836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 1395*7836SJohn.Forte@Sun.COM } 1396*7836SJohn.Forte@Sun.COM 1397*7836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 1398*7836SJohn.Forte@Sun.COM if (pd) { 1399*7836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 1400*7836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 1401*7836SJohn.Forte@Sun.COM 1402*7836SJohn.Forte@Sun.COM newpd = fctl_get_remote_port_by_pwwn_mutex_held(port, 1403*7836SJohn.Forte@Sun.COM &pd->pd_port_name); 1404*7836SJohn.Forte@Sun.COM 1405*7836SJohn.Forte@Sun.COM /* 1406*7836SJohn.Forte@Sun.COM * The remote port (pd) in the packet is no longer 1407*7836SJohn.Forte@Sun.COM * usable, as the old pd still exists we can use the 1408*7836SJohn.Forte@Sun.COM * WWN to check if we have a current pd for the device 1409*7836SJohn.Forte@Sun.COM * we want. Either way we continue with the old logic 1410*7836SJohn.Forte@Sun.COM * whether we have a new pd or not, as the new pd 1411*7836SJohn.Forte@Sun.COM * could be bad, or have become unusable. 1412*7836SJohn.Forte@Sun.COM */ 1413*7836SJohn.Forte@Sun.COM if ((newpd) && (newpd != pd)) { 1414*7836SJohn.Forte@Sun.COM 1415*7836SJohn.Forte@Sun.COM /* 1416*7836SJohn.Forte@Sun.COM * There is a better remote port (pd) to try, 1417*7836SJohn.Forte@Sun.COM * so we need to fix the reference counts, etc. 1418*7836SJohn.Forte@Sun.COM */ 1419*7836SJohn.Forte@Sun.COM mutex_enter(&newpd->pd_mutex); 1420*7836SJohn.Forte@Sun.COM newpd->pd_ref_count++; 1421*7836SJohn.Forte@Sun.COM pkt->pkt_pd = newpd; 1422*7836SJohn.Forte@Sun.COM mutex_exit(&newpd->pd_mutex); 1423*7836SJohn.Forte@Sun.COM 1424*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1425*7836SJohn.Forte@Sun.COM pd->pd_ref_count--; 1426*7836SJohn.Forte@Sun.COM if ((pd->pd_state == PORT_DEVICE_INVALID) && 1427*7836SJohn.Forte@Sun.COM (pd->pd_ref_count == 0)) { 1428*7836SJohn.Forte@Sun.COM fc_remote_node_t *node = 1429*7836SJohn.Forte@Sun.COM pd->pd_remote_nodep; 1430*7836SJohn.Forte@Sun.COM 1431*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1432*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1433*7836SJohn.Forte@Sun.COM 1434*7836SJohn.Forte@Sun.COM /* 1435*7836SJohn.Forte@Sun.COM * This will create another PD hole 1436*7836SJohn.Forte@Sun.COM * where we have a reference to a pd, 1437*7836SJohn.Forte@Sun.COM * but someone else could remove it. 1438*7836SJohn.Forte@Sun.COM */ 1439*7836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) 1440*7836SJohn.Forte@Sun.COM == 0) && (node != NULL)) { 1441*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 1442*7836SJohn.Forte@Sun.COM } 1443*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1444*7836SJohn.Forte@Sun.COM } else { 1445*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1446*7836SJohn.Forte@Sun.COM } 1447*7836SJohn.Forte@Sun.COM pd = newpd; 1448*7836SJohn.Forte@Sun.COM } 1449*7836SJohn.Forte@Sun.COM } 1450*7836SJohn.Forte@Sun.COM 1451*7836SJohn.Forte@Sun.COM if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 1452*7836SJohn.Forte@Sun.COM rval = (pd->pd_state == PORT_DEVICE_VALID) ? 1453*7836SJohn.Forte@Sun.COM FC_LOGINREQ : FC_BADDEV; 1454*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1455*7836SJohn.Forte@Sun.COM return (rval); 1456*7836SJohn.Forte@Sun.COM } 1457*7836SJohn.Forte@Sun.COM 1458*7836SJohn.Forte@Sun.COM if (pd->pd_flags != PD_IDLE) { 1459*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1460*7836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY); 1461*7836SJohn.Forte@Sun.COM } 1462*7836SJohn.Forte@Sun.COM 1463*7836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 1464*7836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 1465*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1466*7836SJohn.Forte@Sun.COM return (FC_BADDEV); 1467*7836SJohn.Forte@Sun.COM } 1468*7836SJohn.Forte@Sun.COM 1469*7836SJohn.Forte@Sun.COM } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) { 1470*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1471*7836SJohn.Forte@Sun.COM return (FC_BADPACKET); 1472*7836SJohn.Forte@Sun.COM } 1473*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1474*7836SJohn.Forte@Sun.COM 1475*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt)); 1476*7836SJohn.Forte@Sun.COM } 1477*7836SJohn.Forte@Sun.COM 1478*7836SJohn.Forte@Sun.COM 1479*7836SJohn.Forte@Sun.COM int 1480*7836SJohn.Forte@Sun.COM fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt) 1481*7836SJohn.Forte@Sun.COM { 1482*7836SJohn.Forte@Sun.COM int rval; 1483*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1484*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 1485*7836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 1486*7836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 1487*7836SJohn.Forte@Sun.COM 1488*7836SJohn.Forte@Sun.COM /* 1489*7836SJohn.Forte@Sun.COM * If the port is OFFLINE, or if the port driver is 1490*7836SJohn.Forte@Sun.COM * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 1491*7836SJohn.Forte@Sun.COM * ELS operations 1492*7836SJohn.Forte@Sun.COM */ 1493*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1494*7836SJohn.Forte@Sun.COM if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 1495*7836SJohn.Forte@Sun.COM (port->fp_soft_state & 1496*7836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 1497*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1498*7836SJohn.Forte@Sun.COM return (FC_OFFLINE); 1499*7836SJohn.Forte@Sun.COM } 1500*7836SJohn.Forte@Sun.COM 1501*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 1502*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1503*7836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 1504*7836SJohn.Forte@Sun.COM } 1505*7836SJohn.Forte@Sun.COM 1506*7836SJohn.Forte@Sun.COM /* 1507*7836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 1508*7836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 1509*7836SJohn.Forte@Sun.COM */ 1510*7836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 1511*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 1512*7836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 1513*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1514*7836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 1515*7836SJohn.Forte@Sun.COM } 1516*7836SJohn.Forte@Sun.COM 1517*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1518*7836SJohn.Forte@Sun.COM 1519*7836SJohn.Forte@Sun.COM if ((pd = pkt->pkt_pd) != NULL) { 1520*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1521*7836SJohn.Forte@Sun.COM if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 1522*7836SJohn.Forte@Sun.COM rval = (pd->pd_state == PORT_DEVICE_VALID) ? 1523*7836SJohn.Forte@Sun.COM FC_LOGINREQ : FC_BADDEV; 1524*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1525*7836SJohn.Forte@Sun.COM return (rval); 1526*7836SJohn.Forte@Sun.COM } 1527*7836SJohn.Forte@Sun.COM 1528*7836SJohn.Forte@Sun.COM if (pd->pd_flags != PD_IDLE) { 1529*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1530*7836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY); 1531*7836SJohn.Forte@Sun.COM } 1532*7836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 1533*7836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 1534*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1535*7836SJohn.Forte@Sun.COM return (FC_BADDEV); 1536*7836SJohn.Forte@Sun.COM } 1537*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1538*7836SJohn.Forte@Sun.COM } 1539*7836SJohn.Forte@Sun.COM 1540*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt)); 1541*7836SJohn.Forte@Sun.COM } 1542*7836SJohn.Forte@Sun.COM 1543*7836SJohn.Forte@Sun.COM 1544*7836SJohn.Forte@Sun.COM int 1545*7836SJohn.Forte@Sun.COM fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size, 1546*7836SJohn.Forte@Sun.COM uint32_t type, uint64_t *tokens) 1547*7836SJohn.Forte@Sun.COM { 1548*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1549*7836SJohn.Forte@Sun.COM 1550*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle, 1551*7836SJohn.Forte@Sun.COM tokens, size, count, type)); 1552*7836SJohn.Forte@Sun.COM } 1553*7836SJohn.Forte@Sun.COM 1554*7836SJohn.Forte@Sun.COM 1555*7836SJohn.Forte@Sun.COM int 1556*7836SJohn.Forte@Sun.COM fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens) 1557*7836SJohn.Forte@Sun.COM { 1558*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1559*7836SJohn.Forte@Sun.COM 1560*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle, 1561*7836SJohn.Forte@Sun.COM count, tokens)); 1562*7836SJohn.Forte@Sun.COM } 1563*7836SJohn.Forte@Sun.COM 1564*7836SJohn.Forte@Sun.COM 1565*7836SJohn.Forte@Sun.COM int 1566*7836SJohn.Forte@Sun.COM fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens) 1567*7836SJohn.Forte@Sun.COM { 1568*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1569*7836SJohn.Forte@Sun.COM 1570*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 1571*7836SJohn.Forte@Sun.COM count, tokens)); 1572*7836SJohn.Forte@Sun.COM } 1573*7836SJohn.Forte@Sun.COM 1574*7836SJohn.Forte@Sun.COM 1575*7836SJohn.Forte@Sun.COM int 1576*7836SJohn.Forte@Sun.COM fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags) 1577*7836SJohn.Forte@Sun.COM { 1578*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1579*7836SJohn.Forte@Sun.COM 1580*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags)); 1581*7836SJohn.Forte@Sun.COM } 1582*7836SJohn.Forte@Sun.COM 1583*7836SJohn.Forte@Sun.COM 1584*7836SJohn.Forte@Sun.COM /* 1585*7836SJohn.Forte@Sun.COM * Submit an asynchronous request to the job handler if the sleep 1586*7836SJohn.Forte@Sun.COM * flag is set to KM_NOSLEEP, as such calls could have been made 1587*7836SJohn.Forte@Sun.COM * in interrupt contexts, and the goal is to avoid busy waiting, 1588*7836SJohn.Forte@Sun.COM * blocking on a conditional variable, a semaphore or any of the 1589*7836SJohn.Forte@Sun.COM * synchronization primitives. A noticeable draw back with this 1590*7836SJohn.Forte@Sun.COM * asynchronous request is that an FC_SUCCESS is returned long 1591*7836SJohn.Forte@Sun.COM * before the reset is complete (successful or not). 1592*7836SJohn.Forte@Sun.COM */ 1593*7836SJohn.Forte@Sun.COM int 1594*7836SJohn.Forte@Sun.COM fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep) 1595*7836SJohn.Forte@Sun.COM { 1596*7836SJohn.Forte@Sun.COM int rval; 1597*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 1598*7836SJohn.Forte@Sun.COM job_request_t *job; 1599*7836SJohn.Forte@Sun.COM 1600*7836SJohn.Forte@Sun.COM port = port_handle; 1601*7836SJohn.Forte@Sun.COM /* 1602*7836SJohn.Forte@Sun.COM * Many a times, this function is called from interrupt 1603*7836SJohn.Forte@Sun.COM * contexts and there have been several dead locks and 1604*7836SJohn.Forte@Sun.COM * hangs - One of the simplest work arounds is to fib 1605*7836SJohn.Forte@Sun.COM * if a RESET is in progress. 1606*7836SJohn.Forte@Sun.COM */ 1607*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1608*7836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 1609*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1610*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 1611*7836SJohn.Forte@Sun.COM } 1612*7836SJohn.Forte@Sun.COM 1613*7836SJohn.Forte@Sun.COM /* 1614*7836SJohn.Forte@Sun.COM * Ward off this reset if a state change is in progress. 1615*7836SJohn.Forte@Sun.COM */ 1616*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 1617*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1618*7836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 1619*7836SJohn.Forte@Sun.COM } 1620*7836SJohn.Forte@Sun.COM port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 1621*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1622*7836SJohn.Forte@Sun.COM 1623*7836SJohn.Forte@Sun.COM if (fctl_busy_port(port) != 0) { 1624*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1625*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1626*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1627*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 1628*7836SJohn.Forte@Sun.COM } 1629*7836SJohn.Forte@Sun.COM 1630*7836SJohn.Forte@Sun.COM if (sleep == KM_SLEEP) { 1631*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep); 1632*7836SJohn.Forte@Sun.COM ASSERT(job != NULL); 1633*7836SJohn.Forte@Sun.COM 1634*7836SJohn.Forte@Sun.COM job->job_private = (void *)pwwn; 1635*7836SJohn.Forte@Sun.COM job->job_counter = 1; 1636*7836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 1637*7836SJohn.Forte@Sun.COM fctl_jobwait(job); 1638*7836SJohn.Forte@Sun.COM 1639*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1640*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1641*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1642*7836SJohn.Forte@Sun.COM 1643*7836SJohn.Forte@Sun.COM fctl_idle_port(port); 1644*7836SJohn.Forte@Sun.COM 1645*7836SJohn.Forte@Sun.COM rval = job->job_result; 1646*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 1647*7836SJohn.Forte@Sun.COM } else { 1648*7836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC, 1649*7836SJohn.Forte@Sun.COM fctl_link_reset_done, port, sleep); 1650*7836SJohn.Forte@Sun.COM if (job == NULL) { 1651*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1652*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 1653*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1654*7836SJohn.Forte@Sun.COM fctl_idle_port(port); 1655*7836SJohn.Forte@Sun.COM return (FC_NOMEM); 1656*7836SJohn.Forte@Sun.COM } 1657*7836SJohn.Forte@Sun.COM job->job_private = (void *)pwwn; 1658*7836SJohn.Forte@Sun.COM job->job_counter = 1; 1659*7836SJohn.Forte@Sun.COM fctl_priority_enque_job(port, job); 1660*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 1661*7836SJohn.Forte@Sun.COM } 1662*7836SJohn.Forte@Sun.COM 1663*7836SJohn.Forte@Sun.COM return (rval); 1664*7836SJohn.Forte@Sun.COM } 1665*7836SJohn.Forte@Sun.COM 1666*7836SJohn.Forte@Sun.COM 1667*7836SJohn.Forte@Sun.COM int 1668*7836SJohn.Forte@Sun.COM fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd) 1669*7836SJohn.Forte@Sun.COM { 1670*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 1671*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1672*7836SJohn.Forte@Sun.COM 1673*7836SJohn.Forte@Sun.COM switch (cmd) { 1674*7836SJohn.Forte@Sun.COM case FC_RESET_PORT: 1675*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 1676*7836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_LINK_RESET); 1677*7836SJohn.Forte@Sun.COM break; 1678*7836SJohn.Forte@Sun.COM 1679*7836SJohn.Forte@Sun.COM case FC_RESET_ADAPTER: 1680*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 1681*7836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_RESET); 1682*7836SJohn.Forte@Sun.COM break; 1683*7836SJohn.Forte@Sun.COM 1684*7836SJohn.Forte@Sun.COM case FC_RESET_DUMP: 1685*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 1686*7836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_CORE); 1687*7836SJohn.Forte@Sun.COM break; 1688*7836SJohn.Forte@Sun.COM 1689*7836SJohn.Forte@Sun.COM case FC_RESET_CRASH: 1690*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 1691*7836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_RESET_CORE); 1692*7836SJohn.Forte@Sun.COM break; 1693*7836SJohn.Forte@Sun.COM 1694*7836SJohn.Forte@Sun.COM default: 1695*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 1696*7836SJohn.Forte@Sun.COM } 1697*7836SJohn.Forte@Sun.COM 1698*7836SJohn.Forte@Sun.COM return (rval); 1699*7836SJohn.Forte@Sun.COM } 1700*7836SJohn.Forte@Sun.COM 1701*7836SJohn.Forte@Sun.COM 1702*7836SJohn.Forte@Sun.COM int 1703*7836SJohn.Forte@Sun.COM fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params) 1704*7836SJohn.Forte@Sun.COM { 1705*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1706*7836SJohn.Forte@Sun.COM 1707*7836SJohn.Forte@Sun.COM /* Copy the login parameters */ 1708*7836SJohn.Forte@Sun.COM *login_params = port->fp_service_params; 1709*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 1710*7836SJohn.Forte@Sun.COM } 1711*7836SJohn.Forte@Sun.COM 1712*7836SJohn.Forte@Sun.COM 1713*7836SJohn.Forte@Sun.COM int 1714*7836SJohn.Forte@Sun.COM fc_ulp_get_port_instance(opaque_t port_handle) 1715*7836SJohn.Forte@Sun.COM { 1716*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1717*7836SJohn.Forte@Sun.COM 1718*7836SJohn.Forte@Sun.COM return (port->fp_instance); 1719*7836SJohn.Forte@Sun.COM } 1720*7836SJohn.Forte@Sun.COM 1721*7836SJohn.Forte@Sun.COM 1722*7836SJohn.Forte@Sun.COM opaque_t 1723*7836SJohn.Forte@Sun.COM fc_ulp_get_port_handle(int port_instance) 1724*7836SJohn.Forte@Sun.COM { 1725*7836SJohn.Forte@Sun.COM opaque_t port_handle = NULL; 1726*7836SJohn.Forte@Sun.COM fc_fca_port_t *cur; 1727*7836SJohn.Forte@Sun.COM 1728*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 1729*7836SJohn.Forte@Sun.COM for (cur = fctl_fca_portlist; cur; cur = cur->port_next) { 1730*7836SJohn.Forte@Sun.COM if (cur->port_handle->fp_instance == port_instance) { 1731*7836SJohn.Forte@Sun.COM port_handle = (opaque_t)cur->port_handle; 1732*7836SJohn.Forte@Sun.COM break; 1733*7836SJohn.Forte@Sun.COM } 1734*7836SJohn.Forte@Sun.COM } 1735*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 1736*7836SJohn.Forte@Sun.COM 1737*7836SJohn.Forte@Sun.COM return (port_handle); 1738*7836SJohn.Forte@Sun.COM } 1739*7836SJohn.Forte@Sun.COM 1740*7836SJohn.Forte@Sun.COM 1741*7836SJohn.Forte@Sun.COM int 1742*7836SJohn.Forte@Sun.COM fc_ulp_error(int fc_errno, char **errmsg) 1743*7836SJohn.Forte@Sun.COM { 1744*7836SJohn.Forte@Sun.COM return (fctl_error(fc_errno, errmsg)); 1745*7836SJohn.Forte@Sun.COM } 1746*7836SJohn.Forte@Sun.COM 1747*7836SJohn.Forte@Sun.COM 1748*7836SJohn.Forte@Sun.COM int 1749*7836SJohn.Forte@Sun.COM fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason, 1750*7836SJohn.Forte@Sun.COM char **action, char **expln) 1751*7836SJohn.Forte@Sun.COM { 1752*7836SJohn.Forte@Sun.COM return (fctl_pkt_error(pkt, state, reason, action, expln)); 1753*7836SJohn.Forte@Sun.COM } 1754*7836SJohn.Forte@Sun.COM 1755*7836SJohn.Forte@Sun.COM 1756*7836SJohn.Forte@Sun.COM /* 1757*7836SJohn.Forte@Sun.COM * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE 1758*7836SJohn.Forte@Sun.COM */ 1759*7836SJohn.Forte@Sun.COM int 1760*7836SJohn.Forte@Sun.COM fc_ulp_is_name_present(caddr_t ulp_name) 1761*7836SJohn.Forte@Sun.COM { 1762*7836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 1763*7836SJohn.Forte@Sun.COM fc_ulp_list_t *list; 1764*7836SJohn.Forte@Sun.COM 1765*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 1766*7836SJohn.Forte@Sun.COM for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) { 1767*7836SJohn.Forte@Sun.COM if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) { 1768*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 1769*7836SJohn.Forte@Sun.COM break; 1770*7836SJohn.Forte@Sun.COM } 1771*7836SJohn.Forte@Sun.COM } 1772*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 1773*7836SJohn.Forte@Sun.COM 1774*7836SJohn.Forte@Sun.COM return (rval); 1775*7836SJohn.Forte@Sun.COM } 1776*7836SJohn.Forte@Sun.COM 1777*7836SJohn.Forte@Sun.COM 1778*7836SJohn.Forte@Sun.COM /* 1779*7836SJohn.Forte@Sun.COM * Return port WWN for a port Identifier 1780*7836SJohn.Forte@Sun.COM */ 1781*7836SJohn.Forte@Sun.COM int 1782*7836SJohn.Forte@Sun.COM fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn) 1783*7836SJohn.Forte@Sun.COM { 1784*7836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 1785*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 1786*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1787*7836SJohn.Forte@Sun.COM 1788*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_did(port, d_id.port_id); 1789*7836SJohn.Forte@Sun.COM if (pd != NULL) { 1790*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1791*7836SJohn.Forte@Sun.COM *pwwn = pd->pd_port_name; 1792*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1793*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 1794*7836SJohn.Forte@Sun.COM } 1795*7836SJohn.Forte@Sun.COM 1796*7836SJohn.Forte@Sun.COM return (rval); 1797*7836SJohn.Forte@Sun.COM } 1798*7836SJohn.Forte@Sun.COM 1799*7836SJohn.Forte@Sun.COM 1800*7836SJohn.Forte@Sun.COM /* 1801*7836SJohn.Forte@Sun.COM * Return a port map for a port WWN 1802*7836SJohn.Forte@Sun.COM */ 1803*7836SJohn.Forte@Sun.COM int 1804*7836SJohn.Forte@Sun.COM fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map) 1805*7836SJohn.Forte@Sun.COM { 1806*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1807*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 1808*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 1809*7836SJohn.Forte@Sun.COM 1810*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, bytes); 1811*7836SJohn.Forte@Sun.COM if (pd == NULL) { 1812*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 1813*7836SJohn.Forte@Sun.COM } 1814*7836SJohn.Forte@Sun.COM 1815*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1816*7836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 1817*7836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 1818*7836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 1819*7836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 1820*7836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 1821*7836SJohn.Forte@Sun.COM map->map_flags = 0; 1822*7836SJohn.Forte@Sun.COM 1823*7836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 1824*7836SJohn.Forte@Sun.COM 1825*7836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 1826*7836SJohn.Forte@Sun.COM 1827*7836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 1828*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1829*7836SJohn.Forte@Sun.COM 1830*7836SJohn.Forte@Sun.COM if (node) { 1831*7836SJohn.Forte@Sun.COM mutex_enter(&node->fd_mutex); 1832*7836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 1833*7836SJohn.Forte@Sun.COM mutex_exit(&node->fd_mutex); 1834*7836SJohn.Forte@Sun.COM } 1835*7836SJohn.Forte@Sun.COM map->map_pd = pd; 1836*7836SJohn.Forte@Sun.COM 1837*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 1838*7836SJohn.Forte@Sun.COM } 1839*7836SJohn.Forte@Sun.COM 1840*7836SJohn.Forte@Sun.COM 1841*7836SJohn.Forte@Sun.COM opaque_t 1842*7836SJohn.Forte@Sun.COM fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id) 1843*7836SJohn.Forte@Sun.COM { 1844*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1845*7836SJohn.Forte@Sun.COM 1846*7836SJohn.Forte@Sun.COM if (port->fp_fca_tran->fca_get_device == NULL) { 1847*7836SJohn.Forte@Sun.COM return (NULL); 1848*7836SJohn.Forte@Sun.COM } 1849*7836SJohn.Forte@Sun.COM 1850*7836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id)); 1851*7836SJohn.Forte@Sun.COM } 1852*7836SJohn.Forte@Sun.COM 1853*7836SJohn.Forte@Sun.COM 1854*7836SJohn.Forte@Sun.COM int 1855*7836SJohn.Forte@Sun.COM fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd) 1856*7836SJohn.Forte@Sun.COM { 1857*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 1858*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 1859*7836SJohn.Forte@Sun.COM 1860*7836SJohn.Forte@Sun.COM if (port->fp_fca_tran->fca_notify) { 1861*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 1862*7836SJohn.Forte@Sun.COM switch (cmd) { 1863*7836SJohn.Forte@Sun.COM case FC_NOTIFY_TARGET_MODE: 1864*7836SJohn.Forte@Sun.COM port->fp_options |= FP_TARGET_MODE; 1865*7836SJohn.Forte@Sun.COM break; 1866*7836SJohn.Forte@Sun.COM case FC_NOTIFY_NO_TARGET_MODE: 1867*7836SJohn.Forte@Sun.COM port->fp_options &= ~FP_TARGET_MODE; 1868*7836SJohn.Forte@Sun.COM break; 1869*7836SJohn.Forte@Sun.COM } 1870*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 1871*7836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd); 1872*7836SJohn.Forte@Sun.COM } 1873*7836SJohn.Forte@Sun.COM 1874*7836SJohn.Forte@Sun.COM return (rval); 1875*7836SJohn.Forte@Sun.COM } 1876*7836SJohn.Forte@Sun.COM 1877*7836SJohn.Forte@Sun.COM 1878*7836SJohn.Forte@Sun.COM void 1879*7836SJohn.Forte@Sun.COM fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 1880*7836SJohn.Forte@Sun.COM { 1881*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 1882*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 1883*7836SJohn.Forte@Sun.COM 1884*7836SJohn.Forte@Sun.COM if (pd) { 1885*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1886*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_DISABLE_RELOGIN; 1887*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1888*7836SJohn.Forte@Sun.COM } 1889*7836SJohn.Forte@Sun.COM } 1890*7836SJohn.Forte@Sun.COM 1891*7836SJohn.Forte@Sun.COM 1892*7836SJohn.Forte@Sun.COM void 1893*7836SJohn.Forte@Sun.COM fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 1894*7836SJohn.Forte@Sun.COM { 1895*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 1896*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 1897*7836SJohn.Forte@Sun.COM 1898*7836SJohn.Forte@Sun.COM if (pd) { 1899*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 1900*7836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN; 1901*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 1902*7836SJohn.Forte@Sun.COM } 1903*7836SJohn.Forte@Sun.COM } 1904*7836SJohn.Forte@Sun.COM 1905*7836SJohn.Forte@Sun.COM 1906*7836SJohn.Forte@Sun.COM /* 1907*7836SJohn.Forte@Sun.COM * fc_fca_init 1908*7836SJohn.Forte@Sun.COM * Overload the FCA bus_ops vector in its dev_ops with 1909*7836SJohn.Forte@Sun.COM * fctl_fca_busops to handle all the INITchilds for "sf" 1910*7836SJohn.Forte@Sun.COM * in one common place. 1911*7836SJohn.Forte@Sun.COM * 1912*7836SJohn.Forte@Sun.COM * Should be called from FCA _init routine. 1913*7836SJohn.Forte@Sun.COM */ 1914*7836SJohn.Forte@Sun.COM void 1915*7836SJohn.Forte@Sun.COM fc_fca_init(struct dev_ops *fca_devops_p) 1916*7836SJohn.Forte@Sun.COM { 1917*7836SJohn.Forte@Sun.COM #ifndef __lock_lint 1918*7836SJohn.Forte@Sun.COM fca_devops_p->devo_bus_ops = &fctl_fca_busops; 1919*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 1920*7836SJohn.Forte@Sun.COM } 1921*7836SJohn.Forte@Sun.COM 1922*7836SJohn.Forte@Sun.COM 1923*7836SJohn.Forte@Sun.COM /* 1924*7836SJohn.Forte@Sun.COM * fc_fca_attach 1925*7836SJohn.Forte@Sun.COM */ 1926*7836SJohn.Forte@Sun.COM int 1927*7836SJohn.Forte@Sun.COM fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran) 1928*7836SJohn.Forte@Sun.COM { 1929*7836SJohn.Forte@Sun.COM /* 1930*7836SJohn.Forte@Sun.COM * When we are in a position to offer downward compatibility 1931*7836SJohn.Forte@Sun.COM * we should change the following check to allow lower revision 1932*7836SJohn.Forte@Sun.COM * of FCAs; But we aren't there right now. 1933*7836SJohn.Forte@Sun.COM */ 1934*7836SJohn.Forte@Sun.COM if (tran->fca_version != FCTL_FCA_MODREV_5) { 1935*7836SJohn.Forte@Sun.COM const char *name = ddi_driver_name(fca_dip); 1936*7836SJohn.Forte@Sun.COM 1937*7836SJohn.Forte@Sun.COM ASSERT(name != NULL); 1938*7836SJohn.Forte@Sun.COM 1939*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: FCA %s version mismatch" 1940*7836SJohn.Forte@Sun.COM " please upgrade %s", name, name); 1941*7836SJohn.Forte@Sun.COM return (DDI_FAILURE); 1942*7836SJohn.Forte@Sun.COM } 1943*7836SJohn.Forte@Sun.COM 1944*7836SJohn.Forte@Sun.COM ddi_set_driver_private(fca_dip, (caddr_t)tran); 1945*7836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 1946*7836SJohn.Forte@Sun.COM } 1947*7836SJohn.Forte@Sun.COM 1948*7836SJohn.Forte@Sun.COM 1949*7836SJohn.Forte@Sun.COM /* 1950*7836SJohn.Forte@Sun.COM * fc_fca_detach 1951*7836SJohn.Forte@Sun.COM */ 1952*7836SJohn.Forte@Sun.COM int 1953*7836SJohn.Forte@Sun.COM fc_fca_detach(dev_info_t *fca_dip) 1954*7836SJohn.Forte@Sun.COM { 1955*7836SJohn.Forte@Sun.COM ddi_set_driver_private(fca_dip, NULL); 1956*7836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 1957*7836SJohn.Forte@Sun.COM } 1958*7836SJohn.Forte@Sun.COM 1959*7836SJohn.Forte@Sun.COM 1960*7836SJohn.Forte@Sun.COM /* 1961*7836SJohn.Forte@Sun.COM * Check if the frame is a Link response Frame; Handle all cases (P_RJT, 1962*7836SJohn.Forte@Sun.COM * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic 1963*7836SJohn.Forte@Sun.COM * Link Service responses such as BA_RJT and Extended Link Service response 1964*7836SJohn.Forte@Sun.COM * such as LS_RJT. If the response is a Link_Data Frame or something that 1965*7836SJohn.Forte@Sun.COM * this function doesn't understand return FC_FAILURE; Otherwise, fill out 1966*7836SJohn.Forte@Sun.COM * various fields (state, action, reason, expln) from the response gotten 1967*7836SJohn.Forte@Sun.COM * in the packet and return FC_SUCCESS. 1968*7836SJohn.Forte@Sun.COM */ 1969*7836SJohn.Forte@Sun.COM int 1970*7836SJohn.Forte@Sun.COM fc_fca_update_errors(fc_packet_t *pkt) 1971*7836SJohn.Forte@Sun.COM { 1972*7836SJohn.Forte@Sun.COM int ret = FC_SUCCESS; 1973*7836SJohn.Forte@Sun.COM 1974*7836SJohn.Forte@Sun.COM switch (pkt->pkt_resp_fhdr.r_ctl) { 1975*7836SJohn.Forte@Sun.COM case R_CTL_P_RJT: { 1976*7836SJohn.Forte@Sun.COM uint32_t prjt; 1977*7836SJohn.Forte@Sun.COM 1978*7836SJohn.Forte@Sun.COM prjt = pkt->pkt_resp_fhdr.ro; 1979*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_NPORT_RJT; 1980*7836SJohn.Forte@Sun.COM pkt->pkt_action = (prjt & 0xFF000000) >> 24; 1981*7836SJohn.Forte@Sun.COM pkt->pkt_reason = (prjt & 0xFF0000) >> 16; 1982*7836SJohn.Forte@Sun.COM break; 1983*7836SJohn.Forte@Sun.COM } 1984*7836SJohn.Forte@Sun.COM 1985*7836SJohn.Forte@Sun.COM case R_CTL_F_RJT: { 1986*7836SJohn.Forte@Sun.COM uint32_t frjt; 1987*7836SJohn.Forte@Sun.COM 1988*7836SJohn.Forte@Sun.COM frjt = pkt->pkt_resp_fhdr.ro; 1989*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_FABRIC_RJT; 1990*7836SJohn.Forte@Sun.COM pkt->pkt_action = (frjt & 0xFF000000) >> 24; 1991*7836SJohn.Forte@Sun.COM pkt->pkt_reason = (frjt & 0xFF0000) >> 16; 1992*7836SJohn.Forte@Sun.COM break; 1993*7836SJohn.Forte@Sun.COM } 1994*7836SJohn.Forte@Sun.COM 1995*7836SJohn.Forte@Sun.COM case R_CTL_P_BSY: { 1996*7836SJohn.Forte@Sun.COM uint32_t pbsy; 1997*7836SJohn.Forte@Sun.COM 1998*7836SJohn.Forte@Sun.COM pbsy = pkt->pkt_resp_fhdr.ro; 1999*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_NPORT_BSY; 2000*7836SJohn.Forte@Sun.COM pkt->pkt_action = (pbsy & 0xFF000000) >> 24; 2001*7836SJohn.Forte@Sun.COM pkt->pkt_reason = (pbsy & 0xFF0000) >> 16; 2002*7836SJohn.Forte@Sun.COM break; 2003*7836SJohn.Forte@Sun.COM } 2004*7836SJohn.Forte@Sun.COM 2005*7836SJohn.Forte@Sun.COM case R_CTL_F_BSY_LC: 2006*7836SJohn.Forte@Sun.COM case R_CTL_F_BSY_DF: { 2007*7836SJohn.Forte@Sun.COM uchar_t fbsy; 2008*7836SJohn.Forte@Sun.COM 2009*7836SJohn.Forte@Sun.COM fbsy = pkt->pkt_resp_fhdr.type; 2010*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_FABRIC_BSY; 2011*7836SJohn.Forte@Sun.COM pkt->pkt_reason = (fbsy & 0xF0) >> 4; 2012*7836SJohn.Forte@Sun.COM break; 2013*7836SJohn.Forte@Sun.COM } 2014*7836SJohn.Forte@Sun.COM 2015*7836SJohn.Forte@Sun.COM case R_CTL_LS_BA_RJT: { 2016*7836SJohn.Forte@Sun.COM uint32_t brjt; 2017*7836SJohn.Forte@Sun.COM 2018*7836SJohn.Forte@Sun.COM brjt = *(uint32_t *)pkt->pkt_resp; 2019*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_BA_RJT; 2020*7836SJohn.Forte@Sun.COM pkt->pkt_reason = (brjt & 0xFF0000) >> 16; 2021*7836SJohn.Forte@Sun.COM pkt->pkt_expln = (brjt & 0xFF00) >> 8; 2022*7836SJohn.Forte@Sun.COM break; 2023*7836SJohn.Forte@Sun.COM } 2024*7836SJohn.Forte@Sun.COM 2025*7836SJohn.Forte@Sun.COM case R_CTL_ELS_RSP: { 2026*7836SJohn.Forte@Sun.COM la_els_rjt_t *lsrjt; 2027*7836SJohn.Forte@Sun.COM 2028*7836SJohn.Forte@Sun.COM lsrjt = (la_els_rjt_t *)pkt->pkt_resp; 2029*7836SJohn.Forte@Sun.COM if (lsrjt->ls_code.ls_code == LA_ELS_RJT) { 2030*7836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_LS_RJT; 2031*7836SJohn.Forte@Sun.COM pkt->pkt_reason = lsrjt->reason; 2032*7836SJohn.Forte@Sun.COM pkt->pkt_action = lsrjt->action; 2033*7836SJohn.Forte@Sun.COM break; 2034*7836SJohn.Forte@Sun.COM } 2035*7836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 2036*7836SJohn.Forte@Sun.COM } 2037*7836SJohn.Forte@Sun.COM 2038*7836SJohn.Forte@Sun.COM default: 2039*7836SJohn.Forte@Sun.COM ret = FC_FAILURE; 2040*7836SJohn.Forte@Sun.COM break; 2041*7836SJohn.Forte@Sun.COM } 2042*7836SJohn.Forte@Sun.COM 2043*7836SJohn.Forte@Sun.COM return (ret); 2044*7836SJohn.Forte@Sun.COM } 2045*7836SJohn.Forte@Sun.COM 2046*7836SJohn.Forte@Sun.COM 2047*7836SJohn.Forte@Sun.COM int 2048*7836SJohn.Forte@Sun.COM fc_fca_error(int fc_errno, char **errmsg) 2049*7836SJohn.Forte@Sun.COM { 2050*7836SJohn.Forte@Sun.COM return (fctl_error(fc_errno, errmsg)); 2051*7836SJohn.Forte@Sun.COM } 2052*7836SJohn.Forte@Sun.COM 2053*7836SJohn.Forte@Sun.COM 2054*7836SJohn.Forte@Sun.COM int 2055*7836SJohn.Forte@Sun.COM fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason, 2056*7836SJohn.Forte@Sun.COM char **action, char **expln) 2057*7836SJohn.Forte@Sun.COM { 2058*7836SJohn.Forte@Sun.COM return (fctl_pkt_error(pkt, state, reason, action, expln)); 2059*7836SJohn.Forte@Sun.COM } 2060*7836SJohn.Forte@Sun.COM 2061*7836SJohn.Forte@Sun.COM 2062*7836SJohn.Forte@Sun.COM /* 2063*7836SJohn.Forte@Sun.COM * WWN to string goodie. Unpredictable results will happen 2064*7836SJohn.Forte@Sun.COM * if enough memory isn't supplied in str argument. If you 2065*7836SJohn.Forte@Sun.COM * are wondering how much does this routine need, it is just 2066*7836SJohn.Forte@Sun.COM * (2 * WWN size + 1). So for a WWN size of 8 bytes the str 2067*7836SJohn.Forte@Sun.COM * argument should have atleast 17 bytes allocated. 2068*7836SJohn.Forte@Sun.COM */ 2069*7836SJohn.Forte@Sun.COM void 2070*7836SJohn.Forte@Sun.COM fc_wwn_to_str(la_wwn_t *wwn, caddr_t str) 2071*7836SJohn.Forte@Sun.COM { 2072*7836SJohn.Forte@Sun.COM int count; 2073*7836SJohn.Forte@Sun.COM 2074*7836SJohn.Forte@Sun.COM for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) { 2075*7836SJohn.Forte@Sun.COM (void) sprintf(str, "%02x", wwn->raw_wwn[count]); 2076*7836SJohn.Forte@Sun.COM } 2077*7836SJohn.Forte@Sun.COM *str = '\0'; 2078*7836SJohn.Forte@Sun.COM } 2079*7836SJohn.Forte@Sun.COM 2080*7836SJohn.Forte@Sun.COM #define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') :\ 2081*7836SJohn.Forte@Sun.COM ((x) >= 'a' && (x) <= 'f') ?\ 2082*7836SJohn.Forte@Sun.COM ((x) - 'a' + 10) : ((x) - 'A' + 10)) 2083*7836SJohn.Forte@Sun.COM 2084*7836SJohn.Forte@Sun.COM void 2085*7836SJohn.Forte@Sun.COM fc_str_to_wwn(caddr_t str, la_wwn_t *wwn) 2086*7836SJohn.Forte@Sun.COM { 2087*7836SJohn.Forte@Sun.COM int count = 0; 2088*7836SJohn.Forte@Sun.COM uchar_t byte; 2089*7836SJohn.Forte@Sun.COM 2090*7836SJohn.Forte@Sun.COM while (*str) { 2091*7836SJohn.Forte@Sun.COM byte = FC_ATOB(*str); 2092*7836SJohn.Forte@Sun.COM str++; 2093*7836SJohn.Forte@Sun.COM byte = byte << 4 | FC_ATOB(*str); 2094*7836SJohn.Forte@Sun.COM str++; 2095*7836SJohn.Forte@Sun.COM wwn->raw_wwn[count++] = byte; 2096*7836SJohn.Forte@Sun.COM } 2097*7836SJohn.Forte@Sun.COM } 2098*7836SJohn.Forte@Sun.COM 2099*7836SJohn.Forte@Sun.COM /* 2100*7836SJohn.Forte@Sun.COM * FCA driver's intercepted bus control operations. 2101*7836SJohn.Forte@Sun.COM */ 2102*7836SJohn.Forte@Sun.COM static int 2103*7836SJohn.Forte@Sun.COM fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 2104*7836SJohn.Forte@Sun.COM ddi_ctl_enum_t op, void *arg, void *result) 2105*7836SJohn.Forte@Sun.COM { 2106*7836SJohn.Forte@Sun.COM switch (op) { 2107*7836SJohn.Forte@Sun.COM case DDI_CTLOPS_REPORTDEV: 2108*7836SJohn.Forte@Sun.COM break; 2109*7836SJohn.Forte@Sun.COM 2110*7836SJohn.Forte@Sun.COM case DDI_CTLOPS_IOMIN: 2111*7836SJohn.Forte@Sun.COM break; 2112*7836SJohn.Forte@Sun.COM 2113*7836SJohn.Forte@Sun.COM case DDI_CTLOPS_INITCHILD: 2114*7836SJohn.Forte@Sun.COM return (fctl_initchild(fca_dip, (dev_info_t *)arg)); 2115*7836SJohn.Forte@Sun.COM 2116*7836SJohn.Forte@Sun.COM case DDI_CTLOPS_UNINITCHILD: 2117*7836SJohn.Forte@Sun.COM return (fctl_uninitchild(fca_dip, (dev_info_t *)arg)); 2118*7836SJohn.Forte@Sun.COM 2119*7836SJohn.Forte@Sun.COM default: 2120*7836SJohn.Forte@Sun.COM return (ddi_ctlops(fca_dip, rip, op, arg, result)); 2121*7836SJohn.Forte@Sun.COM } 2122*7836SJohn.Forte@Sun.COM 2123*7836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 2124*7836SJohn.Forte@Sun.COM } 2125*7836SJohn.Forte@Sun.COM 2126*7836SJohn.Forte@Sun.COM 2127*7836SJohn.Forte@Sun.COM /* 2128*7836SJohn.Forte@Sun.COM * FCAs indicate the maximum number of ports supported in their 2129*7836SJohn.Forte@Sun.COM * tran structure. Fail the INITCHILD if the child port number 2130*7836SJohn.Forte@Sun.COM * is any greater than the maximum number of ports supported 2131*7836SJohn.Forte@Sun.COM * by the FCA. 2132*7836SJohn.Forte@Sun.COM */ 2133*7836SJohn.Forte@Sun.COM static int 2134*7836SJohn.Forte@Sun.COM fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip) 2135*7836SJohn.Forte@Sun.COM { 2136*7836SJohn.Forte@Sun.COM int rval; 2137*7836SJohn.Forte@Sun.COM int port_no; 2138*7836SJohn.Forte@Sun.COM int port_len; 2139*7836SJohn.Forte@Sun.COM char name[20]; 2140*7836SJohn.Forte@Sun.COM fc_fca_tran_t *tran; 2141*7836SJohn.Forte@Sun.COM dev_info_t *dip; 2142*7836SJohn.Forte@Sun.COM int portprop; 2143*7836SJohn.Forte@Sun.COM 2144*7836SJohn.Forte@Sun.COM port_len = sizeof (port_no); 2145*7836SJohn.Forte@Sun.COM 2146*7836SJohn.Forte@Sun.COM /* physical port do not has this property */ 2147*7836SJohn.Forte@Sun.COM portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip, 2148*7836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 2149*7836SJohn.Forte@Sun.COM "phyport-instance", -1); 2150*7836SJohn.Forte@Sun.COM 2151*7836SJohn.Forte@Sun.COM if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) { 2152*7836SJohn.Forte@Sun.COM /* 2153*7836SJohn.Forte@Sun.COM * Clear any addr bindings created by fcode interpreter 2154*7836SJohn.Forte@Sun.COM * in devi_last_addr so that a ndi_devi_find should never 2155*7836SJohn.Forte@Sun.COM * return this fcode node. 2156*7836SJohn.Forte@Sun.COM */ 2157*7836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 2158*7836SJohn.Forte@Sun.COM return (DDI_FAILURE); 2159*7836SJohn.Forte@Sun.COM } 2160*7836SJohn.Forte@Sun.COM 2161*7836SJohn.Forte@Sun.COM rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF, 2162*7836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 2163*7836SJohn.Forte@Sun.COM (caddr_t)&port_no, &port_len); 2164*7836SJohn.Forte@Sun.COM 2165*7836SJohn.Forte@Sun.COM if (rval != DDI_SUCCESS) { 2166*7836SJohn.Forte@Sun.COM return (DDI_FAILURE); 2167*7836SJohn.Forte@Sun.COM } 2168*7836SJohn.Forte@Sun.COM 2169*7836SJohn.Forte@Sun.COM tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip); 2170*7836SJohn.Forte@Sun.COM ASSERT(tran != NULL); 2171*7836SJohn.Forte@Sun.COM 2172*7836SJohn.Forte@Sun.COM (void) sprintf((char *)name, "%x,0", port_no); 2173*7836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, name); 2174*7836SJohn.Forte@Sun.COM 2175*7836SJohn.Forte@Sun.COM dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 2176*7836SJohn.Forte@Sun.COM 2177*7836SJohn.Forte@Sun.COM /* 2178*7836SJohn.Forte@Sun.COM * Even though we never initialize FCode nodes of fp, such a node 2179*7836SJohn.Forte@Sun.COM * could still be there after a DR operation. There will only be 2180*7836SJohn.Forte@Sun.COM * one FCode node, so if this is the one, clear it and issue a 2181*7836SJohn.Forte@Sun.COM * ndi_devi_find again. 2182*7836SJohn.Forte@Sun.COM */ 2183*7836SJohn.Forte@Sun.COM if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) { 2184*7836SJohn.Forte@Sun.COM ddi_set_name_addr(dip, NULL); 2185*7836SJohn.Forte@Sun.COM dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 2186*7836SJohn.Forte@Sun.COM } 2187*7836SJohn.Forte@Sun.COM 2188*7836SJohn.Forte@Sun.COM if ((portprop == -1) && dip && (dip != port_dip)) { 2189*7836SJohn.Forte@Sun.COM /* 2190*7836SJohn.Forte@Sun.COM * Here we have a duplicate .conf entry. Clear the addr 2191*7836SJohn.Forte@Sun.COM * set previously and return failure. 2192*7836SJohn.Forte@Sun.COM */ 2193*7836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 2194*7836SJohn.Forte@Sun.COM return (DDI_FAILURE); 2195*7836SJohn.Forte@Sun.COM } 2196*7836SJohn.Forte@Sun.COM 2197*7836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 2198*7836SJohn.Forte@Sun.COM } 2199*7836SJohn.Forte@Sun.COM 2200*7836SJohn.Forte@Sun.COM 2201*7836SJohn.Forte@Sun.COM /* ARGSUSED */ 2202*7836SJohn.Forte@Sun.COM static int 2203*7836SJohn.Forte@Sun.COM fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip) 2204*7836SJohn.Forte@Sun.COM { 2205*7836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 2206*7836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 2207*7836SJohn.Forte@Sun.COM } 2208*7836SJohn.Forte@Sun.COM 2209*7836SJohn.Forte@Sun.COM 2210*7836SJohn.Forte@Sun.COM static dev_info_t * 2211*7836SJohn.Forte@Sun.COM fctl_findchild(dev_info_t *pdip, char *cname, char *caddr) 2212*7836SJohn.Forte@Sun.COM { 2213*7836SJohn.Forte@Sun.COM dev_info_t *dip; 2214*7836SJohn.Forte@Sun.COM char *addr; 2215*7836SJohn.Forte@Sun.COM 2216*7836SJohn.Forte@Sun.COM ASSERT(cname != NULL && caddr != NULL); 2217*7836SJohn.Forte@Sun.COM /* ASSERT(DEVI_BUSY_OWNED(pdip)); */ 2218*7836SJohn.Forte@Sun.COM 2219*7836SJohn.Forte@Sun.COM for (dip = ddi_get_child(pdip); dip != NULL; 2220*7836SJohn.Forte@Sun.COM dip = ddi_get_next_sibling(dip)) { 2221*7836SJohn.Forte@Sun.COM if (strcmp(cname, ddi_node_name(dip)) != 0) 2222*7836SJohn.Forte@Sun.COM continue; 2223*7836SJohn.Forte@Sun.COM 2224*7836SJohn.Forte@Sun.COM if ((addr = ddi_get_name_addr(dip)) == NULL) { 2225*7836SJohn.Forte@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 2226*7836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 2227*7836SJohn.Forte@Sun.COM "bus-addr", &addr) == DDI_PROP_SUCCESS) { 2228*7836SJohn.Forte@Sun.COM if (strcmp(caddr, addr) == 0) { 2229*7836SJohn.Forte@Sun.COM ddi_prop_free(addr); 2230*7836SJohn.Forte@Sun.COM return (dip); 2231*7836SJohn.Forte@Sun.COM } 2232*7836SJohn.Forte@Sun.COM ddi_prop_free(addr); 2233*7836SJohn.Forte@Sun.COM } 2234*7836SJohn.Forte@Sun.COM } else { 2235*7836SJohn.Forte@Sun.COM if (strcmp(caddr, addr) == 0) 2236*7836SJohn.Forte@Sun.COM return (dip); 2237*7836SJohn.Forte@Sun.COM } 2238*7836SJohn.Forte@Sun.COM } 2239*7836SJohn.Forte@Sun.COM 2240*7836SJohn.Forte@Sun.COM return (NULL); 2241*7836SJohn.Forte@Sun.COM } 2242*7836SJohn.Forte@Sun.COM 2243*7836SJohn.Forte@Sun.COM int 2244*7836SJohn.Forte@Sun.COM fctl_check_npiv_portindex(dev_info_t *dip, int vindex) 2245*7836SJohn.Forte@Sun.COM { 2246*7836SJohn.Forte@Sun.COM int i, instance; 2247*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 2248*7836SJohn.Forte@Sun.COM 2249*7836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 2250*7836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2251*7836SJohn.Forte@Sun.COM if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) { 2252*7836SJohn.Forte@Sun.COM return (0); 2253*7836SJohn.Forte@Sun.COM } 2254*7836SJohn.Forte@Sun.COM 2255*7836SJohn.Forte@Sun.COM i = vindex-1; 2256*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 2257*7836SJohn.Forte@Sun.COM if (port->fp_npiv_portindex[i] == 0) { 2258*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2259*7836SJohn.Forte@Sun.COM return (vindex); 2260*7836SJohn.Forte@Sun.COM } 2261*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2262*7836SJohn.Forte@Sun.COM return (0); 2263*7836SJohn.Forte@Sun.COM } 2264*7836SJohn.Forte@Sun.COM 2265*7836SJohn.Forte@Sun.COM int 2266*7836SJohn.Forte@Sun.COM fctl_get_npiv_portindex(dev_info_t *dip) 2267*7836SJohn.Forte@Sun.COM { 2268*7836SJohn.Forte@Sun.COM int i, instance; 2269*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 2270*7836SJohn.Forte@Sun.COM 2271*7836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 2272*7836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2273*7836SJohn.Forte@Sun.COM if (!port) { 2274*7836SJohn.Forte@Sun.COM return (0); 2275*7836SJohn.Forte@Sun.COM } 2276*7836SJohn.Forte@Sun.COM 2277*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 2278*7836SJohn.Forte@Sun.COM for (i = 0; i < FC_NPIV_MAX_PORT; i++) { 2279*7836SJohn.Forte@Sun.COM if (port->fp_npiv_portindex[i] == 0) { 2280*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2281*7836SJohn.Forte@Sun.COM return (i+1); 2282*7836SJohn.Forte@Sun.COM } 2283*7836SJohn.Forte@Sun.COM } 2284*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2285*7836SJohn.Forte@Sun.COM return (0); 2286*7836SJohn.Forte@Sun.COM } 2287*7836SJohn.Forte@Sun.COM 2288*7836SJohn.Forte@Sun.COM 2289*7836SJohn.Forte@Sun.COM void 2290*7836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(dev_info_t *dip, int index) 2291*7836SJohn.Forte@Sun.COM { 2292*7836SJohn.Forte@Sun.COM int instance; 2293*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 2294*7836SJohn.Forte@Sun.COM 2295*7836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 2296*7836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 2297*7836SJohn.Forte@Sun.COM if (!port) { 2298*7836SJohn.Forte@Sun.COM return; 2299*7836SJohn.Forte@Sun.COM } 2300*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 2301*7836SJohn.Forte@Sun.COM port->fp_npiv_portindex[index - 1] = 1; 2302*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2303*7836SJohn.Forte@Sun.COM } 2304*7836SJohn.Forte@Sun.COM 2305*7836SJohn.Forte@Sun.COM 2306*7836SJohn.Forte@Sun.COM int 2307*7836SJohn.Forte@Sun.COM fctl_fca_create_npivport(dev_info_t *parent, 2308*7836SJohn.Forte@Sun.COM dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex) 2309*7836SJohn.Forte@Sun.COM { 2310*7836SJohn.Forte@Sun.COM int rval = 0, devstrlen; 2311*7836SJohn.Forte@Sun.COM char *devname, *cname, *caddr, *devstr; 2312*7836SJohn.Forte@Sun.COM dev_info_t *child = NULL; 2313*7836SJohn.Forte@Sun.COM int portnum; 2314*7836SJohn.Forte@Sun.COM 2315*7836SJohn.Forte@Sun.COM if (*vindex == 0) { 2316*7836SJohn.Forte@Sun.COM portnum = fctl_get_npiv_portindex(phydip); 2317*7836SJohn.Forte@Sun.COM *vindex = portnum; 2318*7836SJohn.Forte@Sun.COM } else { 2319*7836SJohn.Forte@Sun.COM portnum = fctl_check_npiv_portindex(phydip, *vindex); 2320*7836SJohn.Forte@Sun.COM } 2321*7836SJohn.Forte@Sun.COM 2322*7836SJohn.Forte@Sun.COM if (portnum == 0) { 2323*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 2324*7836SJohn.Forte@Sun.COM "Cann't find valid port index, fail to create devnode"); 2325*7836SJohn.Forte@Sun.COM return (NDI_FAILURE); 2326*7836SJohn.Forte@Sun.COM } 2327*7836SJohn.Forte@Sun.COM 2328*7836SJohn.Forte@Sun.COM devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 2329*7836SJohn.Forte@Sun.COM (void) sprintf(devname, "fp@%x,0", portnum); 2330*7836SJohn.Forte@Sun.COM devstrlen = strlen(devname) + 1; 2331*7836SJohn.Forte@Sun.COM devstr = i_ddi_strdup(devname, KM_SLEEP); 2332*7836SJohn.Forte@Sun.COM i_ddi_parse_name(devstr, &cname, &caddr, NULL); 2333*7836SJohn.Forte@Sun.COM 2334*7836SJohn.Forte@Sun.COM if (fctl_findchild(parent, cname, caddr) != NULL) { 2335*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2336*7836SJohn.Forte@Sun.COM goto freememory; 2337*7836SJohn.Forte@Sun.COM } 2338*7836SJohn.Forte@Sun.COM 2339*7836SJohn.Forte@Sun.COM ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child); 2340*7836SJohn.Forte@Sun.COM if (child == NULL) { 2341*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 2342*7836SJohn.Forte@Sun.COM "fctl_create_npiv_port fail to create new devinfo"); 2343*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2344*7836SJohn.Forte@Sun.COM goto freememory; 2345*7836SJohn.Forte@Sun.COM } 2346*7836SJohn.Forte@Sun.COM 2347*7836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2348*7836SJohn.Forte@Sun.COM "bus-addr", caddr) != DDI_PROP_SUCCESS) { 2349*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed", 2350*7836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 2351*7836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 2352*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2353*7836SJohn.Forte@Sun.COM goto freememory; 2354*7836SJohn.Forte@Sun.COM } 2355*7836SJohn.Forte@Sun.COM 2356*7836SJohn.Forte@Sun.COM if (strlen(nname) != 0) { 2357*7836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2358*7836SJohn.Forte@Sun.COM "node-name", nname) != DDI_PROP_SUCCESS) { 2359*7836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 2360*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2361*7836SJohn.Forte@Sun.COM goto freememory; 2362*7836SJohn.Forte@Sun.COM } 2363*7836SJohn.Forte@Sun.COM } 2364*7836SJohn.Forte@Sun.COM 2365*7836SJohn.Forte@Sun.COM if (strlen(pname) != 0) { 2366*7836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 2367*7836SJohn.Forte@Sun.COM "port-name", pname) != DDI_PROP_SUCCESS) { 2368*7836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 2369*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2370*7836SJohn.Forte@Sun.COM goto freememory; 2371*7836SJohn.Forte@Sun.COM } 2372*7836SJohn.Forte@Sun.COM } 2373*7836SJohn.Forte@Sun.COM 2374*7836SJohn.Forte@Sun.COM if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 2375*7836SJohn.Forte@Sun.COM "port", portnum) != DDI_PROP_SUCCESS) { 2376*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed", 2377*7836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 2378*7836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 2379*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2380*7836SJohn.Forte@Sun.COM goto freememory; 2381*7836SJohn.Forte@Sun.COM } 2382*7836SJohn.Forte@Sun.COM 2383*7836SJohn.Forte@Sun.COM if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 2384*7836SJohn.Forte@Sun.COM "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) { 2385*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 2386*7836SJohn.Forte@Sun.COM "fp%d: prop_update phyport-instance %s@%s failed", 2387*7836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 2388*7836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 2389*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2390*7836SJohn.Forte@Sun.COM goto freememory; 2391*7836SJohn.Forte@Sun.COM } 2392*7836SJohn.Forte@Sun.COM 2393*7836SJohn.Forte@Sun.COM rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); 2394*7836SJohn.Forte@Sun.COM if (rval != NDI_SUCCESS) { 2395*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fp%d: online_driver %s failed", 2396*7836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname); 2397*7836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 2398*7836SJohn.Forte@Sun.COM goto freememory; 2399*7836SJohn.Forte@Sun.COM } 2400*7836SJohn.Forte@Sun.COM 2401*7836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(phydip, portnum); 2402*7836SJohn.Forte@Sun.COM freememory: 2403*7836SJohn.Forte@Sun.COM kmem_free(devstr, devstrlen); 2404*7836SJohn.Forte@Sun.COM kmem_free(devname, MAXNAMELEN); 2405*7836SJohn.Forte@Sun.COM 2406*7836SJohn.Forte@Sun.COM return (rval); 2407*7836SJohn.Forte@Sun.COM } 2408*7836SJohn.Forte@Sun.COM 2409*7836SJohn.Forte@Sun.COM 2410*7836SJohn.Forte@Sun.COM void 2411*7836SJohn.Forte@Sun.COM fctl_add_port(fc_local_port_t *port) 2412*7836SJohn.Forte@Sun.COM { 2413*7836SJohn.Forte@Sun.COM fc_fca_port_t *new; 2414*7836SJohn.Forte@Sun.COM 2415*7836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), KM_SLEEP); 2416*7836SJohn.Forte@Sun.COM 2417*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 2418*7836SJohn.Forte@Sun.COM new->port_handle = port; 2419*7836SJohn.Forte@Sun.COM new->port_next = fctl_fca_portlist; 2420*7836SJohn.Forte@Sun.COM fctl_fca_portlist = new; 2421*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 2422*7836SJohn.Forte@Sun.COM } 2423*7836SJohn.Forte@Sun.COM 2424*7836SJohn.Forte@Sun.COM 2425*7836SJohn.Forte@Sun.COM void 2426*7836SJohn.Forte@Sun.COM fctl_remove_port(fc_local_port_t *port) 2427*7836SJohn.Forte@Sun.COM { 2428*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 2429*7836SJohn.Forte@Sun.COM fc_fca_port_t *prev; 2430*7836SJohn.Forte@Sun.COM fc_fca_port_t *list; 2431*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 2432*7836SJohn.Forte@Sun.COM 2433*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_WRITER); 2434*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 2435*7836SJohn.Forte@Sun.COM 2436*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2437*7836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 2438*7836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 2439*7836SJohn.Forte@Sun.COM continue; 2440*7836SJohn.Forte@Sun.COM } 2441*7836SJohn.Forte@Sun.COM 2442*7836SJohn.Forte@Sun.COM #ifndef __lock_lint 2443*7836SJohn.Forte@Sun.COM ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0); 2444*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 2445*7836SJohn.Forte@Sun.COM 2446*7836SJohn.Forte@Sun.COM (void) fctl_remove_ulp_port(mod, port); 2447*7836SJohn.Forte@Sun.COM } 2448*7836SJohn.Forte@Sun.COM 2449*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 2450*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 2451*7836SJohn.Forte@Sun.COM 2452*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 2453*7836SJohn.Forte@Sun.COM 2454*7836SJohn.Forte@Sun.COM list = fctl_fca_portlist; 2455*7836SJohn.Forte@Sun.COM prev = NULL; 2456*7836SJohn.Forte@Sun.COM while (list != NULL) { 2457*7836SJohn.Forte@Sun.COM if (list->port_handle == port) { 2458*7836SJohn.Forte@Sun.COM if (prev == NULL) { 2459*7836SJohn.Forte@Sun.COM fctl_fca_portlist = list->port_next; 2460*7836SJohn.Forte@Sun.COM } else { 2461*7836SJohn.Forte@Sun.COM prev->port_next = list->port_next; 2462*7836SJohn.Forte@Sun.COM } 2463*7836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 2464*7836SJohn.Forte@Sun.COM break; 2465*7836SJohn.Forte@Sun.COM } 2466*7836SJohn.Forte@Sun.COM prev = list; 2467*7836SJohn.Forte@Sun.COM list = list->port_next; 2468*7836SJohn.Forte@Sun.COM } 2469*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 2470*7836SJohn.Forte@Sun.COM } 2471*7836SJohn.Forte@Sun.COM 2472*7836SJohn.Forte@Sun.COM 2473*7836SJohn.Forte@Sun.COM void 2474*7836SJohn.Forte@Sun.COM fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd, 2475*7836SJohn.Forte@Sun.COM struct modlinkage *linkage) 2476*7836SJohn.Forte@Sun.COM { 2477*7836SJohn.Forte@Sun.COM int rval; 2478*7836SJohn.Forte@Sun.COM uint32_t s_id; 2479*7836SJohn.Forte@Sun.COM uint32_t state; 2480*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 2481*7836SJohn.Forte@Sun.COM fc_ulp_port_info_t info; 2482*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 2483*7836SJohn.Forte@Sun.COM 2484*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 2485*7836SJohn.Forte@Sun.COM 2486*7836SJohn.Forte@Sun.COM info.port_linkage = linkage; 2487*7836SJohn.Forte@Sun.COM info.port_dip = port->fp_port_dip; 2488*7836SJohn.Forte@Sun.COM info.port_handle = (opaque_t)port; 2489*7836SJohn.Forte@Sun.COM info.port_dma_behavior = port->fp_dma_behavior; 2490*7836SJohn.Forte@Sun.COM info.port_fcp_dma = port->fp_fcp_dma; 2491*7836SJohn.Forte@Sun.COM info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 2492*7836SJohn.Forte@Sun.COM info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 2493*7836SJohn.Forte@Sun.COM info.port_reset_action = port->fp_reset_action; 2494*7836SJohn.Forte@Sun.COM 2495*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 2496*7836SJohn.Forte@Sun.COM 2497*7836SJohn.Forte@Sun.COM /* 2498*7836SJohn.Forte@Sun.COM * It is still possible that another thread could have gotten 2499*7836SJohn.Forte@Sun.COM * into the detach process before we got here. 2500*7836SJohn.Forte@Sun.COM */ 2501*7836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 2502*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2503*7836SJohn.Forte@Sun.COM return; 2504*7836SJohn.Forte@Sun.COM } 2505*7836SJohn.Forte@Sun.COM 2506*7836SJohn.Forte@Sun.COM s_id = port->fp_port_id.port_id; 2507*7836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 2508*7836SJohn.Forte@Sun.COM info.port_state = port->fp_bind_state; 2509*7836SJohn.Forte@Sun.COM } else { 2510*7836SJohn.Forte@Sun.COM info.port_state = port->fp_state; 2511*7836SJohn.Forte@Sun.COM } 2512*7836SJohn.Forte@Sun.COM 2513*7836SJohn.Forte@Sun.COM switch (state = FC_PORT_STATE_MASK(info.port_state)) { 2514*7836SJohn.Forte@Sun.COM case FC_STATE_LOOP: 2515*7836SJohn.Forte@Sun.COM case FC_STATE_NAMESERVICE: 2516*7836SJohn.Forte@Sun.COM info.port_state &= ~state; 2517*7836SJohn.Forte@Sun.COM info.port_state |= FC_STATE_ONLINE; 2518*7836SJohn.Forte@Sun.COM break; 2519*7836SJohn.Forte@Sun.COM 2520*7836SJohn.Forte@Sun.COM default: 2521*7836SJohn.Forte@Sun.COM break; 2522*7836SJohn.Forte@Sun.COM } 2523*7836SJohn.Forte@Sun.COM ASSERT((info.port_state & FC_STATE_LOOP) == 0); 2524*7836SJohn.Forte@Sun.COM 2525*7836SJohn.Forte@Sun.COM info.port_flags = port->fp_topology; 2526*7836SJohn.Forte@Sun.COM info.port_pwwn = port->fp_service_params.nport_ww_name; 2527*7836SJohn.Forte@Sun.COM info.port_nwwn = port->fp_service_params.node_ww_name; 2528*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2529*7836SJohn.Forte@Sun.COM 2530*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 2531*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 2532*7836SJohn.Forte@Sun.COM 2533*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2534*7836SJohn.Forte@Sun.COM if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 2535*7836SJohn.Forte@Sun.COM ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP); 2536*7836SJohn.Forte@Sun.COM ASSERT(ulp_port != NULL); 2537*7836SJohn.Forte@Sun.COM 2538*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2539*7836SJohn.Forte@Sun.COM ulp_port->port_statec = (info.port_state & 2540*7836SJohn.Forte@Sun.COM FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE : 2541*7836SJohn.Forte@Sun.COM FC_ULP_STATEC_OFFLINE; 2542*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2543*7836SJohn.Forte@Sun.COM } 2544*7836SJohn.Forte@Sun.COM } 2545*7836SJohn.Forte@Sun.COM 2546*7836SJohn.Forte@Sun.COM rw_downgrade(&fctl_mod_ports_lock); 2547*7836SJohn.Forte@Sun.COM 2548*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2549*7836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 2550*7836SJohn.Forte@Sun.COM ASSERT(ulp_port != NULL); 2551*7836SJohn.Forte@Sun.COM 2552*7836SJohn.Forte@Sun.COM if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) { 2553*7836SJohn.Forte@Sun.COM continue; 2554*7836SJohn.Forte@Sun.COM } 2555*7836SJohn.Forte@Sun.COM 2556*7836SJohn.Forte@Sun.COM fctl_init_dma_attr(port, mod, &info); 2557*7836SJohn.Forte@Sun.COM 2558*7836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_port_attach( 2559*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, &info, cmd, s_id); 2560*7836SJohn.Forte@Sun.COM 2561*7836SJohn.Forte@Sun.COM fctl_post_attach(mod, ulp_port, cmd, rval); 2562*7836SJohn.Forte@Sun.COM 2563*7836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH && 2564*7836SJohn.Forte@Sun.COM strcmp(mod->mod_info->ulp_name, "fcp") == 0) { 2565*7836SJohn.Forte@Sun.COM ASSERT(ddi_get_driver_private(info.port_dip) != NULL); 2566*7836SJohn.Forte@Sun.COM } 2567*7836SJohn.Forte@Sun.COM } 2568*7836SJohn.Forte@Sun.COM 2569*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 2570*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 2571*7836SJohn.Forte@Sun.COM } 2572*7836SJohn.Forte@Sun.COM 2573*7836SJohn.Forte@Sun.COM 2574*7836SJohn.Forte@Sun.COM static int 2575*7836SJohn.Forte@Sun.COM fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd) 2576*7836SJohn.Forte@Sun.COM { 2577*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 2578*7836SJohn.Forte@Sun.COM 2579*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2580*7836SJohn.Forte@Sun.COM 2581*7836SJohn.Forte@Sun.COM switch (cmd) { 2582*7836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 2583*7836SJohn.Forte@Sun.COM if (ulp_port->port_dstate & ULP_PORT_ATTACH) { 2584*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2585*7836SJohn.Forte@Sun.COM } 2586*7836SJohn.Forte@Sun.COM break; 2587*7836SJohn.Forte@Sun.COM 2588*7836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 2589*7836SJohn.Forte@Sun.COM ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0); 2590*7836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2591*7836SJohn.Forte@Sun.COM !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) { 2592*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2593*7836SJohn.Forte@Sun.COM } 2594*7836SJohn.Forte@Sun.COM break; 2595*7836SJohn.Forte@Sun.COM 2596*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 2597*7836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2598*7836SJohn.Forte@Sun.COM !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) { 2599*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2600*7836SJohn.Forte@Sun.COM } 2601*7836SJohn.Forte@Sun.COM break; 2602*7836SJohn.Forte@Sun.COM } 2603*7836SJohn.Forte@Sun.COM 2604*7836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 2605*7836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_BUSY; 2606*7836SJohn.Forte@Sun.COM } 2607*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2608*7836SJohn.Forte@Sun.COM 2609*7836SJohn.Forte@Sun.COM return (rval); 2610*7836SJohn.Forte@Sun.COM } 2611*7836SJohn.Forte@Sun.COM 2612*7836SJohn.Forte@Sun.COM 2613*7836SJohn.Forte@Sun.COM static void 2614*7836SJohn.Forte@Sun.COM fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 2615*7836SJohn.Forte@Sun.COM fc_attach_cmd_t cmd, int rval) 2616*7836SJohn.Forte@Sun.COM { 2617*7836SJohn.Forte@Sun.COM int be_chatty; 2618*7836SJohn.Forte@Sun.COM 2619*7836SJohn.Forte@Sun.COM ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME || 2620*7836SJohn.Forte@Sun.COM cmd == FC_CMD_POWER_UP); 2621*7836SJohn.Forte@Sun.COM 2622*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2623*7836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_BUSY; 2624*7836SJohn.Forte@Sun.COM 2625*7836SJohn.Forte@Sun.COM be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1; 2626*7836SJohn.Forte@Sun.COM 2627*7836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 2628*7836SJohn.Forte@Sun.COM caddr_t op; 2629*7836SJohn.Forte@Sun.COM fc_local_port_t *port = ulp_port->port_handle; 2630*7836SJohn.Forte@Sun.COM 2631*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2632*7836SJohn.Forte@Sun.COM 2633*7836SJohn.Forte@Sun.COM switch (cmd) { 2634*7836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 2635*7836SJohn.Forte@Sun.COM op = "attach"; 2636*7836SJohn.Forte@Sun.COM break; 2637*7836SJohn.Forte@Sun.COM 2638*7836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 2639*7836SJohn.Forte@Sun.COM op = "resume"; 2640*7836SJohn.Forte@Sun.COM break; 2641*7836SJohn.Forte@Sun.COM 2642*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 2643*7836SJohn.Forte@Sun.COM op = "power up"; 2644*7836SJohn.Forte@Sun.COM break; 2645*7836SJohn.Forte@Sun.COM } 2646*7836SJohn.Forte@Sun.COM 2647*7836SJohn.Forte@Sun.COM if (be_chatty) { 2648*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 2649*7836SJohn.Forte@Sun.COM port->fp_instance, op, mod->mod_info->ulp_name); 2650*7836SJohn.Forte@Sun.COM } 2651*7836SJohn.Forte@Sun.COM 2652*7836SJohn.Forte@Sun.COM return; 2653*7836SJohn.Forte@Sun.COM } 2654*7836SJohn.Forte@Sun.COM 2655*7836SJohn.Forte@Sun.COM switch (cmd) { 2656*7836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 2657*7836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_ATTACH; 2658*7836SJohn.Forte@Sun.COM break; 2659*7836SJohn.Forte@Sun.COM 2660*7836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 2661*7836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_SUSPEND; 2662*7836SJohn.Forte@Sun.COM break; 2663*7836SJohn.Forte@Sun.COM 2664*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 2665*7836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN; 2666*7836SJohn.Forte@Sun.COM break; 2667*7836SJohn.Forte@Sun.COM } 2668*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2669*7836SJohn.Forte@Sun.COM } 2670*7836SJohn.Forte@Sun.COM 2671*7836SJohn.Forte@Sun.COM 2672*7836SJohn.Forte@Sun.COM int 2673*7836SJohn.Forte@Sun.COM fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd, 2674*7836SJohn.Forte@Sun.COM struct modlinkage *linkage) 2675*7836SJohn.Forte@Sun.COM { 2676*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 2677*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 2678*7836SJohn.Forte@Sun.COM fc_ulp_port_info_t info; 2679*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 2680*7836SJohn.Forte@Sun.COM 2681*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 2682*7836SJohn.Forte@Sun.COM 2683*7836SJohn.Forte@Sun.COM info.port_linkage = linkage; 2684*7836SJohn.Forte@Sun.COM info.port_dip = port->fp_port_dip; 2685*7836SJohn.Forte@Sun.COM info.port_handle = (opaque_t)port; 2686*7836SJohn.Forte@Sun.COM info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 2687*7836SJohn.Forte@Sun.COM info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 2688*7836SJohn.Forte@Sun.COM 2689*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 2690*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 2691*7836SJohn.Forte@Sun.COM 2692*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 2693*7836SJohn.Forte@Sun.COM if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 2694*7836SJohn.Forte@Sun.COM continue; 2695*7836SJohn.Forte@Sun.COM } 2696*7836SJohn.Forte@Sun.COM 2697*7836SJohn.Forte@Sun.COM if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) { 2698*7836SJohn.Forte@Sun.COM continue; 2699*7836SJohn.Forte@Sun.COM } 2700*7836SJohn.Forte@Sun.COM 2701*7836SJohn.Forte@Sun.COM fctl_init_dma_attr(port, mod, &info); 2702*7836SJohn.Forte@Sun.COM 2703*7836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_port_detach( 2704*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, &info, cmd); 2705*7836SJohn.Forte@Sun.COM 2706*7836SJohn.Forte@Sun.COM fctl_post_detach(mod, ulp_port, cmd, rval); 2707*7836SJohn.Forte@Sun.COM 2708*7836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 2709*7836SJohn.Forte@Sun.COM break; 2710*7836SJohn.Forte@Sun.COM } 2711*7836SJohn.Forte@Sun.COM 2712*7836SJohn.Forte@Sun.COM if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name, 2713*7836SJohn.Forte@Sun.COM "fcp") == 0) { 2714*7836SJohn.Forte@Sun.COM ASSERT(ddi_get_driver_private(info.port_dip) == NULL); 2715*7836SJohn.Forte@Sun.COM } 2716*7836SJohn.Forte@Sun.COM 2717*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2718*7836SJohn.Forte@Sun.COM ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE; 2719*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2720*7836SJohn.Forte@Sun.COM } 2721*7836SJohn.Forte@Sun.COM 2722*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 2723*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 2724*7836SJohn.Forte@Sun.COM 2725*7836SJohn.Forte@Sun.COM return (rval); 2726*7836SJohn.Forte@Sun.COM } 2727*7836SJohn.Forte@Sun.COM 2728*7836SJohn.Forte@Sun.COM static void 2729*7836SJohn.Forte@Sun.COM fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod, 2730*7836SJohn.Forte@Sun.COM fc_ulp_port_info_t *info) 2731*7836SJohn.Forte@Sun.COM { 2732*7836SJohn.Forte@Sun.COM 2733*7836SJohn.Forte@Sun.COM if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) || 2734*7836SJohn.Forte@Sun.COM (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) { 2735*7836SJohn.Forte@Sun.COM info->port_cmd_dma_attr = 2736*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcp_cmd_attr; 2737*7836SJohn.Forte@Sun.COM info->port_data_dma_attr = 2738*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcp_data_attr; 2739*7836SJohn.Forte@Sun.COM info->port_resp_dma_attr = 2740*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcp_rsp_attr; 2741*7836SJohn.Forte@Sun.COM } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) { 2742*7836SJohn.Forte@Sun.COM info->port_cmd_dma_attr = 2743*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcsm_cmd_attr; 2744*7836SJohn.Forte@Sun.COM info->port_data_dma_attr = 2745*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_attr; 2746*7836SJohn.Forte@Sun.COM info->port_resp_dma_attr = 2747*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcsm_rsp_attr; 2748*7836SJohn.Forte@Sun.COM } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) { 2749*7836SJohn.Forte@Sun.COM info->port_cmd_dma_attr = 2750*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcip_cmd_attr; 2751*7836SJohn.Forte@Sun.COM info->port_data_dma_attr = 2752*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_attr; 2753*7836SJohn.Forte@Sun.COM info->port_resp_dma_attr = 2754*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_fcip_rsp_attr; 2755*7836SJohn.Forte@Sun.COM } else { 2756*7836SJohn.Forte@Sun.COM info->port_cmd_dma_attr = info->port_data_dma_attr = 2757*7836SJohn.Forte@Sun.COM info->port_resp_dma_attr = 2758*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_dma_attr; /* default */ 2759*7836SJohn.Forte@Sun.COM } 2760*7836SJohn.Forte@Sun.COM } 2761*7836SJohn.Forte@Sun.COM 2762*7836SJohn.Forte@Sun.COM static int 2763*7836SJohn.Forte@Sun.COM fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd) 2764*7836SJohn.Forte@Sun.COM { 2765*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 2766*7836SJohn.Forte@Sun.COM 2767*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2768*7836SJohn.Forte@Sun.COM 2769*7836SJohn.Forte@Sun.COM switch (cmd) { 2770*7836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 2771*7836SJohn.Forte@Sun.COM if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) { 2772*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2773*7836SJohn.Forte@Sun.COM } 2774*7836SJohn.Forte@Sun.COM break; 2775*7836SJohn.Forte@Sun.COM 2776*7836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 2777*7836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2778*7836SJohn.Forte@Sun.COM ulp_port->port_dstate & ULP_PORT_SUSPEND) { 2779*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2780*7836SJohn.Forte@Sun.COM } 2781*7836SJohn.Forte@Sun.COM break; 2782*7836SJohn.Forte@Sun.COM 2783*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 2784*7836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 2785*7836SJohn.Forte@Sun.COM ulp_port->port_dstate & ULP_PORT_POWER_DOWN) { 2786*7836SJohn.Forte@Sun.COM rval = FC_FAILURE; 2787*7836SJohn.Forte@Sun.COM } 2788*7836SJohn.Forte@Sun.COM break; 2789*7836SJohn.Forte@Sun.COM } 2790*7836SJohn.Forte@Sun.COM 2791*7836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 2792*7836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_BUSY; 2793*7836SJohn.Forte@Sun.COM } 2794*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2795*7836SJohn.Forte@Sun.COM 2796*7836SJohn.Forte@Sun.COM return (rval); 2797*7836SJohn.Forte@Sun.COM } 2798*7836SJohn.Forte@Sun.COM 2799*7836SJohn.Forte@Sun.COM 2800*7836SJohn.Forte@Sun.COM static void 2801*7836SJohn.Forte@Sun.COM fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 2802*7836SJohn.Forte@Sun.COM fc_detach_cmd_t cmd, int rval) 2803*7836SJohn.Forte@Sun.COM { 2804*7836SJohn.Forte@Sun.COM ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND || 2805*7836SJohn.Forte@Sun.COM cmd == FC_CMD_POWER_DOWN); 2806*7836SJohn.Forte@Sun.COM 2807*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 2808*7836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_BUSY; 2809*7836SJohn.Forte@Sun.COM 2810*7836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 2811*7836SJohn.Forte@Sun.COM caddr_t op; 2812*7836SJohn.Forte@Sun.COM fc_local_port_t *port = ulp_port->port_handle; 2813*7836SJohn.Forte@Sun.COM 2814*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2815*7836SJohn.Forte@Sun.COM 2816*7836SJohn.Forte@Sun.COM switch (cmd) { 2817*7836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 2818*7836SJohn.Forte@Sun.COM op = "detach"; 2819*7836SJohn.Forte@Sun.COM break; 2820*7836SJohn.Forte@Sun.COM 2821*7836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 2822*7836SJohn.Forte@Sun.COM op = "suspend"; 2823*7836SJohn.Forte@Sun.COM break; 2824*7836SJohn.Forte@Sun.COM 2825*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 2826*7836SJohn.Forte@Sun.COM op = "power down"; 2827*7836SJohn.Forte@Sun.COM break; 2828*7836SJohn.Forte@Sun.COM } 2829*7836SJohn.Forte@Sun.COM 2830*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 2831*7836SJohn.Forte@Sun.COM port->fp_instance, op, mod->mod_info->ulp_name); 2832*7836SJohn.Forte@Sun.COM 2833*7836SJohn.Forte@Sun.COM return; 2834*7836SJohn.Forte@Sun.COM } 2835*7836SJohn.Forte@Sun.COM 2836*7836SJohn.Forte@Sun.COM switch (cmd) { 2837*7836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 2838*7836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_ATTACH; 2839*7836SJohn.Forte@Sun.COM break; 2840*7836SJohn.Forte@Sun.COM 2841*7836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 2842*7836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_SUSPEND; 2843*7836SJohn.Forte@Sun.COM break; 2844*7836SJohn.Forte@Sun.COM 2845*7836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 2846*7836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_POWER_DOWN; 2847*7836SJohn.Forte@Sun.COM break; 2848*7836SJohn.Forte@Sun.COM } 2849*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 2850*7836SJohn.Forte@Sun.COM } 2851*7836SJohn.Forte@Sun.COM 2852*7836SJohn.Forte@Sun.COM 2853*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 2854*7836SJohn.Forte@Sun.COM fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle, 2855*7836SJohn.Forte@Sun.COM int sleep) 2856*7836SJohn.Forte@Sun.COM { 2857*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *last; 2858*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 2859*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *new; 2860*7836SJohn.Forte@Sun.COM 2861*7836SJohn.Forte@Sun.COM ASSERT(RW_READ_HELD(&fctl_ulp_lock)); 2862*7836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 2863*7836SJohn.Forte@Sun.COM 2864*7836SJohn.Forte@Sun.COM last = NULL; 2865*7836SJohn.Forte@Sun.COM next = ulp_module->mod_ports; 2866*7836SJohn.Forte@Sun.COM 2867*7836SJohn.Forte@Sun.COM while (next != NULL) { 2868*7836SJohn.Forte@Sun.COM last = next; 2869*7836SJohn.Forte@Sun.COM next = next->port_next; 2870*7836SJohn.Forte@Sun.COM } 2871*7836SJohn.Forte@Sun.COM 2872*7836SJohn.Forte@Sun.COM new = fctl_alloc_ulp_port(sleep); 2873*7836SJohn.Forte@Sun.COM if (new == NULL) { 2874*7836SJohn.Forte@Sun.COM return (new); 2875*7836SJohn.Forte@Sun.COM } 2876*7836SJohn.Forte@Sun.COM 2877*7836SJohn.Forte@Sun.COM new->port_handle = port_handle; 2878*7836SJohn.Forte@Sun.COM if (last == NULL) { 2879*7836SJohn.Forte@Sun.COM ulp_module->mod_ports = new; 2880*7836SJohn.Forte@Sun.COM } else { 2881*7836SJohn.Forte@Sun.COM last->port_next = new; 2882*7836SJohn.Forte@Sun.COM } 2883*7836SJohn.Forte@Sun.COM 2884*7836SJohn.Forte@Sun.COM return (new); 2885*7836SJohn.Forte@Sun.COM } 2886*7836SJohn.Forte@Sun.COM 2887*7836SJohn.Forte@Sun.COM 2888*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 2889*7836SJohn.Forte@Sun.COM fctl_alloc_ulp_port(int sleep) 2890*7836SJohn.Forte@Sun.COM { 2891*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *new; 2892*7836SJohn.Forte@Sun.COM 2893*7836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), sleep); 2894*7836SJohn.Forte@Sun.COM if (new == NULL) { 2895*7836SJohn.Forte@Sun.COM return (new); 2896*7836SJohn.Forte@Sun.COM } 2897*7836SJohn.Forte@Sun.COM mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL); 2898*7836SJohn.Forte@Sun.COM 2899*7836SJohn.Forte@Sun.COM return (new); 2900*7836SJohn.Forte@Sun.COM } 2901*7836SJohn.Forte@Sun.COM 2902*7836SJohn.Forte@Sun.COM 2903*7836SJohn.Forte@Sun.COM static int 2904*7836SJohn.Forte@Sun.COM fctl_remove_ulp_port(struct ulp_module *ulp_module, 2905*7836SJohn.Forte@Sun.COM fc_local_port_t *port_handle) 2906*7836SJohn.Forte@Sun.COM { 2907*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *last; 2908*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 2909*7836SJohn.Forte@Sun.COM 2910*7836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_ulp_lock)); 2911*7836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 2912*7836SJohn.Forte@Sun.COM 2913*7836SJohn.Forte@Sun.COM last = NULL; 2914*7836SJohn.Forte@Sun.COM next = ulp_module->mod_ports; 2915*7836SJohn.Forte@Sun.COM 2916*7836SJohn.Forte@Sun.COM while (next != NULL) { 2917*7836SJohn.Forte@Sun.COM if (next->port_handle == port_handle) { 2918*7836SJohn.Forte@Sun.COM if (next->port_dstate & ULP_PORT_ATTACH) { 2919*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 2920*7836SJohn.Forte@Sun.COM } 2921*7836SJohn.Forte@Sun.COM break; 2922*7836SJohn.Forte@Sun.COM } 2923*7836SJohn.Forte@Sun.COM last = next; 2924*7836SJohn.Forte@Sun.COM next = next->port_next; 2925*7836SJohn.Forte@Sun.COM } 2926*7836SJohn.Forte@Sun.COM 2927*7836SJohn.Forte@Sun.COM if (next != NULL) { 2928*7836SJohn.Forte@Sun.COM ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0); 2929*7836SJohn.Forte@Sun.COM 2930*7836SJohn.Forte@Sun.COM if (last == NULL) { 2931*7836SJohn.Forte@Sun.COM ulp_module->mod_ports = next->port_next; 2932*7836SJohn.Forte@Sun.COM } else { 2933*7836SJohn.Forte@Sun.COM last->port_next = next->port_next; 2934*7836SJohn.Forte@Sun.COM } 2935*7836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(next); 2936*7836SJohn.Forte@Sun.COM 2937*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 2938*7836SJohn.Forte@Sun.COM } else { 2939*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 2940*7836SJohn.Forte@Sun.COM } 2941*7836SJohn.Forte@Sun.COM } 2942*7836SJohn.Forte@Sun.COM 2943*7836SJohn.Forte@Sun.COM 2944*7836SJohn.Forte@Sun.COM static void 2945*7836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(fc_ulp_ports_t *next) 2946*7836SJohn.Forte@Sun.COM { 2947*7836SJohn.Forte@Sun.COM mutex_destroy(&next->port_mutex); 2948*7836SJohn.Forte@Sun.COM kmem_free(next, sizeof (*next)); 2949*7836SJohn.Forte@Sun.COM } 2950*7836SJohn.Forte@Sun.COM 2951*7836SJohn.Forte@Sun.COM 2952*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 2953*7836SJohn.Forte@Sun.COM fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle) 2954*7836SJohn.Forte@Sun.COM { 2955*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 2956*7836SJohn.Forte@Sun.COM 2957*7836SJohn.Forte@Sun.COM ASSERT(RW_LOCK_HELD(&fctl_ulp_lock)); 2958*7836SJohn.Forte@Sun.COM ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock)); 2959*7836SJohn.Forte@Sun.COM 2960*7836SJohn.Forte@Sun.COM for (next = ulp_module->mod_ports; next != NULL; 2961*7836SJohn.Forte@Sun.COM next = next->port_next) { 2962*7836SJohn.Forte@Sun.COM if (next->port_handle == port_handle) { 2963*7836SJohn.Forte@Sun.COM return (next); 2964*7836SJohn.Forte@Sun.COM } 2965*7836SJohn.Forte@Sun.COM } 2966*7836SJohn.Forte@Sun.COM 2967*7836SJohn.Forte@Sun.COM return (NULL); 2968*7836SJohn.Forte@Sun.COM } 2969*7836SJohn.Forte@Sun.COM 2970*7836SJohn.Forte@Sun.COM 2971*7836SJohn.Forte@Sun.COM /* 2972*7836SJohn.Forte@Sun.COM * Pass state change notfications on to registered ULPs. 2973*7836SJohn.Forte@Sun.COM * 2974*7836SJohn.Forte@Sun.COM * Can issue wakeups to client callers who might be waiting for completions 2975*7836SJohn.Forte@Sun.COM * on other threads. 2976*7836SJohn.Forte@Sun.COM * 2977*7836SJohn.Forte@Sun.COM * Caution: will silently deallocate any fc_remote_port_t and/or 2978*7836SJohn.Forte@Sun.COM * fc_remote_node_t structs it finds that are not in use. 2979*7836SJohn.Forte@Sun.COM */ 2980*7836SJohn.Forte@Sun.COM void 2981*7836SJohn.Forte@Sun.COM fctl_ulp_statec_cb(void *arg) 2982*7836SJohn.Forte@Sun.COM { 2983*7836SJohn.Forte@Sun.COM uint32_t s_id; 2984*7836SJohn.Forte@Sun.COM uint32_t new_state; 2985*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 2986*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 2987*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 2988*7836SJohn.Forte@Sun.COM fc_port_clist_t *clist = (fc_port_clist_t *)arg; 2989*7836SJohn.Forte@Sun.COM 2990*7836SJohn.Forte@Sun.COM ASSERT(clist != NULL); 2991*7836SJohn.Forte@Sun.COM 2992*7836SJohn.Forte@Sun.COM port = clist->clist_port; 2993*7836SJohn.Forte@Sun.COM 2994*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 2995*7836SJohn.Forte@Sun.COM s_id = port->fp_port_id.port_id; 2996*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 2997*7836SJohn.Forte@Sun.COM 2998*7836SJohn.Forte@Sun.COM switch (clist->clist_state) { 2999*7836SJohn.Forte@Sun.COM case FC_STATE_ONLINE: 3000*7836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_ONLINE; 3001*7836SJohn.Forte@Sun.COM break; 3002*7836SJohn.Forte@Sun.COM 3003*7836SJohn.Forte@Sun.COM case FC_STATE_OFFLINE: 3004*7836SJohn.Forte@Sun.COM if (clist->clist_len) { 3005*7836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT; 3006*7836SJohn.Forte@Sun.COM } else { 3007*7836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_OFFLINE; 3008*7836SJohn.Forte@Sun.COM } 3009*7836SJohn.Forte@Sun.COM break; 3010*7836SJohn.Forte@Sun.COM 3011*7836SJohn.Forte@Sun.COM default: 3012*7836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_DONT_CARE; 3013*7836SJohn.Forte@Sun.COM break; 3014*7836SJohn.Forte@Sun.COM } 3015*7836SJohn.Forte@Sun.COM 3016*7836SJohn.Forte@Sun.COM #ifdef DEBUG 3017*7836SJohn.Forte@Sun.COM /* 3018*7836SJohn.Forte@Sun.COM * sanity check for presence of OLD devices in the hash lists 3019*7836SJohn.Forte@Sun.COM */ 3020*7836SJohn.Forte@Sun.COM if (clist->clist_size) { 3021*7836SJohn.Forte@Sun.COM int count; 3022*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3023*7836SJohn.Forte@Sun.COM 3024*7836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 3025*7836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len; count++) { 3026*7836SJohn.Forte@Sun.COM if (clist->clist_map[count].map_state == 3027*7836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID) { 3028*7836SJohn.Forte@Sun.COM la_wwn_t pwwn; 3029*7836SJohn.Forte@Sun.COM fc_portid_t d_id; 3030*7836SJohn.Forte@Sun.COM 3031*7836SJohn.Forte@Sun.COM pd = clist->clist_map[count].map_pd; 3032*7836SJohn.Forte@Sun.COM if (pd != NULL) { 3033*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3034*7836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 3035*7836SJohn.Forte@Sun.COM d_id = pd->pd_port_id; 3036*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3037*7836SJohn.Forte@Sun.COM 3038*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, 3039*7836SJohn.Forte@Sun.COM &pwwn); 3040*7836SJohn.Forte@Sun.COM 3041*7836SJohn.Forte@Sun.COM ASSERT(pd != clist->clist_map[count]. 3042*7836SJohn.Forte@Sun.COM map_pd); 3043*7836SJohn.Forte@Sun.COM 3044*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_did(port, 3045*7836SJohn.Forte@Sun.COM d_id.port_id); 3046*7836SJohn.Forte@Sun.COM ASSERT(pd != clist->clist_map[count]. 3047*7836SJohn.Forte@Sun.COM map_pd); 3048*7836SJohn.Forte@Sun.COM } 3049*7836SJohn.Forte@Sun.COM } 3050*7836SJohn.Forte@Sun.COM } 3051*7836SJohn.Forte@Sun.COM } 3052*7836SJohn.Forte@Sun.COM #endif 3053*7836SJohn.Forte@Sun.COM 3054*7836SJohn.Forte@Sun.COM /* 3055*7836SJohn.Forte@Sun.COM * Check for duplicate map entries 3056*7836SJohn.Forte@Sun.COM */ 3057*7836SJohn.Forte@Sun.COM if (clist->clist_size) { 3058*7836SJohn.Forte@Sun.COM int count; 3059*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd1, *pd2; 3060*7836SJohn.Forte@Sun.COM 3061*7836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 3062*7836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len-1; count++) { 3063*7836SJohn.Forte@Sun.COM int count2; 3064*7836SJohn.Forte@Sun.COM 3065*7836SJohn.Forte@Sun.COM pd1 = clist->clist_map[count].map_pd; 3066*7836SJohn.Forte@Sun.COM if (pd1 == NULL) { 3067*7836SJohn.Forte@Sun.COM continue; 3068*7836SJohn.Forte@Sun.COM } 3069*7836SJohn.Forte@Sun.COM 3070*7836SJohn.Forte@Sun.COM for (count2 = count+1; 3071*7836SJohn.Forte@Sun.COM count2 < clist->clist_len; 3072*7836SJohn.Forte@Sun.COM count2++) { 3073*7836SJohn.Forte@Sun.COM 3074*7836SJohn.Forte@Sun.COM pd2 = clist->clist_map[count2].map_pd; 3075*7836SJohn.Forte@Sun.COM if (pd2 == NULL) { 3076*7836SJohn.Forte@Sun.COM continue; 3077*7836SJohn.Forte@Sun.COM } 3078*7836SJohn.Forte@Sun.COM 3079*7836SJohn.Forte@Sun.COM if (pd1 == pd2) { 3080*7836SJohn.Forte@Sun.COM clist->clist_map[count].map_flags |= 3081*7836SJohn.Forte@Sun.COM PORT_DEVICE_DUPLICATE_MAP_ENTRY; 3082*7836SJohn.Forte@Sun.COM break; 3083*7836SJohn.Forte@Sun.COM } 3084*7836SJohn.Forte@Sun.COM } 3085*7836SJohn.Forte@Sun.COM } 3086*7836SJohn.Forte@Sun.COM } 3087*7836SJohn.Forte@Sun.COM 3088*7836SJohn.Forte@Sun.COM 3089*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 3090*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 3091*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 3092*7836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 3093*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 3094*7836SJohn.Forte@Sun.COM 3095*7836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 3096*7836SJohn.Forte@Sun.COM continue; 3097*7836SJohn.Forte@Sun.COM } 3098*7836SJohn.Forte@Sun.COM 3099*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 3100*7836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 3101*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 3102*7836SJohn.Forte@Sun.COM continue; 3103*7836SJohn.Forte@Sun.COM } 3104*7836SJohn.Forte@Sun.COM 3105*7836SJohn.Forte@Sun.COM switch (ulp_port->port_statec) { 3106*7836SJohn.Forte@Sun.COM case FC_ULP_STATEC_DONT_CARE: 3107*7836SJohn.Forte@Sun.COM if (ulp_port->port_statec != new_state) { 3108*7836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 3109*7836SJohn.Forte@Sun.COM } 3110*7836SJohn.Forte@Sun.COM break; 3111*7836SJohn.Forte@Sun.COM 3112*7836SJohn.Forte@Sun.COM case FC_ULP_STATEC_ONLINE: 3113*7836SJohn.Forte@Sun.COM case FC_ULP_STATEC_OFFLINE: 3114*7836SJohn.Forte@Sun.COM if (ulp_port->port_statec == new_state) { 3115*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 3116*7836SJohn.Forte@Sun.COM continue; 3117*7836SJohn.Forte@Sun.COM } 3118*7836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 3119*7836SJohn.Forte@Sun.COM break; 3120*7836SJohn.Forte@Sun.COM 3121*7836SJohn.Forte@Sun.COM case FC_ULP_STATEC_OFFLINE_TIMEOUT: 3122*7836SJohn.Forte@Sun.COM if (ulp_port->port_statec == new_state || 3123*7836SJohn.Forte@Sun.COM new_state == FC_ULP_STATEC_OFFLINE) { 3124*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 3125*7836SJohn.Forte@Sun.COM continue; 3126*7836SJohn.Forte@Sun.COM } 3127*7836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 3128*7836SJohn.Forte@Sun.COM break; 3129*7836SJohn.Forte@Sun.COM 3130*7836SJohn.Forte@Sun.COM default: 3131*7836SJohn.Forte@Sun.COM ASSERT(0); 3132*7836SJohn.Forte@Sun.COM break; 3133*7836SJohn.Forte@Sun.COM } 3134*7836SJohn.Forte@Sun.COM 3135*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_statec_callback( 3136*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, (opaque_t)port, 3137*7836SJohn.Forte@Sun.COM clist->clist_state, clist->clist_flags, 3138*7836SJohn.Forte@Sun.COM clist->clist_map, clist->clist_len, s_id); 3139*7836SJohn.Forte@Sun.COM 3140*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 3141*7836SJohn.Forte@Sun.COM } 3142*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 3143*7836SJohn.Forte@Sun.COM 3144*7836SJohn.Forte@Sun.COM if (clist->clist_size) { 3145*7836SJohn.Forte@Sun.COM int count; 3146*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 3147*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3148*7836SJohn.Forte@Sun.COM 3149*7836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 3150*7836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len; count++) { 3151*7836SJohn.Forte@Sun.COM 3152*7836SJohn.Forte@Sun.COM if ((pd = clist->clist_map[count].map_pd) == NULL) { 3153*7836SJohn.Forte@Sun.COM continue; 3154*7836SJohn.Forte@Sun.COM } 3155*7836SJohn.Forte@Sun.COM 3156*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3157*7836SJohn.Forte@Sun.COM 3158*7836SJohn.Forte@Sun.COM pd->pd_ref_count--; 3159*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 3160*7836SJohn.Forte@Sun.COM 3161*7836SJohn.Forte@Sun.COM if (clist->clist_map[count].map_state != 3162*7836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID) { 3163*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3164*7836SJohn.Forte@Sun.COM continue; 3165*7836SJohn.Forte@Sun.COM } 3166*7836SJohn.Forte@Sun.COM 3167*7836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 3168*7836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS; 3169*7836SJohn.Forte@Sun.COM 3170*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3171*7836SJohn.Forte@Sun.COM 3172*7836SJohn.Forte@Sun.COM /* 3173*7836SJohn.Forte@Sun.COM * This fc_remote_port_t is no longer referenced 3174*7836SJohn.Forte@Sun.COM * by any ULPs. Deallocate it if its pd_ref_count 3175*7836SJohn.Forte@Sun.COM * has reached zero. 3176*7836SJohn.Forte@Sun.COM */ 3177*7836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) == 0) && 3178*7836SJohn.Forte@Sun.COM (node != NULL)) { 3179*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 3180*7836SJohn.Forte@Sun.COM } 3181*7836SJohn.Forte@Sun.COM } 3182*7836SJohn.Forte@Sun.COM 3183*7836SJohn.Forte@Sun.COM kmem_free(clist->clist_map, 3184*7836SJohn.Forte@Sun.COM sizeof (*(clist->clist_map)) * clist->clist_size); 3185*7836SJohn.Forte@Sun.COM } 3186*7836SJohn.Forte@Sun.COM 3187*7836SJohn.Forte@Sun.COM if (clist->clist_wait) { 3188*7836SJohn.Forte@Sun.COM mutex_enter(&clist->clist_mutex); 3189*7836SJohn.Forte@Sun.COM clist->clist_wait = 0; 3190*7836SJohn.Forte@Sun.COM cv_signal(&clist->clist_cv); 3191*7836SJohn.Forte@Sun.COM mutex_exit(&clist->clist_mutex); 3192*7836SJohn.Forte@Sun.COM } else { 3193*7836SJohn.Forte@Sun.COM kmem_free(clist, sizeof (*clist)); 3194*7836SJohn.Forte@Sun.COM } 3195*7836SJohn.Forte@Sun.COM } 3196*7836SJohn.Forte@Sun.COM 3197*7836SJohn.Forte@Sun.COM 3198*7836SJohn.Forte@Sun.COM /* 3199*7836SJohn.Forte@Sun.COM * Allocate an fc_remote_node_t struct to represent a remote node for the 3200*7836SJohn.Forte@Sun.COM * given nwwn. This will also add the nwwn to the global nwwn table. 3201*7836SJohn.Forte@Sun.COM * 3202*7836SJohn.Forte@Sun.COM * Returns a pointer to the newly-allocated struct. Returns NULL if 3203*7836SJohn.Forte@Sun.COM * the kmem_zalloc fails or if the enlist_wwn attempt fails. 3204*7836SJohn.Forte@Sun.COM */ 3205*7836SJohn.Forte@Sun.COM fc_remote_node_t * 3206*7836SJohn.Forte@Sun.COM fctl_create_remote_node(la_wwn_t *nwwn, int sleep) 3207*7836SJohn.Forte@Sun.COM { 3208*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 3209*7836SJohn.Forte@Sun.COM 3210*7836SJohn.Forte@Sun.COM if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) { 3211*7836SJohn.Forte@Sun.COM return (NULL); 3212*7836SJohn.Forte@Sun.COM } 3213*7836SJohn.Forte@Sun.COM 3214*7836SJohn.Forte@Sun.COM mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL); 3215*7836SJohn.Forte@Sun.COM 3216*7836SJohn.Forte@Sun.COM rnodep->fd_node_name = *nwwn; 3217*7836SJohn.Forte@Sun.COM rnodep->fd_flags = FC_REMOTE_NODE_VALID; 3218*7836SJohn.Forte@Sun.COM rnodep->fd_numports = 1; 3219*7836SJohn.Forte@Sun.COM 3220*7836SJohn.Forte@Sun.COM if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) { 3221*7836SJohn.Forte@Sun.COM mutex_destroy(&rnodep->fd_mutex); 3222*7836SJohn.Forte@Sun.COM kmem_free(rnodep, sizeof (*rnodep)); 3223*7836SJohn.Forte@Sun.COM return (NULL); 3224*7836SJohn.Forte@Sun.COM } 3225*7836SJohn.Forte@Sun.COM 3226*7836SJohn.Forte@Sun.COM return (rnodep); 3227*7836SJohn.Forte@Sun.COM } 3228*7836SJohn.Forte@Sun.COM 3229*7836SJohn.Forte@Sun.COM /* 3230*7836SJohn.Forte@Sun.COM * Deconstruct and free the given fc_remote_node_t struct (remote node struct). 3231*7836SJohn.Forte@Sun.COM * Silently skips the deconstruct/free if there are any fc_remote_port_t 3232*7836SJohn.Forte@Sun.COM * (remote port device) structs still referenced by the given 3233*7836SJohn.Forte@Sun.COM * fc_remote_node_t struct. 3234*7836SJohn.Forte@Sun.COM */ 3235*7836SJohn.Forte@Sun.COM void 3236*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(fc_remote_node_t *rnodep) 3237*7836SJohn.Forte@Sun.COM { 3238*7836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 3239*7836SJohn.Forte@Sun.COM 3240*7836SJohn.Forte@Sun.COM /* 3241*7836SJohn.Forte@Sun.COM * Look at the count and linked list of of remote ports 3242*7836SJohn.Forte@Sun.COM * (fc_remote_port_t structs); bail if these indicate that 3243*7836SJohn.Forte@Sun.COM * given fc_remote_node_t may be in use. 3244*7836SJohn.Forte@Sun.COM */ 3245*7836SJohn.Forte@Sun.COM if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) { 3246*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3247*7836SJohn.Forte@Sun.COM return; 3248*7836SJohn.Forte@Sun.COM } 3249*7836SJohn.Forte@Sun.COM 3250*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3251*7836SJohn.Forte@Sun.COM 3252*7836SJohn.Forte@Sun.COM mutex_destroy(&rnodep->fd_mutex); 3253*7836SJohn.Forte@Sun.COM kmem_free(rnodep, sizeof (*rnodep)); 3254*7836SJohn.Forte@Sun.COM } 3255*7836SJohn.Forte@Sun.COM 3256*7836SJohn.Forte@Sun.COM 3257*7836SJohn.Forte@Sun.COM /* 3258*7836SJohn.Forte@Sun.COM * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This 3259*7836SJohn.Forte@Sun.COM * uses the nwwn in the fd_node_name.raw_wwn of the given struct. 3260*7836SJohn.Forte@Sun.COM * This only fails if the kmem_zalloc fails. This does not check for a 3261*7836SJohn.Forte@Sun.COM * unique or pre-existing nwwn in the fctl_nwwn_hash_table[]. 3262*7836SJohn.Forte@Sun.COM * This is only called from fctl_create_remote_node(). 3263*7836SJohn.Forte@Sun.COM */ 3264*7836SJohn.Forte@Sun.COM int 3265*7836SJohn.Forte@Sun.COM fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep) 3266*7836SJohn.Forte@Sun.COM { 3267*7836SJohn.Forte@Sun.COM int index; 3268*7836SJohn.Forte@Sun.COM fctl_nwwn_elem_t *new; 3269*7836SJohn.Forte@Sun.COM fctl_nwwn_list_t *head; 3270*7836SJohn.Forte@Sun.COM 3271*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 3272*7836SJohn.Forte@Sun.COM 3273*7836SJohn.Forte@Sun.COM if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) { 3274*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 3275*7836SJohn.Forte@Sun.COM } 3276*7836SJohn.Forte@Sun.COM 3277*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 3278*7836SJohn.Forte@Sun.COM new->fne_nodep = rnodep; 3279*7836SJohn.Forte@Sun.COM 3280*7836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 3281*7836SJohn.Forte@Sun.COM ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE); 3282*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 3283*7836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 3284*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3285*7836SJohn.Forte@Sun.COM 3286*7836SJohn.Forte@Sun.COM head = &fctl_nwwn_hash_table[index]; 3287*7836SJohn.Forte@Sun.COM 3288*7836SJohn.Forte@Sun.COM /* Link it in at the head of the hash list */ 3289*7836SJohn.Forte@Sun.COM new->fne_nextp = head->fnl_headp; 3290*7836SJohn.Forte@Sun.COM head->fnl_headp = new; 3291*7836SJohn.Forte@Sun.COM 3292*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 3293*7836SJohn.Forte@Sun.COM 3294*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 3295*7836SJohn.Forte@Sun.COM } 3296*7836SJohn.Forte@Sun.COM 3297*7836SJohn.Forte@Sun.COM 3298*7836SJohn.Forte@Sun.COM /* 3299*7836SJohn.Forte@Sun.COM * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[]. 3300*7836SJohn.Forte@Sun.COM * This uses the nwwn in the fd_node_name.raw_wwn of the given struct. 3301*7836SJohn.Forte@Sun.COM */ 3302*7836SJohn.Forte@Sun.COM void 3303*7836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(fc_remote_node_t *rnodep) 3304*7836SJohn.Forte@Sun.COM { 3305*7836SJohn.Forte@Sun.COM int index; 3306*7836SJohn.Forte@Sun.COM fctl_nwwn_list_t *head; 3307*7836SJohn.Forte@Sun.COM fctl_nwwn_elem_t *elem; 3308*7836SJohn.Forte@Sun.COM fctl_nwwn_elem_t *prev; 3309*7836SJohn.Forte@Sun.COM 3310*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex)); 3311*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&rnodep->fd_mutex)); 3312*7836SJohn.Forte@Sun.COM 3313*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 3314*7836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 3315*7836SJohn.Forte@Sun.COM 3316*7836SJohn.Forte@Sun.COM head = &fctl_nwwn_hash_table[index]; 3317*7836SJohn.Forte@Sun.COM elem = head->fnl_headp; 3318*7836SJohn.Forte@Sun.COM prev = NULL; 3319*7836SJohn.Forte@Sun.COM 3320*7836SJohn.Forte@Sun.COM while (elem != NULL) { 3321*7836SJohn.Forte@Sun.COM if (elem->fne_nodep == rnodep) { 3322*7836SJohn.Forte@Sun.COM /* 3323*7836SJohn.Forte@Sun.COM * Found it -- unlink it from the list & decrement 3324*7836SJohn.Forte@Sun.COM * the count for the hash chain. 3325*7836SJohn.Forte@Sun.COM */ 3326*7836SJohn.Forte@Sun.COM if (prev == NULL) { 3327*7836SJohn.Forte@Sun.COM head->fnl_headp = elem->fne_nextp; 3328*7836SJohn.Forte@Sun.COM } else { 3329*7836SJohn.Forte@Sun.COM prev->fne_nextp = elem->fne_nextp; 3330*7836SJohn.Forte@Sun.COM } 3331*7836SJohn.Forte@Sun.COM break; 3332*7836SJohn.Forte@Sun.COM } 3333*7836SJohn.Forte@Sun.COM prev = elem; 3334*7836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 3335*7836SJohn.Forte@Sun.COM } 3336*7836SJohn.Forte@Sun.COM 3337*7836SJohn.Forte@Sun.COM if (elem != NULL) { 3338*7836SJohn.Forte@Sun.COM kmem_free(elem, sizeof (*elem)); 3339*7836SJohn.Forte@Sun.COM } 3340*7836SJohn.Forte@Sun.COM } 3341*7836SJohn.Forte@Sun.COM 3342*7836SJohn.Forte@Sun.COM 3343*7836SJohn.Forte@Sun.COM /* 3344*7836SJohn.Forte@Sun.COM * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 3345*7836SJohn.Forte@Sun.COM * Looks in the global fctl_nwwn_hash_table[]. Identical to the 3346*7836SJohn.Forte@Sun.COM * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment 3347*7836SJohn.Forte@Sun.COM * the fc_count reference count in the f_device_t before returning. 3348*7836SJohn.Forte@Sun.COM * 3349*7836SJohn.Forte@Sun.COM * This function is called by: fctl_create_remote_port_t(). 3350*7836SJohn.Forte@Sun.COM * 3351*7836SJohn.Forte@Sun.COM * OLD COMMENT: 3352*7836SJohn.Forte@Sun.COM * Note: The calling thread needs to make sure it isn't holding any device 3353*7836SJohn.Forte@Sun.COM * mutex (more so the fc_remote_node_t that could potentially have this wwn). 3354*7836SJohn.Forte@Sun.COM */ 3355*7836SJohn.Forte@Sun.COM fc_remote_node_t * 3356*7836SJohn.Forte@Sun.COM fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn) 3357*7836SJohn.Forte@Sun.COM { 3358*7836SJohn.Forte@Sun.COM int index; 3359*7836SJohn.Forte@Sun.COM fctl_nwwn_elem_t *elem; 3360*7836SJohn.Forte@Sun.COM fc_remote_node_t *next; 3361*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep = NULL; 3362*7836SJohn.Forte@Sun.COM 3363*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 3364*7836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 3365*7836SJohn.Forte@Sun.COM ASSERT(index >= 0 && index < fctl_nwwn_table_size); 3366*7836SJohn.Forte@Sun.COM 3367*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 3368*7836SJohn.Forte@Sun.COM elem = fctl_nwwn_hash_table[index].fnl_headp; 3369*7836SJohn.Forte@Sun.COM while (elem != NULL) { 3370*7836SJohn.Forte@Sun.COM next = elem->fne_nodep; 3371*7836SJohn.Forte@Sun.COM if (next != NULL) { 3372*7836SJohn.Forte@Sun.COM mutex_enter(&next->fd_mutex); 3373*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 3374*7836SJohn.Forte@Sun.COM rnodep = next; 3375*7836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 3376*7836SJohn.Forte@Sun.COM break; 3377*7836SJohn.Forte@Sun.COM } 3378*7836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 3379*7836SJohn.Forte@Sun.COM } 3380*7836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 3381*7836SJohn.Forte@Sun.COM } 3382*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 3383*7836SJohn.Forte@Sun.COM 3384*7836SJohn.Forte@Sun.COM return (rnodep); 3385*7836SJohn.Forte@Sun.COM } 3386*7836SJohn.Forte@Sun.COM 3387*7836SJohn.Forte@Sun.COM 3388*7836SJohn.Forte@Sun.COM /* 3389*7836SJohn.Forte@Sun.COM * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 3390*7836SJohn.Forte@Sun.COM * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports 3391*7836SJohn.Forte@Sun.COM * reference count in the f_device_t before returning. 3392*7836SJohn.Forte@Sun.COM * 3393*7836SJohn.Forte@Sun.COM * This function is only called by fctl_create_remote_port_t(). 3394*7836SJohn.Forte@Sun.COM */ 3395*7836SJohn.Forte@Sun.COM fc_remote_node_t * 3396*7836SJohn.Forte@Sun.COM fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn) 3397*7836SJohn.Forte@Sun.COM { 3398*7836SJohn.Forte@Sun.COM int index; 3399*7836SJohn.Forte@Sun.COM fctl_nwwn_elem_t *elem; 3400*7836SJohn.Forte@Sun.COM fc_remote_node_t *next; 3401*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep = NULL; 3402*7836SJohn.Forte@Sun.COM 3403*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 3404*7836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 3405*7836SJohn.Forte@Sun.COM ASSERT(index >= 0 && index < fctl_nwwn_table_size); 3406*7836SJohn.Forte@Sun.COM 3407*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 3408*7836SJohn.Forte@Sun.COM elem = fctl_nwwn_hash_table[index].fnl_headp; 3409*7836SJohn.Forte@Sun.COM while (elem != NULL) { 3410*7836SJohn.Forte@Sun.COM next = elem->fne_nodep; 3411*7836SJohn.Forte@Sun.COM if (next != NULL) { 3412*7836SJohn.Forte@Sun.COM mutex_enter(&next->fd_mutex); 3413*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 3414*7836SJohn.Forte@Sun.COM rnodep = next; 3415*7836SJohn.Forte@Sun.COM rnodep->fd_numports++; 3416*7836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 3417*7836SJohn.Forte@Sun.COM break; 3418*7836SJohn.Forte@Sun.COM } 3419*7836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 3420*7836SJohn.Forte@Sun.COM } 3421*7836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 3422*7836SJohn.Forte@Sun.COM } 3423*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 3424*7836SJohn.Forte@Sun.COM 3425*7836SJohn.Forte@Sun.COM return (rnodep); 3426*7836SJohn.Forte@Sun.COM } 3427*7836SJohn.Forte@Sun.COM 3428*7836SJohn.Forte@Sun.COM 3429*7836SJohn.Forte@Sun.COM /* 3430*7836SJohn.Forte@Sun.COM * Allocate and initialize an fc_remote_port_t struct & returns a pointer to 3431*7836SJohn.Forte@Sun.COM * the newly allocated struct. Only fails if the kmem_zalloc() fails. 3432*7836SJohn.Forte@Sun.COM */ 3433*7836SJohn.Forte@Sun.COM fc_remote_port_t * 3434*7836SJohn.Forte@Sun.COM fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn, 3435*7836SJohn.Forte@Sun.COM uint32_t d_id, uchar_t recepient, int sleep) 3436*7836SJohn.Forte@Sun.COM { 3437*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3438*7836SJohn.Forte@Sun.COM 3439*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3440*7836SJohn.Forte@Sun.COM ASSERT(FC_IS_REAL_DEVICE(d_id)); 3441*7836SJohn.Forte@Sun.COM 3442*7836SJohn.Forte@Sun.COM if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) { 3443*7836SJohn.Forte@Sun.COM return (NULL); 3444*7836SJohn.Forte@Sun.COM } 3445*7836SJohn.Forte@Sun.COM fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT, 3446*7836SJohn.Forte@Sun.COM FC_LOGO_TOLERANCE_TIME_LIMIT); 3447*7836SJohn.Forte@Sun.COM 3448*7836SJohn.Forte@Sun.COM mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL); 3449*7836SJohn.Forte@Sun.COM 3450*7836SJohn.Forte@Sun.COM pd->pd_port_id.port_id = d_id; 3451*7836SJohn.Forte@Sun.COM pd->pd_port_name = *port_wwn; 3452*7836SJohn.Forte@Sun.COM pd->pd_port = port; 3453*7836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 3454*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NEW; 3455*7836SJohn.Forte@Sun.COM pd->pd_recepient = recepient; 3456*7836SJohn.Forte@Sun.COM 3457*7836SJohn.Forte@Sun.COM return (pd); 3458*7836SJohn.Forte@Sun.COM } 3459*7836SJohn.Forte@Sun.COM 3460*7836SJohn.Forte@Sun.COM 3461*7836SJohn.Forte@Sun.COM /* 3462*7836SJohn.Forte@Sun.COM * Deconstruct and free the given fc_remote_port_t struct (unconditionally). 3463*7836SJohn.Forte@Sun.COM */ 3464*7836SJohn.Forte@Sun.COM void 3465*7836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(fc_remote_port_t *pd) 3466*7836SJohn.Forte@Sun.COM { 3467*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 3468*7836SJohn.Forte@Sun.COM 3469*7836SJohn.Forte@Sun.COM fctl_tc_destructor(&pd->pd_logo_tc); 3470*7836SJohn.Forte@Sun.COM mutex_destroy(&pd->pd_mutex); 3471*7836SJohn.Forte@Sun.COM kmem_free(pd, sizeof (*pd)); 3472*7836SJohn.Forte@Sun.COM } 3473*7836SJohn.Forte@Sun.COM 3474*7836SJohn.Forte@Sun.COM /* 3475*7836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t onto the linked list of remote port 3476*7836SJohn.Forte@Sun.COM * devices associated with the given fc_remote_node_t. Does NOT add the 3477*7836SJohn.Forte@Sun.COM * fc_remote_port_t to the list if already exists on the list. 3478*7836SJohn.Forte@Sun.COM */ 3479*7836SJohn.Forte@Sun.COM void 3480*7836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep, 3481*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd) 3482*7836SJohn.Forte@Sun.COM { 3483*7836SJohn.Forte@Sun.COM fc_remote_port_t *last; 3484*7836SJohn.Forte@Sun.COM fc_remote_port_t *ports; 3485*7836SJohn.Forte@Sun.COM 3486*7836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 3487*7836SJohn.Forte@Sun.COM 3488*7836SJohn.Forte@Sun.COM last = NULL; 3489*7836SJohn.Forte@Sun.COM for (ports = rnodep->fd_portlistp; ports != NULL; 3490*7836SJohn.Forte@Sun.COM ports = ports->pd_port_next) { 3491*7836SJohn.Forte@Sun.COM if (ports == pd) { 3492*7836SJohn.Forte@Sun.COM /* 3493*7836SJohn.Forte@Sun.COM * The given fc_remote_port_t is already on the linked 3494*7836SJohn.Forte@Sun.COM * list chain for the given remote node, so bail now. 3495*7836SJohn.Forte@Sun.COM */ 3496*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3497*7836SJohn.Forte@Sun.COM return; 3498*7836SJohn.Forte@Sun.COM } 3499*7836SJohn.Forte@Sun.COM last = ports; 3500*7836SJohn.Forte@Sun.COM } 3501*7836SJohn.Forte@Sun.COM 3502*7836SJohn.Forte@Sun.COM /* Add the fc_remote_port_t to the tail of the linked list */ 3503*7836SJohn.Forte@Sun.COM if (last != NULL) { 3504*7836SJohn.Forte@Sun.COM last->pd_port_next = pd; 3505*7836SJohn.Forte@Sun.COM } else { 3506*7836SJohn.Forte@Sun.COM rnodep->fd_portlistp = pd; 3507*7836SJohn.Forte@Sun.COM } 3508*7836SJohn.Forte@Sun.COM pd->pd_port_next = NULL; 3509*7836SJohn.Forte@Sun.COM 3510*7836SJohn.Forte@Sun.COM /* 3511*7836SJohn.Forte@Sun.COM * Link the fc_remote_port_t back to the associated fc_remote_node_t. 3512*7836SJohn.Forte@Sun.COM */ 3513*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3514*7836SJohn.Forte@Sun.COM pd->pd_remote_nodep = rnodep; 3515*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3516*7836SJohn.Forte@Sun.COM 3517*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3518*7836SJohn.Forte@Sun.COM } 3519*7836SJohn.Forte@Sun.COM 3520*7836SJohn.Forte@Sun.COM 3521*7836SJohn.Forte@Sun.COM /* 3522*7836SJohn.Forte@Sun.COM * Remove the specified fc_remote_port_t from the linked list of remote ports 3523*7836SJohn.Forte@Sun.COM * for the given fc_remote_node_t. 3524*7836SJohn.Forte@Sun.COM * 3525*7836SJohn.Forte@Sun.COM * Returns a count of the _remaining_ fc_remote_port_t structs on the linked 3526*7836SJohn.Forte@Sun.COM * list of the fc_remote_node_t. 3527*7836SJohn.Forte@Sun.COM * 3528*7836SJohn.Forte@Sun.COM * The fd_numports on the given fc_remote_node_t is decremented, and if 3529*7836SJohn.Forte@Sun.COM * it hits zero then this function also removes the fc_remote_node_t from the 3530*7836SJohn.Forte@Sun.COM * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries 3531*7836SJohn.Forte@Sun.COM * are removed from the fctl_nwwn_hash_table[]. 3532*7836SJohn.Forte@Sun.COM */ 3533*7836SJohn.Forte@Sun.COM int 3534*7836SJohn.Forte@Sun.COM fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep, 3535*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd) 3536*7836SJohn.Forte@Sun.COM { 3537*7836SJohn.Forte@Sun.COM int rcount = 0; 3538*7836SJohn.Forte@Sun.COM fc_remote_port_t *last; 3539*7836SJohn.Forte@Sun.COM fc_remote_port_t *ports; 3540*7836SJohn.Forte@Sun.COM 3541*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 3542*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 3543*7836SJohn.Forte@Sun.COM 3544*7836SJohn.Forte@Sun.COM last = NULL; 3545*7836SJohn.Forte@Sun.COM 3546*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 3547*7836SJohn.Forte@Sun.COM 3548*7836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 3549*7836SJohn.Forte@Sun.COM 3550*7836SJohn.Forte@Sun.COM /* 3551*7836SJohn.Forte@Sun.COM * Go thru the linked list of fc_remote_port_t structs for the given 3552*7836SJohn.Forte@Sun.COM * fc_remote_node_t; try to find the specified fc_remote_port_t (pd). 3553*7836SJohn.Forte@Sun.COM */ 3554*7836SJohn.Forte@Sun.COM ports = rnodep->fd_portlistp; 3555*7836SJohn.Forte@Sun.COM while (ports != NULL) { 3556*7836SJohn.Forte@Sun.COM if (ports == pd) { 3557*7836SJohn.Forte@Sun.COM break; /* Found the requested fc_remote_port_t */ 3558*7836SJohn.Forte@Sun.COM } 3559*7836SJohn.Forte@Sun.COM last = ports; 3560*7836SJohn.Forte@Sun.COM ports = ports->pd_port_next; 3561*7836SJohn.Forte@Sun.COM } 3562*7836SJohn.Forte@Sun.COM 3563*7836SJohn.Forte@Sun.COM if (ports) { 3564*7836SJohn.Forte@Sun.COM rcount = --rnodep->fd_numports; 3565*7836SJohn.Forte@Sun.COM if (rcount == 0) { 3566*7836SJohn.Forte@Sun.COM /* Note: this is only ever called from here */ 3567*7836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(rnodep); 3568*7836SJohn.Forte@Sun.COM } 3569*7836SJohn.Forte@Sun.COM if (last) { 3570*7836SJohn.Forte@Sun.COM last->pd_port_next = pd->pd_port_next; 3571*7836SJohn.Forte@Sun.COM } else { 3572*7836SJohn.Forte@Sun.COM rnodep->fd_portlistp = pd->pd_port_next; 3573*7836SJohn.Forte@Sun.COM } 3574*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3575*7836SJohn.Forte@Sun.COM pd->pd_remote_nodep = NULL; 3576*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3577*7836SJohn.Forte@Sun.COM } 3578*7836SJohn.Forte@Sun.COM 3579*7836SJohn.Forte@Sun.COM pd->pd_port_next = NULL; 3580*7836SJohn.Forte@Sun.COM 3581*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 3582*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 3583*7836SJohn.Forte@Sun.COM 3584*7836SJohn.Forte@Sun.COM return (rcount); 3585*7836SJohn.Forte@Sun.COM } 3586*7836SJohn.Forte@Sun.COM 3587*7836SJohn.Forte@Sun.COM 3588*7836SJohn.Forte@Sun.COM /* 3589*7836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t struct to the d_id table in the given 3590*7836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 3591*7836SJohn.Forte@Sun.COM * fc_remote_port_t. 3592*7836SJohn.Forte@Sun.COM * 3593*7836SJohn.Forte@Sun.COM * No memory allocs are required, so this never fails, but it does use the 3594*7836SJohn.Forte@Sun.COM * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list. 3595*7836SJohn.Forte@Sun.COM * (There does not seem to be a way to tell the caller that a duplicate 3596*7836SJohn.Forte@Sun.COM * exists.) 3597*7836SJohn.Forte@Sun.COM */ 3598*7836SJohn.Forte@Sun.COM void 3599*7836SJohn.Forte@Sun.COM fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 3600*7836SJohn.Forte@Sun.COM { 3601*7836SJohn.Forte@Sun.COM struct d_id_hash *head; 3602*7836SJohn.Forte@Sun.COM 3603*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3604*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3605*7836SJohn.Forte@Sun.COM 3606*7836SJohn.Forte@Sun.COM if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 3607*7836SJohn.Forte@Sun.COM return; 3608*7836SJohn.Forte@Sun.COM } 3609*7836SJohn.Forte@Sun.COM 3610*7836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id, 3611*7836SJohn.Forte@Sun.COM did_table_size)]; 3612*7836SJohn.Forte@Sun.COM 3613*7836SJohn.Forte@Sun.COM #ifdef DEBUG 3614*7836SJohn.Forte@Sun.COM { 3615*7836SJohn.Forte@Sun.COM int index; 3616*7836SJohn.Forte@Sun.COM fc_remote_port_t *tmp_pd; 3617*7836SJohn.Forte@Sun.COM struct d_id_hash *tmp_head; 3618*7836SJohn.Forte@Sun.COM 3619*7836SJohn.Forte@Sun.COM /* 3620*7836SJohn.Forte@Sun.COM * Search down in each bucket for a duplicate pd 3621*7836SJohn.Forte@Sun.COM * Also search for duplicate D_IDs 3622*7836SJohn.Forte@Sun.COM * This DEBUG code will force an ASSERT if a duplicate 3623*7836SJohn.Forte@Sun.COM * is ever found. 3624*7836SJohn.Forte@Sun.COM */ 3625*7836SJohn.Forte@Sun.COM for (index = 0; index < did_table_size; index++) { 3626*7836SJohn.Forte@Sun.COM tmp_head = &port->fp_did_table[index]; 3627*7836SJohn.Forte@Sun.COM 3628*7836SJohn.Forte@Sun.COM tmp_pd = tmp_head->d_id_head; 3629*7836SJohn.Forte@Sun.COM while (tmp_pd != NULL) { 3630*7836SJohn.Forte@Sun.COM ASSERT(tmp_pd != pd); 3631*7836SJohn.Forte@Sun.COM 3632*7836SJohn.Forte@Sun.COM if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 3633*7836SJohn.Forte@Sun.COM tmp_pd->pd_type != PORT_DEVICE_OLD) { 3634*7836SJohn.Forte@Sun.COM ASSERT(tmp_pd->pd_port_id.port_id != 3635*7836SJohn.Forte@Sun.COM pd->pd_port_id.port_id); 3636*7836SJohn.Forte@Sun.COM } 3637*7836SJohn.Forte@Sun.COM 3638*7836SJohn.Forte@Sun.COM tmp_pd = tmp_pd->pd_did_hnext; 3639*7836SJohn.Forte@Sun.COM } 3640*7836SJohn.Forte@Sun.COM } 3641*7836SJohn.Forte@Sun.COM } 3642*7836SJohn.Forte@Sun.COM 3643*7836SJohn.Forte@Sun.COM bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack)); 3644*7836SJohn.Forte@Sun.COM pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH); 3645*7836SJohn.Forte@Sun.COM #endif 3646*7836SJohn.Forte@Sun.COM 3647*7836SJohn.Forte@Sun.COM pd->pd_did_hnext = head->d_id_head; 3648*7836SJohn.Forte@Sun.COM head->d_id_head = pd; 3649*7836SJohn.Forte@Sun.COM 3650*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_IN_DID_QUEUE; 3651*7836SJohn.Forte@Sun.COM head->d_id_count++; 3652*7836SJohn.Forte@Sun.COM } 3653*7836SJohn.Forte@Sun.COM 3654*7836SJohn.Forte@Sun.COM 3655*7836SJohn.Forte@Sun.COM /* 3656*7836SJohn.Forte@Sun.COM * Remove the given fc_remote_port_t struct from the d_id table in the given 3657*7836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 3658*7836SJohn.Forte@Sun.COM * fc_remote_port_t. 3659*7836SJohn.Forte@Sun.COM * 3660*7836SJohn.Forte@Sun.COM * Does nothing if the requested fc_remote_port_t was not found. 3661*7836SJohn.Forte@Sun.COM */ 3662*7836SJohn.Forte@Sun.COM void 3663*7836SJohn.Forte@Sun.COM fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 3664*7836SJohn.Forte@Sun.COM { 3665*7836SJohn.Forte@Sun.COM uint32_t d_id; 3666*7836SJohn.Forte@Sun.COM struct d_id_hash *head; 3667*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd_next; 3668*7836SJohn.Forte@Sun.COM fc_remote_port_t *last; 3669*7836SJohn.Forte@Sun.COM 3670*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3671*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3672*7836SJohn.Forte@Sun.COM 3673*7836SJohn.Forte@Sun.COM d_id = pd->pd_port_id.port_id; 3674*7836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3675*7836SJohn.Forte@Sun.COM 3676*7836SJohn.Forte@Sun.COM pd_next = head->d_id_head; 3677*7836SJohn.Forte@Sun.COM last = NULL; 3678*7836SJohn.Forte@Sun.COM while (pd_next != NULL) { 3679*7836SJohn.Forte@Sun.COM if (pd == pd_next) { 3680*7836SJohn.Forte@Sun.COM break; /* Found the given fc_remote_port_t */ 3681*7836SJohn.Forte@Sun.COM } 3682*7836SJohn.Forte@Sun.COM last = pd_next; 3683*7836SJohn.Forte@Sun.COM pd_next = pd_next->pd_did_hnext; 3684*7836SJohn.Forte@Sun.COM } 3685*7836SJohn.Forte@Sun.COM 3686*7836SJohn.Forte@Sun.COM if (pd_next) { 3687*7836SJohn.Forte@Sun.COM /* 3688*7836SJohn.Forte@Sun.COM * Found the given fc_remote_port_t; now remove it from the 3689*7836SJohn.Forte@Sun.COM * d_id list. 3690*7836SJohn.Forte@Sun.COM */ 3691*7836SJohn.Forte@Sun.COM head->d_id_count--; 3692*7836SJohn.Forte@Sun.COM if (last == NULL) { 3693*7836SJohn.Forte@Sun.COM head->d_id_head = pd->pd_did_hnext; 3694*7836SJohn.Forte@Sun.COM } else { 3695*7836SJohn.Forte@Sun.COM last->pd_did_hnext = pd->pd_did_hnext; 3696*7836SJohn.Forte@Sun.COM } 3697*7836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 3698*7836SJohn.Forte@Sun.COM pd->pd_did_hnext = NULL; 3699*7836SJohn.Forte@Sun.COM } 3700*7836SJohn.Forte@Sun.COM } 3701*7836SJohn.Forte@Sun.COM 3702*7836SJohn.Forte@Sun.COM 3703*7836SJohn.Forte@Sun.COM /* 3704*7836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t struct to the pwwn table in the given 3705*7836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 3706*7836SJohn.Forte@Sun.COM * in the fc_remote_port_t. 3707*7836SJohn.Forte@Sun.COM * 3708*7836SJohn.Forte@Sun.COM * No memory allocs are required, so this never fails. 3709*7836SJohn.Forte@Sun.COM */ 3710*7836SJohn.Forte@Sun.COM void 3711*7836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 3712*7836SJohn.Forte@Sun.COM { 3713*7836SJohn.Forte@Sun.COM int index; 3714*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 3715*7836SJohn.Forte@Sun.COM 3716*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3717*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3718*7836SJohn.Forte@Sun.COM 3719*7836SJohn.Forte@Sun.COM ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE); 3720*7836SJohn.Forte@Sun.COM 3721*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn), 3722*7836SJohn.Forte@Sun.COM pwwn_table_size); 3723*7836SJohn.Forte@Sun.COM 3724*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 3725*7836SJohn.Forte@Sun.COM 3726*7836SJohn.Forte@Sun.COM #ifdef DEBUG 3727*7836SJohn.Forte@Sun.COM { 3728*7836SJohn.Forte@Sun.COM int index; 3729*7836SJohn.Forte@Sun.COM fc_remote_port_t *tmp_pd; 3730*7836SJohn.Forte@Sun.COM struct pwwn_hash *tmp_head; 3731*7836SJohn.Forte@Sun.COM 3732*7836SJohn.Forte@Sun.COM /* 3733*7836SJohn.Forte@Sun.COM * Search down in each bucket for a duplicate pd 3734*7836SJohn.Forte@Sun.COM * Search also for a duplicate WWN 3735*7836SJohn.Forte@Sun.COM * Throw an ASSERT if any duplicate is found. 3736*7836SJohn.Forte@Sun.COM */ 3737*7836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 3738*7836SJohn.Forte@Sun.COM tmp_head = &port->fp_pwwn_table[index]; 3739*7836SJohn.Forte@Sun.COM 3740*7836SJohn.Forte@Sun.COM tmp_pd = tmp_head->pwwn_head; 3741*7836SJohn.Forte@Sun.COM while (tmp_pd != NULL) { 3742*7836SJohn.Forte@Sun.COM ASSERT(tmp_pd != pd); 3743*7836SJohn.Forte@Sun.COM 3744*7836SJohn.Forte@Sun.COM if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 3745*7836SJohn.Forte@Sun.COM tmp_pd->pd_type != PORT_DEVICE_OLD) { 3746*7836SJohn.Forte@Sun.COM ASSERT(fctl_wwn_cmp( 3747*7836SJohn.Forte@Sun.COM &tmp_pd->pd_port_name, 3748*7836SJohn.Forte@Sun.COM &pd->pd_port_name) != 0); 3749*7836SJohn.Forte@Sun.COM } 3750*7836SJohn.Forte@Sun.COM 3751*7836SJohn.Forte@Sun.COM tmp_pd = tmp_pd->pd_wwn_hnext; 3752*7836SJohn.Forte@Sun.COM } 3753*7836SJohn.Forte@Sun.COM } 3754*7836SJohn.Forte@Sun.COM } 3755*7836SJohn.Forte@Sun.COM 3756*7836SJohn.Forte@Sun.COM bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack)); 3757*7836SJohn.Forte@Sun.COM pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH); 3758*7836SJohn.Forte@Sun.COM #endif /* DEBUG */ 3759*7836SJohn.Forte@Sun.COM 3760*7836SJohn.Forte@Sun.COM pd->pd_wwn_hnext = head->pwwn_head; 3761*7836SJohn.Forte@Sun.COM head->pwwn_head = pd; 3762*7836SJohn.Forte@Sun.COM 3763*7836SJohn.Forte@Sun.COM head->pwwn_count++; 3764*7836SJohn.Forte@Sun.COM /* 3765*7836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 3766*7836SJohn.Forte@Sun.COM * pwwn_table 3767*7836SJohn.Forte@Sun.COM */ 3768*7836SJohn.Forte@Sun.COM port->fp_dev_count++; 3769*7836SJohn.Forte@Sun.COM } 3770*7836SJohn.Forte@Sun.COM 3771*7836SJohn.Forte@Sun.COM 3772*7836SJohn.Forte@Sun.COM /* 3773*7836SJohn.Forte@Sun.COM * Remove the given fc_remote_port_t struct from the pwwn table in the given 3774*7836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 3775*7836SJohn.Forte@Sun.COM * in the fc_remote_port_t. 3776*7836SJohn.Forte@Sun.COM * 3777*7836SJohn.Forte@Sun.COM * Does nothing if the requested fc_remote_port_t was not found. 3778*7836SJohn.Forte@Sun.COM */ 3779*7836SJohn.Forte@Sun.COM void 3780*7836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 3781*7836SJohn.Forte@Sun.COM { 3782*7836SJohn.Forte@Sun.COM int index; 3783*7836SJohn.Forte@Sun.COM la_wwn_t pwwn; 3784*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 3785*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd_next; 3786*7836SJohn.Forte@Sun.COM fc_remote_port_t *last; 3787*7836SJohn.Forte@Sun.COM 3788*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3789*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 3790*7836SJohn.Forte@Sun.COM 3791*7836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 3792*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size); 3793*7836SJohn.Forte@Sun.COM 3794*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 3795*7836SJohn.Forte@Sun.COM 3796*7836SJohn.Forte@Sun.COM last = NULL; 3797*7836SJohn.Forte@Sun.COM pd_next = head->pwwn_head; 3798*7836SJohn.Forte@Sun.COM while (pd_next != NULL) { 3799*7836SJohn.Forte@Sun.COM if (pd_next == pd) { 3800*7836SJohn.Forte@Sun.COM break; /* Found the given fc_remote_port_t */ 3801*7836SJohn.Forte@Sun.COM } 3802*7836SJohn.Forte@Sun.COM last = pd_next; 3803*7836SJohn.Forte@Sun.COM pd_next = pd_next->pd_wwn_hnext; 3804*7836SJohn.Forte@Sun.COM } 3805*7836SJohn.Forte@Sun.COM 3806*7836SJohn.Forte@Sun.COM if (pd_next) { 3807*7836SJohn.Forte@Sun.COM /* 3808*7836SJohn.Forte@Sun.COM * Found the given fc_remote_port_t; now remove it from the 3809*7836SJohn.Forte@Sun.COM * pwwn list. 3810*7836SJohn.Forte@Sun.COM */ 3811*7836SJohn.Forte@Sun.COM head->pwwn_count--; 3812*7836SJohn.Forte@Sun.COM /* 3813*7836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 3814*7836SJohn.Forte@Sun.COM * pwwn_table 3815*7836SJohn.Forte@Sun.COM */ 3816*7836SJohn.Forte@Sun.COM port->fp_dev_count--; 3817*7836SJohn.Forte@Sun.COM if (last == NULL) { 3818*7836SJohn.Forte@Sun.COM head->pwwn_head = pd->pd_wwn_hnext; 3819*7836SJohn.Forte@Sun.COM } else { 3820*7836SJohn.Forte@Sun.COM last->pd_wwn_hnext = pd->pd_wwn_hnext; 3821*7836SJohn.Forte@Sun.COM } 3822*7836SJohn.Forte@Sun.COM pd->pd_wwn_hnext = NULL; 3823*7836SJohn.Forte@Sun.COM } 3824*7836SJohn.Forte@Sun.COM } 3825*7836SJohn.Forte@Sun.COM 3826*7836SJohn.Forte@Sun.COM 3827*7836SJohn.Forte@Sun.COM /* 3828*7836SJohn.Forte@Sun.COM * Looks in the d_id table of the specified fc_local_port_t for the 3829*7836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon 3830*7836SJohn.Forte@Sun.COM * the given d_id. 3831*7836SJohn.Forte@Sun.COM * Returns a pointer to the fc_remote_port_t struct, but does not update any 3832*7836SJohn.Forte@Sun.COM * reference counts or otherwise indicate that the fc_remote_port_t is in 3833*7836SJohn.Forte@Sun.COM * use. 3834*7836SJohn.Forte@Sun.COM */ 3835*7836SJohn.Forte@Sun.COM fc_remote_port_t * 3836*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 3837*7836SJohn.Forte@Sun.COM { 3838*7836SJohn.Forte@Sun.COM struct d_id_hash *head; 3839*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3840*7836SJohn.Forte@Sun.COM 3841*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3842*7836SJohn.Forte@Sun.COM 3843*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 3844*7836SJohn.Forte@Sun.COM 3845*7836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3846*7836SJohn.Forte@Sun.COM 3847*7836SJohn.Forte@Sun.COM pd = head->d_id_head; 3848*7836SJohn.Forte@Sun.COM while (pd != NULL) { 3849*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3850*7836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id) { 3851*7836SJohn.Forte@Sun.COM /* Match found -- break out of the loop */ 3852*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3853*7836SJohn.Forte@Sun.COM break; 3854*7836SJohn.Forte@Sun.COM } 3855*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3856*7836SJohn.Forte@Sun.COM pd = pd->pd_did_hnext; 3857*7836SJohn.Forte@Sun.COM } 3858*7836SJohn.Forte@Sun.COM 3859*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 3860*7836SJohn.Forte@Sun.COM 3861*7836SJohn.Forte@Sun.COM return (pd); 3862*7836SJohn.Forte@Sun.COM } 3863*7836SJohn.Forte@Sun.COM 3864*7836SJohn.Forte@Sun.COM 3865*7836SJohn.Forte@Sun.COM #ifndef __lock_lint /* uncomment when there is a consumer */ 3866*7836SJohn.Forte@Sun.COM 3867*7836SJohn.Forte@Sun.COM void 3868*7836SJohn.Forte@Sun.COM fc_ulp_hold_remote_port(opaque_t port_handle) 3869*7836SJohn.Forte@Sun.COM { 3870*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd = port_handle; 3871*7836SJohn.Forte@Sun.COM 3872*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3873*7836SJohn.Forte@Sun.COM pd->pd_ref_count++; 3874*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3875*7836SJohn.Forte@Sun.COM } 3876*7836SJohn.Forte@Sun.COM 3877*7836SJohn.Forte@Sun.COM /* 3878*7836SJohn.Forte@Sun.COM * Looks in the d_id table of the specified fc_local_port_t for the 3879*7836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon 3880*7836SJohn.Forte@Sun.COM * the given d_id. Returns a pointer to the fc_remote_port_t struct. 3881*7836SJohn.Forte@Sun.COM * 3882*7836SJohn.Forte@Sun.COM * Increments pd_ref_count in the fc_remote_port_t if the 3883*7836SJohn.Forte@Sun.COM * fc_remote_port_t is found at the given d_id. 3884*7836SJohn.Forte@Sun.COM * 3885*7836SJohn.Forte@Sun.COM * The fc_remote_port_t is ignored (treated as non-existent) if either 3886*7836SJohn.Forte@Sun.COM * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 3887*7836SJohn.Forte@Sun.COM */ 3888*7836SJohn.Forte@Sun.COM fc_remote_port_t * 3889*7836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 3890*7836SJohn.Forte@Sun.COM { 3891*7836SJohn.Forte@Sun.COM struct d_id_hash *head; 3892*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3893*7836SJohn.Forte@Sun.COM 3894*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3895*7836SJohn.Forte@Sun.COM 3896*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 3897*7836SJohn.Forte@Sun.COM 3898*7836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 3899*7836SJohn.Forte@Sun.COM 3900*7836SJohn.Forte@Sun.COM pd = head->d_id_head; 3901*7836SJohn.Forte@Sun.COM while (pd != NULL) { 3902*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3903*7836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id && pd->pd_state != 3904*7836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) { 3905*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 3906*7836SJohn.Forte@Sun.COM pd->pd_ref_count++; 3907*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3908*7836SJohn.Forte@Sun.COM break; 3909*7836SJohn.Forte@Sun.COM } 3910*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3911*7836SJohn.Forte@Sun.COM pd = pd->pd_did_hnext; 3912*7836SJohn.Forte@Sun.COM } 3913*7836SJohn.Forte@Sun.COM 3914*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 3915*7836SJohn.Forte@Sun.COM 3916*7836SJohn.Forte@Sun.COM return (pd); 3917*7836SJohn.Forte@Sun.COM } 3918*7836SJohn.Forte@Sun.COM 3919*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 3920*7836SJohn.Forte@Sun.COM 3921*7836SJohn.Forte@Sun.COM /* 3922*7836SJohn.Forte@Sun.COM * Looks in the pwwn table of the specified fc_local_port_t for the 3923*7836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given pwwn. Hashes based upon the 3924*7836SJohn.Forte@Sun.COM * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct, 3925*7836SJohn.Forte@Sun.COM * but does not update any reference counts or otherwise indicate that 3926*7836SJohn.Forte@Sun.COM * the fc_remote_port_t is in use. 3927*7836SJohn.Forte@Sun.COM */ 3928*7836SJohn.Forte@Sun.COM fc_remote_port_t * 3929*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 3930*7836SJohn.Forte@Sun.COM { 3931*7836SJohn.Forte@Sun.COM int index; 3932*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 3933*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3934*7836SJohn.Forte@Sun.COM 3935*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 3936*7836SJohn.Forte@Sun.COM 3937*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 3938*7836SJohn.Forte@Sun.COM 3939*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 3940*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 3941*7836SJohn.Forte@Sun.COM 3942*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 3943*7836SJohn.Forte@Sun.COM while (pd != NULL) { 3944*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3945*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 3946*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3947*7836SJohn.Forte@Sun.COM break; 3948*7836SJohn.Forte@Sun.COM } 3949*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3950*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 3951*7836SJohn.Forte@Sun.COM } 3952*7836SJohn.Forte@Sun.COM 3953*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 3954*7836SJohn.Forte@Sun.COM 3955*7836SJohn.Forte@Sun.COM return (pd); 3956*7836SJohn.Forte@Sun.COM } 3957*7836SJohn.Forte@Sun.COM 3958*7836SJohn.Forte@Sun.COM 3959*7836SJohn.Forte@Sun.COM /* 3960*7836SJohn.Forte@Sun.COM * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that 3961*7836SJohn.Forte@Sun.COM * the caller already hold the fp_mutex in the fc_local_port_t struct. 3962*7836SJohn.Forte@Sun.COM */ 3963*7836SJohn.Forte@Sun.COM fc_remote_port_t * 3964*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn) 3965*7836SJohn.Forte@Sun.COM { 3966*7836SJohn.Forte@Sun.COM int index; 3967*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 3968*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 3969*7836SJohn.Forte@Sun.COM 3970*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 3971*7836SJohn.Forte@Sun.COM 3972*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 3973*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 3974*7836SJohn.Forte@Sun.COM 3975*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 3976*7836SJohn.Forte@Sun.COM while (pd != NULL) { 3977*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 3978*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 3979*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3980*7836SJohn.Forte@Sun.COM break; 3981*7836SJohn.Forte@Sun.COM } 3982*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 3983*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 3984*7836SJohn.Forte@Sun.COM } 3985*7836SJohn.Forte@Sun.COM 3986*7836SJohn.Forte@Sun.COM return (pd); 3987*7836SJohn.Forte@Sun.COM } 3988*7836SJohn.Forte@Sun.COM 3989*7836SJohn.Forte@Sun.COM 3990*7836SJohn.Forte@Sun.COM /* 3991*7836SJohn.Forte@Sun.COM * Looks in the pwwn table of the specified fc_local_port_t for the 3992*7836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon the 3993*7836SJohn.Forte@Sun.COM * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct. 3994*7836SJohn.Forte@Sun.COM * 3995*7836SJohn.Forte@Sun.COM * Increments pd_ref_count in the fc_remote_port_t if the 3996*7836SJohn.Forte@Sun.COM * fc_remote_port_t is found at the given pwwn. 3997*7836SJohn.Forte@Sun.COM * 3998*7836SJohn.Forte@Sun.COM * The fc_remote_port_t is ignored (treated as non-existent) if either 3999*7836SJohn.Forte@Sun.COM * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 4000*7836SJohn.Forte@Sun.COM */ 4001*7836SJohn.Forte@Sun.COM fc_remote_port_t * 4002*7836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 4003*7836SJohn.Forte@Sun.COM { 4004*7836SJohn.Forte@Sun.COM int index; 4005*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 4006*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 4007*7836SJohn.Forte@Sun.COM 4008*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4009*7836SJohn.Forte@Sun.COM 4010*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4011*7836SJohn.Forte@Sun.COM 4012*7836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 4013*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 4014*7836SJohn.Forte@Sun.COM 4015*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 4016*7836SJohn.Forte@Sun.COM while (pd != NULL) { 4017*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4018*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 && 4019*7836SJohn.Forte@Sun.COM pd->pd_state != PORT_DEVICE_INVALID && 4020*7836SJohn.Forte@Sun.COM pd->pd_type != PORT_DEVICE_OLD) { 4021*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 4022*7836SJohn.Forte@Sun.COM pd->pd_ref_count++; 4023*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4024*7836SJohn.Forte@Sun.COM break; 4025*7836SJohn.Forte@Sun.COM } 4026*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4027*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 4028*7836SJohn.Forte@Sun.COM } 4029*7836SJohn.Forte@Sun.COM 4030*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4031*7836SJohn.Forte@Sun.COM 4032*7836SJohn.Forte@Sun.COM return (pd); 4033*7836SJohn.Forte@Sun.COM } 4034*7836SJohn.Forte@Sun.COM 4035*7836SJohn.Forte@Sun.COM 4036*7836SJohn.Forte@Sun.COM /* 4037*7836SJohn.Forte@Sun.COM * Unconditionally decrement pd_ref_count in the given fc_remote_port_t 4038*7836SJohn.Forte@Sun.COM * struct. 4039*7836SJohn.Forte@Sun.COM * 4040*7836SJohn.Forte@Sun.COM * If pd_ref_count reaches zero, then this function will see if the 4041*7836SJohn.Forte@Sun.COM * fc_remote_port_t has been marked for deallocation. If so (and also if there 4042*7836SJohn.Forte@Sun.COM * are no other potential operations in progress, as indicated by the 4043*7836SJohn.Forte@Sun.COM * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then 4044*7836SJohn.Forte@Sun.COM * fctl_destroy_remote_port_t() is called to deconstruct/free the given 4045*7836SJohn.Forte@Sun.COM * fc_remote_port_t (which will also remove it from the d_id and pwwn tables 4046*7836SJohn.Forte@Sun.COM * on the associated fc_local_port_t). If the associated fc_remote_node_t is no 4047*7836SJohn.Forte@Sun.COM * longer in use, then it too is deconstructed/freed. 4048*7836SJohn.Forte@Sun.COM */ 4049*7836SJohn.Forte@Sun.COM void 4050*7836SJohn.Forte@Sun.COM fctl_release_remote_port(fc_remote_port_t *pd) 4051*7836SJohn.Forte@Sun.COM { 4052*7836SJohn.Forte@Sun.COM int remove = 0; 4053*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 4054*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 4055*7836SJohn.Forte@Sun.COM 4056*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4057*7836SJohn.Forte@Sun.COM port = pd->pd_port; 4058*7836SJohn.Forte@Sun.COM 4059*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count > 0); 4060*7836SJohn.Forte@Sun.COM pd->pd_ref_count--; 4061*7836SJohn.Forte@Sun.COM if (pd->pd_ref_count == 0 && 4062*7836SJohn.Forte@Sun.COM (pd->pd_aux_flags & PD_NEEDS_REMOVAL) && 4063*7836SJohn.Forte@Sun.COM (pd->pd_flags != PD_ELS_IN_PROGRESS) && 4064*7836SJohn.Forte@Sun.COM (pd->pd_flags != PD_ELS_MARK)) { 4065*7836SJohn.Forte@Sun.COM remove = 1; 4066*7836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL; 4067*7836SJohn.Forte@Sun.COM } 4068*7836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 4069*7836SJohn.Forte@Sun.COM ASSERT(node != NULL); 4070*7836SJohn.Forte@Sun.COM 4071*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4072*7836SJohn.Forte@Sun.COM 4073*7836SJohn.Forte@Sun.COM if (remove) { 4074*7836SJohn.Forte@Sun.COM /* 4075*7836SJohn.Forte@Sun.COM * The fc_remote_port_t struct has to go away now, so call the 4076*7836SJohn.Forte@Sun.COM * cleanup function to get it off the various lists and remove 4077*7836SJohn.Forte@Sun.COM * references to it in any other associated structs. 4078*7836SJohn.Forte@Sun.COM */ 4079*7836SJohn.Forte@Sun.COM if (fctl_destroy_remote_port(port, pd) == 0) { 4080*7836SJohn.Forte@Sun.COM /* 4081*7836SJohn.Forte@Sun.COM * No more fc_remote_port_t references found in the 4082*7836SJohn.Forte@Sun.COM * associated fc_remote_node_t, so deallocate the 4083*7836SJohn.Forte@Sun.COM * fc_remote_node_t (if it even exists). 4084*7836SJohn.Forte@Sun.COM */ 4085*7836SJohn.Forte@Sun.COM if (node) { 4086*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 4087*7836SJohn.Forte@Sun.COM } 4088*7836SJohn.Forte@Sun.COM } 4089*7836SJohn.Forte@Sun.COM } 4090*7836SJohn.Forte@Sun.COM } 4091*7836SJohn.Forte@Sun.COM 4092*7836SJohn.Forte@Sun.COM 4093*7836SJohn.Forte@Sun.COM void 4094*7836SJohn.Forte@Sun.COM fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len, 4095*7836SJohn.Forte@Sun.COM int whole_map, int justcopy, int orphan) 4096*7836SJohn.Forte@Sun.COM { 4097*7836SJohn.Forte@Sun.COM int index; 4098*7836SJohn.Forte@Sun.COM int listlen; 4099*7836SJohn.Forte@Sun.COM int full_list; 4100*7836SJohn.Forte@Sun.COM int initiator; 4101*7836SJohn.Forte@Sun.COM uint32_t topology; 4102*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 4103*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 4104*7836SJohn.Forte@Sun.COM fc_remote_port_t *old_pd; 4105*7836SJohn.Forte@Sun.COM fc_remote_port_t *last_pd; 4106*7836SJohn.Forte@Sun.COM fc_portmap_t *listptr; 4107*7836SJohn.Forte@Sun.COM 4108*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4109*7836SJohn.Forte@Sun.COM 4110*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4111*7836SJohn.Forte@Sun.COM 4112*7836SJohn.Forte@Sun.COM topology = port->fp_topology; 4113*7836SJohn.Forte@Sun.COM 4114*7836SJohn.Forte@Sun.COM if (orphan) { 4115*7836SJohn.Forte@Sun.COM ASSERT(!FC_IS_TOP_SWITCH(topology)); 4116*7836SJohn.Forte@Sun.COM } 4117*7836SJohn.Forte@Sun.COM 4118*7836SJohn.Forte@Sun.COM for (full_list = listlen = index = 0; 4119*7836SJohn.Forte@Sun.COM index < pwwn_table_size; index++) { 4120*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 4121*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 4122*7836SJohn.Forte@Sun.COM while (pd != NULL) { 4123*7836SJohn.Forte@Sun.COM full_list++; 4124*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4125*7836SJohn.Forte@Sun.COM if (pd->pd_type != PORT_DEVICE_NOCHANGE) { 4126*7836SJohn.Forte@Sun.COM listlen++; 4127*7836SJohn.Forte@Sun.COM } 4128*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4129*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 4130*7836SJohn.Forte@Sun.COM } 4131*7836SJohn.Forte@Sun.COM } 4132*7836SJohn.Forte@Sun.COM 4133*7836SJohn.Forte@Sun.COM if (whole_map == 0) { 4134*7836SJohn.Forte@Sun.COM if (listlen == 0 && *len == 0) { 4135*7836SJohn.Forte@Sun.COM *map = NULL; 4136*7836SJohn.Forte@Sun.COM *len = listlen; 4137*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4138*7836SJohn.Forte@Sun.COM return; 4139*7836SJohn.Forte@Sun.COM } 4140*7836SJohn.Forte@Sun.COM } else { 4141*7836SJohn.Forte@Sun.COM if (full_list == 0 && *len == 0) { 4142*7836SJohn.Forte@Sun.COM *map = NULL; 4143*7836SJohn.Forte@Sun.COM *len = full_list; 4144*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4145*7836SJohn.Forte@Sun.COM return; 4146*7836SJohn.Forte@Sun.COM } 4147*7836SJohn.Forte@Sun.COM } 4148*7836SJohn.Forte@Sun.COM 4149*7836SJohn.Forte@Sun.COM if (*len == 0) { 4150*7836SJohn.Forte@Sun.COM ASSERT(*map == NULL); 4151*7836SJohn.Forte@Sun.COM if (whole_map == 0) { 4152*7836SJohn.Forte@Sun.COM listptr = *map = kmem_zalloc( 4153*7836SJohn.Forte@Sun.COM sizeof (*listptr) * listlen, KM_SLEEP); 4154*7836SJohn.Forte@Sun.COM *len = listlen; 4155*7836SJohn.Forte@Sun.COM } else { 4156*7836SJohn.Forte@Sun.COM listptr = *map = kmem_zalloc( 4157*7836SJohn.Forte@Sun.COM sizeof (*listptr) * full_list, KM_SLEEP); 4158*7836SJohn.Forte@Sun.COM *len = full_list; 4159*7836SJohn.Forte@Sun.COM } 4160*7836SJohn.Forte@Sun.COM } else { 4161*7836SJohn.Forte@Sun.COM /* 4162*7836SJohn.Forte@Sun.COM * By design this routine mandates the callers to 4163*7836SJohn.Forte@Sun.COM * ask for a whole map when they specify the length 4164*7836SJohn.Forte@Sun.COM * and the listptr. 4165*7836SJohn.Forte@Sun.COM */ 4166*7836SJohn.Forte@Sun.COM ASSERT(whole_map == 1); 4167*7836SJohn.Forte@Sun.COM if (*len < full_list) { 4168*7836SJohn.Forte@Sun.COM *len = full_list; 4169*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4170*7836SJohn.Forte@Sun.COM return; 4171*7836SJohn.Forte@Sun.COM } 4172*7836SJohn.Forte@Sun.COM listptr = *map; 4173*7836SJohn.Forte@Sun.COM *len = full_list; 4174*7836SJohn.Forte@Sun.COM } 4175*7836SJohn.Forte@Sun.COM 4176*7836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 4177*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 4178*7836SJohn.Forte@Sun.COM last_pd = NULL; 4179*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 4180*7836SJohn.Forte@Sun.COM while (pd != NULL) { 4181*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4182*7836SJohn.Forte@Sun.COM if ((whole_map == 0 && 4183*7836SJohn.Forte@Sun.COM pd->pd_type == PORT_DEVICE_NOCHANGE) || 4184*7836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 4185*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4186*7836SJohn.Forte@Sun.COM last_pd = pd; 4187*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 4188*7836SJohn.Forte@Sun.COM continue; 4189*7836SJohn.Forte@Sun.COM } 4190*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4191*7836SJohn.Forte@Sun.COM 4192*7836SJohn.Forte@Sun.COM fctl_copy_portmap(listptr, pd); 4193*7836SJohn.Forte@Sun.COM 4194*7836SJohn.Forte@Sun.COM if (justcopy) { 4195*7836SJohn.Forte@Sun.COM last_pd = pd; 4196*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 4197*7836SJohn.Forte@Sun.COM listptr++; 4198*7836SJohn.Forte@Sun.COM continue; 4199*7836SJohn.Forte@Sun.COM } 4200*7836SJohn.Forte@Sun.COM 4201*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4202*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_state != PORT_DEVICE_INVALID); 4203*7836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD) { 4204*7836SJohn.Forte@Sun.COM listptr->map_pd = pd; 4205*7836SJohn.Forte@Sun.COM listptr->map_state = pd->pd_state = 4206*7836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID; 4207*7836SJohn.Forte@Sun.COM /* 4208*7836SJohn.Forte@Sun.COM * Remove this from the PWWN hash table. 4209*7836SJohn.Forte@Sun.COM */ 4210*7836SJohn.Forte@Sun.COM old_pd = pd; 4211*7836SJohn.Forte@Sun.COM pd = old_pd->pd_wwn_hnext; 4212*7836SJohn.Forte@Sun.COM 4213*7836SJohn.Forte@Sun.COM if (last_pd == NULL) { 4214*7836SJohn.Forte@Sun.COM ASSERT(old_pd == head->pwwn_head); 4215*7836SJohn.Forte@Sun.COM 4216*7836SJohn.Forte@Sun.COM head->pwwn_head = pd; 4217*7836SJohn.Forte@Sun.COM } else { 4218*7836SJohn.Forte@Sun.COM last_pd->pd_wwn_hnext = pd; 4219*7836SJohn.Forte@Sun.COM } 4220*7836SJohn.Forte@Sun.COM head->pwwn_count--; 4221*7836SJohn.Forte@Sun.COM /* 4222*7836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size 4223*7836SJohn.Forte@Sun.COM * of the pwwn_table 4224*7836SJohn.Forte@Sun.COM */ 4225*7836SJohn.Forte@Sun.COM port->fp_dev_count--; 4226*7836SJohn.Forte@Sun.COM old_pd->pd_wwn_hnext = NULL; 4227*7836SJohn.Forte@Sun.COM 4228*7836SJohn.Forte@Sun.COM if (port->fp_topology == FC_TOP_PRIVATE_LOOP && 4229*7836SJohn.Forte@Sun.COM port->fp_statec_busy && !orphan) { 4230*7836SJohn.Forte@Sun.COM fctl_check_alpa_list(port, old_pd); 4231*7836SJohn.Forte@Sun.COM } 4232*7836SJohn.Forte@Sun.COM 4233*7836SJohn.Forte@Sun.COM /* 4234*7836SJohn.Forte@Sun.COM * Remove if the port device has stealthily 4235*7836SJohn.Forte@Sun.COM * present in the D_ID hash table 4236*7836SJohn.Forte@Sun.COM */ 4237*7836SJohn.Forte@Sun.COM fctl_delist_did_table(port, old_pd); 4238*7836SJohn.Forte@Sun.COM 4239*7836SJohn.Forte@Sun.COM ASSERT(old_pd->pd_remote_nodep != NULL); 4240*7836SJohn.Forte@Sun.COM 4241*7836SJohn.Forte@Sun.COM initiator = (old_pd->pd_recepient == 4242*7836SJohn.Forte@Sun.COM PD_PLOGI_INITIATOR) ? 1 : 0; 4243*7836SJohn.Forte@Sun.COM 4244*7836SJohn.Forte@Sun.COM mutex_exit(&old_pd->pd_mutex); 4245*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4246*7836SJohn.Forte@Sun.COM 4247*7836SJohn.Forte@Sun.COM if (orphan) { 4248*7836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(port, old_pd); 4249*7836SJohn.Forte@Sun.COM 4250*7836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 4251*7836SJohn.Forte@Sun.COM KM_NOSLEEP); 4252*7836SJohn.Forte@Sun.COM } 4253*7836SJohn.Forte@Sun.COM 4254*7836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(topology) && initiator) { 4255*7836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 4256*7836SJohn.Forte@Sun.COM KM_NOSLEEP); 4257*7836SJohn.Forte@Sun.COM } 4258*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4259*7836SJohn.Forte@Sun.COM } else { 4260*7836SJohn.Forte@Sun.COM listptr->map_pd = pd; 4261*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 4262*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4263*7836SJohn.Forte@Sun.COM last_pd = pd; 4264*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 4265*7836SJohn.Forte@Sun.COM } 4266*7836SJohn.Forte@Sun.COM listptr++; 4267*7836SJohn.Forte@Sun.COM } 4268*7836SJohn.Forte@Sun.COM } 4269*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4270*7836SJohn.Forte@Sun.COM } 4271*7836SJohn.Forte@Sun.COM 4272*7836SJohn.Forte@Sun.COM 4273*7836SJohn.Forte@Sun.COM job_request_t * 4274*7836SJohn.Forte@Sun.COM fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t), 4275*7836SJohn.Forte@Sun.COM opaque_t arg, int sleep) 4276*7836SJohn.Forte@Sun.COM { 4277*7836SJohn.Forte@Sun.COM job_request_t *job; 4278*7836SJohn.Forte@Sun.COM 4279*7836SJohn.Forte@Sun.COM job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep); 4280*7836SJohn.Forte@Sun.COM if (job != NULL) { 4281*7836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 4282*7836SJohn.Forte@Sun.COM job->job_code = job_code; 4283*7836SJohn.Forte@Sun.COM job->job_flags = job_flags; 4284*7836SJohn.Forte@Sun.COM job->job_cb_arg = arg; 4285*7836SJohn.Forte@Sun.COM job->job_comp = comp; 4286*7836SJohn.Forte@Sun.COM job->job_private = NULL; 4287*7836SJohn.Forte@Sun.COM job->job_ulp_pkts = NULL; 4288*7836SJohn.Forte@Sun.COM job->job_ulp_listlen = 0; 4289*7836SJohn.Forte@Sun.COM #ifndef __lock_lint 4290*7836SJohn.Forte@Sun.COM job->job_counter = 0; 4291*7836SJohn.Forte@Sun.COM job->job_next = NULL; 4292*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 4293*7836SJohn.Forte@Sun.COM } 4294*7836SJohn.Forte@Sun.COM 4295*7836SJohn.Forte@Sun.COM return (job); 4296*7836SJohn.Forte@Sun.COM } 4297*7836SJohn.Forte@Sun.COM 4298*7836SJohn.Forte@Sun.COM 4299*7836SJohn.Forte@Sun.COM void 4300*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job_request_t *job) 4301*7836SJohn.Forte@Sun.COM { 4302*7836SJohn.Forte@Sun.COM kmem_cache_free(fctl_job_cache, (void *)job); 4303*7836SJohn.Forte@Sun.COM } 4304*7836SJohn.Forte@Sun.COM 4305*7836SJohn.Forte@Sun.COM 4306*7836SJohn.Forte@Sun.COM void 4307*7836SJohn.Forte@Sun.COM fctl_enque_job(fc_local_port_t *port, job_request_t *job) 4308*7836SJohn.Forte@Sun.COM { 4309*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4310*7836SJohn.Forte@Sun.COM 4311*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4312*7836SJohn.Forte@Sun.COM 4313*7836SJohn.Forte@Sun.COM if (port->fp_job_tail == NULL) { 4314*7836SJohn.Forte@Sun.COM ASSERT(port->fp_job_head == NULL); 4315*7836SJohn.Forte@Sun.COM port->fp_job_head = port->fp_job_tail = job; 4316*7836SJohn.Forte@Sun.COM } else { 4317*7836SJohn.Forte@Sun.COM port->fp_job_tail->job_next = job; 4318*7836SJohn.Forte@Sun.COM port->fp_job_tail = job; 4319*7836SJohn.Forte@Sun.COM } 4320*7836SJohn.Forte@Sun.COM job->job_next = NULL; 4321*7836SJohn.Forte@Sun.COM 4322*7836SJohn.Forte@Sun.COM cv_signal(&port->fp_cv); 4323*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4324*7836SJohn.Forte@Sun.COM } 4325*7836SJohn.Forte@Sun.COM 4326*7836SJohn.Forte@Sun.COM 4327*7836SJohn.Forte@Sun.COM job_request_t * 4328*7836SJohn.Forte@Sun.COM fctl_deque_job(fc_local_port_t *port) 4329*7836SJohn.Forte@Sun.COM { 4330*7836SJohn.Forte@Sun.COM job_request_t *job; 4331*7836SJohn.Forte@Sun.COM 4332*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 4333*7836SJohn.Forte@Sun.COM 4334*7836SJohn.Forte@Sun.COM if (port->fp_job_head == NULL) { 4335*7836SJohn.Forte@Sun.COM ASSERT(port->fp_job_tail == NULL); 4336*7836SJohn.Forte@Sun.COM job = NULL; 4337*7836SJohn.Forte@Sun.COM } else { 4338*7836SJohn.Forte@Sun.COM job = port->fp_job_head; 4339*7836SJohn.Forte@Sun.COM if (job->job_next == NULL) { 4340*7836SJohn.Forte@Sun.COM ASSERT(job == port->fp_job_tail); 4341*7836SJohn.Forte@Sun.COM port->fp_job_tail = NULL; 4342*7836SJohn.Forte@Sun.COM } 4343*7836SJohn.Forte@Sun.COM port->fp_job_head = job->job_next; 4344*7836SJohn.Forte@Sun.COM } 4345*7836SJohn.Forte@Sun.COM 4346*7836SJohn.Forte@Sun.COM return (job); 4347*7836SJohn.Forte@Sun.COM } 4348*7836SJohn.Forte@Sun.COM 4349*7836SJohn.Forte@Sun.COM 4350*7836SJohn.Forte@Sun.COM void 4351*7836SJohn.Forte@Sun.COM fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job) 4352*7836SJohn.Forte@Sun.COM { 4353*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 4354*7836SJohn.Forte@Sun.COM 4355*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4356*7836SJohn.Forte@Sun.COM if (port->fp_job_tail == NULL) { 4357*7836SJohn.Forte@Sun.COM ASSERT(port->fp_job_head == NULL); 4358*7836SJohn.Forte@Sun.COM port->fp_job_head = port->fp_job_tail = job; 4359*7836SJohn.Forte@Sun.COM job->job_next = NULL; 4360*7836SJohn.Forte@Sun.COM } else { 4361*7836SJohn.Forte@Sun.COM job->job_next = port->fp_job_head; 4362*7836SJohn.Forte@Sun.COM port->fp_job_head = job; 4363*7836SJohn.Forte@Sun.COM } 4364*7836SJohn.Forte@Sun.COM cv_signal(&port->fp_cv); 4365*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4366*7836SJohn.Forte@Sun.COM } 4367*7836SJohn.Forte@Sun.COM 4368*7836SJohn.Forte@Sun.COM 4369*7836SJohn.Forte@Sun.COM void 4370*7836SJohn.Forte@Sun.COM fctl_jobwait(job_request_t *job) 4371*7836SJohn.Forte@Sun.COM { 4372*7836SJohn.Forte@Sun.COM ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC)); 4373*7836SJohn.Forte@Sun.COM sema_p(&job->job_fctl_sema); 4374*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&job->job_mutex)); 4375*7836SJohn.Forte@Sun.COM } 4376*7836SJohn.Forte@Sun.COM 4377*7836SJohn.Forte@Sun.COM 4378*7836SJohn.Forte@Sun.COM void 4379*7836SJohn.Forte@Sun.COM fctl_jobdone(job_request_t *job) 4380*7836SJohn.Forte@Sun.COM { 4381*7836SJohn.Forte@Sun.COM if (job->job_flags & JOB_TYPE_FCTL_ASYNC) { 4382*7836SJohn.Forte@Sun.COM if (job->job_comp) { 4383*7836SJohn.Forte@Sun.COM job->job_comp(job->job_cb_arg, job->job_result); 4384*7836SJohn.Forte@Sun.COM } 4385*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 4386*7836SJohn.Forte@Sun.COM } else { 4387*7836SJohn.Forte@Sun.COM sema_v(&job->job_fctl_sema); 4388*7836SJohn.Forte@Sun.COM } 4389*7836SJohn.Forte@Sun.COM } 4390*7836SJohn.Forte@Sun.COM 4391*7836SJohn.Forte@Sun.COM 4392*7836SJohn.Forte@Sun.COM /* 4393*7836SJohn.Forte@Sun.COM * Compare two WWNs. The NAA is omitted for comparison. 4394*7836SJohn.Forte@Sun.COM * 4395*7836SJohn.Forte@Sun.COM * Note particularly that the indentation used in this 4396*7836SJohn.Forte@Sun.COM * function isn't according to Sun recommendations. It 4397*7836SJohn.Forte@Sun.COM * is indented to make reading a bit easy. 4398*7836SJohn.Forte@Sun.COM * 4399*7836SJohn.Forte@Sun.COM * Return Values: 4400*7836SJohn.Forte@Sun.COM * if src == dst return 0 4401*7836SJohn.Forte@Sun.COM * if src > dst return 1 4402*7836SJohn.Forte@Sun.COM * if src < dst return -1 4403*7836SJohn.Forte@Sun.COM */ 4404*7836SJohn.Forte@Sun.COM int 4405*7836SJohn.Forte@Sun.COM fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst) 4406*7836SJohn.Forte@Sun.COM { 4407*7836SJohn.Forte@Sun.COM la_wwn_t tmpsrc, tmpdst; 4408*7836SJohn.Forte@Sun.COM 4409*7836SJohn.Forte@Sun.COM /* 4410*7836SJohn.Forte@Sun.COM * Fibre Channel protocol is big endian, so compare 4411*7836SJohn.Forte@Sun.COM * as big endian values 4412*7836SJohn.Forte@Sun.COM */ 4413*7836SJohn.Forte@Sun.COM tmpsrc.i_wwn[0] = BE_32(src->i_wwn[0]); 4414*7836SJohn.Forte@Sun.COM tmpsrc.i_wwn[1] = BE_32(src->i_wwn[1]); 4415*7836SJohn.Forte@Sun.COM 4416*7836SJohn.Forte@Sun.COM tmpdst.i_wwn[0] = BE_32(dst->i_wwn[0]); 4417*7836SJohn.Forte@Sun.COM tmpdst.i_wwn[1] = BE_32(dst->i_wwn[1]); 4418*7836SJohn.Forte@Sun.COM 4419*7836SJohn.Forte@Sun.COM return ( 4420*7836SJohn.Forte@Sun.COM (tmpsrc.w.nport_id == tmpdst.w.nport_id) ? 4421*7836SJohn.Forte@Sun.COM ((tmpsrc.w.wwn_hi == tmpdst.w.wwn_hi) ? 4422*7836SJohn.Forte@Sun.COM ((tmpsrc.w.wwn_lo == tmpdst.w.wwn_lo) ? 0 : 4423*7836SJohn.Forte@Sun.COM (tmpsrc.w.wwn_lo > tmpdst.w.wwn_lo) ? 1 : -1) : 4424*7836SJohn.Forte@Sun.COM (tmpsrc.w.wwn_hi > tmpdst.w.wwn_hi) ? 1 : -1) : 4425*7836SJohn.Forte@Sun.COM (tmpsrc.w.nport_id > tmpdst.w.nport_id) ? 1 : -1); 4426*7836SJohn.Forte@Sun.COM } 4427*7836SJohn.Forte@Sun.COM 4428*7836SJohn.Forte@Sun.COM 4429*7836SJohn.Forte@Sun.COM /* 4430*7836SJohn.Forte@Sun.COM * ASCII to Integer goodie with support for base 16, 10, 2 and 8 4431*7836SJohn.Forte@Sun.COM */ 4432*7836SJohn.Forte@Sun.COM int 4433*7836SJohn.Forte@Sun.COM fctl_atoi(char *s, int base) 4434*7836SJohn.Forte@Sun.COM { 4435*7836SJohn.Forte@Sun.COM int val; 4436*7836SJohn.Forte@Sun.COM int ch; 4437*7836SJohn.Forte@Sun.COM 4438*7836SJohn.Forte@Sun.COM for (val = 0; *s != '\0'; s++) { 4439*7836SJohn.Forte@Sun.COM switch (base) { 4440*7836SJohn.Forte@Sun.COM case 16: 4441*7836SJohn.Forte@Sun.COM if (*s >= '0' && *s <= '9') { 4442*7836SJohn.Forte@Sun.COM ch = *s - '0'; 4443*7836SJohn.Forte@Sun.COM } else if (*s >= 'a' && *s <= 'f') { 4444*7836SJohn.Forte@Sun.COM ch = *s - 'a' + 10; 4445*7836SJohn.Forte@Sun.COM } else if (*s >= 'A' && *s <= 'F') { 4446*7836SJohn.Forte@Sun.COM ch = *s - 'A' + 10; 4447*7836SJohn.Forte@Sun.COM } else { 4448*7836SJohn.Forte@Sun.COM return (-1); 4449*7836SJohn.Forte@Sun.COM } 4450*7836SJohn.Forte@Sun.COM break; 4451*7836SJohn.Forte@Sun.COM 4452*7836SJohn.Forte@Sun.COM case 10: 4453*7836SJohn.Forte@Sun.COM if (*s < '0' || *s > '9') { 4454*7836SJohn.Forte@Sun.COM return (-1); 4455*7836SJohn.Forte@Sun.COM } 4456*7836SJohn.Forte@Sun.COM ch = *s - '0'; 4457*7836SJohn.Forte@Sun.COM break; 4458*7836SJohn.Forte@Sun.COM 4459*7836SJohn.Forte@Sun.COM case 2: 4460*7836SJohn.Forte@Sun.COM if (*s < '0' || *s > '1') { 4461*7836SJohn.Forte@Sun.COM return (-1); 4462*7836SJohn.Forte@Sun.COM } 4463*7836SJohn.Forte@Sun.COM ch = *s - '0'; 4464*7836SJohn.Forte@Sun.COM break; 4465*7836SJohn.Forte@Sun.COM 4466*7836SJohn.Forte@Sun.COM case 8: 4467*7836SJohn.Forte@Sun.COM if (*s < '0' || *s > '7') { 4468*7836SJohn.Forte@Sun.COM return (-1); 4469*7836SJohn.Forte@Sun.COM } 4470*7836SJohn.Forte@Sun.COM ch = *s - '0'; 4471*7836SJohn.Forte@Sun.COM break; 4472*7836SJohn.Forte@Sun.COM 4473*7836SJohn.Forte@Sun.COM default: 4474*7836SJohn.Forte@Sun.COM return (-1); 4475*7836SJohn.Forte@Sun.COM } 4476*7836SJohn.Forte@Sun.COM val = (val * base) + ch; 4477*7836SJohn.Forte@Sun.COM } 4478*7836SJohn.Forte@Sun.COM return (val); 4479*7836SJohn.Forte@Sun.COM } 4480*7836SJohn.Forte@Sun.COM 4481*7836SJohn.Forte@Sun.COM 4482*7836SJohn.Forte@Sun.COM /* 4483*7836SJohn.Forte@Sun.COM * Create the fc_remote_port_t struct for the given port_wwn and d_id. 4484*7836SJohn.Forte@Sun.COM * 4485*7836SJohn.Forte@Sun.COM * If the struct already exists (and is "valid"), then use it. Before using 4486*7836SJohn.Forte@Sun.COM * it, the code below also checks: (a) if the d_id has changed, and (b) if 4487*7836SJohn.Forte@Sun.COM * the device is maked as PORT_DEVICE_OLD. 4488*7836SJohn.Forte@Sun.COM * 4489*7836SJohn.Forte@Sun.COM * If no fc_remote_node_t struct exists for the given node_wwn, then that 4490*7836SJohn.Forte@Sun.COM * struct is also created (and linked with the fc_remote_port_t). 4491*7836SJohn.Forte@Sun.COM * 4492*7836SJohn.Forte@Sun.COM * The given fc_local_port_t struct is updated with the info on the new 4493*7836SJohn.Forte@Sun.COM * struct(s). The d_id and pwwn hash tables in the port_wwn are updated. 4494*7836SJohn.Forte@Sun.COM * The global node_hash_table[] is updated (if necessary). 4495*7836SJohn.Forte@Sun.COM */ 4496*7836SJohn.Forte@Sun.COM fc_remote_port_t * 4497*7836SJohn.Forte@Sun.COM fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn, 4498*7836SJohn.Forte@Sun.COM la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep) 4499*7836SJohn.Forte@Sun.COM { 4500*7836SJohn.Forte@Sun.COM int invalid = 0; 4501*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 4502*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 4503*7836SJohn.Forte@Sun.COM 4504*7836SJohn.Forte@Sun.COM rnodep = fctl_get_remote_node_by_nwwn(node_wwn); 4505*7836SJohn.Forte@Sun.COM if (rnodep) { 4506*7836SJohn.Forte@Sun.COM /* 4507*7836SJohn.Forte@Sun.COM * We found an fc_remote_node_t for the remote node -- see if 4508*7836SJohn.Forte@Sun.COM * anyone has marked it as going away or gone. 4509*7836SJohn.Forte@Sun.COM */ 4510*7836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 4511*7836SJohn.Forte@Sun.COM invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0; 4512*7836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 4513*7836SJohn.Forte@Sun.COM } 4514*7836SJohn.Forte@Sun.COM if (rnodep == NULL || invalid) { 4515*7836SJohn.Forte@Sun.COM /* 4516*7836SJohn.Forte@Sun.COM * No valid remote node struct found -- create it. 4517*7836SJohn.Forte@Sun.COM * Note: this is the only place that this func is called. 4518*7836SJohn.Forte@Sun.COM */ 4519*7836SJohn.Forte@Sun.COM rnodep = fctl_create_remote_node(node_wwn, sleep); 4520*7836SJohn.Forte@Sun.COM if (rnodep == NULL) { 4521*7836SJohn.Forte@Sun.COM return (NULL); 4522*7836SJohn.Forte@Sun.COM } 4523*7836SJohn.Forte@Sun.COM } 4524*7836SJohn.Forte@Sun.COM 4525*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4526*7836SJohn.Forte@Sun.COM 4527*7836SJohn.Forte@Sun.COM /* 4528*7836SJohn.Forte@Sun.COM * See if there already is an fc_remote_port_t struct in existence 4529*7836SJohn.Forte@Sun.COM * on the specified fc_local_port_t for the given pwwn. If so, then 4530*7836SJohn.Forte@Sun.COM * grab a reference to it. The 'held' here just means that fp_mutex 4531*7836SJohn.Forte@Sun.COM * is held by the caller -- no reference counts are updated. 4532*7836SJohn.Forte@Sun.COM */ 4533*7836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn); 4534*7836SJohn.Forte@Sun.COM if (pd) { 4535*7836SJohn.Forte@Sun.COM /* 4536*7836SJohn.Forte@Sun.COM * An fc_remote_port_t struct was found -- see if anyone has 4537*7836SJohn.Forte@Sun.COM * marked it as "invalid", which means that it is in the 4538*7836SJohn.Forte@Sun.COM * process of going away & we don't want to use it. 4539*7836SJohn.Forte@Sun.COM */ 4540*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4541*7836SJohn.Forte@Sun.COM invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0; 4542*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4543*7836SJohn.Forte@Sun.COM } 4544*7836SJohn.Forte@Sun.COM 4545*7836SJohn.Forte@Sun.COM if (pd == NULL || invalid) { 4546*7836SJohn.Forte@Sun.COM /* 4547*7836SJohn.Forte@Sun.COM * No fc_remote_port_t was found (or the existing one is 4548*7836SJohn.Forte@Sun.COM * marked as "invalid".) Allocate a new one and use that. 4549*7836SJohn.Forte@Sun.COM * This call will also update the d_id and pwwn hash tables 4550*7836SJohn.Forte@Sun.COM * in the given fc_local_port_t struct with the newly allocated 4551*7836SJohn.Forte@Sun.COM * fc_remote_port_t. 4552*7836SJohn.Forte@Sun.COM */ 4553*7836SJohn.Forte@Sun.COM if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id, 4554*7836SJohn.Forte@Sun.COM recepient, sleep)) == NULL) { 4555*7836SJohn.Forte@Sun.COM /* Just give up if the allocation fails. */ 4556*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4557*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(rnodep); 4558*7836SJohn.Forte@Sun.COM return (pd); 4559*7836SJohn.Forte@Sun.COM } 4560*7836SJohn.Forte@Sun.COM 4561*7836SJohn.Forte@Sun.COM /* 4562*7836SJohn.Forte@Sun.COM * Add the new fc_remote_port_t struct to the d_id and pwwn 4563*7836SJohn.Forte@Sun.COM * hash tables on the associated fc_local_port_t struct. 4564*7836SJohn.Forte@Sun.COM */ 4565*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4566*7836SJohn.Forte@Sun.COM pd->pd_remote_nodep = rnodep; 4567*7836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 4568*7836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(port, pd); 4569*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4570*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4571*7836SJohn.Forte@Sun.COM 4572*7836SJohn.Forte@Sun.COM /* 4573*7836SJohn.Forte@Sun.COM * Retrieve a pointer to the fc_remote_node_t (i.e., remote 4574*7836SJohn.Forte@Sun.COM * node) specified by the given node_wwn. This looks in the 4575*7836SJohn.Forte@Sun.COM * global fctl_nwwn_hash_table[]. The fd_numports reference 4576*7836SJohn.Forte@Sun.COM * count in the fc_remote_node_t struct is incremented. 4577*7836SJohn.Forte@Sun.COM */ 4578*7836SJohn.Forte@Sun.COM rnodep = fctl_lock_remote_node_by_nwwn(node_wwn); 4579*7836SJohn.Forte@Sun.COM 4580*7836SJohn.Forte@Sun.COM } else { 4581*7836SJohn.Forte@Sun.COM /* 4582*7836SJohn.Forte@Sun.COM * An existing and valid fc_remote_port_t struct already 4583*7836SJohn.Forte@Sun.COM * exists on the fc_local_port_t for the given pwwn. 4584*7836SJohn.Forte@Sun.COM */ 4585*7836SJohn.Forte@Sun.COM 4586*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4587*7836SJohn.Forte@Sun.COM ASSERT(pd->pd_remote_nodep != NULL); 4588*7836SJohn.Forte@Sun.COM 4589*7836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id != d_id) { 4590*7836SJohn.Forte@Sun.COM /* 4591*7836SJohn.Forte@Sun.COM * A very unlikely occurance in a well 4592*7836SJohn.Forte@Sun.COM * behaved environment. 4593*7836SJohn.Forte@Sun.COM */ 4594*7836SJohn.Forte@Sun.COM 4595*7836SJohn.Forte@Sun.COM /* 4596*7836SJohn.Forte@Sun.COM * The existing fc_remote_port_t has a different 4597*7836SJohn.Forte@Sun.COM * d_id than what we were given. This code will 4598*7836SJohn.Forte@Sun.COM * update the existing one with the one that was 4599*7836SJohn.Forte@Sun.COM * just given. 4600*7836SJohn.Forte@Sun.COM */ 4601*7836SJohn.Forte@Sun.COM char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1]; 4602*7836SJohn.Forte@Sun.COM uint32_t old_id; 4603*7836SJohn.Forte@Sun.COM 4604*7836SJohn.Forte@Sun.COM fc_wwn_to_str(port_wwn, string); 4605*7836SJohn.Forte@Sun.COM 4606*7836SJohn.Forte@Sun.COM old_id = pd->pd_port_id.port_id; 4607*7836SJohn.Forte@Sun.COM 4608*7836SJohn.Forte@Sun.COM fctl_delist_did_table(port, pd); 4609*7836SJohn.Forte@Sun.COM 4610*7836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device" 4611*7836SJohn.Forte@Sun.COM " with PWWN %s changed. New D_ID = %x," 4612*7836SJohn.Forte@Sun.COM " OLD D_ID = %x", port->fp_instance, string, 4613*7836SJohn.Forte@Sun.COM d_id, old_id); 4614*7836SJohn.Forte@Sun.COM 4615*7836SJohn.Forte@Sun.COM pd->pd_port_id.port_id = d_id; 4616*7836SJohn.Forte@Sun.COM 4617*7836SJohn.Forte@Sun.COM /* 4618*7836SJohn.Forte@Sun.COM * Looks like we have to presume here that the 4619*7836SJohn.Forte@Sun.COM * remote port could be something entirely different 4620*7836SJohn.Forte@Sun.COM * from what was previously existing & valid at this 4621*7836SJohn.Forte@Sun.COM * pwwn. 4622*7836SJohn.Forte@Sun.COM */ 4623*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_CHANGED; 4624*7836SJohn.Forte@Sun.COM 4625*7836SJohn.Forte@Sun.COM /* Record (update) the new d_id for the remote port */ 4626*7836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 4627*7836SJohn.Forte@Sun.COM 4628*7836SJohn.Forte@Sun.COM } else if (pd->pd_type == PORT_DEVICE_OLD) { 4629*7836SJohn.Forte@Sun.COM /* 4630*7836SJohn.Forte@Sun.COM * OK at least the old & new d_id's match. So for 4631*7836SJohn.Forte@Sun.COM * PORT_DEVICE_OLD, this assumes that the remote 4632*7836SJohn.Forte@Sun.COM * port had disappeared but now has come back. 4633*7836SJohn.Forte@Sun.COM * Update the pd_type and pd_state to put the 4634*7836SJohn.Forte@Sun.COM * remote port back into service. 4635*7836SJohn.Forte@Sun.COM */ 4636*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 4637*7836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 4638*7836SJohn.Forte@Sun.COM 4639*7836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 4640*7836SJohn.Forte@Sun.COM 4641*7836SJohn.Forte@Sun.COM } else { 4642*7836SJohn.Forte@Sun.COM /* 4643*7836SJohn.Forte@Sun.COM * OK the old & new d_id's match, and the remote 4644*7836SJohn.Forte@Sun.COM * port struct is not marked as PORT_DEVICE_OLD, so 4645*7836SJohn.Forte@Sun.COM * presume that it's still the same device and is 4646*7836SJohn.Forte@Sun.COM * still in good shape. Also this presumes that we 4647*7836SJohn.Forte@Sun.COM * do not need to update d_id or pwwn hash tables. 4648*7836SJohn.Forte@Sun.COM */ 4649*7836SJohn.Forte@Sun.COM /* sanitize device values */ 4650*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 4651*7836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 4652*7836SJohn.Forte@Sun.COM } 4653*7836SJohn.Forte@Sun.COM 4654*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4655*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4656*7836SJohn.Forte@Sun.COM 4657*7836SJohn.Forte@Sun.COM if (rnodep != pd->pd_remote_nodep) { 4658*7836SJohn.Forte@Sun.COM if ((rnodep != NULL) && 4659*7836SJohn.Forte@Sun.COM (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name, 4660*7836SJohn.Forte@Sun.COM node_wwn) != 0)) { 4661*7836SJohn.Forte@Sun.COM /* 4662*7836SJohn.Forte@Sun.COM * Rut-roh, there is an fc_remote_node_t remote 4663*7836SJohn.Forte@Sun.COM * node struct for the given node_wwn, but the 4664*7836SJohn.Forte@Sun.COM * fc_remote_port_t remote port struct doesn't 4665*7836SJohn.Forte@Sun.COM * know about it. This just prints a warning 4666*7836SJohn.Forte@Sun.COM * message & fails the fc_remote_port_t 4667*7836SJohn.Forte@Sun.COM * allocation (possible leak here?). 4668*7836SJohn.Forte@Sun.COM */ 4669*7836SJohn.Forte@Sun.COM char ww1_name[17]; 4670*7836SJohn.Forte@Sun.COM char ww2_name[17]; 4671*7836SJohn.Forte@Sun.COM 4672*7836SJohn.Forte@Sun.COM fc_wwn_to_str( 4673*7836SJohn.Forte@Sun.COM &pd->pd_remote_nodep->fd_node_name, 4674*7836SJohn.Forte@Sun.COM ww1_name); 4675*7836SJohn.Forte@Sun.COM fc_wwn_to_str(node_wwn, ww2_name); 4676*7836SJohn.Forte@Sun.COM 4677*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: " 4678*7836SJohn.Forte@Sun.COM "Expected %s Got %s", port->fp_instance, 4679*7836SJohn.Forte@Sun.COM ww1_name, ww2_name); 4680*7836SJohn.Forte@Sun.COM } 4681*7836SJohn.Forte@Sun.COM 4682*7836SJohn.Forte@Sun.COM return (NULL); 4683*7836SJohn.Forte@Sun.COM } 4684*7836SJohn.Forte@Sun.COM } 4685*7836SJohn.Forte@Sun.COM 4686*7836SJohn.Forte@Sun.COM /* 4687*7836SJohn.Forte@Sun.COM * Add the fc_remote_port_t onto the linked list of remote port 4688*7836SJohn.Forte@Sun.COM * devices associated with the given fc_remote_node_t (remote node). 4689*7836SJohn.Forte@Sun.COM */ 4690*7836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(rnodep, pd); 4691*7836SJohn.Forte@Sun.COM 4692*7836SJohn.Forte@Sun.COM return (pd); 4693*7836SJohn.Forte@Sun.COM } 4694*7836SJohn.Forte@Sun.COM 4695*7836SJohn.Forte@Sun.COM 4696*7836SJohn.Forte@Sun.COM /* 4697*7836SJohn.Forte@Sun.COM * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes 4698*7836SJohn.Forte@Sun.COM * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any 4699*7836SJohn.Forte@Sun.COM * references to the fc_remote_port_t from the d_id and pwwn tables in the 4700*7836SJohn.Forte@Sun.COM * given fc_local_port_t. Deallocates the given fc_remote_port_t. 4701*7836SJohn.Forte@Sun.COM * 4702*7836SJohn.Forte@Sun.COM * Returns a count of the number of remaining fc_remote_port_t structs 4703*7836SJohn.Forte@Sun.COM * associated with the fc_remote_node_t struct. 4704*7836SJohn.Forte@Sun.COM * 4705*7836SJohn.Forte@Sun.COM * If pd_ref_count in the given fc_remote_port_t is nonzero, then this 4706*7836SJohn.Forte@Sun.COM * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the 4707*7836SJohn.Forte@Sun.COM * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about 4708*7836SJohn.Forte@Sun.COM * the cleanup. The function then also returns '1' 4709*7836SJohn.Forte@Sun.COM * instead of the actual number of remaining fc_remote_port_t structs 4710*7836SJohn.Forte@Sun.COM * 4711*7836SJohn.Forte@Sun.COM * If there are no more remote ports on the remote node, return 0. 4712*7836SJohn.Forte@Sun.COM * Otherwise, return non-zero. 4713*7836SJohn.Forte@Sun.COM */ 4714*7836SJohn.Forte@Sun.COM int 4715*7836SJohn.Forte@Sun.COM fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd) 4716*7836SJohn.Forte@Sun.COM { 4717*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 4718*7836SJohn.Forte@Sun.COM int rcount = 0; 4719*7836SJohn.Forte@Sun.COM 4720*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4721*7836SJohn.Forte@Sun.COM 4722*7836SJohn.Forte@Sun.COM /* 4723*7836SJohn.Forte@Sun.COM * If pd_ref_count > 0, we can't pull the rug out from any 4724*7836SJohn.Forte@Sun.COM * current users of this fc_remote_port_t. We'll mark it as old 4725*7836SJohn.Forte@Sun.COM * and in need of removal. The same goes for any fc_remote_port_t 4726*7836SJohn.Forte@Sun.COM * that has a reference handle(s) in a ULP(s) but for which the ULP(s) 4727*7836SJohn.Forte@Sun.COM * have not yet been notified that the handle is no longer valid 4728*7836SJohn.Forte@Sun.COM * (i.e., PD_GIVEN_TO_ULPS is set). 4729*7836SJohn.Forte@Sun.COM */ 4730*7836SJohn.Forte@Sun.COM if ((pd->pd_ref_count > 0) || 4731*7836SJohn.Forte@Sun.COM (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) { 4732*7836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_NEEDS_REMOVAL; 4733*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_OLD; 4734*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4735*7836SJohn.Forte@Sun.COM return (1); 4736*7836SJohn.Forte@Sun.COM } 4737*7836SJohn.Forte@Sun.COM 4738*7836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_OLD; 4739*7836SJohn.Forte@Sun.COM 4740*7836SJohn.Forte@Sun.COM rnodep = pd->pd_remote_nodep; 4741*7836SJohn.Forte@Sun.COM 4742*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4743*7836SJohn.Forte@Sun.COM 4744*7836SJohn.Forte@Sun.COM if (rnodep != NULL) { 4745*7836SJohn.Forte@Sun.COM /* 4746*7836SJohn.Forte@Sun.COM * Remove the fc_remote_port_t from the linked list of remote 4747*7836SJohn.Forte@Sun.COM * ports for the given fc_remote_node_t. This is only called 4748*7836SJohn.Forte@Sun.COM * here and in fctl_destroy_all_remote_ports(). 4749*7836SJohn.Forte@Sun.COM */ 4750*7836SJohn.Forte@Sun.COM rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd); 4751*7836SJohn.Forte@Sun.COM } 4752*7836SJohn.Forte@Sun.COM 4753*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4754*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4755*7836SJohn.Forte@Sun.COM 4756*7836SJohn.Forte@Sun.COM fctl_delist_did_table(port, pd); 4757*7836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(port, pd); 4758*7836SJohn.Forte@Sun.COM 4759*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4760*7836SJohn.Forte@Sun.COM 4761*7836SJohn.Forte@Sun.COM /* 4762*7836SJohn.Forte@Sun.COM * Deconstruct & free the fc_remote_port_t. This is only called 4763*7836SJohn.Forte@Sun.COM * here and in fctl_destroy_all_remote_ports(). 4764*7836SJohn.Forte@Sun.COM */ 4765*7836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(pd); 4766*7836SJohn.Forte@Sun.COM 4767*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4768*7836SJohn.Forte@Sun.COM 4769*7836SJohn.Forte@Sun.COM return (rcount); 4770*7836SJohn.Forte@Sun.COM } 4771*7836SJohn.Forte@Sun.COM 4772*7836SJohn.Forte@Sun.COM 4773*7836SJohn.Forte@Sun.COM /* 4774*7836SJohn.Forte@Sun.COM * This goes thru the d_id table on the given fc_local_port_t. 4775*7836SJohn.Forte@Sun.COM * For each fc_remote_port_t found, this will: 4776*7836SJohn.Forte@Sun.COM * 4777*7836SJohn.Forte@Sun.COM * - Remove the fc_remote_port_t from the linked list of remote ports for 4778*7836SJohn.Forte@Sun.COM * the associated fc_remote_node_t. If the linked list goes empty, then this 4779*7836SJohn.Forte@Sun.COM * tries to deconstruct & free the fc_remote_node_t (that also removes the 4780*7836SJohn.Forte@Sun.COM * fc_remote_node_t from the global fctl_nwwn_hash_table[]). 4781*7836SJohn.Forte@Sun.COM * 4782*7836SJohn.Forte@Sun.COM * - Remove the fc_remote_port_t from the pwwn list on the given 4783*7836SJohn.Forte@Sun.COM * fc_local_port_t. 4784*7836SJohn.Forte@Sun.COM * 4785*7836SJohn.Forte@Sun.COM * - Deconstruct and free the fc_remote_port_t. 4786*7836SJohn.Forte@Sun.COM * 4787*7836SJohn.Forte@Sun.COM * - Removes the link to the fc_remote_port_t in the d_id table. Note, this 4788*7836SJohn.Forte@Sun.COM * does not appear to correctle decrement the d_id_count tho. 4789*7836SJohn.Forte@Sun.COM */ 4790*7836SJohn.Forte@Sun.COM void 4791*7836SJohn.Forte@Sun.COM fctl_destroy_all_remote_ports(fc_local_port_t *port) 4792*7836SJohn.Forte@Sun.COM { 4793*7836SJohn.Forte@Sun.COM int index; 4794*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 4795*7836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 4796*7836SJohn.Forte@Sun.COM struct d_id_hash *head; 4797*7836SJohn.Forte@Sun.COM 4798*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4799*7836SJohn.Forte@Sun.COM 4800*7836SJohn.Forte@Sun.COM for (index = 0; index < did_table_size; index++) { 4801*7836SJohn.Forte@Sun.COM 4802*7836SJohn.Forte@Sun.COM head = &port->fp_did_table[index]; 4803*7836SJohn.Forte@Sun.COM 4804*7836SJohn.Forte@Sun.COM while (head->d_id_head != NULL) { 4805*7836SJohn.Forte@Sun.COM pd = head->d_id_head; 4806*7836SJohn.Forte@Sun.COM 4807*7836SJohn.Forte@Sun.COM /* 4808*7836SJohn.Forte@Sun.COM * See if this remote port (fc_remote_port_t) has a 4809*7836SJohn.Forte@Sun.COM * reference to a remote node (fc_remote_node_t) in its 4810*7836SJohn.Forte@Sun.COM * pd->pd_remote_nodep pointer. 4811*7836SJohn.Forte@Sun.COM */ 4812*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4813*7836SJohn.Forte@Sun.COM rnodep = pd->pd_remote_nodep; 4814*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4815*7836SJohn.Forte@Sun.COM 4816*7836SJohn.Forte@Sun.COM if (rnodep != NULL) { 4817*7836SJohn.Forte@Sun.COM /* 4818*7836SJohn.Forte@Sun.COM * An fc_remote_node_t reference exists. Remove 4819*7836SJohn.Forte@Sun.COM * the fc_remote_port_t from the linked list of 4820*7836SJohn.Forte@Sun.COM * remote ports for fc_remote_node_t. 4821*7836SJohn.Forte@Sun.COM */ 4822*7836SJohn.Forte@Sun.COM if (fctl_unlink_remote_port_from_remote_node( 4823*7836SJohn.Forte@Sun.COM rnodep, pd) == 0) { 4824*7836SJohn.Forte@Sun.COM /* 4825*7836SJohn.Forte@Sun.COM * The fd_numports reference count 4826*7836SJohn.Forte@Sun.COM * in the fc_remote_node_t has come 4827*7836SJohn.Forte@Sun.COM * back as zero, so we can free the 4828*7836SJohn.Forte@Sun.COM * fc_remote_node_t. This also means 4829*7836SJohn.Forte@Sun.COM * that the fc_remote_node_t was 4830*7836SJohn.Forte@Sun.COM * removed from the 4831*7836SJohn.Forte@Sun.COM * fctl_nwwn_hash_table[]. 4832*7836SJohn.Forte@Sun.COM * 4833*7836SJohn.Forte@Sun.COM * This will silently skip the 4834*7836SJohn.Forte@Sun.COM * kmem_free() if either the 4835*7836SJohn.Forte@Sun.COM * fd_numports is nonzero or 4836*7836SJohn.Forte@Sun.COM * the fd_port is not NULL in 4837*7836SJohn.Forte@Sun.COM * the fc_remote_node_t. 4838*7836SJohn.Forte@Sun.COM */ 4839*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(rnodep); 4840*7836SJohn.Forte@Sun.COM } 4841*7836SJohn.Forte@Sun.COM } 4842*7836SJohn.Forte@Sun.COM 4843*7836SJohn.Forte@Sun.COM /* 4844*7836SJohn.Forte@Sun.COM * Clean up the entry in the fc_local_port_t's pwwn 4845*7836SJohn.Forte@Sun.COM * table for the given fc_remote_port_t (i.e., the pd). 4846*7836SJohn.Forte@Sun.COM */ 4847*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 4848*7836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(port, pd); 4849*7836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 4850*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 4851*7836SJohn.Forte@Sun.COM 4852*7836SJohn.Forte@Sun.COM /* 4853*7836SJohn.Forte@Sun.COM * Remove the current entry from the d_id list. 4854*7836SJohn.Forte@Sun.COM */ 4855*7836SJohn.Forte@Sun.COM head->d_id_head = pd->pd_did_hnext; 4856*7836SJohn.Forte@Sun.COM 4857*7836SJohn.Forte@Sun.COM /* 4858*7836SJohn.Forte@Sun.COM * Deconstruct & free the fc_remote_port_t (pd) 4859*7836SJohn.Forte@Sun.COM * Note: this is only called here and in 4860*7836SJohn.Forte@Sun.COM * fctl_destroy_remote_port_t(). 4861*7836SJohn.Forte@Sun.COM */ 4862*7836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(pd); 4863*7836SJohn.Forte@Sun.COM } 4864*7836SJohn.Forte@Sun.COM } 4865*7836SJohn.Forte@Sun.COM 4866*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4867*7836SJohn.Forte@Sun.COM } 4868*7836SJohn.Forte@Sun.COM 4869*7836SJohn.Forte@Sun.COM 4870*7836SJohn.Forte@Sun.COM int 4871*7836SJohn.Forte@Sun.COM fctl_is_wwn_zero(la_wwn_t *wwn) 4872*7836SJohn.Forte@Sun.COM { 4873*7836SJohn.Forte@Sun.COM int count; 4874*7836SJohn.Forte@Sun.COM 4875*7836SJohn.Forte@Sun.COM for (count = 0; count < sizeof (la_wwn_t); count++) { 4876*7836SJohn.Forte@Sun.COM if (wwn->raw_wwn[count] != 0) { 4877*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 4878*7836SJohn.Forte@Sun.COM } 4879*7836SJohn.Forte@Sun.COM } 4880*7836SJohn.Forte@Sun.COM 4881*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 4882*7836SJohn.Forte@Sun.COM } 4883*7836SJohn.Forte@Sun.COM 4884*7836SJohn.Forte@Sun.COM 4885*7836SJohn.Forte@Sun.COM void 4886*7836SJohn.Forte@Sun.COM fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type) 4887*7836SJohn.Forte@Sun.COM { 4888*7836SJohn.Forte@Sun.COM int data_cb; 4889*7836SJohn.Forte@Sun.COM int check_type; 4890*7836SJohn.Forte@Sun.COM int rval; 4891*7836SJohn.Forte@Sun.COM uint32_t claimed; 4892*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 4893*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 4894*7836SJohn.Forte@Sun.COM 4895*7836SJohn.Forte@Sun.COM claimed = 0; 4896*7836SJohn.Forte@Sun.COM check_type = 1; 4897*7836SJohn.Forte@Sun.COM 4898*7836SJohn.Forte@Sun.COM switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) { 4899*7836SJohn.Forte@Sun.COM case R_CTL_DEVICE_DATA: 4900*7836SJohn.Forte@Sun.COM data_cb = 1; 4901*7836SJohn.Forte@Sun.COM break; 4902*7836SJohn.Forte@Sun.COM 4903*7836SJohn.Forte@Sun.COM case R_CTL_EXTENDED_SVC: 4904*7836SJohn.Forte@Sun.COM check_type = 0; 4905*7836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 4906*7836SJohn.Forte@Sun.COM 4907*7836SJohn.Forte@Sun.COM case R_CTL_FC4_SVC: 4908*7836SJohn.Forte@Sun.COM data_cb = 0; 4909*7836SJohn.Forte@Sun.COM break; 4910*7836SJohn.Forte@Sun.COM 4911*7836SJohn.Forte@Sun.COM default: 4912*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4913*7836SJohn.Forte@Sun.COM ASSERT(port->fp_active_ubs > 0); 4914*7836SJohn.Forte@Sun.COM if (--(port->fp_active_ubs) == 0) { 4915*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4916*7836SJohn.Forte@Sun.COM } 4917*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4918*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 4919*7836SJohn.Forte@Sun.COM 1, &buf->ub_token); 4920*7836SJohn.Forte@Sun.COM return; 4921*7836SJohn.Forte@Sun.COM } 4922*7836SJohn.Forte@Sun.COM 4923*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 4924*7836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 4925*7836SJohn.Forte@Sun.COM if (check_type && mod->mod_info->ulp_type != type) { 4926*7836SJohn.Forte@Sun.COM continue; 4927*7836SJohn.Forte@Sun.COM } 4928*7836SJohn.Forte@Sun.COM 4929*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 4930*7836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 4931*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 4932*7836SJohn.Forte@Sun.COM 4933*7836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 4934*7836SJohn.Forte@Sun.COM continue; 4935*7836SJohn.Forte@Sun.COM } 4936*7836SJohn.Forte@Sun.COM 4937*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 4938*7836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 4939*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 4940*7836SJohn.Forte@Sun.COM continue; 4941*7836SJohn.Forte@Sun.COM } 4942*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 4943*7836SJohn.Forte@Sun.COM 4944*7836SJohn.Forte@Sun.COM if (data_cb == 1) { 4945*7836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_data_callback( 4946*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, 4947*7836SJohn.Forte@Sun.COM (opaque_t)port, buf, claimed); 4948*7836SJohn.Forte@Sun.COM } else { 4949*7836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_els_callback( 4950*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, 4951*7836SJohn.Forte@Sun.COM (opaque_t)port, buf, claimed); 4952*7836SJohn.Forte@Sun.COM } 4953*7836SJohn.Forte@Sun.COM 4954*7836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS && claimed == 0) { 4955*7836SJohn.Forte@Sun.COM claimed = 1; 4956*7836SJohn.Forte@Sun.COM } 4957*7836SJohn.Forte@Sun.COM } 4958*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 4959*7836SJohn.Forte@Sun.COM 4960*7836SJohn.Forte@Sun.COM if (claimed == 0) { 4961*7836SJohn.Forte@Sun.COM /* 4962*7836SJohn.Forte@Sun.COM * We should actually RJT since nobody claimed it. 4963*7836SJohn.Forte@Sun.COM */ 4964*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4965*7836SJohn.Forte@Sun.COM ASSERT(port->fp_active_ubs > 0); 4966*7836SJohn.Forte@Sun.COM if (--(port->fp_active_ubs) == 0) { 4967*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4968*7836SJohn.Forte@Sun.COM } 4969*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4970*7836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 4971*7836SJohn.Forte@Sun.COM 1, &buf->ub_token); 4972*7836SJohn.Forte@Sun.COM 4973*7836SJohn.Forte@Sun.COM } else { 4974*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 4975*7836SJohn.Forte@Sun.COM if (--port->fp_active_ubs == 0) { 4976*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 4977*7836SJohn.Forte@Sun.COM } 4978*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 4979*7836SJohn.Forte@Sun.COM } 4980*7836SJohn.Forte@Sun.COM } 4981*7836SJohn.Forte@Sun.COM 4982*7836SJohn.Forte@Sun.COM 4983*7836SJohn.Forte@Sun.COM /* 4984*7836SJohn.Forte@Sun.COM * Both fd_mutex and pd_mutex are held (in that order) coming in to this func 4985*7836SJohn.Forte@Sun.COM * 4986*7836SJohn.Forte@Sun.COM * With all these mutexes held, we should make sure this function does not eat 4987*7836SJohn.Forte@Sun.COM * up much time. 4988*7836SJohn.Forte@Sun.COM */ 4989*7836SJohn.Forte@Sun.COM void 4990*7836SJohn.Forte@Sun.COM fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd) 4991*7836SJohn.Forte@Sun.COM { 4992*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 4993*7836SJohn.Forte@Sun.COM 4994*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 4995*7836SJohn.Forte@Sun.COM 4996*7836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 4997*7836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 4998*7836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 4999*7836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 5000*7836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 5001*7836SJohn.Forte@Sun.COM map->map_flags = 0; 5002*7836SJohn.Forte@Sun.COM 5003*7836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 5004*7836SJohn.Forte@Sun.COM 5005*7836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 5006*7836SJohn.Forte@Sun.COM 5007*7836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 5008*7836SJohn.Forte@Sun.COM 5009*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&node->fd_mutex)); 5010*7836SJohn.Forte@Sun.COM 5011*7836SJohn.Forte@Sun.COM if (node) { 5012*7836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 5013*7836SJohn.Forte@Sun.COM } 5014*7836SJohn.Forte@Sun.COM map->map_pd = pd; 5015*7836SJohn.Forte@Sun.COM } 5016*7836SJohn.Forte@Sun.COM 5017*7836SJohn.Forte@Sun.COM void 5018*7836SJohn.Forte@Sun.COM fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd) 5019*7836SJohn.Forte@Sun.COM { 5020*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 5021*7836SJohn.Forte@Sun.COM 5022*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 5023*7836SJohn.Forte@Sun.COM 5024*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 5025*7836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 5026*7836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 5027*7836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 5028*7836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 5029*7836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 5030*7836SJohn.Forte@Sun.COM map->map_flags = 0; 5031*7836SJohn.Forte@Sun.COM 5032*7836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 5033*7836SJohn.Forte@Sun.COM 5034*7836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 5035*7836SJohn.Forte@Sun.COM 5036*7836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 5037*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5038*7836SJohn.Forte@Sun.COM 5039*7836SJohn.Forte@Sun.COM if (node) { 5040*7836SJohn.Forte@Sun.COM mutex_enter(&node->fd_mutex); 5041*7836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 5042*7836SJohn.Forte@Sun.COM mutex_exit(&node->fd_mutex); 5043*7836SJohn.Forte@Sun.COM } 5044*7836SJohn.Forte@Sun.COM map->map_pd = pd; 5045*7836SJohn.Forte@Sun.COM } 5046*7836SJohn.Forte@Sun.COM 5047*7836SJohn.Forte@Sun.COM 5048*7836SJohn.Forte@Sun.COM static int 5049*7836SJohn.Forte@Sun.COM fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 5050*7836SJohn.Forte@Sun.COM { 5051*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 5052*7836SJohn.Forte@Sun.COM 5053*7836SJohn.Forte@Sun.COM switch (ns_req->ns_cmd) { 5054*7836SJohn.Forte@Sun.COM case NS_RFT_ID: { 5055*7836SJohn.Forte@Sun.COM int count; 5056*7836SJohn.Forte@Sun.COM uint32_t *src; 5057*7836SJohn.Forte@Sun.COM uint32_t *dst; 5058*7836SJohn.Forte@Sun.COM ns_rfc_type_t *rfc; 5059*7836SJohn.Forte@Sun.COM 5060*7836SJohn.Forte@Sun.COM rfc = (ns_rfc_type_t *)ns_req->ns_req_payload; 5061*7836SJohn.Forte@Sun.COM 5062*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5063*7836SJohn.Forte@Sun.COM src = (uint32_t *)port->fp_fc4_types; 5064*7836SJohn.Forte@Sun.COM dst = (uint32_t *)rfc->rfc_types; 5065*7836SJohn.Forte@Sun.COM 5066*7836SJohn.Forte@Sun.COM for (count = 0; count < 8; count++) { 5067*7836SJohn.Forte@Sun.COM *src++ |= *dst++; 5068*7836SJohn.Forte@Sun.COM } 5069*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5070*7836SJohn.Forte@Sun.COM 5071*7836SJohn.Forte@Sun.COM break; 5072*7836SJohn.Forte@Sun.COM } 5073*7836SJohn.Forte@Sun.COM 5074*7836SJohn.Forte@Sun.COM case NS_RSPN_ID: { 5075*7836SJohn.Forte@Sun.COM ns_spn_t *spn; 5076*7836SJohn.Forte@Sun.COM 5077*7836SJohn.Forte@Sun.COM spn = (ns_spn_t *)ns_req->ns_req_payload; 5078*7836SJohn.Forte@Sun.COM 5079*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5080*7836SJohn.Forte@Sun.COM port->fp_sym_port_namelen = spn->spn_len; 5081*7836SJohn.Forte@Sun.COM if (spn->spn_len) { 5082*7836SJohn.Forte@Sun.COM bcopy((caddr_t)spn + sizeof (ns_spn_t), 5083*7836SJohn.Forte@Sun.COM port->fp_sym_port_name, spn->spn_len); 5084*7836SJohn.Forte@Sun.COM } 5085*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5086*7836SJohn.Forte@Sun.COM 5087*7836SJohn.Forte@Sun.COM break; 5088*7836SJohn.Forte@Sun.COM } 5089*7836SJohn.Forte@Sun.COM 5090*7836SJohn.Forte@Sun.COM case NS_RSNN_NN: { 5091*7836SJohn.Forte@Sun.COM ns_snn_t *snn; 5092*7836SJohn.Forte@Sun.COM 5093*7836SJohn.Forte@Sun.COM snn = (ns_snn_t *)ns_req->ns_req_payload; 5094*7836SJohn.Forte@Sun.COM 5095*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5096*7836SJohn.Forte@Sun.COM port->fp_sym_node_namelen = snn->snn_len; 5097*7836SJohn.Forte@Sun.COM if (snn->snn_len) { 5098*7836SJohn.Forte@Sun.COM bcopy((caddr_t)snn + sizeof (ns_snn_t), 5099*7836SJohn.Forte@Sun.COM port->fp_sym_node_name, snn->snn_len); 5100*7836SJohn.Forte@Sun.COM } 5101*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5102*7836SJohn.Forte@Sun.COM 5103*7836SJohn.Forte@Sun.COM break; 5104*7836SJohn.Forte@Sun.COM } 5105*7836SJohn.Forte@Sun.COM 5106*7836SJohn.Forte@Sun.COM case NS_RIP_NN: { 5107*7836SJohn.Forte@Sun.COM ns_rip_t *rip; 5108*7836SJohn.Forte@Sun.COM 5109*7836SJohn.Forte@Sun.COM rip = (ns_rip_t *)ns_req->ns_req_payload; 5110*7836SJohn.Forte@Sun.COM 5111*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5112*7836SJohn.Forte@Sun.COM bcopy(rip->rip_ip_addr, port->fp_ip_addr, 5113*7836SJohn.Forte@Sun.COM sizeof (rip->rip_ip_addr)); 5114*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5115*7836SJohn.Forte@Sun.COM 5116*7836SJohn.Forte@Sun.COM break; 5117*7836SJohn.Forte@Sun.COM } 5118*7836SJohn.Forte@Sun.COM 5119*7836SJohn.Forte@Sun.COM case NS_RIPA_NN: { 5120*7836SJohn.Forte@Sun.COM ns_ipa_t *ipa; 5121*7836SJohn.Forte@Sun.COM 5122*7836SJohn.Forte@Sun.COM ipa = (ns_ipa_t *)ns_req->ns_req_payload; 5123*7836SJohn.Forte@Sun.COM 5124*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5125*7836SJohn.Forte@Sun.COM bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value)); 5126*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5127*7836SJohn.Forte@Sun.COM 5128*7836SJohn.Forte@Sun.COM break; 5129*7836SJohn.Forte@Sun.COM } 5130*7836SJohn.Forte@Sun.COM 5131*7836SJohn.Forte@Sun.COM default: 5132*7836SJohn.Forte@Sun.COM rval = FC_BADOBJECT; 5133*7836SJohn.Forte@Sun.COM break; 5134*7836SJohn.Forte@Sun.COM } 5135*7836SJohn.Forte@Sun.COM 5136*7836SJohn.Forte@Sun.COM return (rval); 5137*7836SJohn.Forte@Sun.COM } 5138*7836SJohn.Forte@Sun.COM 5139*7836SJohn.Forte@Sun.COM 5140*7836SJohn.Forte@Sun.COM static int 5141*7836SJohn.Forte@Sun.COM fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 5142*7836SJohn.Forte@Sun.COM { 5143*7836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 5144*7836SJohn.Forte@Sun.COM 5145*7836SJohn.Forte@Sun.COM switch (ns_req->ns_cmd) { 5146*7836SJohn.Forte@Sun.COM case NS_GFT_ID: { 5147*7836SJohn.Forte@Sun.COM ns_rfc_type_t *rfc; 5148*7836SJohn.Forte@Sun.COM 5149*7836SJohn.Forte@Sun.COM rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload; 5150*7836SJohn.Forte@Sun.COM 5151*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5152*7836SJohn.Forte@Sun.COM bcopy(port->fp_fc4_types, rfc->rfc_types, 5153*7836SJohn.Forte@Sun.COM sizeof (rfc->rfc_types)); 5154*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5155*7836SJohn.Forte@Sun.COM break; 5156*7836SJohn.Forte@Sun.COM } 5157*7836SJohn.Forte@Sun.COM 5158*7836SJohn.Forte@Sun.COM case NS_GSPN_ID: { 5159*7836SJohn.Forte@Sun.COM ns_spn_t *spn; 5160*7836SJohn.Forte@Sun.COM 5161*7836SJohn.Forte@Sun.COM spn = (ns_spn_t *)ns_req->ns_resp_payload; 5162*7836SJohn.Forte@Sun.COM 5163*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5164*7836SJohn.Forte@Sun.COM spn->spn_len = port->fp_sym_port_namelen; 5165*7836SJohn.Forte@Sun.COM if (spn->spn_len) { 5166*7836SJohn.Forte@Sun.COM bcopy(port->fp_sym_port_name, (caddr_t)spn + 5167*7836SJohn.Forte@Sun.COM sizeof (ns_spn_t), spn->spn_len); 5168*7836SJohn.Forte@Sun.COM } 5169*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5170*7836SJohn.Forte@Sun.COM 5171*7836SJohn.Forte@Sun.COM break; 5172*7836SJohn.Forte@Sun.COM } 5173*7836SJohn.Forte@Sun.COM 5174*7836SJohn.Forte@Sun.COM case NS_GSNN_NN: { 5175*7836SJohn.Forte@Sun.COM ns_snn_t *snn; 5176*7836SJohn.Forte@Sun.COM 5177*7836SJohn.Forte@Sun.COM snn = (ns_snn_t *)ns_req->ns_resp_payload; 5178*7836SJohn.Forte@Sun.COM 5179*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5180*7836SJohn.Forte@Sun.COM snn->snn_len = port->fp_sym_node_namelen; 5181*7836SJohn.Forte@Sun.COM if (snn->snn_len) { 5182*7836SJohn.Forte@Sun.COM bcopy(port->fp_sym_node_name, (caddr_t)snn + 5183*7836SJohn.Forte@Sun.COM sizeof (ns_snn_t), snn->snn_len); 5184*7836SJohn.Forte@Sun.COM } 5185*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5186*7836SJohn.Forte@Sun.COM 5187*7836SJohn.Forte@Sun.COM break; 5188*7836SJohn.Forte@Sun.COM } 5189*7836SJohn.Forte@Sun.COM 5190*7836SJohn.Forte@Sun.COM case NS_GIP_NN: { 5191*7836SJohn.Forte@Sun.COM ns_rip_t *rip; 5192*7836SJohn.Forte@Sun.COM 5193*7836SJohn.Forte@Sun.COM rip = (ns_rip_t *)ns_req->ns_resp_payload; 5194*7836SJohn.Forte@Sun.COM 5195*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5196*7836SJohn.Forte@Sun.COM bcopy(port->fp_ip_addr, rip->rip_ip_addr, 5197*7836SJohn.Forte@Sun.COM sizeof (rip->rip_ip_addr)); 5198*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5199*7836SJohn.Forte@Sun.COM 5200*7836SJohn.Forte@Sun.COM break; 5201*7836SJohn.Forte@Sun.COM } 5202*7836SJohn.Forte@Sun.COM 5203*7836SJohn.Forte@Sun.COM case NS_GIPA_NN: { 5204*7836SJohn.Forte@Sun.COM ns_ipa_t *ipa; 5205*7836SJohn.Forte@Sun.COM 5206*7836SJohn.Forte@Sun.COM ipa = (ns_ipa_t *)ns_req->ns_resp_payload; 5207*7836SJohn.Forte@Sun.COM 5208*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5209*7836SJohn.Forte@Sun.COM bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value)); 5210*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5211*7836SJohn.Forte@Sun.COM 5212*7836SJohn.Forte@Sun.COM break; 5213*7836SJohn.Forte@Sun.COM } 5214*7836SJohn.Forte@Sun.COM 5215*7836SJohn.Forte@Sun.COM default: 5216*7836SJohn.Forte@Sun.COM rval = FC_BADOBJECT; 5217*7836SJohn.Forte@Sun.COM break; 5218*7836SJohn.Forte@Sun.COM } 5219*7836SJohn.Forte@Sun.COM 5220*7836SJohn.Forte@Sun.COM return (rval); 5221*7836SJohn.Forte@Sun.COM } 5222*7836SJohn.Forte@Sun.COM 5223*7836SJohn.Forte@Sun.COM 5224*7836SJohn.Forte@Sun.COM fctl_ns_req_t * 5225*7836SJohn.Forte@Sun.COM fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len, 5226*7836SJohn.Forte@Sun.COM uint32_t ns_flags, int sleep) 5227*7836SJohn.Forte@Sun.COM { 5228*7836SJohn.Forte@Sun.COM fctl_ns_req_t *ns_cmd; 5229*7836SJohn.Forte@Sun.COM 5230*7836SJohn.Forte@Sun.COM ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep); 5231*7836SJohn.Forte@Sun.COM if (ns_cmd == NULL) { 5232*7836SJohn.Forte@Sun.COM return (NULL); 5233*7836SJohn.Forte@Sun.COM } 5234*7836SJohn.Forte@Sun.COM 5235*7836SJohn.Forte@Sun.COM if (cmd_len) { 5236*7836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep); 5237*7836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_buf == NULL) { 5238*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 5239*7836SJohn.Forte@Sun.COM return (NULL); 5240*7836SJohn.Forte@Sun.COM } 5241*7836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_size = cmd_len; 5242*7836SJohn.Forte@Sun.COM } 5243*7836SJohn.Forte@Sun.COM 5244*7836SJohn.Forte@Sun.COM ns_cmd->ns_resp_size = resp_len; 5245*7836SJohn.Forte@Sun.COM 5246*7836SJohn.Forte@Sun.COM if (data_len) { 5247*7836SJohn.Forte@Sun.COM ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep); 5248*7836SJohn.Forte@Sun.COM if (ns_cmd->ns_data_buf == NULL) { 5249*7836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_buf && cmd_len) { 5250*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_cmd_buf, cmd_len); 5251*7836SJohn.Forte@Sun.COM } 5252*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 5253*7836SJohn.Forte@Sun.COM return (NULL); 5254*7836SJohn.Forte@Sun.COM } 5255*7836SJohn.Forte@Sun.COM ns_cmd->ns_data_len = data_len; 5256*7836SJohn.Forte@Sun.COM } 5257*7836SJohn.Forte@Sun.COM ns_cmd->ns_flags = ns_flags; 5258*7836SJohn.Forte@Sun.COM 5259*7836SJohn.Forte@Sun.COM return (ns_cmd); 5260*7836SJohn.Forte@Sun.COM } 5261*7836SJohn.Forte@Sun.COM 5262*7836SJohn.Forte@Sun.COM 5263*7836SJohn.Forte@Sun.COM void 5264*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd) 5265*7836SJohn.Forte@Sun.COM { 5266*7836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) { 5267*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size); 5268*7836SJohn.Forte@Sun.COM } 5269*7836SJohn.Forte@Sun.COM if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) { 5270*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len); 5271*7836SJohn.Forte@Sun.COM } 5272*7836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 5273*7836SJohn.Forte@Sun.COM } 5274*7836SJohn.Forte@Sun.COM 5275*7836SJohn.Forte@Sun.COM 5276*7836SJohn.Forte@Sun.COM int 5277*7836SJohn.Forte@Sun.COM fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd, 5278*7836SJohn.Forte@Sun.COM intptr_t data, int mode, cred_t *credp, int *rval) 5279*7836SJohn.Forte@Sun.COM { 5280*7836SJohn.Forte@Sun.COM int ret; 5281*7836SJohn.Forte@Sun.COM int save; 5282*7836SJohn.Forte@Sun.COM uint32_t claimed; 5283*7836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 5284*7836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 5285*7836SJohn.Forte@Sun.COM 5286*7836SJohn.Forte@Sun.COM save = *rval; 5287*7836SJohn.Forte@Sun.COM *rval = ENOTTY; 5288*7836SJohn.Forte@Sun.COM 5289*7836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 5290*7836SJohn.Forte@Sun.COM for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 5291*7836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 5292*7836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 5293*7836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 5294*7836SJohn.Forte@Sun.COM 5295*7836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 5296*7836SJohn.Forte@Sun.COM continue; 5297*7836SJohn.Forte@Sun.COM } 5298*7836SJohn.Forte@Sun.COM 5299*7836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 5300*7836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) || 5301*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_port_ioctl == NULL) { 5302*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 5303*7836SJohn.Forte@Sun.COM continue; 5304*7836SJohn.Forte@Sun.COM } 5305*7836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 5306*7836SJohn.Forte@Sun.COM 5307*7836SJohn.Forte@Sun.COM ret = mod->mod_info->ulp_port_ioctl( 5308*7836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, (opaque_t)port, 5309*7836SJohn.Forte@Sun.COM dev, cmd, data, mode, credp, rval, claimed); 5310*7836SJohn.Forte@Sun.COM 5311*7836SJohn.Forte@Sun.COM if (ret == FC_SUCCESS && claimed == 0) { 5312*7836SJohn.Forte@Sun.COM claimed = 1; 5313*7836SJohn.Forte@Sun.COM } 5314*7836SJohn.Forte@Sun.COM } 5315*7836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 5316*7836SJohn.Forte@Sun.COM 5317*7836SJohn.Forte@Sun.COM ret = *rval; 5318*7836SJohn.Forte@Sun.COM *rval = save; 5319*7836SJohn.Forte@Sun.COM 5320*7836SJohn.Forte@Sun.COM return (ret); 5321*7836SJohn.Forte@Sun.COM } 5322*7836SJohn.Forte@Sun.COM 5323*7836SJohn.Forte@Sun.COM /* 5324*7836SJohn.Forte@Sun.COM * raise power if necessary, and set the port busy 5325*7836SJohn.Forte@Sun.COM * 5326*7836SJohn.Forte@Sun.COM * this may cause power to be raised, so no power related locks should 5327*7836SJohn.Forte@Sun.COM * be held 5328*7836SJohn.Forte@Sun.COM */ 5329*7836SJohn.Forte@Sun.COM int 5330*7836SJohn.Forte@Sun.COM fc_ulp_busy_port(opaque_t port_handle) 5331*7836SJohn.Forte@Sun.COM { 5332*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 5333*7836SJohn.Forte@Sun.COM 5334*7836SJohn.Forte@Sun.COM return (fctl_busy_port(port)); 5335*7836SJohn.Forte@Sun.COM } 5336*7836SJohn.Forte@Sun.COM 5337*7836SJohn.Forte@Sun.COM void 5338*7836SJohn.Forte@Sun.COM fc_ulp_idle_port(opaque_t port_handle) 5339*7836SJohn.Forte@Sun.COM { 5340*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 5341*7836SJohn.Forte@Sun.COM fctl_idle_port(port); 5342*7836SJohn.Forte@Sun.COM } 5343*7836SJohn.Forte@Sun.COM 5344*7836SJohn.Forte@Sun.COM void 5345*7836SJohn.Forte@Sun.COM fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd) 5346*7836SJohn.Forte@Sun.COM { 5347*7836SJohn.Forte@Sun.COM fctl_copy_portmap(map, (fc_remote_port_t *)pd); 5348*7836SJohn.Forte@Sun.COM } 5349*7836SJohn.Forte@Sun.COM 5350*7836SJohn.Forte@Sun.COM 5351*7836SJohn.Forte@Sun.COM int 5352*7836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_num(opaque_t port_handle) 5353*7836SJohn.Forte@Sun.COM { 5354*7836SJohn.Forte@Sun.COM int portsnum = 0; 5355*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 5356*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 5357*7836SJohn.Forte@Sun.COM 5358*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5359*7836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 5360*7836SJohn.Forte@Sun.COM if (!tmpport) { 5361*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5362*7836SJohn.Forte@Sun.COM return (portsnum); 5363*7836SJohn.Forte@Sun.COM } 5364*7836SJohn.Forte@Sun.COM while (tmpport != port) { 5365*7836SJohn.Forte@Sun.COM portsnum ++; 5366*7836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 5367*7836SJohn.Forte@Sun.COM } 5368*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5369*7836SJohn.Forte@Sun.COM return (portsnum); 5370*7836SJohn.Forte@Sun.COM } 5371*7836SJohn.Forte@Sun.COM 5372*7836SJohn.Forte@Sun.COM fc_local_port_t * 5373*7836SJohn.Forte@Sun.COM fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn) 5374*7836SJohn.Forte@Sun.COM { 5375*7836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 5376*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = phyport; 5377*7836SJohn.Forte@Sun.COM 5378*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 5379*7836SJohn.Forte@Sun.COM 5380*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 5381*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 5382*7836SJohn.Forte@Sun.COM tmpPort = fca_port->port_handle; 5383*7836SJohn.Forte@Sun.COM if (tmpPort == NULL) { 5384*7836SJohn.Forte@Sun.COM continue; 5385*7836SJohn.Forte@Sun.COM } 5386*7836SJohn.Forte@Sun.COM mutex_enter(&tmpPort->fp_mutex); 5387*7836SJohn.Forte@Sun.COM if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn, 5388*7836SJohn.Forte@Sun.COM pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) { 5389*7836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 5390*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 5391*7836SJohn.Forte@Sun.COM return (tmpPort); 5392*7836SJohn.Forte@Sun.COM } 5393*7836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 5394*7836SJohn.Forte@Sun.COM } 5395*7836SJohn.Forte@Sun.COM 5396*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 5397*7836SJohn.Forte@Sun.COM 5398*7836SJohn.Forte@Sun.COM return (NULL); 5399*7836SJohn.Forte@Sun.COM } 5400*7836SJohn.Forte@Sun.COM 5401*7836SJohn.Forte@Sun.COM int 5402*7836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList) 5403*7836SJohn.Forte@Sun.COM { 5404*7836SJohn.Forte@Sun.COM int portsnum = 0; 5405*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 5406*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 5407*7836SJohn.Forte@Sun.COM 5408*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5409*7836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 5410*7836SJohn.Forte@Sun.COM if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 5411*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5412*7836SJohn.Forte@Sun.COM return (portsnum); 5413*7836SJohn.Forte@Sun.COM } 5414*7836SJohn.Forte@Sun.COM 5415*7836SJohn.Forte@Sun.COM while (tmpport != port) { 5416*7836SJohn.Forte@Sun.COM (void) ddi_pathname(tmpport->fp_port_dip, 5417*7836SJohn.Forte@Sun.COM &pathList[MAXPATHLEN * portsnum]); 5418*7836SJohn.Forte@Sun.COM portsnum ++; 5419*7836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 5420*7836SJohn.Forte@Sun.COM } 5421*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5422*7836SJohn.Forte@Sun.COM 5423*7836SJohn.Forte@Sun.COM return (portsnum); 5424*7836SJohn.Forte@Sun.COM } 5425*7836SJohn.Forte@Sun.COM 5426*7836SJohn.Forte@Sun.COM 5427*7836SJohn.Forte@Sun.COM fc_local_port_t * 5428*7836SJohn.Forte@Sun.COM fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn) 5429*7836SJohn.Forte@Sun.COM { 5430*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 5431*7836SJohn.Forte@Sun.COM 5432*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5433*7836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 5434*7836SJohn.Forte@Sun.COM if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 5435*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5436*7836SJohn.Forte@Sun.COM return (NULL); 5437*7836SJohn.Forte@Sun.COM } 5438*7836SJohn.Forte@Sun.COM 5439*7836SJohn.Forte@Sun.COM while (tmpport != port) { 5440*7836SJohn.Forte@Sun.COM if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn, 5441*7836SJohn.Forte@Sun.COM pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) && 5442*7836SJohn.Forte@Sun.COM (tmpport->fp_npiv_state == 0)) { 5443*7836SJohn.Forte@Sun.COM tmpport->fp_npiv_state = FC_NPIV_DELETING; 5444*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5445*7836SJohn.Forte@Sun.COM return (tmpport); 5446*7836SJohn.Forte@Sun.COM } 5447*7836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 5448*7836SJohn.Forte@Sun.COM } 5449*7836SJohn.Forte@Sun.COM 5450*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5451*7836SJohn.Forte@Sun.COM return (NULL); 5452*7836SJohn.Forte@Sun.COM } 5453*7836SJohn.Forte@Sun.COM 5454*7836SJohn.Forte@Sun.COM /* 5455*7836SJohn.Forte@Sun.COM * Get the list of Adapters. On multi-ported adapters, 5456*7836SJohn.Forte@Sun.COM * only ONE port on the adapter will be returned. 5457*7836SJohn.Forte@Sun.COM * pathList should be (count * MAXPATHLEN) long. 5458*7836SJohn.Forte@Sun.COM * The return value will be set to the number of 5459*7836SJohn.Forte@Sun.COM * HBAs that were found on the system. If the value 5460*7836SJohn.Forte@Sun.COM * is greater than count, the routine should be retried 5461*7836SJohn.Forte@Sun.COM * with a larger buffer. 5462*7836SJohn.Forte@Sun.COM */ 5463*7836SJohn.Forte@Sun.COM int 5464*7836SJohn.Forte@Sun.COM fc_ulp_get_adapter_paths(char *pathList, int count) 5465*7836SJohn.Forte@Sun.COM { 5466*7836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 5467*7836SJohn.Forte@Sun.COM int in = 0, out = 0, check, skip, maxPorts = 0; 5468*7836SJohn.Forte@Sun.COM fc_local_port_t **portList; 5469*7836SJohn.Forte@Sun.COM fc_local_port_t *new_port, *stored_port; 5470*7836SJohn.Forte@Sun.COM fca_hba_fru_details_t *new_fru, *stored_fru; 5471*7836SJohn.Forte@Sun.COM 5472*7836SJohn.Forte@Sun.COM ASSERT(pathList != NULL); 5473*7836SJohn.Forte@Sun.COM 5474*7836SJohn.Forte@Sun.COM /* First figure out how many ports we have */ 5475*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 5476*7836SJohn.Forte@Sun.COM 5477*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 5478*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 5479*7836SJohn.Forte@Sun.COM maxPorts ++; 5480*7836SJohn.Forte@Sun.COM } 5481*7836SJohn.Forte@Sun.COM 5482*7836SJohn.Forte@Sun.COM /* Now allocate a buffer to store all the pointers for comparisons */ 5483*7836SJohn.Forte@Sun.COM portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP); 5484*7836SJohn.Forte@Sun.COM 5485*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 5486*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 5487*7836SJohn.Forte@Sun.COM skip = 0; 5488*7836SJohn.Forte@Sun.COM 5489*7836SJohn.Forte@Sun.COM /* Lock the new port for subsequent comparisons */ 5490*7836SJohn.Forte@Sun.COM new_port = fca_port->port_handle; 5491*7836SJohn.Forte@Sun.COM mutex_enter(&new_port->fp_mutex); 5492*7836SJohn.Forte@Sun.COM new_fru = &new_port->fp_hba_port_attrs.hba_fru_details; 5493*7836SJohn.Forte@Sun.COM 5494*7836SJohn.Forte@Sun.COM /* Filter out secondary ports from the list */ 5495*7836SJohn.Forte@Sun.COM for (check = 0; check < out; check++) { 5496*7836SJohn.Forte@Sun.COM if (portList[check] == NULL) { 5497*7836SJohn.Forte@Sun.COM continue; 5498*7836SJohn.Forte@Sun.COM } 5499*7836SJohn.Forte@Sun.COM /* Guard against duplicates (should never happen) */ 5500*7836SJohn.Forte@Sun.COM if (portList[check] == fca_port->port_handle) { 5501*7836SJohn.Forte@Sun.COM /* Same port */ 5502*7836SJohn.Forte@Sun.COM skip = 1; 5503*7836SJohn.Forte@Sun.COM break; 5504*7836SJohn.Forte@Sun.COM } 5505*7836SJohn.Forte@Sun.COM 5506*7836SJohn.Forte@Sun.COM /* Lock the already stored port for comparison */ 5507*7836SJohn.Forte@Sun.COM stored_port = portList[check]; 5508*7836SJohn.Forte@Sun.COM mutex_enter(&stored_port->fp_mutex); 5509*7836SJohn.Forte@Sun.COM stored_fru = &stored_port->fp_hba_port_attrs.hba_fru_details; 5510*7836SJohn.Forte@Sun.COM 5511*7836SJohn.Forte@Sun.COM /* Are these ports on the same HBA? */ 5512*7836SJohn.Forte@Sun.COM if (new_fru->high == stored_fru->high && 5513*7836SJohn.Forte@Sun.COM new_fru->low == stored_fru->low) { 5514*7836SJohn.Forte@Sun.COM /* Now double check driver */ 5515*7836SJohn.Forte@Sun.COM if (strncmp(new_port->fp_hba_port_attrs.driver_name, 5516*7836SJohn.Forte@Sun.COM stored_port->fp_hba_port_attrs.driver_name, 5517*7836SJohn.Forte@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 5518*7836SJohn.Forte@Sun.COM /* we no we don't need to grow the list */ 5519*7836SJohn.Forte@Sun.COM skip = 1; 5520*7836SJohn.Forte@Sun.COM /* Are we looking at a lower port index? */ 5521*7836SJohn.Forte@Sun.COM if (new_fru->port_index < stored_fru->port_index) { 5522*7836SJohn.Forte@Sun.COM /* Replace the port in the list */ 5523*7836SJohn.Forte@Sun.COM mutex_exit(&stored_port->fp_mutex); 5524*7836SJohn.Forte@Sun.COM if (new_port->fp_npiv_type == FC_NPIV_PORT) { 5525*7836SJohn.Forte@Sun.COM break; 5526*7836SJohn.Forte@Sun.COM } 5527*7836SJohn.Forte@Sun.COM portList[check] = new_port; 5528*7836SJohn.Forte@Sun.COM break; 5529*7836SJohn.Forte@Sun.COM } /* Else, just skip this port */ 5530*7836SJohn.Forte@Sun.COM } 5531*7836SJohn.Forte@Sun.COM } 5532*7836SJohn.Forte@Sun.COM 5533*7836SJohn.Forte@Sun.COM mutex_exit(&stored_port->fp_mutex); 5534*7836SJohn.Forte@Sun.COM } 5535*7836SJohn.Forte@Sun.COM mutex_exit(&new_port->fp_mutex); 5536*7836SJohn.Forte@Sun.COM 5537*7836SJohn.Forte@Sun.COM if (!skip) { 5538*7836SJohn.Forte@Sun.COM /* 5539*7836SJohn.Forte@Sun.COM * Either this is the first port for this HBA, or 5540*7836SJohn.Forte@Sun.COM * it's a secondary port and we haven't stored the 5541*7836SJohn.Forte@Sun.COM * primary/first port for that HBA. In the latter case, 5542*7836SJohn.Forte@Sun.COM * will just filter it out as we proceed to loop. 5543*7836SJohn.Forte@Sun.COM */ 5544*7836SJohn.Forte@Sun.COM if (fca_port->port_handle->fp_npiv_type == FC_NPIV_PORT) { 5545*7836SJohn.Forte@Sun.COM continue; 5546*7836SJohn.Forte@Sun.COM } else { 5547*7836SJohn.Forte@Sun.COM portList[out++] = fca_port->port_handle; 5548*7836SJohn.Forte@Sun.COM } 5549*7836SJohn.Forte@Sun.COM } 5550*7836SJohn.Forte@Sun.COM } 5551*7836SJohn.Forte@Sun.COM 5552*7836SJohn.Forte@Sun.COM if (out <= count) { 5553*7836SJohn.Forte@Sun.COM for (in = 0; in < out; in++) { 5554*7836SJohn.Forte@Sun.COM (void) ddi_pathname(portList[in]->fp_port_dip, 5555*7836SJohn.Forte@Sun.COM &pathList[MAXPATHLEN * in]); 5556*7836SJohn.Forte@Sun.COM } 5557*7836SJohn.Forte@Sun.COM } 5558*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 5559*7836SJohn.Forte@Sun.COM kmem_free(portList, sizeof (*portList) * maxPorts); 5560*7836SJohn.Forte@Sun.COM return (out); 5561*7836SJohn.Forte@Sun.COM } 5562*7836SJohn.Forte@Sun.COM 5563*7836SJohn.Forte@Sun.COM uint32_t 5564*7836SJohn.Forte@Sun.COM fc_ulp_get_rscn_count(opaque_t port_handle) 5565*7836SJohn.Forte@Sun.COM { 5566*7836SJohn.Forte@Sun.COM uint32_t count; 5567*7836SJohn.Forte@Sun.COM fc_local_port_t *port; 5568*7836SJohn.Forte@Sun.COM 5569*7836SJohn.Forte@Sun.COM port = (fc_local_port_t *)port_handle; 5570*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5571*7836SJohn.Forte@Sun.COM count = port->fp_rscn_count; 5572*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5573*7836SJohn.Forte@Sun.COM 5574*7836SJohn.Forte@Sun.COM return (count); 5575*7836SJohn.Forte@Sun.COM } 5576*7836SJohn.Forte@Sun.COM 5577*7836SJohn.Forte@Sun.COM 5578*7836SJohn.Forte@Sun.COM /* 5579*7836SJohn.Forte@Sun.COM * This function is a very similar to fctl_add_orphan except that it expects 5580*7836SJohn.Forte@Sun.COM * that the fp_mutex and pd_mutex of the pd passed in are held coming in. 5581*7836SJohn.Forte@Sun.COM * 5582*7836SJohn.Forte@Sun.COM * Note that there is a lock hierarchy here (fp_mutex should be held first) but 5583*7836SJohn.Forte@Sun.COM * since this function could be called with a different pd's pd_mutex held, we 5584*7836SJohn.Forte@Sun.COM * should take care not to release fp_mutex in this function. 5585*7836SJohn.Forte@Sun.COM */ 5586*7836SJohn.Forte@Sun.COM int 5587*7836SJohn.Forte@Sun.COM fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd) 5588*7836SJohn.Forte@Sun.COM { 5589*7836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 5590*7836SJohn.Forte@Sun.COM la_wwn_t pwwn; 5591*7836SJohn.Forte@Sun.COM fc_orphan_t *orp; 5592*7836SJohn.Forte@Sun.COM fc_orphan_t *orphan; 5593*7836SJohn.Forte@Sun.COM 5594*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 5595*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 5596*7836SJohn.Forte@Sun.COM 5597*7836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 5598*7836SJohn.Forte@Sun.COM 5599*7836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5600*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5601*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 5602*7836SJohn.Forte@Sun.COM } 5603*7836SJohn.Forte@Sun.COM } 5604*7836SJohn.Forte@Sun.COM 5605*7836SJohn.Forte@Sun.COM orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP); 5606*7836SJohn.Forte@Sun.COM if (orphan) { 5607*7836SJohn.Forte@Sun.COM orphan->orp_pwwn = pwwn; 5608*7836SJohn.Forte@Sun.COM orphan->orp_tstamp = ddi_get_lbolt(); 5609*7836SJohn.Forte@Sun.COM 5610*7836SJohn.Forte@Sun.COM if (port->fp_orphan_list) { 5611*7836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_count > 0); 5612*7836SJohn.Forte@Sun.COM orphan->orp_next = port->fp_orphan_list; 5613*7836SJohn.Forte@Sun.COM } 5614*7836SJohn.Forte@Sun.COM port->fp_orphan_list = orphan; 5615*7836SJohn.Forte@Sun.COM port->fp_orphan_count++; 5616*7836SJohn.Forte@Sun.COM 5617*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 5618*7836SJohn.Forte@Sun.COM } 5619*7836SJohn.Forte@Sun.COM 5620*7836SJohn.Forte@Sun.COM return (rval); 5621*7836SJohn.Forte@Sun.COM } 5622*7836SJohn.Forte@Sun.COM 5623*7836SJohn.Forte@Sun.COM int 5624*7836SJohn.Forte@Sun.COM fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep) 5625*7836SJohn.Forte@Sun.COM { 5626*7836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 5627*7836SJohn.Forte@Sun.COM la_wwn_t pwwn; 5628*7836SJohn.Forte@Sun.COM fc_orphan_t *orp; 5629*7836SJohn.Forte@Sun.COM fc_orphan_t *orphan; 5630*7836SJohn.Forte@Sun.COM 5631*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5632*7836SJohn.Forte@Sun.COM 5633*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 5634*7836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 5635*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5636*7836SJohn.Forte@Sun.COM 5637*7836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5638*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5639*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5640*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 5641*7836SJohn.Forte@Sun.COM } 5642*7836SJohn.Forte@Sun.COM } 5643*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5644*7836SJohn.Forte@Sun.COM 5645*7836SJohn.Forte@Sun.COM orphan = kmem_zalloc(sizeof (*orphan), sleep); 5646*7836SJohn.Forte@Sun.COM if (orphan != NULL) { 5647*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5648*7836SJohn.Forte@Sun.COM 5649*7836SJohn.Forte@Sun.COM orphan->orp_pwwn = pwwn; 5650*7836SJohn.Forte@Sun.COM orphan->orp_tstamp = ddi_get_lbolt(); 5651*7836SJohn.Forte@Sun.COM 5652*7836SJohn.Forte@Sun.COM if (port->fp_orphan_list) { 5653*7836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_count > 0); 5654*7836SJohn.Forte@Sun.COM orphan->orp_next = port->fp_orphan_list; 5655*7836SJohn.Forte@Sun.COM } 5656*7836SJohn.Forte@Sun.COM port->fp_orphan_list = orphan; 5657*7836SJohn.Forte@Sun.COM port->fp_orphan_count++; 5658*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5659*7836SJohn.Forte@Sun.COM 5660*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 5661*7836SJohn.Forte@Sun.COM } 5662*7836SJohn.Forte@Sun.COM 5663*7836SJohn.Forte@Sun.COM return (rval); 5664*7836SJohn.Forte@Sun.COM } 5665*7836SJohn.Forte@Sun.COM 5666*7836SJohn.Forte@Sun.COM 5667*7836SJohn.Forte@Sun.COM int 5668*7836SJohn.Forte@Sun.COM fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn) 5669*7836SJohn.Forte@Sun.COM { 5670*7836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 5671*7836SJohn.Forte@Sun.COM fc_orphan_t *prev = NULL; 5672*7836SJohn.Forte@Sun.COM fc_orphan_t *orp; 5673*7836SJohn.Forte@Sun.COM 5674*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5675*7836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5676*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) { 5677*7836SJohn.Forte@Sun.COM if (prev) { 5678*7836SJohn.Forte@Sun.COM prev->orp_next = orp->orp_next; 5679*7836SJohn.Forte@Sun.COM } else { 5680*7836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_list == orp); 5681*7836SJohn.Forte@Sun.COM port->fp_orphan_list = orp->orp_next; 5682*7836SJohn.Forte@Sun.COM } 5683*7836SJohn.Forte@Sun.COM port->fp_orphan_count--; 5684*7836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 5685*7836SJohn.Forte@Sun.COM break; 5686*7836SJohn.Forte@Sun.COM } 5687*7836SJohn.Forte@Sun.COM prev = orp; 5688*7836SJohn.Forte@Sun.COM } 5689*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5690*7836SJohn.Forte@Sun.COM 5691*7836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 5692*7836SJohn.Forte@Sun.COM kmem_free(orp, sizeof (*orp)); 5693*7836SJohn.Forte@Sun.COM } 5694*7836SJohn.Forte@Sun.COM 5695*7836SJohn.Forte@Sun.COM return (rval); 5696*7836SJohn.Forte@Sun.COM } 5697*7836SJohn.Forte@Sun.COM 5698*7836SJohn.Forte@Sun.COM 5699*7836SJohn.Forte@Sun.COM static void 5700*7836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd) 5701*7836SJohn.Forte@Sun.COM { 5702*7836SJohn.Forte@Sun.COM char ww_name[17]; 5703*7836SJohn.Forte@Sun.COM la_wwn_t pwwn; 5704*7836SJohn.Forte@Sun.COM fc_orphan_t *orp; 5705*7836SJohn.Forte@Sun.COM 5706*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5707*7836SJohn.Forte@Sun.COM 5708*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 5709*7836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 5710*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5711*7836SJohn.Forte@Sun.COM 5712*7836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 5713*7836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 5714*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5715*7836SJohn.Forte@Sun.COM return; 5716*7836SJohn.Forte@Sun.COM } 5717*7836SJohn.Forte@Sun.COM } 5718*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5719*7836SJohn.Forte@Sun.COM 5720*7836SJohn.Forte@Sun.COM fc_wwn_to_str(&pwwn, ww_name); 5721*7836SJohn.Forte@Sun.COM 5722*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s" 5723*7836SJohn.Forte@Sun.COM " disappeared from fabric", port->fp_instance, 5724*7836SJohn.Forte@Sun.COM pd->pd_port_id.port_id, ww_name); 5725*7836SJohn.Forte@Sun.COM } 5726*7836SJohn.Forte@Sun.COM 5727*7836SJohn.Forte@Sun.COM 5728*7836SJohn.Forte@Sun.COM /* ARGSUSED */ 5729*7836SJohn.Forte@Sun.COM static void 5730*7836SJohn.Forte@Sun.COM fctl_link_reset_done(opaque_t port_handle, uchar_t result) 5731*7836SJohn.Forte@Sun.COM { 5732*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 5733*7836SJohn.Forte@Sun.COM 5734*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5735*7836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 5736*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5737*7836SJohn.Forte@Sun.COM 5738*7836SJohn.Forte@Sun.COM fctl_idle_port(port); 5739*7836SJohn.Forte@Sun.COM } 5740*7836SJohn.Forte@Sun.COM 5741*7836SJohn.Forte@Sun.COM 5742*7836SJohn.Forte@Sun.COM static int 5743*7836SJohn.Forte@Sun.COM fctl_error(int fc_errno, char **errmsg) 5744*7836SJohn.Forte@Sun.COM { 5745*7836SJohn.Forte@Sun.COM int count; 5746*7836SJohn.Forte@Sun.COM 5747*7836SJohn.Forte@Sun.COM for (count = 0; count < sizeof (fc_errlist) / 5748*7836SJohn.Forte@Sun.COM sizeof (fc_errlist[0]); count++) { 5749*7836SJohn.Forte@Sun.COM if (fc_errlist[count].fc_errno == fc_errno) { 5750*7836SJohn.Forte@Sun.COM *errmsg = fc_errlist[count].fc_errname; 5751*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 5752*7836SJohn.Forte@Sun.COM } 5753*7836SJohn.Forte@Sun.COM } 5754*7836SJohn.Forte@Sun.COM *errmsg = fctl_undefined; 5755*7836SJohn.Forte@Sun.COM 5756*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 5757*7836SJohn.Forte@Sun.COM } 5758*7836SJohn.Forte@Sun.COM 5759*7836SJohn.Forte@Sun.COM 5760*7836SJohn.Forte@Sun.COM /* 5761*7836SJohn.Forte@Sun.COM * Return number of successful translations. 5762*7836SJohn.Forte@Sun.COM * Anybody with some userland programming experience would have 5763*7836SJohn.Forte@Sun.COM * figured it by now that the return value exactly resembles that 5764*7836SJohn.Forte@Sun.COM * of scanf(3c). This function returns a count of successful 5765*7836SJohn.Forte@Sun.COM * translations. It could range from 0 (no match for state, reason, 5766*7836SJohn.Forte@Sun.COM * action, expln) to 4 (successful matches for all state, reason, 5767*7836SJohn.Forte@Sun.COM * action, expln) and where translation isn't successful into a 5768*7836SJohn.Forte@Sun.COM * friendlier message the relevent field is set to "Undefined" 5769*7836SJohn.Forte@Sun.COM */ 5770*7836SJohn.Forte@Sun.COM static int 5771*7836SJohn.Forte@Sun.COM fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason, 5772*7836SJohn.Forte@Sun.COM char **action, char **expln) 5773*7836SJohn.Forte@Sun.COM { 5774*7836SJohn.Forte@Sun.COM int ret; 5775*7836SJohn.Forte@Sun.COM int len; 5776*7836SJohn.Forte@Sun.COM int index; 5777*7836SJohn.Forte@Sun.COM fc_pkt_error_t *error; 5778*7836SJohn.Forte@Sun.COM fc_pkt_reason_t *reason_b; /* Base pointer */ 5779*7836SJohn.Forte@Sun.COM fc_pkt_action_t *action_b; /* Base pointer */ 5780*7836SJohn.Forte@Sun.COM fc_pkt_expln_t *expln_b; /* Base pointer */ 5781*7836SJohn.Forte@Sun.COM 5782*7836SJohn.Forte@Sun.COM ret = 0; 5783*7836SJohn.Forte@Sun.COM *state = *reason = *action = *expln = fctl_undefined; 5784*7836SJohn.Forte@Sun.COM 5785*7836SJohn.Forte@Sun.COM len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0]; 5786*7836SJohn.Forte@Sun.COM for (index = 0; index < len; index++) { 5787*7836SJohn.Forte@Sun.COM error = fc_pkt_errlist + index; 5788*7836SJohn.Forte@Sun.COM if (pkt->pkt_state == error->pkt_state) { 5789*7836SJohn.Forte@Sun.COM *state = error->pkt_msg; 5790*7836SJohn.Forte@Sun.COM ret++; 5791*7836SJohn.Forte@Sun.COM 5792*7836SJohn.Forte@Sun.COM reason_b = error->pkt_reason; 5793*7836SJohn.Forte@Sun.COM action_b = error->pkt_action; 5794*7836SJohn.Forte@Sun.COM expln_b = error->pkt_expln; 5795*7836SJohn.Forte@Sun.COM 5796*7836SJohn.Forte@Sun.COM while (reason_b != NULL && 5797*7836SJohn.Forte@Sun.COM reason_b->reason_val != FC_REASON_INVALID) { 5798*7836SJohn.Forte@Sun.COM if (reason_b->reason_val == pkt->pkt_reason) { 5799*7836SJohn.Forte@Sun.COM *reason = reason_b->reason_msg; 5800*7836SJohn.Forte@Sun.COM ret++; 5801*7836SJohn.Forte@Sun.COM break; 5802*7836SJohn.Forte@Sun.COM } 5803*7836SJohn.Forte@Sun.COM reason_b++; 5804*7836SJohn.Forte@Sun.COM } 5805*7836SJohn.Forte@Sun.COM 5806*7836SJohn.Forte@Sun.COM while (action_b != NULL && 5807*7836SJohn.Forte@Sun.COM action_b->action_val != FC_ACTION_INVALID) { 5808*7836SJohn.Forte@Sun.COM if (action_b->action_val == pkt->pkt_action) { 5809*7836SJohn.Forte@Sun.COM *action = action_b->action_msg; 5810*7836SJohn.Forte@Sun.COM ret++; 5811*7836SJohn.Forte@Sun.COM break; 5812*7836SJohn.Forte@Sun.COM } 5813*7836SJohn.Forte@Sun.COM action_b++; 5814*7836SJohn.Forte@Sun.COM } 5815*7836SJohn.Forte@Sun.COM 5816*7836SJohn.Forte@Sun.COM while (expln_b != NULL && 5817*7836SJohn.Forte@Sun.COM expln_b->expln_val != FC_EXPLN_INVALID) { 5818*7836SJohn.Forte@Sun.COM if (expln_b->expln_val == pkt->pkt_expln) { 5819*7836SJohn.Forte@Sun.COM *expln = expln_b->expln_msg; 5820*7836SJohn.Forte@Sun.COM ret++; 5821*7836SJohn.Forte@Sun.COM break; 5822*7836SJohn.Forte@Sun.COM } 5823*7836SJohn.Forte@Sun.COM expln_b++; 5824*7836SJohn.Forte@Sun.COM } 5825*7836SJohn.Forte@Sun.COM break; 5826*7836SJohn.Forte@Sun.COM } 5827*7836SJohn.Forte@Sun.COM } 5828*7836SJohn.Forte@Sun.COM 5829*7836SJohn.Forte@Sun.COM return (ret); 5830*7836SJohn.Forte@Sun.COM } 5831*7836SJohn.Forte@Sun.COM 5832*7836SJohn.Forte@Sun.COM 5833*7836SJohn.Forte@Sun.COM /* 5834*7836SJohn.Forte@Sun.COM * Remove all port devices that are marked OLD, remove 5835*7836SJohn.Forte@Sun.COM * corresponding node devices (fc_remote_node_t) 5836*7836SJohn.Forte@Sun.COM */ 5837*7836SJohn.Forte@Sun.COM void 5838*7836SJohn.Forte@Sun.COM fctl_remove_oldies(fc_local_port_t *port) 5839*7836SJohn.Forte@Sun.COM { 5840*7836SJohn.Forte@Sun.COM int index; 5841*7836SJohn.Forte@Sun.COM int initiator; 5842*7836SJohn.Forte@Sun.COM fc_remote_node_t *node; 5843*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 5844*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 5845*7836SJohn.Forte@Sun.COM fc_remote_port_t *old_pd; 5846*7836SJohn.Forte@Sun.COM fc_remote_port_t *last_pd; 5847*7836SJohn.Forte@Sun.COM 5848*7836SJohn.Forte@Sun.COM /* 5849*7836SJohn.Forte@Sun.COM * Nuke all OLD devices 5850*7836SJohn.Forte@Sun.COM */ 5851*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5852*7836SJohn.Forte@Sun.COM 5853*7836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 5854*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 5855*7836SJohn.Forte@Sun.COM last_pd = NULL; 5856*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 5857*7836SJohn.Forte@Sun.COM 5858*7836SJohn.Forte@Sun.COM while (pd != NULL) { 5859*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 5860*7836SJohn.Forte@Sun.COM if (pd->pd_type != PORT_DEVICE_OLD) { 5861*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5862*7836SJohn.Forte@Sun.COM last_pd = pd; 5863*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 5864*7836SJohn.Forte@Sun.COM continue; 5865*7836SJohn.Forte@Sun.COM } 5866*7836SJohn.Forte@Sun.COM 5867*7836SJohn.Forte@Sun.COM /* 5868*7836SJohn.Forte@Sun.COM * Remove this from the PWWN hash table 5869*7836SJohn.Forte@Sun.COM */ 5870*7836SJohn.Forte@Sun.COM old_pd = pd; 5871*7836SJohn.Forte@Sun.COM pd = old_pd->pd_wwn_hnext; 5872*7836SJohn.Forte@Sun.COM 5873*7836SJohn.Forte@Sun.COM if (last_pd == NULL) { 5874*7836SJohn.Forte@Sun.COM ASSERT(old_pd == head->pwwn_head); 5875*7836SJohn.Forte@Sun.COM head->pwwn_head = pd; 5876*7836SJohn.Forte@Sun.COM } else { 5877*7836SJohn.Forte@Sun.COM last_pd->pd_wwn_hnext = pd; 5878*7836SJohn.Forte@Sun.COM } 5879*7836SJohn.Forte@Sun.COM head->pwwn_count--; 5880*7836SJohn.Forte@Sun.COM /* 5881*7836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 5882*7836SJohn.Forte@Sun.COM * pwwn_table 5883*7836SJohn.Forte@Sun.COM */ 5884*7836SJohn.Forte@Sun.COM port->fp_dev_count--; 5885*7836SJohn.Forte@Sun.COM old_pd->pd_wwn_hnext = NULL; 5886*7836SJohn.Forte@Sun.COM 5887*7836SJohn.Forte@Sun.COM fctl_delist_did_table(port, old_pd); 5888*7836SJohn.Forte@Sun.COM node = old_pd->pd_remote_nodep; 5889*7836SJohn.Forte@Sun.COM ASSERT(node != NULL); 5890*7836SJohn.Forte@Sun.COM 5891*7836SJohn.Forte@Sun.COM initiator = (old_pd->pd_recepient == 5892*7836SJohn.Forte@Sun.COM PD_PLOGI_INITIATOR) ? 1 : 0; 5893*7836SJohn.Forte@Sun.COM 5894*7836SJohn.Forte@Sun.COM mutex_exit(&old_pd->pd_mutex); 5895*7836SJohn.Forte@Sun.COM 5896*7836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) { 5897*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5898*7836SJohn.Forte@Sun.COM 5899*7836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 5900*7836SJohn.Forte@Sun.COM KM_NOSLEEP); 5901*7836SJohn.Forte@Sun.COM } else { 5902*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5903*7836SJohn.Forte@Sun.COM } 5904*7836SJohn.Forte@Sun.COM 5905*7836SJohn.Forte@Sun.COM if (fctl_destroy_remote_port(port, old_pd) == 0) { 5906*7836SJohn.Forte@Sun.COM if (node) { 5907*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 5908*7836SJohn.Forte@Sun.COM } 5909*7836SJohn.Forte@Sun.COM } 5910*7836SJohn.Forte@Sun.COM 5911*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 5912*7836SJohn.Forte@Sun.COM } 5913*7836SJohn.Forte@Sun.COM } 5914*7836SJohn.Forte@Sun.COM 5915*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 5916*7836SJohn.Forte@Sun.COM } 5917*7836SJohn.Forte@Sun.COM 5918*7836SJohn.Forte@Sun.COM 5919*7836SJohn.Forte@Sun.COM static void 5920*7836SJohn.Forte@Sun.COM fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd) 5921*7836SJohn.Forte@Sun.COM { 5922*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 5923*7836SJohn.Forte@Sun.COM ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 5924*7836SJohn.Forte@Sun.COM 5925*7836SJohn.Forte@Sun.COM if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) { 5926*7836SJohn.Forte@Sun.COM return; 5927*7836SJohn.Forte@Sun.COM } 5928*7836SJohn.Forte@Sun.COM 5929*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map", 5930*7836SJohn.Forte@Sun.COM port->fp_instance, pd->pd_port_id.port_id); 5931*7836SJohn.Forte@Sun.COM } 5932*7836SJohn.Forte@Sun.COM 5933*7836SJohn.Forte@Sun.COM 5934*7836SJohn.Forte@Sun.COM static int 5935*7836SJohn.Forte@Sun.COM fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa) 5936*7836SJohn.Forte@Sun.COM { 5937*7836SJohn.Forte@Sun.COM int index; 5938*7836SJohn.Forte@Sun.COM 5939*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 5940*7836SJohn.Forte@Sun.COM ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 5941*7836SJohn.Forte@Sun.COM 5942*7836SJohn.Forte@Sun.COM for (index = 0; index < port->fp_lilp_map.lilp_length; index++) { 5943*7836SJohn.Forte@Sun.COM if (port->fp_lilp_map.lilp_alpalist[index] == alpa) { 5944*7836SJohn.Forte@Sun.COM return (FC_SUCCESS); 5945*7836SJohn.Forte@Sun.COM } 5946*7836SJohn.Forte@Sun.COM } 5947*7836SJohn.Forte@Sun.COM 5948*7836SJohn.Forte@Sun.COM return (FC_FAILURE); 5949*7836SJohn.Forte@Sun.COM } 5950*7836SJohn.Forte@Sun.COM 5951*7836SJohn.Forte@Sun.COM 5952*7836SJohn.Forte@Sun.COM fc_remote_port_t * 5953*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id) 5954*7836SJohn.Forte@Sun.COM { 5955*7836SJohn.Forte@Sun.COM int index; 5956*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 5957*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 5958*7836SJohn.Forte@Sun.COM 5959*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 5960*7836SJohn.Forte@Sun.COM 5961*7836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 5962*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 5963*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 5964*7836SJohn.Forte@Sun.COM 5965*7836SJohn.Forte@Sun.COM while (pd != NULL) { 5966*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 5967*7836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id) { 5968*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5969*7836SJohn.Forte@Sun.COM return (pd); 5970*7836SJohn.Forte@Sun.COM } 5971*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 5972*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 5973*7836SJohn.Forte@Sun.COM } 5974*7836SJohn.Forte@Sun.COM } 5975*7836SJohn.Forte@Sun.COM 5976*7836SJohn.Forte@Sun.COM return (pd); 5977*7836SJohn.Forte@Sun.COM } 5978*7836SJohn.Forte@Sun.COM 5979*7836SJohn.Forte@Sun.COM 5980*7836SJohn.Forte@Sun.COM /* 5981*7836SJohn.Forte@Sun.COM * trace debugging 5982*7836SJohn.Forte@Sun.COM */ 5983*7836SJohn.Forte@Sun.COM void 5984*7836SJohn.Forte@Sun.COM fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel, 5985*7836SJohn.Forte@Sun.COM int errno, const char *fmt, ...) 5986*7836SJohn.Forte@Sun.COM { 5987*7836SJohn.Forte@Sun.COM char buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */ 5988*7836SJohn.Forte@Sun.COM char *bufptr = buf; 5989*7836SJohn.Forte@Sun.COM va_list ap; 5990*7836SJohn.Forte@Sun.COM int cnt = 0; 5991*7836SJohn.Forte@Sun.COM 5992*7836SJohn.Forte@Sun.COM if ((dlevel & dflag) == 0) { 5993*7836SJohn.Forte@Sun.COM return; 5994*7836SJohn.Forte@Sun.COM } 5995*7836SJohn.Forte@Sun.COM 5996*7836SJohn.Forte@Sun.COM if (name) { 5997*7836SJohn.Forte@Sun.COM cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::", 5998*7836SJohn.Forte@Sun.COM logq->il_id++, name); 5999*7836SJohn.Forte@Sun.COM } else { 6000*7836SJohn.Forte@Sun.COM cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::", 6001*7836SJohn.Forte@Sun.COM logq->il_id++); 6002*7836SJohn.Forte@Sun.COM } 6003*7836SJohn.Forte@Sun.COM 6004*7836SJohn.Forte@Sun.COM if (cnt < FC_MAX_TRACE_BUF_LEN) { 6005*7836SJohn.Forte@Sun.COM va_start(ap, fmt); 6006*7836SJohn.Forte@Sun.COM cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 6007*7836SJohn.Forte@Sun.COM fmt, ap); 6008*7836SJohn.Forte@Sun.COM va_end(ap); 6009*7836SJohn.Forte@Sun.COM } 6010*7836SJohn.Forte@Sun.COM 6011*7836SJohn.Forte@Sun.COM if (cnt > FC_MAX_TRACE_BUF_LEN) { 6012*7836SJohn.Forte@Sun.COM cnt = FC_MAX_TRACE_BUF_LEN; 6013*7836SJohn.Forte@Sun.COM } 6014*7836SJohn.Forte@Sun.COM if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) { 6015*7836SJohn.Forte@Sun.COM cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 6016*7836SJohn.Forte@Sun.COM "error=0x%x\n", errno); 6017*7836SJohn.Forte@Sun.COM } 6018*7836SJohn.Forte@Sun.COM (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n"); 6019*7836SJohn.Forte@Sun.COM 6020*7836SJohn.Forte@Sun.COM if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) { 6021*7836SJohn.Forte@Sun.COM fc_trace_logmsg(logq, buf, dlevel); 6022*7836SJohn.Forte@Sun.COM } 6023*7836SJohn.Forte@Sun.COM 6024*7836SJohn.Forte@Sun.COM /* 6025*7836SJohn.Forte@Sun.COM * We do not want to print the log numbers that appear as 6026*7836SJohn.Forte@Sun.COM * random numbers at the console and messages files, to 6027*7836SJohn.Forte@Sun.COM * the user. 6028*7836SJohn.Forte@Sun.COM */ 6029*7836SJohn.Forte@Sun.COM if ((bufptr = strchr(buf, '>')) == NULL) { 6030*7836SJohn.Forte@Sun.COM /* 6031*7836SJohn.Forte@Sun.COM * We would have added the a string with "=>" above and so, 6032*7836SJohn.Forte@Sun.COM * ideally, we should not get here at all. But, if we do, 6033*7836SJohn.Forte@Sun.COM * we'll just use the full buf. 6034*7836SJohn.Forte@Sun.COM */ 6035*7836SJohn.Forte@Sun.COM bufptr = buf; 6036*7836SJohn.Forte@Sun.COM } else { 6037*7836SJohn.Forte@Sun.COM bufptr++; 6038*7836SJohn.Forte@Sun.COM } 6039*7836SJohn.Forte@Sun.COM 6040*7836SJohn.Forte@Sun.COM switch (dlevel & FC_TRACE_LOG_MASK) { 6041*7836SJohn.Forte@Sun.COM case FC_TRACE_LOG_CONSOLE: 6042*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "%s", bufptr); 6043*7836SJohn.Forte@Sun.COM break; 6044*7836SJohn.Forte@Sun.COM 6045*7836SJohn.Forte@Sun.COM case FC_TRACE_LOG_CONSOLE_MSG: 6046*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "%s", bufptr); 6047*7836SJohn.Forte@Sun.COM break; 6048*7836SJohn.Forte@Sun.COM 6049*7836SJohn.Forte@Sun.COM case FC_TRACE_LOG_MSG: 6050*7836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!%s", bufptr); 6051*7836SJohn.Forte@Sun.COM break; 6052*7836SJohn.Forte@Sun.COM 6053*7836SJohn.Forte@Sun.COM default: 6054*7836SJohn.Forte@Sun.COM break; 6055*7836SJohn.Forte@Sun.COM } 6056*7836SJohn.Forte@Sun.COM } 6057*7836SJohn.Forte@Sun.COM 6058*7836SJohn.Forte@Sun.COM 6059*7836SJohn.Forte@Sun.COM /* 6060*7836SJohn.Forte@Sun.COM * This function can block 6061*7836SJohn.Forte@Sun.COM */ 6062*7836SJohn.Forte@Sun.COM fc_trace_logq_t * 6063*7836SJohn.Forte@Sun.COM fc_trace_alloc_logq(int maxsize) 6064*7836SJohn.Forte@Sun.COM { 6065*7836SJohn.Forte@Sun.COM fc_trace_logq_t *logq; 6066*7836SJohn.Forte@Sun.COM 6067*7836SJohn.Forte@Sun.COM logq = kmem_zalloc(sizeof (*logq), KM_SLEEP); 6068*7836SJohn.Forte@Sun.COM 6069*7836SJohn.Forte@Sun.COM mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL); 6070*7836SJohn.Forte@Sun.COM logq->il_hiwat = maxsize; 6071*7836SJohn.Forte@Sun.COM logq->il_flags |= FC_TRACE_LOGQ_V2; 6072*7836SJohn.Forte@Sun.COM 6073*7836SJohn.Forte@Sun.COM return (logq); 6074*7836SJohn.Forte@Sun.COM } 6075*7836SJohn.Forte@Sun.COM 6076*7836SJohn.Forte@Sun.COM 6077*7836SJohn.Forte@Sun.COM void 6078*7836SJohn.Forte@Sun.COM fc_trace_free_logq(fc_trace_logq_t *logq) 6079*7836SJohn.Forte@Sun.COM { 6080*7836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 6081*7836SJohn.Forte@Sun.COM while (logq->il_msgh) { 6082*7836SJohn.Forte@Sun.COM fc_trace_freemsg(logq); 6083*7836SJohn.Forte@Sun.COM } 6084*7836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 6085*7836SJohn.Forte@Sun.COM 6086*7836SJohn.Forte@Sun.COM mutex_destroy(&logq->il_lock); 6087*7836SJohn.Forte@Sun.COM kmem_free(logq, sizeof (*logq)); 6088*7836SJohn.Forte@Sun.COM } 6089*7836SJohn.Forte@Sun.COM 6090*7836SJohn.Forte@Sun.COM 6091*7836SJohn.Forte@Sun.COM /* ARGSUSED */ 6092*7836SJohn.Forte@Sun.COM void 6093*7836SJohn.Forte@Sun.COM fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level) 6094*7836SJohn.Forte@Sun.COM { 6095*7836SJohn.Forte@Sun.COM int qfull = 0; 6096*7836SJohn.Forte@Sun.COM fc_trace_dmsg_t *dmsg; 6097*7836SJohn.Forte@Sun.COM 6098*7836SJohn.Forte@Sun.COM dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP); 6099*7836SJohn.Forte@Sun.COM if (dmsg == NULL) { 6100*7836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 6101*7836SJohn.Forte@Sun.COM logq->il_afail++; 6102*7836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 6103*7836SJohn.Forte@Sun.COM 6104*7836SJohn.Forte@Sun.COM return; 6105*7836SJohn.Forte@Sun.COM } 6106*7836SJohn.Forte@Sun.COM 6107*7836SJohn.Forte@Sun.COM gethrestime(&dmsg->id_time); 6108*7836SJohn.Forte@Sun.COM 6109*7836SJohn.Forte@Sun.COM dmsg->id_size = strlen(buf) + 1; 6110*7836SJohn.Forte@Sun.COM dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP); 6111*7836SJohn.Forte@Sun.COM if (dmsg->id_buf == NULL) { 6112*7836SJohn.Forte@Sun.COM kmem_free(dmsg, sizeof (*dmsg)); 6113*7836SJohn.Forte@Sun.COM 6114*7836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 6115*7836SJohn.Forte@Sun.COM logq->il_afail++; 6116*7836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 6117*7836SJohn.Forte@Sun.COM 6118*7836SJohn.Forte@Sun.COM return; 6119*7836SJohn.Forte@Sun.COM } 6120*7836SJohn.Forte@Sun.COM bcopy(buf, dmsg->id_buf, strlen(buf)); 6121*7836SJohn.Forte@Sun.COM dmsg->id_buf[strlen(buf)] = '\0'; 6122*7836SJohn.Forte@Sun.COM 6123*7836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 6124*7836SJohn.Forte@Sun.COM 6125*7836SJohn.Forte@Sun.COM logq->il_size += dmsg->id_size; 6126*7836SJohn.Forte@Sun.COM if (logq->il_size >= logq->il_hiwat) { 6127*7836SJohn.Forte@Sun.COM qfull = 1; 6128*7836SJohn.Forte@Sun.COM } 6129*7836SJohn.Forte@Sun.COM 6130*7836SJohn.Forte@Sun.COM if (qfull) { 6131*7836SJohn.Forte@Sun.COM fc_trace_freemsg(logq); 6132*7836SJohn.Forte@Sun.COM } 6133*7836SJohn.Forte@Sun.COM 6134*7836SJohn.Forte@Sun.COM dmsg->id_next = NULL; 6135*7836SJohn.Forte@Sun.COM if (logq->il_msgt) { 6136*7836SJohn.Forte@Sun.COM logq->il_msgt->id_next = dmsg; 6137*7836SJohn.Forte@Sun.COM } else { 6138*7836SJohn.Forte@Sun.COM ASSERT(logq->il_msgh == NULL); 6139*7836SJohn.Forte@Sun.COM logq->il_msgh = dmsg; 6140*7836SJohn.Forte@Sun.COM } 6141*7836SJohn.Forte@Sun.COM logq->il_msgt = dmsg; 6142*7836SJohn.Forte@Sun.COM 6143*7836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 6144*7836SJohn.Forte@Sun.COM } 6145*7836SJohn.Forte@Sun.COM 6146*7836SJohn.Forte@Sun.COM 6147*7836SJohn.Forte@Sun.COM static void 6148*7836SJohn.Forte@Sun.COM fc_trace_freemsg(fc_trace_logq_t *logq) 6149*7836SJohn.Forte@Sun.COM { 6150*7836SJohn.Forte@Sun.COM fc_trace_dmsg_t *dmsg; 6151*7836SJohn.Forte@Sun.COM 6152*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&logq->il_lock)); 6153*7836SJohn.Forte@Sun.COM 6154*7836SJohn.Forte@Sun.COM if ((dmsg = logq->il_msgh) != NULL) { 6155*7836SJohn.Forte@Sun.COM logq->il_msgh = dmsg->id_next; 6156*7836SJohn.Forte@Sun.COM if (logq->il_msgh == NULL) { 6157*7836SJohn.Forte@Sun.COM logq->il_msgt = NULL; 6158*7836SJohn.Forte@Sun.COM } 6159*7836SJohn.Forte@Sun.COM 6160*7836SJohn.Forte@Sun.COM logq->il_size -= dmsg->id_size; 6161*7836SJohn.Forte@Sun.COM kmem_free(dmsg->id_buf, dmsg->id_size); 6162*7836SJohn.Forte@Sun.COM kmem_free(dmsg, sizeof (*dmsg)); 6163*7836SJohn.Forte@Sun.COM } else { 6164*7836SJohn.Forte@Sun.COM ASSERT(logq->il_msgt == NULL); 6165*7836SJohn.Forte@Sun.COM } 6166*7836SJohn.Forte@Sun.COM } 6167*7836SJohn.Forte@Sun.COM 6168*7836SJohn.Forte@Sun.COM /* 6169*7836SJohn.Forte@Sun.COM * Used by T11 FC-HBA to fetch discovered ports by index. 6170*7836SJohn.Forte@Sun.COM * Returns NULL if the index isn't valid. 6171*7836SJohn.Forte@Sun.COM */ 6172*7836SJohn.Forte@Sun.COM fc_remote_port_t * 6173*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index) 6174*7836SJohn.Forte@Sun.COM { 6175*7836SJohn.Forte@Sun.COM int outer; 6176*7836SJohn.Forte@Sun.COM int match = 0; 6177*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 6178*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 6179*7836SJohn.Forte@Sun.COM 6180*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 6181*7836SJohn.Forte@Sun.COM 6182*7836SJohn.Forte@Sun.COM for (outer = 0; 6183*7836SJohn.Forte@Sun.COM outer < pwwn_table_size && match <= index; 6184*7836SJohn.Forte@Sun.COM outer++) { 6185*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[outer]; 6186*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 6187*7836SJohn.Forte@Sun.COM if (pd != NULL) match ++; 6188*7836SJohn.Forte@Sun.COM 6189*7836SJohn.Forte@Sun.COM while (pd != NULL && match <= index) { 6190*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 6191*7836SJohn.Forte@Sun.COM if (pd != NULL) match ++; 6192*7836SJohn.Forte@Sun.COM } 6193*7836SJohn.Forte@Sun.COM } 6194*7836SJohn.Forte@Sun.COM 6195*7836SJohn.Forte@Sun.COM return (pd); 6196*7836SJohn.Forte@Sun.COM } 6197*7836SJohn.Forte@Sun.COM 6198*7836SJohn.Forte@Sun.COM /* 6199*7836SJohn.Forte@Sun.COM * Search for a matching Node or Port WWN in the discovered port list 6200*7836SJohn.Forte@Sun.COM */ 6201*7836SJohn.Forte@Sun.COM fc_remote_port_t * 6202*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn) 6203*7836SJohn.Forte@Sun.COM { 6204*7836SJohn.Forte@Sun.COM int index; 6205*7836SJohn.Forte@Sun.COM struct pwwn_hash *head; 6206*7836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 6207*7836SJohn.Forte@Sun.COM 6208*7836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 6209*7836SJohn.Forte@Sun.COM 6210*7836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 6211*7836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 6212*7836SJohn.Forte@Sun.COM pd = head->pwwn_head; 6213*7836SJohn.Forte@Sun.COM 6214*7836SJohn.Forte@Sun.COM while (pd != NULL) { 6215*7836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 6216*7836SJohn.Forte@Sun.COM if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn, 6217*7836SJohn.Forte@Sun.COM sizeof (la_wwn_t)) == 0) { 6218*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 6219*7836SJohn.Forte@Sun.COM return (pd); 6220*7836SJohn.Forte@Sun.COM } 6221*7836SJohn.Forte@Sun.COM if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn, wwn.raw_wwn, 6222*7836SJohn.Forte@Sun.COM sizeof (la_wwn_t)) == 0) { 6223*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 6224*7836SJohn.Forte@Sun.COM return (pd); 6225*7836SJohn.Forte@Sun.COM } 6226*7836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 6227*7836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 6228*7836SJohn.Forte@Sun.COM } 6229*7836SJohn.Forte@Sun.COM } 6230*7836SJohn.Forte@Sun.COM /* No match */ 6231*7836SJohn.Forte@Sun.COM return (NULL); 6232*7836SJohn.Forte@Sun.COM } 6233*7836SJohn.Forte@Sun.COM 6234*7836SJohn.Forte@Sun.COM 6235*7836SJohn.Forte@Sun.COM /* 6236*7836SJohn.Forte@Sun.COM * Count the number of ports on this adapter. 6237*7836SJohn.Forte@Sun.COM * This routine will walk the port list and count up the number of adapters 6238*7836SJohn.Forte@Sun.COM * with matching fp_hba_port_attrs.hba_fru_details.high and 6239*7836SJohn.Forte@Sun.COM * fp_hba_port_attrs.hba_fru_details.low. 6240*7836SJohn.Forte@Sun.COM * 6241*7836SJohn.Forte@Sun.COM * port->fp_mutex must not be held. 6242*7836SJohn.Forte@Sun.COM */ 6243*7836SJohn.Forte@Sun.COM int 6244*7836SJohn.Forte@Sun.COM fctl_count_fru_ports(fc_local_port_t *port, int npivflag) 6245*7836SJohn.Forte@Sun.COM { 6246*7836SJohn.Forte@Sun.COM fca_hba_fru_details_t *fru; 6247*7836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 6248*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = NULL; 6249*7836SJohn.Forte@Sun.COM uint32_t count = 1; 6250*7836SJohn.Forte@Sun.COM 6251*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 6252*7836SJohn.Forte@Sun.COM 6253*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6254*7836SJohn.Forte@Sun.COM fru = &port->fp_hba_port_attrs.hba_fru_details; 6255*7836SJohn.Forte@Sun.COM 6256*7836SJohn.Forte@Sun.COM /* Detect FCA drivers that don't support linking HBA ports */ 6257*7836SJohn.Forte@Sun.COM if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 6258*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6259*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6260*7836SJohn.Forte@Sun.COM return (1); 6261*7836SJohn.Forte@Sun.COM } 6262*7836SJohn.Forte@Sun.COM 6263*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 6264*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 6265*7836SJohn.Forte@Sun.COM tmpPort = fca_port->port_handle; 6266*7836SJohn.Forte@Sun.COM if (tmpPort == port) { 6267*7836SJohn.Forte@Sun.COM continue; 6268*7836SJohn.Forte@Sun.COM } 6269*7836SJohn.Forte@Sun.COM mutex_enter(&tmpPort->fp_mutex); 6270*7836SJohn.Forte@Sun.COM 6271*7836SJohn.Forte@Sun.COM /* 6272*7836SJohn.Forte@Sun.COM * If an FCA driver returns unique fru->high and fru->low for 6273*7836SJohn.Forte@Sun.COM * ports on the same card, there is no way for the transport 6274*7836SJohn.Forte@Sun.COM * layer to determine that the two ports on the same FRU. So, 6275*7836SJohn.Forte@Sun.COM * the discovery of the ports on a same FRU is limited to what 6276*7836SJohn.Forte@Sun.COM * the FCA driver can report back. 6277*7836SJohn.Forte@Sun.COM */ 6278*7836SJohn.Forte@Sun.COM if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 6279*7836SJohn.Forte@Sun.COM fru->high && 6280*7836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.hba_fru_details.low == 6281*7836SJohn.Forte@Sun.COM fru->low) { 6282*7836SJohn.Forte@Sun.COM /* Now double check driver */ 6283*7836SJohn.Forte@Sun.COM if (strncmp(port->fp_hba_port_attrs.driver_name, 6284*7836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.driver_name, 6285*7836SJohn.Forte@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 6286*7836SJohn.Forte@Sun.COM if (!npivflag || 6287*7836SJohn.Forte@Sun.COM (tmpPort->fp_npiv_type != FC_NPIV_PORT)) { 6288*7836SJohn.Forte@Sun.COM count++; 6289*7836SJohn.Forte@Sun.COM } 6290*7836SJohn.Forte@Sun.COM } /* Else, different FCA driver */ 6291*7836SJohn.Forte@Sun.COM } /* Else not the same HBA FRU */ 6292*7836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 6293*7836SJohn.Forte@Sun.COM } 6294*7836SJohn.Forte@Sun.COM 6295*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6296*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6297*7836SJohn.Forte@Sun.COM 6298*7836SJohn.Forte@Sun.COM return (count); 6299*7836SJohn.Forte@Sun.COM } 6300*7836SJohn.Forte@Sun.COM 6301*7836SJohn.Forte@Sun.COM fc_fca_port_t * 6302*7836SJohn.Forte@Sun.COM fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port) 6303*7836SJohn.Forte@Sun.COM { 6304*7836SJohn.Forte@Sun.COM fc_fca_port_t *tmp = list, *newentry = NULL; 6305*7836SJohn.Forte@Sun.COM 6306*7836SJohn.Forte@Sun.COM newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP); 6307*7836SJohn.Forte@Sun.COM if (newentry == NULL) { 6308*7836SJohn.Forte@Sun.COM return (list); 6309*7836SJohn.Forte@Sun.COM } 6310*7836SJohn.Forte@Sun.COM newentry->port_handle = port; 6311*7836SJohn.Forte@Sun.COM 6312*7836SJohn.Forte@Sun.COM if (tmp == NULL) { 6313*7836SJohn.Forte@Sun.COM return (newentry); 6314*7836SJohn.Forte@Sun.COM } 6315*7836SJohn.Forte@Sun.COM while (tmp->port_next != NULL) tmp = tmp->port_next; 6316*7836SJohn.Forte@Sun.COM tmp->port_next = newentry; 6317*7836SJohn.Forte@Sun.COM 6318*7836SJohn.Forte@Sun.COM return (list); 6319*7836SJohn.Forte@Sun.COM } 6320*7836SJohn.Forte@Sun.COM 6321*7836SJohn.Forte@Sun.COM void 6322*7836SJohn.Forte@Sun.COM fctl_local_port_list_free(fc_fca_port_t *list) 6323*7836SJohn.Forte@Sun.COM { 6324*7836SJohn.Forte@Sun.COM fc_fca_port_t *tmp = list, *nextentry; 6325*7836SJohn.Forte@Sun.COM 6326*7836SJohn.Forte@Sun.COM if (tmp == NULL) { 6327*7836SJohn.Forte@Sun.COM return; 6328*7836SJohn.Forte@Sun.COM } 6329*7836SJohn.Forte@Sun.COM 6330*7836SJohn.Forte@Sun.COM while (tmp != NULL) { 6331*7836SJohn.Forte@Sun.COM nextentry = tmp->port_next; 6332*7836SJohn.Forte@Sun.COM kmem_free(tmp, sizeof (*tmp)); 6333*7836SJohn.Forte@Sun.COM tmp = nextentry; 6334*7836SJohn.Forte@Sun.COM } 6335*7836SJohn.Forte@Sun.COM } 6336*7836SJohn.Forte@Sun.COM 6337*7836SJohn.Forte@Sun.COM /* 6338*7836SJohn.Forte@Sun.COM * Fetch another port on the HBA FRU based on index. 6339*7836SJohn.Forte@Sun.COM * Returns NULL if index not found. 6340*7836SJohn.Forte@Sun.COM * 6341*7836SJohn.Forte@Sun.COM * port->fp_mutex must not be held. 6342*7836SJohn.Forte@Sun.COM */ 6343*7836SJohn.Forte@Sun.COM fc_local_port_t * 6344*7836SJohn.Forte@Sun.COM fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index) 6345*7836SJohn.Forte@Sun.COM { 6346*7836SJohn.Forte@Sun.COM fca_hba_fru_details_t *fru; 6347*7836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 6348*7836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = NULL; 6349*7836SJohn.Forte@Sun.COM fc_fca_port_t *list = NULL, *tmpEntry; 6350*7836SJohn.Forte@Sun.COM fc_local_port_t *phyPort, *virPort = NULL; 6351*7836SJohn.Forte@Sun.COM int index, phyPortNum = 0; 6352*7836SJohn.Forte@Sun.COM 6353*7836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 6354*7836SJohn.Forte@Sun.COM 6355*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6356*7836SJohn.Forte@Sun.COM fru = &port->fp_hba_port_attrs.hba_fru_details; 6357*7836SJohn.Forte@Sun.COM 6358*7836SJohn.Forte@Sun.COM /* Are we looking for this port? */ 6359*7836SJohn.Forte@Sun.COM if (fru->port_index == port_index) { 6360*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6361*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6362*7836SJohn.Forte@Sun.COM return (port); 6363*7836SJohn.Forte@Sun.COM } 6364*7836SJohn.Forte@Sun.COM 6365*7836SJohn.Forte@Sun.COM /* Detect FCA drivers that don't support linking HBA ports */ 6366*7836SJohn.Forte@Sun.COM if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 6367*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6368*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6369*7836SJohn.Forte@Sun.COM return (NULL); 6370*7836SJohn.Forte@Sun.COM } 6371*7836SJohn.Forte@Sun.COM 6372*7836SJohn.Forte@Sun.COM list = fctl_local_port_list_add(list, port); 6373*7836SJohn.Forte@Sun.COM phyPortNum++; 6374*7836SJohn.Forte@Sun.COM /* Loop through all known ports */ 6375*7836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 6376*7836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 6377*7836SJohn.Forte@Sun.COM tmpPort = fca_port->port_handle; 6378*7836SJohn.Forte@Sun.COM if (tmpPort == port) { 6379*7836SJohn.Forte@Sun.COM /* Skip over the port that was passed in as the argument */ 6380*7836SJohn.Forte@Sun.COM continue; 6381*7836SJohn.Forte@Sun.COM } 6382*7836SJohn.Forte@Sun.COM mutex_enter(&tmpPort->fp_mutex); 6383*7836SJohn.Forte@Sun.COM 6384*7836SJohn.Forte@Sun.COM /* See if this port is on the same HBA FRU (fast check) */ 6385*7836SJohn.Forte@Sun.COM if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 6386*7836SJohn.Forte@Sun.COM fru->high && 6387*7836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.hba_fru_details.low == 6388*7836SJohn.Forte@Sun.COM fru->low) { 6389*7836SJohn.Forte@Sun.COM /* Now double check driver (slower check) */ 6390*7836SJohn.Forte@Sun.COM if (strncmp(port->fp_hba_port_attrs.driver_name, 6391*7836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.driver_name, 6392*7836SJohn.Forte@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 6393*7836SJohn.Forte@Sun.COM 6394*7836SJohn.Forte@Sun.COM fru = &tmpPort->fp_hba_port_attrs.hba_fru_details; 6395*7836SJohn.Forte@Sun.COM /* Check for the matching port_index */ 6396*7836SJohn.Forte@Sun.COM if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) && 6397*7836SJohn.Forte@Sun.COM (fru->port_index == port_index)) { 6398*7836SJohn.Forte@Sun.COM /* Found it! */ 6399*7836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 6400*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6401*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6402*7836SJohn.Forte@Sun.COM fctl_local_port_list_free(list); 6403*7836SJohn.Forte@Sun.COM return (tmpPort); 6404*7836SJohn.Forte@Sun.COM } 6405*7836SJohn.Forte@Sun.COM if (tmpPort->fp_npiv_type != FC_NPIV_PORT) { 6406*7836SJohn.Forte@Sun.COM (void) fctl_local_port_list_add(list, tmpPort); 6407*7836SJohn.Forte@Sun.COM phyPortNum++; 6408*7836SJohn.Forte@Sun.COM } 6409*7836SJohn.Forte@Sun.COM } /* Else, different FCA driver */ 6410*7836SJohn.Forte@Sun.COM } /* Else not the same HBA FRU */ 6411*7836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 6412*7836SJohn.Forte@Sun.COM 6413*7836SJohn.Forte@Sun.COM } 6414*7836SJohn.Forte@Sun.COM 6415*7836SJohn.Forte@Sun.COM /* scan all physical port on same chip to find virtual port */ 6416*7836SJohn.Forte@Sun.COM tmpEntry = list; 6417*7836SJohn.Forte@Sun.COM index = phyPortNum - 1; 6418*7836SJohn.Forte@Sun.COM virPort = NULL; 6419*7836SJohn.Forte@Sun.COM while (index < port_index) { 6420*7836SJohn.Forte@Sun.COM if (tmpEntry == NULL) { 6421*7836SJohn.Forte@Sun.COM break; 6422*7836SJohn.Forte@Sun.COM } 6423*7836SJohn.Forte@Sun.COM if (virPort == NULL) { 6424*7836SJohn.Forte@Sun.COM phyPort = tmpEntry->port_handle; 6425*7836SJohn.Forte@Sun.COM virPort = phyPort->fp_port_next; 6426*7836SJohn.Forte@Sun.COM if (virPort == NULL) { 6427*7836SJohn.Forte@Sun.COM tmpEntry = tmpEntry->port_next; 6428*7836SJohn.Forte@Sun.COM continue; 6429*7836SJohn.Forte@Sun.COM } 6430*7836SJohn.Forte@Sun.COM } else { 6431*7836SJohn.Forte@Sun.COM virPort = virPort->fp_port_next; 6432*7836SJohn.Forte@Sun.COM } 6433*7836SJohn.Forte@Sun.COM if (virPort == phyPort) { 6434*7836SJohn.Forte@Sun.COM tmpEntry = tmpEntry->port_next; 6435*7836SJohn.Forte@Sun.COM virPort = NULL; 6436*7836SJohn.Forte@Sun.COM } else { 6437*7836SJohn.Forte@Sun.COM index++; 6438*7836SJohn.Forte@Sun.COM } 6439*7836SJohn.Forte@Sun.COM } 6440*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6441*7836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 6442*7836SJohn.Forte@Sun.COM 6443*7836SJohn.Forte@Sun.COM fctl_local_port_list_free(list); 6444*7836SJohn.Forte@Sun.COM if (virPort) { 6445*7836SJohn.Forte@Sun.COM return (virPort); 6446*7836SJohn.Forte@Sun.COM } 6447*7836SJohn.Forte@Sun.COM return (NULL); 6448*7836SJohn.Forte@Sun.COM } 6449*7836SJohn.Forte@Sun.COM 6450*7836SJohn.Forte@Sun.COM int 6451*7836SJohn.Forte@Sun.COM fctl_busy_port(fc_local_port_t *port) 6452*7836SJohn.Forte@Sun.COM { 6453*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 6454*7836SJohn.Forte@Sun.COM 6455*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6456*7836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 6457*7836SJohn.Forte@Sun.COM /* 6458*7836SJohn.Forte@Sun.COM * If fctl_busy_port() is called before we've registered our 6459*7836SJohn.Forte@Sun.COM * PM components, we return success. We need to be aware of 6460*7836SJohn.Forte@Sun.COM * this because the caller will eventually call fctl_idle_port. 6461*7836SJohn.Forte@Sun.COM * This wouldn't be a problem except that if we have 6462*7836SJohn.Forte@Sun.COM * registered our PM components in the meantime, we will 6463*7836SJohn.Forte@Sun.COM * then be idling a component that was never busied. PM 6464*7836SJohn.Forte@Sun.COM * will be very unhappy if we do this. Thus, we keep 6465*7836SJohn.Forte@Sun.COM * track of this with port->fp_pm_busy_nocomp. 6466*7836SJohn.Forte@Sun.COM */ 6467*7836SJohn.Forte@Sun.COM port->fp_pm_busy_nocomp++; 6468*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6469*7836SJohn.Forte@Sun.COM return (0); 6470*7836SJohn.Forte@Sun.COM } 6471*7836SJohn.Forte@Sun.COM port->fp_pm_busy++; 6472*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6473*7836SJohn.Forte@Sun.COM 6474*7836SJohn.Forte@Sun.COM if (pm_busy_component(port->fp_port_dip, 6475*7836SJohn.Forte@Sun.COM FP_PM_COMPONENT) != DDI_SUCCESS) { 6476*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6477*7836SJohn.Forte@Sun.COM port->fp_pm_busy--; 6478*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6479*7836SJohn.Forte@Sun.COM return (ENXIO); 6480*7836SJohn.Forte@Sun.COM } 6481*7836SJohn.Forte@Sun.COM 6482*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6483*7836SJohn.Forte@Sun.COM if (port->fp_pm_level == FP_PM_PORT_DOWN) { 6484*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6485*7836SJohn.Forte@Sun.COM if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT, 6486*7836SJohn.Forte@Sun.COM FP_PM_PORT_UP) != DDI_SUCCESS) { 6487*7836SJohn.Forte@Sun.COM 6488*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6489*7836SJohn.Forte@Sun.COM port->fp_pm_busy--; 6490*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6491*7836SJohn.Forte@Sun.COM 6492*7836SJohn.Forte@Sun.COM (void) pm_idle_component(port->fp_port_dip, 6493*7836SJohn.Forte@Sun.COM FP_PM_COMPONENT); 6494*7836SJohn.Forte@Sun.COM return (EIO); 6495*7836SJohn.Forte@Sun.COM } 6496*7836SJohn.Forte@Sun.COM return (0); 6497*7836SJohn.Forte@Sun.COM } 6498*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6499*7836SJohn.Forte@Sun.COM return (0); 6500*7836SJohn.Forte@Sun.COM } 6501*7836SJohn.Forte@Sun.COM 6502*7836SJohn.Forte@Sun.COM void 6503*7836SJohn.Forte@Sun.COM fctl_idle_port(fc_local_port_t *port) 6504*7836SJohn.Forte@Sun.COM { 6505*7836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 6506*7836SJohn.Forte@Sun.COM 6507*7836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 6508*7836SJohn.Forte@Sun.COM 6509*7836SJohn.Forte@Sun.COM /* 6510*7836SJohn.Forte@Sun.COM * If port->fp_pm_busy_nocomp is > 0, that means somebody had 6511*7836SJohn.Forte@Sun.COM * called fctl_busy_port prior to us registering our PM components. 6512*7836SJohn.Forte@Sun.COM * In that case, we just decrement fp_pm_busy_nocomp and return. 6513*7836SJohn.Forte@Sun.COM */ 6514*7836SJohn.Forte@Sun.COM 6515*7836SJohn.Forte@Sun.COM if (port->fp_pm_busy_nocomp > 0) { 6516*7836SJohn.Forte@Sun.COM port->fp_pm_busy_nocomp--; 6517*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6518*7836SJohn.Forte@Sun.COM return; 6519*7836SJohn.Forte@Sun.COM } 6520*7836SJohn.Forte@Sun.COM 6521*7836SJohn.Forte@Sun.COM port->fp_pm_busy--; 6522*7836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 6523*7836SJohn.Forte@Sun.COM 6524*7836SJohn.Forte@Sun.COM (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT); 6525*7836SJohn.Forte@Sun.COM } 6526*7836SJohn.Forte@Sun.COM 6527*7836SJohn.Forte@Sun.COM /* 6528*7836SJohn.Forte@Sun.COM * Function: fctl_tc_timer 6529*7836SJohn.Forte@Sun.COM * 6530*7836SJohn.Forte@Sun.COM * Description: Resets the value of the timed counter. 6531*7836SJohn.Forte@Sun.COM * 6532*7836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter 6533*7836SJohn.Forte@Sun.COM * 6534*7836SJohn.Forte@Sun.COM * Return Value: Nothing 6535*7836SJohn.Forte@Sun.COM * 6536*7836SJohn.Forte@Sun.COM * Context: Kernel context. 6537*7836SJohn.Forte@Sun.COM */ 6538*7836SJohn.Forte@Sun.COM static void 6539*7836SJohn.Forte@Sun.COM fctl_tc_timer( 6540*7836SJohn.Forte@Sun.COM void *arg 6541*7836SJohn.Forte@Sun.COM ) 6542*7836SJohn.Forte@Sun.COM { 6543*7836SJohn.Forte@Sun.COM timed_counter_t *tc = (timed_counter_t *)arg; 6544*7836SJohn.Forte@Sun.COM 6545*7836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 6546*7836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 6547*7836SJohn.Forte@Sun.COM 6548*7836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 6549*7836SJohn.Forte@Sun.COM if (tc->active) { 6550*7836SJohn.Forte@Sun.COM tc->active = B_FALSE; 6551*7836SJohn.Forte@Sun.COM tc->counter = 0; 6552*7836SJohn.Forte@Sun.COM } 6553*7836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 6554*7836SJohn.Forte@Sun.COM } 6555*7836SJohn.Forte@Sun.COM 6556*7836SJohn.Forte@Sun.COM /* 6557*7836SJohn.Forte@Sun.COM * Function: fctl_tc_constructor 6558*7836SJohn.Forte@Sun.COM * 6559*7836SJohn.Forte@Sun.COM * Description: Constructs a timed counter. 6560*7836SJohn.Forte@Sun.COM * 6561*7836SJohn.Forte@Sun.COM * Arguments: *tc Address where the timed counter will reside. 6562*7836SJohn.Forte@Sun.COM * max_value Maximum value the counter is allowed to take. 6563*7836SJohn.Forte@Sun.COM * timer Number of microseconds after which the counter 6564*7836SJohn.Forte@Sun.COM * will be reset. The timer is started when the 6565*7836SJohn.Forte@Sun.COM * value of the counter goes from 0 to 1. 6566*7836SJohn.Forte@Sun.COM * 6567*7836SJohn.Forte@Sun.COM * Return Value: Nothing 6568*7836SJohn.Forte@Sun.COM * 6569*7836SJohn.Forte@Sun.COM * Context: Kernel context. 6570*7836SJohn.Forte@Sun.COM */ 6571*7836SJohn.Forte@Sun.COM void 6572*7836SJohn.Forte@Sun.COM fctl_tc_constructor( 6573*7836SJohn.Forte@Sun.COM timed_counter_t *tc, 6574*7836SJohn.Forte@Sun.COM uint32_t max_value, 6575*7836SJohn.Forte@Sun.COM clock_t timer 6576*7836SJohn.Forte@Sun.COM ) 6577*7836SJohn.Forte@Sun.COM { 6578*7836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 6579*7836SJohn.Forte@Sun.COM ASSERT(tc->sig != tc); 6580*7836SJohn.Forte@Sun.COM 6581*7836SJohn.Forte@Sun.COM bzero(tc, sizeof (*tc)); 6582*7836SJohn.Forte@Sun.COM mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL); 6583*7836SJohn.Forte@Sun.COM tc->timer = drv_usectohz(timer); 6584*7836SJohn.Forte@Sun.COM tc->active = B_FALSE; 6585*7836SJohn.Forte@Sun.COM tc->maxed_out = B_FALSE; 6586*7836SJohn.Forte@Sun.COM tc->max_value = max_value; 6587*7836SJohn.Forte@Sun.COM tc->sig = tc; 6588*7836SJohn.Forte@Sun.COM } 6589*7836SJohn.Forte@Sun.COM 6590*7836SJohn.Forte@Sun.COM /* 6591*7836SJohn.Forte@Sun.COM * Function: fctl_tc_destructor 6592*7836SJohn.Forte@Sun.COM * 6593*7836SJohn.Forte@Sun.COM * Description: Destroyes a timed counter. 6594*7836SJohn.Forte@Sun.COM * 6595*7836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to destroy. 6596*7836SJohn.Forte@Sun.COM * 6597*7836SJohn.Forte@Sun.COM * Return Value: Nothing 6598*7836SJohn.Forte@Sun.COM * 6599*7836SJohn.Forte@Sun.COM * Context: Kernel context. 6600*7836SJohn.Forte@Sun.COM */ 6601*7836SJohn.Forte@Sun.COM void 6602*7836SJohn.Forte@Sun.COM fctl_tc_destructor( 6603*7836SJohn.Forte@Sun.COM timed_counter_t *tc 6604*7836SJohn.Forte@Sun.COM ) 6605*7836SJohn.Forte@Sun.COM { 6606*7836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 6607*7836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 6608*7836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&tc->mutex)); 6609*7836SJohn.Forte@Sun.COM 6610*7836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 6611*7836SJohn.Forte@Sun.COM if (tc->active) { 6612*7836SJohn.Forte@Sun.COM tc->active = B_FALSE; 6613*7836SJohn.Forte@Sun.COM (void) untimeout(tc->tid); 6614*7836SJohn.Forte@Sun.COM tc->sig = NULL; 6615*7836SJohn.Forte@Sun.COM } 6616*7836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 6617*7836SJohn.Forte@Sun.COM mutex_destroy(&tc->mutex); 6618*7836SJohn.Forte@Sun.COM } 6619*7836SJohn.Forte@Sun.COM 6620*7836SJohn.Forte@Sun.COM /* 6621*7836SJohn.Forte@Sun.COM * Function: fctl_tc_increment 6622*7836SJohn.Forte@Sun.COM * 6623*7836SJohn.Forte@Sun.COM * Description: Increments a timed counter 6624*7836SJohn.Forte@Sun.COM * 6625*7836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to increment. 6626*7836SJohn.Forte@Sun.COM * 6627*7836SJohn.Forte@Sun.COM * Return Value: B_TRUE Counter reached the max value. 6628*7836SJohn.Forte@Sun.COM * B_FALSE Counter hasn't reached the max value. 6629*7836SJohn.Forte@Sun.COM * 6630*7836SJohn.Forte@Sun.COM * Context: Kernel or interrupt context. 6631*7836SJohn.Forte@Sun.COM */ 6632*7836SJohn.Forte@Sun.COM boolean_t 6633*7836SJohn.Forte@Sun.COM fctl_tc_increment( 6634*7836SJohn.Forte@Sun.COM timed_counter_t *tc 6635*7836SJohn.Forte@Sun.COM ) 6636*7836SJohn.Forte@Sun.COM { 6637*7836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 6638*7836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 6639*7836SJohn.Forte@Sun.COM 6640*7836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 6641*7836SJohn.Forte@Sun.COM if (!tc->maxed_out) { 6642*7836SJohn.Forte@Sun.COM /* Hasn't maxed out yet. */ 6643*7836SJohn.Forte@Sun.COM ++tc->counter; 6644*7836SJohn.Forte@Sun.COM if (tc->counter >= tc->max_value) { 6645*7836SJohn.Forte@Sun.COM /* Just maxed out. */ 6646*7836SJohn.Forte@Sun.COM tc->maxed_out = B_TRUE; 6647*7836SJohn.Forte@Sun.COM } 6648*7836SJohn.Forte@Sun.COM if (!tc->active) { 6649*7836SJohn.Forte@Sun.COM tc->tid = timeout(fctl_tc_timer, tc, tc->timer); 6650*7836SJohn.Forte@Sun.COM tc->active = B_TRUE; 6651*7836SJohn.Forte@Sun.COM } 6652*7836SJohn.Forte@Sun.COM } 6653*7836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 6654*7836SJohn.Forte@Sun.COM 6655*7836SJohn.Forte@Sun.COM return (tc->maxed_out); 6656*7836SJohn.Forte@Sun.COM } 6657*7836SJohn.Forte@Sun.COM 6658*7836SJohn.Forte@Sun.COM /* 6659*7836SJohn.Forte@Sun.COM * Function: fctl_tc_reset 6660*7836SJohn.Forte@Sun.COM * 6661*7836SJohn.Forte@Sun.COM * Description: Resets a timed counter. The caller of this function has to 6662*7836SJohn.Forte@Sun.COM * to make sure that while in fctl_tc_reset() fctl_tc_increment() 6663*7836SJohn.Forte@Sun.COM * is not called. 6664*7836SJohn.Forte@Sun.COM * 6665*7836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to reset. 6666*7836SJohn.Forte@Sun.COM * 6667*7836SJohn.Forte@Sun.COM * Return Value: 0 Counter reached the max value. 6668*7836SJohn.Forte@Sun.COM * Not 0 Counter hasn't reached the max value. 6669*7836SJohn.Forte@Sun.COM * 6670*7836SJohn.Forte@Sun.COM * Context: Kernel or interrupt context. 6671*7836SJohn.Forte@Sun.COM */ 6672*7836SJohn.Forte@Sun.COM void 6673*7836SJohn.Forte@Sun.COM fctl_tc_reset( 6674*7836SJohn.Forte@Sun.COM timed_counter_t *tc 6675*7836SJohn.Forte@Sun.COM ) 6676*7836SJohn.Forte@Sun.COM { 6677*7836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 6678*7836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 6679*7836SJohn.Forte@Sun.COM 6680*7836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 6681*7836SJohn.Forte@Sun.COM tc->counter = 0; 6682*7836SJohn.Forte@Sun.COM tc->maxed_out = B_FALSE; 6683*7836SJohn.Forte@Sun.COM if (tc->active) { 6684*7836SJohn.Forte@Sun.COM tc->active = B_FALSE; 6685*7836SJohn.Forte@Sun.COM (void) untimeout(tc->tid); 6686*7836SJohn.Forte@Sun.COM } 6687*7836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 6688*7836SJohn.Forte@Sun.COM } 6689*7836SJohn.Forte@Sun.COM 6690*7836SJohn.Forte@Sun.COM void 6691*7836SJohn.Forte@Sun.COM fc_ulp_log_device_event(opaque_t port_handle, int type) 6692*7836SJohn.Forte@Sun.COM { 6693*7836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 6694*7836SJohn.Forte@Sun.COM nvlist_t *attr_list; 6695*7836SJohn.Forte@Sun.COM 6696*7836SJohn.Forte@Sun.COM if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 6697*7836SJohn.Forte@Sun.COM KM_SLEEP) != DDI_SUCCESS) { 6698*7836SJohn.Forte@Sun.COM return; 6699*7836SJohn.Forte@Sun.COM } 6700*7836SJohn.Forte@Sun.COM 6701*7836SJohn.Forte@Sun.COM if (nvlist_add_uint32(attr_list, "instance", 6702*7836SJohn.Forte@Sun.COM port->fp_instance) != DDI_SUCCESS) { 6703*7836SJohn.Forte@Sun.COM goto error; 6704*7836SJohn.Forte@Sun.COM } 6705*7836SJohn.Forte@Sun.COM 6706*7836SJohn.Forte@Sun.COM if (nvlist_add_byte_array(attr_list, "port-wwn", 6707*7836SJohn.Forte@Sun.COM port->fp_service_params.nport_ww_name.raw_wwn, 6708*7836SJohn.Forte@Sun.COM sizeof (la_wwn_t)) != DDI_SUCCESS) { 6709*7836SJohn.Forte@Sun.COM goto error; 6710*7836SJohn.Forte@Sun.COM } 6711*7836SJohn.Forte@Sun.COM 6712*7836SJohn.Forte@Sun.COM (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 6713*7836SJohn.Forte@Sun.COM (type == FC_ULP_DEVICE_ONLINE) ? 6714*7836SJohn.Forte@Sun.COM ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE, 6715*7836SJohn.Forte@Sun.COM attr_list, NULL, DDI_SLEEP); 6716*7836SJohn.Forte@Sun.COM nvlist_free(attr_list); 6717*7836SJohn.Forte@Sun.COM return; 6718*7836SJohn.Forte@Sun.COM 6719*7836SJohn.Forte@Sun.COM error: 6720*7836SJohn.Forte@Sun.COM nvlist_free(attr_list); 6721*7836SJohn.Forte@Sun.COM } 6722