17836SJohn.Forte@Sun.COM /* 27836SJohn.Forte@Sun.COM * CDDL HEADER START 37836SJohn.Forte@Sun.COM * 47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the 57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License"). 67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License. 77836SJohn.Forte@Sun.COM * 87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing. 107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions 117836SJohn.Forte@Sun.COM * and limitations under the License. 127836SJohn.Forte@Sun.COM * 137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187836SJohn.Forte@Sun.COM * 197836SJohn.Forte@Sun.COM * CDDL HEADER END 207836SJohn.Forte@Sun.COM */ 217836SJohn.Forte@Sun.COM /* 22*11922SSriram.Popuri@sun.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237836SJohn.Forte@Sun.COM * Use is subject to license terms. 247836SJohn.Forte@Sun.COM * 257836SJohn.Forte@Sun.COM * Fibre channel Transport Library (fctl) 267836SJohn.Forte@Sun.COM * 277836SJohn.Forte@Sun.COM * Function naming conventions: 287836SJohn.Forte@Sun.COM * Functions called from ULPs begin with fc_ulp_ 297836SJohn.Forte@Sun.COM * Functions called from FCAs begin with fc_fca_ 307836SJohn.Forte@Sun.COM * Internal functions begin with fctl_ 317836SJohn.Forte@Sun.COM * 327836SJohn.Forte@Sun.COM * Fibre channel packet layout: 3310264SZhong.Wang@Sun.COM * +---------------------+<--------+ 3410264SZhong.Wang@Sun.COM * | | | 3510264SZhong.Wang@Sun.COM * | ULP Packet private | | 3610264SZhong.Wang@Sun.COM * | | | 3710264SZhong.Wang@Sun.COM * +---------------------+ | 3810264SZhong.Wang@Sun.COM * | |---------+ 3910264SZhong.Wang@Sun.COM * | struct fc_packet |---------+ 4010264SZhong.Wang@Sun.COM * | | | 4110264SZhong.Wang@Sun.COM * +---------------------+<--------+ 4210264SZhong.Wang@Sun.COM * | | 4310264SZhong.Wang@Sun.COM * | FCA Packet private | 4410264SZhong.Wang@Sun.COM * | | 4510264SZhong.Wang@Sun.COM * +---------------------+ 467836SJohn.Forte@Sun.COM * 4710264SZhong.Wang@Sun.COM * So you loved the ascii art ? It's strongly desirable to cache 487836SJohn.Forte@Sun.COM * allocate the entire packet in one common place. So we define a set a 4910264SZhong.Wang@Sun.COM * of rules. In a contiguous block of memory, the top portion of the 5010264SZhong.Wang@Sun.COM * block points to ulp packet private area, next follows the fc_packet 517836SJohn.Forte@Sun.COM * structure used extensively by all the consumers and what follows this 5210264SZhong.Wang@Sun.COM * is the FCA packet private. Note that given a packet structure, it is 5310264SZhong.Wang@Sun.COM * possible to get to the ULP and FCA Packet private fields using 547836SJohn.Forte@Sun.COM * ulp_private and fca_private fields (which hold pointers) respectively. 557836SJohn.Forte@Sun.COM * 567836SJohn.Forte@Sun.COM * It should be noted with a grain of salt that ULP Packet private size 577836SJohn.Forte@Sun.COM * varies between two different ULP types, So this poses a challenge to 5810264SZhong.Wang@Sun.COM * compute the correct size of the whole block on a per port basis. The 597836SJohn.Forte@Sun.COM * transport layer doesn't have a problem in dealing with FCA packet 607836SJohn.Forte@Sun.COM * private sizes as it is the sole manager of ports underneath. Since 617836SJohn.Forte@Sun.COM * it's not a good idea to cache allocate different sizes of memory for 627836SJohn.Forte@Sun.COM * different ULPs and have the ability to choose from one of these caches 637836SJohn.Forte@Sun.COM * based on ULP type during every packet allocation, the transport some 6410264SZhong.Wang@Sun.COM * what wisely (?) hands off this job of cache allocation to the ULPs 657836SJohn.Forte@Sun.COM * themselves. 667836SJohn.Forte@Sun.COM * 677836SJohn.Forte@Sun.COM * That means FCAs need to make their packet private size known to the 6810264SZhong.Wang@Sun.COM * transport to pass it up to the ULPs. This is done during 697836SJohn.Forte@Sun.COM * fc_fca_attach(). And the transport passes this size up to ULPs during 707836SJohn.Forte@Sun.COM * fc_ulp_port_attach() of each ULP. 717836SJohn.Forte@Sun.COM * 7210264SZhong.Wang@Sun.COM * This leaves us with another possible question; How are packets 7310264SZhong.Wang@Sun.COM * allocated for ELS's started by the transport itself ? Well, the port 7410264SZhong.Wang@Sun.COM * driver during attach time, cache allocates on a per port basis to 757836SJohn.Forte@Sun.COM * handle ELSs too. 767836SJohn.Forte@Sun.COM */ 777836SJohn.Forte@Sun.COM 787836SJohn.Forte@Sun.COM #include <sys/note.h> 797836SJohn.Forte@Sun.COM #include <sys/types.h> 807836SJohn.Forte@Sun.COM #include <sys/varargs.h> 817836SJohn.Forte@Sun.COM #include <sys/param.h> 827836SJohn.Forte@Sun.COM #include <sys/errno.h> 837836SJohn.Forte@Sun.COM #include <sys/uio.h> 847836SJohn.Forte@Sun.COM #include <sys/buf.h> 857836SJohn.Forte@Sun.COM #include <sys/modctl.h> 867836SJohn.Forte@Sun.COM #include <sys/open.h> 877836SJohn.Forte@Sun.COM #include <sys/kmem.h> 887836SJohn.Forte@Sun.COM #include <sys/poll.h> 897836SJohn.Forte@Sun.COM #include <sys/conf.h> 907836SJohn.Forte@Sun.COM #include <sys/cmn_err.h> 917836SJohn.Forte@Sun.COM #include <sys/stat.h> 927836SJohn.Forte@Sun.COM #include <sys/ddi.h> 937836SJohn.Forte@Sun.COM #include <sys/sunddi.h> 947836SJohn.Forte@Sun.COM #include <sys/promif.h> 957836SJohn.Forte@Sun.COM #include <sys/byteorder.h> 967836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fc.h> 977836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_ulpif.h> 987836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_fcaif.h> 997836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fctl_private.h> 1007836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_portif.h> 1017836SJohn.Forte@Sun.COM 1027836SJohn.Forte@Sun.COM /* These are referenced by fp.c! */ 1037836SJohn.Forte@Sun.COM int did_table_size = D_ID_HASH_TABLE_SIZE; 1047836SJohn.Forte@Sun.COM int pwwn_table_size = PWWN_HASH_TABLE_SIZE; 1057836SJohn.Forte@Sun.COM 10610264SZhong.Wang@Sun.COM static fc_ulp_module_t *fctl_ulp_modules; 10710264SZhong.Wang@Sun.COM static fc_fca_port_t *fctl_fca_portlist; 1087836SJohn.Forte@Sun.COM static fc_ulp_list_t *fctl_ulp_list; 1097836SJohn.Forte@Sun.COM 1107836SJohn.Forte@Sun.COM static char fctl_greeting[] = 1117836SJohn.Forte@Sun.COM "fctl: %s ULP same type (0x%x) as existing module.\n"; 1127836SJohn.Forte@Sun.COM 1137836SJohn.Forte@Sun.COM static char *fctl_undefined = "Undefined"; 1147836SJohn.Forte@Sun.COM 1157836SJohn.Forte@Sun.COM /* 1167836SJohn.Forte@Sun.COM * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field) 1177836SJohn.Forte@Sun.COM */ 1187836SJohn.Forte@Sun.COM 1197836SJohn.Forte@Sun.COM static krwlock_t fctl_ulp_lock; 1207836SJohn.Forte@Sun.COM 1217836SJohn.Forte@Sun.COM /* 1227836SJohn.Forte@Sun.COM * The fctl_mod_ports_lock protects the mod_ports element in the 1237836SJohn.Forte@Sun.COM * fc_ulp_ports_t structure 1247836SJohn.Forte@Sun.COM */ 1257836SJohn.Forte@Sun.COM 1267836SJohn.Forte@Sun.COM static krwlock_t fctl_mod_ports_lock; 1277836SJohn.Forte@Sun.COM 1287836SJohn.Forte@Sun.COM /* 1297836SJohn.Forte@Sun.COM * fctl_port_lock protects the linked list of local port structures 13010264SZhong.Wang@Sun.COM * (fctl_fca_portlist). When walking the list, this lock must be obtained 1317836SJohn.Forte@Sun.COM * prior to any local port locks. 1327836SJohn.Forte@Sun.COM */ 1337836SJohn.Forte@Sun.COM 1347836SJohn.Forte@Sun.COM static kmutex_t fctl_port_lock; 1357836SJohn.Forte@Sun.COM static kmutex_t fctl_ulp_list_mutex; 1367836SJohn.Forte@Sun.COM 1377836SJohn.Forte@Sun.COM static fctl_nwwn_list_t *fctl_nwwn_hash_table; 1387836SJohn.Forte@Sun.COM static kmutex_t fctl_nwwn_hash_mutex; 1397836SJohn.Forte@Sun.COM int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE; 1407836SJohn.Forte@Sun.COM 1417836SJohn.Forte@Sun.COM #if !defined(lint) 1427836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table)) 1437836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list)) 1447836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next)) 1457836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports 1467836SJohn.Forte@Sun.COM ulp_ports::port_handle)) 1477836SJohn.Forte@Sun.COM _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info)) 1487836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec 1497836SJohn.Forte@Sun.COM ulp_ports::port_dstate)) 1507836SJohn.Forte@Sun.COM #endif /* lint */ 1517836SJohn.Forte@Sun.COM 15210264SZhong.Wang@Sun.COM #define FCTL_VERSION "20090729-1.70" 1537836SJohn.Forte@Sun.COM #define FCTL_NAME_VERSION "SunFC Transport v" FCTL_VERSION 1547836SJohn.Forte@Sun.COM 1557836SJohn.Forte@Sun.COM char *fctl_version = FCTL_NAME_VERSION; 1567836SJohn.Forte@Sun.COM 1577836SJohn.Forte@Sun.COM extern struct mod_ops mod_miscops; 1587836SJohn.Forte@Sun.COM 1597836SJohn.Forte@Sun.COM static struct modlmisc modlmisc = { 1607836SJohn.Forte@Sun.COM &mod_miscops, /* type of module */ 1617836SJohn.Forte@Sun.COM FCTL_NAME_VERSION /* Module name */ 1627836SJohn.Forte@Sun.COM }; 1637836SJohn.Forte@Sun.COM 1647836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = { 1657836SJohn.Forte@Sun.COM MODREV_1, (void *)&modlmisc, NULL 1667836SJohn.Forte@Sun.COM }; 1677836SJohn.Forte@Sun.COM 1687836SJohn.Forte@Sun.COM static struct bus_ops fctl_fca_busops = { 1697836SJohn.Forte@Sun.COM BUSO_REV, 1707836SJohn.Forte@Sun.COM nullbusmap, /* bus_map */ 1717836SJohn.Forte@Sun.COM NULL, /* bus_get_intrspec */ 1727836SJohn.Forte@Sun.COM NULL, /* bus_add_intrspec */ 1737836SJohn.Forte@Sun.COM NULL, /* bus_remove_intrspec */ 1747836SJohn.Forte@Sun.COM i_ddi_map_fault, /* bus_map_fault */ 1757836SJohn.Forte@Sun.COM ddi_dma_map, /* bus_dma_map */ 1767836SJohn.Forte@Sun.COM ddi_dma_allochdl, /* bus_dma_allochdl */ 1777836SJohn.Forte@Sun.COM ddi_dma_freehdl, /* bus_dma_freehdl */ 1787836SJohn.Forte@Sun.COM ddi_dma_bindhdl, /* bus_dma_bindhdl */ 1797836SJohn.Forte@Sun.COM ddi_dma_unbindhdl, /* bus_unbindhdl */ 1807836SJohn.Forte@Sun.COM ddi_dma_flush, /* bus_dma_flush */ 1817836SJohn.Forte@Sun.COM ddi_dma_win, /* bus_dma_win */ 1827836SJohn.Forte@Sun.COM ddi_dma_mctl, /* bus_dma_ctl */ 1837836SJohn.Forte@Sun.COM fctl_fca_bus_ctl, /* bus_ctl */ 1847836SJohn.Forte@Sun.COM ddi_bus_prop_op, /* bus_prop_op */ 1857836SJohn.Forte@Sun.COM NULL, /* bus_get_eventcookie */ 1867836SJohn.Forte@Sun.COM NULL, /* bus_add_eventcall */ 1877836SJohn.Forte@Sun.COM NULL, /* bus_remove_event */ 1887836SJohn.Forte@Sun.COM NULL, /* bus_post_event */ 1897836SJohn.Forte@Sun.COM NULL, /* bus_intr_ctl */ 1907836SJohn.Forte@Sun.COM NULL, /* bus_config */ 1917836SJohn.Forte@Sun.COM NULL, /* bus_unconfig */ 1927836SJohn.Forte@Sun.COM NULL, /* bus_fm_init */ 1937836SJohn.Forte@Sun.COM NULL, /* bus_fm_fini */ 1947836SJohn.Forte@Sun.COM NULL, /* bus_fm_access_enter */ 1957836SJohn.Forte@Sun.COM NULL, /* bus_fm_access_exit */ 1967836SJohn.Forte@Sun.COM NULL, /* bus_power */ 1977836SJohn.Forte@Sun.COM NULL 1987836SJohn.Forte@Sun.COM }; 1997836SJohn.Forte@Sun.COM 2007836SJohn.Forte@Sun.COM struct kmem_cache *fctl_job_cache; 2017836SJohn.Forte@Sun.COM 2027836SJohn.Forte@Sun.COM static fc_errmap_t fc_errlist [] = { 20310264SZhong.Wang@Sun.COM { FC_FAILURE, "Operation failed" }, 20410264SZhong.Wang@Sun.COM { FC_SUCCESS, "Operation success" }, 20510264SZhong.Wang@Sun.COM { FC_CAP_ERROR, "Capability error" }, 20610264SZhong.Wang@Sun.COM { FC_CAP_FOUND, "Capability found" }, 20710264SZhong.Wang@Sun.COM { FC_CAP_SETTABLE, "Capability settable" }, 20810264SZhong.Wang@Sun.COM { FC_UNBOUND, "Port not bound" }, 20910264SZhong.Wang@Sun.COM { FC_NOMEM, "No memory" }, 21010264SZhong.Wang@Sun.COM { FC_BADPACKET, "Bad packet" }, 21110264SZhong.Wang@Sun.COM { FC_OFFLINE, "Port offline" }, 21210264SZhong.Wang@Sun.COM { FC_OLDPORT, "Old Port" }, 21310264SZhong.Wang@Sun.COM { FC_NO_MAP, "No map available" }, 21410264SZhong.Wang@Sun.COM { FC_TRANSPORT_ERROR, "Transport error" }, 21510264SZhong.Wang@Sun.COM { FC_ELS_FREJECT, "ELS Frejected" }, 21610264SZhong.Wang@Sun.COM { FC_ELS_PREJECT, "ELS PRejected" }, 21710264SZhong.Wang@Sun.COM { FC_ELS_BAD, "Bad ELS request" }, 21810264SZhong.Wang@Sun.COM { FC_ELS_MALFORMED, "Malformed ELS request" }, 21910264SZhong.Wang@Sun.COM { FC_TOOMANY, "Too many commands" }, 22010264SZhong.Wang@Sun.COM { FC_UB_BADTOKEN, "Bad Unsolicited buffer token" }, 22110264SZhong.Wang@Sun.COM { FC_UB_ERROR, "Unsolicited buffer error" }, 22210264SZhong.Wang@Sun.COM { FC_UB_BUSY, "Unsolicited buffer busy" }, 22310264SZhong.Wang@Sun.COM { FC_BADULP, "Bad ULP" }, 22410264SZhong.Wang@Sun.COM { FC_BADTYPE, "Bad Type" }, 22510264SZhong.Wang@Sun.COM { FC_UNCLAIMED, "Not Claimed" }, 22610264SZhong.Wang@Sun.COM { FC_ULP_SAMEMODULE, "Same ULP Module" }, 22710264SZhong.Wang@Sun.COM { FC_ULP_SAMETYPE, "Same ULP Type" }, 22810264SZhong.Wang@Sun.COM { FC_ABORTED, "Command Aborted" }, 22910264SZhong.Wang@Sun.COM { FC_ABORT_FAILED, "Abort Failed" }, 23010264SZhong.Wang@Sun.COM { FC_BADEXCHANGE, "Bad Exchange" }, 23110264SZhong.Wang@Sun.COM { FC_BADWWN, "Bad World Wide Name" }, 23210264SZhong.Wang@Sun.COM { FC_BADDEV, "Bad Device" }, 23310264SZhong.Wang@Sun.COM { FC_BADCMD, "Bad Command" }, 23410264SZhong.Wang@Sun.COM { FC_BADOBJECT, "Bad Object" }, 23510264SZhong.Wang@Sun.COM { FC_BADPORT, "Bad Port" }, 23610264SZhong.Wang@Sun.COM { FC_NOTTHISPORT, "Not on this Port" }, 23710264SZhong.Wang@Sun.COM { FC_PREJECT, "Operation Prejected" }, 23810264SZhong.Wang@Sun.COM { FC_FREJECT, "Operation Frejected" }, 23910264SZhong.Wang@Sun.COM { FC_PBUSY, "Operation Pbusyed" }, 24010264SZhong.Wang@Sun.COM { FC_FBUSY, "Operation Fbusyed" }, 24110264SZhong.Wang@Sun.COM { FC_ALREADY, "Already done" }, 24210264SZhong.Wang@Sun.COM { FC_LOGINREQ, "PLOGI Required" }, 24310264SZhong.Wang@Sun.COM { FC_RESETFAIL, "Reset operation failed" }, 24410264SZhong.Wang@Sun.COM { FC_INVALID_REQUEST, "Invalid Request" }, 24510264SZhong.Wang@Sun.COM { FC_OUTOFBOUNDS, "Out of Bounds" }, 24610264SZhong.Wang@Sun.COM { FC_TRAN_BUSY, "Command transport Busy" }, 24710264SZhong.Wang@Sun.COM { FC_STATEC_BUSY, "State change Busy" }, 2487836SJohn.Forte@Sun.COM { FC_DEVICE_BUSY, "Port driver is working on this device" } 2497836SJohn.Forte@Sun.COM }; 2507836SJohn.Forte@Sun.COM 2517836SJohn.Forte@Sun.COM fc_pkt_reason_t remote_stop_reasons [] = { 2527836SJohn.Forte@Sun.COM { FC_REASON_ABTS, "Abort Sequence" }, 2537836SJohn.Forte@Sun.COM { FC_REASON_ABTX, "Abort Exchange" }, 2547836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 2557836SJohn.Forte@Sun.COM }; 2567836SJohn.Forte@Sun.COM 2577836SJohn.Forte@Sun.COM fc_pkt_reason_t general_reasons [] = { 25810264SZhong.Wang@Sun.COM { FC_REASON_HW_ERROR, "Hardware Error" }, 2597836SJohn.Forte@Sun.COM { FC_REASON_SEQ_TIMEOUT, "Sequence Timeout" }, 2607836SJohn.Forte@Sun.COM { FC_REASON_ABORTED, "Aborted" }, 2617836SJohn.Forte@Sun.COM { FC_REASON_ABORT_FAILED, "Abort Failed" }, 2627836SJohn.Forte@Sun.COM { FC_REASON_NO_CONNECTION, "No Connection" }, 2637836SJohn.Forte@Sun.COM { FC_REASON_XCHG_DROPPED, "Exchange Dropped" }, 2647836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_FRAME, "Illegal Frame" }, 2657836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_LENGTH, "Illegal Length" }, 2667836SJohn.Forte@Sun.COM { FC_REASON_UNSUPPORTED, "Unsuported" }, 2677836SJohn.Forte@Sun.COM { FC_REASON_RX_BUF_TIMEOUT, "Receive Buffer Timeout" }, 2687836SJohn.Forte@Sun.COM { FC_REASON_FCAL_OPN_FAIL, "FC AL Open Failed" }, 2697836SJohn.Forte@Sun.COM { FC_REASON_OVERRUN, "Over run" }, 2707836SJohn.Forte@Sun.COM { FC_REASON_QFULL, "Queue Full" }, 2717836SJohn.Forte@Sun.COM { FC_REASON_ILLEGAL_REQ, "Illegal Request", }, 2727836SJohn.Forte@Sun.COM { FC_REASON_PKT_BUSY, "Busy" }, 2737836SJohn.Forte@Sun.COM { FC_REASON_OFFLINE, "Offline" }, 2747836SJohn.Forte@Sun.COM { FC_REASON_BAD_XID, "Bad Exchange Id" }, 2757836SJohn.Forte@Sun.COM { FC_REASON_XCHG_BSY, "Exchange Busy" }, 2767836SJohn.Forte@Sun.COM { FC_REASON_NOMEM, "No Memory" }, 2777836SJohn.Forte@Sun.COM { FC_REASON_BAD_SID, "Bad S_ID" }, 2787836SJohn.Forte@Sun.COM { FC_REASON_NO_SEQ_INIT, "No Sequence Initiative" }, 2797836SJohn.Forte@Sun.COM { FC_REASON_DIAG_BUSY, "Diagnostic Busy" }, 2807836SJohn.Forte@Sun.COM { FC_REASON_DMA_ERROR, "DMA Error" }, 2817836SJohn.Forte@Sun.COM { FC_REASON_CRC_ERROR, "CRC Error" }, 2827836SJohn.Forte@Sun.COM { FC_REASON_ABORT_TIMEOUT, "Abort Timeout" }, 2837836SJohn.Forte@Sun.COM { FC_REASON_FCA_UNIQUE, "FCA Unique" }, 2847836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 2857836SJohn.Forte@Sun.COM }; 2867836SJohn.Forte@Sun.COM 2877836SJohn.Forte@Sun.COM fc_pkt_reason_t rjt_reasons [] = { 2887836SJohn.Forte@Sun.COM { FC_REASON_INVALID_D_ID, "Invalid D_ID" }, 2897836SJohn.Forte@Sun.COM { FC_REASON_INVALID_S_ID, "Invalid S_ID" }, 2907836SJohn.Forte@Sun.COM { FC_REASON_TEMP_UNAVAILABLE, "Temporarily Unavailable" }, 2917836SJohn.Forte@Sun.COM { FC_REASON_PERM_UNAVAILABLE, "Permamnently Unavailable" }, 2927836SJohn.Forte@Sun.COM { FC_REASON_CLASS_NOT_SUPP, "Class Not Supported", }, 2937836SJohn.Forte@Sun.COM { FC_REASON_DELIMTER_USAGE_ERROR, 29410264SZhong.Wang@Sun.COM "Delimeter Usage Error" }, 2957836SJohn.Forte@Sun.COM { FC_REASON_TYPE_NOT_SUPP, "Type Not Supported" }, 2967836SJohn.Forte@Sun.COM { FC_REASON_INVALID_LINK_CTRL, "Invalid Link Control" }, 2977836SJohn.Forte@Sun.COM { FC_REASON_INVALID_R_CTL, "Invalid R_CTL" }, 2987836SJohn.Forte@Sun.COM { FC_REASON_INVALID_F_CTL, "Invalid F_CTL" }, 2997836SJohn.Forte@Sun.COM { FC_REASON_INVALID_OX_ID, "Invalid OX_ID" }, 3007836SJohn.Forte@Sun.COM { FC_REASON_INVALID_RX_ID, "Invalid RX_ID" }, 3017836SJohn.Forte@Sun.COM { FC_REASON_INVALID_SEQ_ID, "Invalid Sequence ID" }, 3027836SJohn.Forte@Sun.COM { FC_REASON_INVALID_DF_CTL, "Invalid DF_CTL" }, 3037836SJohn.Forte@Sun.COM { FC_REASON_INVALID_SEQ_CNT, "Invalid Sequence count" }, 3047836SJohn.Forte@Sun.COM { FC_REASON_INVALID_PARAM, "Invalid Parameter" }, 3057836SJohn.Forte@Sun.COM { FC_REASON_EXCH_ERROR, "Exchange Error" }, 3067836SJohn.Forte@Sun.COM { FC_REASON_PROTOCOL_ERROR, "Protocol Error" }, 3077836SJohn.Forte@Sun.COM { FC_REASON_INCORRECT_LENGTH, "Incorrect Length" }, 3087836SJohn.Forte@Sun.COM { FC_REASON_UNEXPECTED_ACK, "Unexpected Ack" }, 30910264SZhong.Wang@Sun.COM { FC_REASON_UNEXPECTED_LR, "Unexpected Link reset" }, 3107836SJohn.Forte@Sun.COM { FC_REASON_LOGIN_REQUIRED, "Login Required" }, 3117836SJohn.Forte@Sun.COM { FC_REASON_EXCESSIVE_SEQS, "Excessive Sequences" 31210264SZhong.Wang@Sun.COM " Attempted" }, 3137836SJohn.Forte@Sun.COM { FC_REASON_EXCH_UNABLE, "Exchange incapable" }, 3147836SJohn.Forte@Sun.COM { FC_REASON_ESH_NOT_SUPP, "Expiration Security Header " 31510264SZhong.Wang@Sun.COM "Not Supported" }, 3167836SJohn.Forte@Sun.COM { FC_REASON_NO_FABRIC_PATH, "No Fabric Path" }, 3177836SJohn.Forte@Sun.COM { FC_REASON_VENDOR_UNIQUE, "Vendor Unique" }, 3187836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3197836SJohn.Forte@Sun.COM }; 3207836SJohn.Forte@Sun.COM 3217836SJohn.Forte@Sun.COM fc_pkt_reason_t n_port_busy_reasons [] = { 3227836SJohn.Forte@Sun.COM { FC_REASON_PHYSICAL_BUSY, "Physical Busy" }, 3237836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_RESOURCE_BSY, "Resource Busy" }, 3247836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_VENDOR_UNIQUE, "Vendor Unique" }, 3257836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3267836SJohn.Forte@Sun.COM }; 3277836SJohn.Forte@Sun.COM 3287836SJohn.Forte@Sun.COM fc_pkt_reason_t f_busy_reasons [] = { 3297836SJohn.Forte@Sun.COM { FC_REASON_FABRIC_BSY, "Fabric Busy" }, 3307836SJohn.Forte@Sun.COM { FC_REASON_N_PORT_BSY, "N_Port Busy" }, 3317836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3327836SJohn.Forte@Sun.COM }; 3337836SJohn.Forte@Sun.COM 3347836SJohn.Forte@Sun.COM fc_pkt_reason_t ls_ba_rjt_reasons [] = { 3357836SJohn.Forte@Sun.COM { FC_REASON_INVALID_LA_CODE, "Invalid Link Application Code" }, 3367836SJohn.Forte@Sun.COM { FC_REASON_LOGICAL_ERROR, "Logical Error" }, 3377836SJohn.Forte@Sun.COM { FC_REASON_LOGICAL_BSY, "Logical Busy" }, 3387836SJohn.Forte@Sun.COM { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject" }, 3397836SJohn.Forte@Sun.COM { FC_REASON_CMD_UNABLE, "Unable to Perform Command" }, 3407836SJohn.Forte@Sun.COM { FC_REASON_CMD_UNSUPPORTED, "Unsupported Command" }, 3417836SJohn.Forte@Sun.COM { FC_REASON_VU_RJT, "Vendor Unique" }, 3427836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3437836SJohn.Forte@Sun.COM }; 3447836SJohn.Forte@Sun.COM 3457836SJohn.Forte@Sun.COM fc_pkt_reason_t fs_rjt_reasons [] = { 3467836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_CMD, "Invalid Command" }, 3477836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_VER, "Invalid Version" }, 3487836SJohn.Forte@Sun.COM { FC_REASON_FS_LOGICAL_ERR, "Logical Error" }, 3497836SJohn.Forte@Sun.COM { FC_REASON_FS_INVALID_IUSIZE, "Invalid IU Size" }, 3507836SJohn.Forte@Sun.COM { FC_REASON_FS_LOGICAL_BUSY, "Logical Busy" }, 3517836SJohn.Forte@Sun.COM { FC_REASON_FS_PROTOCOL_ERR, "Protocol Error" }, 3527836SJohn.Forte@Sun.COM { FC_REASON_FS_CMD_UNABLE, "Unable to Perform Command" }, 3537836SJohn.Forte@Sun.COM { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command" }, 3547836SJohn.Forte@Sun.COM { FC_REASON_FS_VENDOR_UNIQUE, "Vendor Unique" }, 3557836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3567836SJohn.Forte@Sun.COM }; 3577836SJohn.Forte@Sun.COM 3587836SJohn.Forte@Sun.COM fc_pkt_action_t n_port_busy_actions [] = { 3597836SJohn.Forte@Sun.COM { FC_ACTION_SEQ_TERM_RETRY, "Retry terminated Sequence" }, 3607836SJohn.Forte@Sun.COM { FC_ACTION_SEQ_ACTIVE_RETRY, "Retry Active Sequence" }, 3617836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3627836SJohn.Forte@Sun.COM }; 3637836SJohn.Forte@Sun.COM 3647836SJohn.Forte@Sun.COM fc_pkt_action_t rjt_timeout_actions [] = { 3657836SJohn.Forte@Sun.COM { FC_ACTION_RETRYABLE, "Retryable" }, 3667836SJohn.Forte@Sun.COM { FC_ACTION_NON_RETRYABLE, "Non Retryable" }, 3677836SJohn.Forte@Sun.COM { FC_REASON_INVALID, NULL } 3687836SJohn.Forte@Sun.COM }; 3697836SJohn.Forte@Sun.COM 3707836SJohn.Forte@Sun.COM fc_pkt_expln_t ba_rjt_explns [] = { 3717836SJohn.Forte@Sun.COM { FC_EXPLN_NONE, "No Explanation" }, 3727836SJohn.Forte@Sun.COM { FC_EXPLN_INVALID_OX_RX_ID, "Invalid X_ID" }, 3737836SJohn.Forte@Sun.COM { FC_EXPLN_SEQ_ABORTED, "Sequence Aborted" }, 3747836SJohn.Forte@Sun.COM { FC_EXPLN_INVALID, NULL } 3757836SJohn.Forte@Sun.COM }; 3767836SJohn.Forte@Sun.COM 3777836SJohn.Forte@Sun.COM fc_pkt_error_t fc_pkt_errlist[] = { 3787836SJohn.Forte@Sun.COM { 3797836SJohn.Forte@Sun.COM FC_PKT_SUCCESS, 3807836SJohn.Forte@Sun.COM "Operation Success", 3817836SJohn.Forte@Sun.COM NULL, 3827836SJohn.Forte@Sun.COM NULL, 3837836SJohn.Forte@Sun.COM NULL 3847836SJohn.Forte@Sun.COM }, 3857836SJohn.Forte@Sun.COM { FC_PKT_REMOTE_STOP, 38610264SZhong.Wang@Sun.COM "Remote Stop", 38710264SZhong.Wang@Sun.COM remote_stop_reasons, 38810264SZhong.Wang@Sun.COM NULL, 38910264SZhong.Wang@Sun.COM NULL 3907836SJohn.Forte@Sun.COM }, 3917836SJohn.Forte@Sun.COM { 3927836SJohn.Forte@Sun.COM FC_PKT_LOCAL_RJT, 3937836SJohn.Forte@Sun.COM "Local Reject", 3947836SJohn.Forte@Sun.COM general_reasons, 3957836SJohn.Forte@Sun.COM rjt_timeout_actions, 3967836SJohn.Forte@Sun.COM NULL 3977836SJohn.Forte@Sun.COM }, 3987836SJohn.Forte@Sun.COM { 3997836SJohn.Forte@Sun.COM FC_PKT_NPORT_RJT, 4007836SJohn.Forte@Sun.COM "N_Port Reject", 4017836SJohn.Forte@Sun.COM rjt_reasons, 4027836SJohn.Forte@Sun.COM rjt_timeout_actions, 4037836SJohn.Forte@Sun.COM NULL 4047836SJohn.Forte@Sun.COM }, 4057836SJohn.Forte@Sun.COM { 4067836SJohn.Forte@Sun.COM FC_PKT_FABRIC_RJT, 4077836SJohn.Forte@Sun.COM "Fabric Reject", 4087836SJohn.Forte@Sun.COM rjt_reasons, 4097836SJohn.Forte@Sun.COM rjt_timeout_actions, 4107836SJohn.Forte@Sun.COM NULL 4117836SJohn.Forte@Sun.COM }, 4127836SJohn.Forte@Sun.COM { 4137836SJohn.Forte@Sun.COM FC_PKT_LOCAL_BSY, 4147836SJohn.Forte@Sun.COM "Local Busy", 4157836SJohn.Forte@Sun.COM general_reasons, 4167836SJohn.Forte@Sun.COM NULL, 4177836SJohn.Forte@Sun.COM NULL, 4187836SJohn.Forte@Sun.COM }, 4197836SJohn.Forte@Sun.COM { 4207836SJohn.Forte@Sun.COM FC_PKT_TRAN_BSY, 4217836SJohn.Forte@Sun.COM "Transport Busy", 4227836SJohn.Forte@Sun.COM general_reasons, 4237836SJohn.Forte@Sun.COM NULL, 4247836SJohn.Forte@Sun.COM NULL, 4257836SJohn.Forte@Sun.COM }, 4267836SJohn.Forte@Sun.COM { 4277836SJohn.Forte@Sun.COM FC_PKT_NPORT_BSY, 4287836SJohn.Forte@Sun.COM "N_Port Busy", 4297836SJohn.Forte@Sun.COM n_port_busy_reasons, 4307836SJohn.Forte@Sun.COM n_port_busy_actions, 4317836SJohn.Forte@Sun.COM NULL 4327836SJohn.Forte@Sun.COM }, 4337836SJohn.Forte@Sun.COM { 4347836SJohn.Forte@Sun.COM FC_PKT_FABRIC_BSY, 4357836SJohn.Forte@Sun.COM "Fabric Busy", 4367836SJohn.Forte@Sun.COM f_busy_reasons, 4377836SJohn.Forte@Sun.COM NULL, 4387836SJohn.Forte@Sun.COM NULL, 4397836SJohn.Forte@Sun.COM }, 4407836SJohn.Forte@Sun.COM { 4417836SJohn.Forte@Sun.COM FC_PKT_LS_RJT, 4427836SJohn.Forte@Sun.COM "Link Service Reject", 4437836SJohn.Forte@Sun.COM ls_ba_rjt_reasons, 4447836SJohn.Forte@Sun.COM NULL, 4457836SJohn.Forte@Sun.COM NULL, 4467836SJohn.Forte@Sun.COM }, 4477836SJohn.Forte@Sun.COM { 4487836SJohn.Forte@Sun.COM FC_PKT_BA_RJT, 4497836SJohn.Forte@Sun.COM "Basic Reject", 4507836SJohn.Forte@Sun.COM ls_ba_rjt_reasons, 4517836SJohn.Forte@Sun.COM NULL, 4527836SJohn.Forte@Sun.COM ba_rjt_explns, 4537836SJohn.Forte@Sun.COM }, 4547836SJohn.Forte@Sun.COM { 4557836SJohn.Forte@Sun.COM FC_PKT_TIMEOUT, 4567836SJohn.Forte@Sun.COM "Timeout", 4577836SJohn.Forte@Sun.COM general_reasons, 4587836SJohn.Forte@Sun.COM rjt_timeout_actions, 4597836SJohn.Forte@Sun.COM NULL 4607836SJohn.Forte@Sun.COM }, 4617836SJohn.Forte@Sun.COM { 4627836SJohn.Forte@Sun.COM FC_PKT_FS_RJT, 4637836SJohn.Forte@Sun.COM "Fabric Switch Reject", 4647836SJohn.Forte@Sun.COM fs_rjt_reasons, 4657836SJohn.Forte@Sun.COM NULL, 4667836SJohn.Forte@Sun.COM NULL 4677836SJohn.Forte@Sun.COM }, 4687836SJohn.Forte@Sun.COM { 4697836SJohn.Forte@Sun.COM FC_PKT_TRAN_ERROR, 4707836SJohn.Forte@Sun.COM "Packet Transport error", 4717836SJohn.Forte@Sun.COM general_reasons, 4727836SJohn.Forte@Sun.COM NULL, 4737836SJohn.Forte@Sun.COM NULL 4747836SJohn.Forte@Sun.COM }, 4757836SJohn.Forte@Sun.COM { 4767836SJohn.Forte@Sun.COM FC_PKT_FAILURE, 4777836SJohn.Forte@Sun.COM "Packet Failure", 4787836SJohn.Forte@Sun.COM general_reasons, 4797836SJohn.Forte@Sun.COM NULL, 4807836SJohn.Forte@Sun.COM NULL 4817836SJohn.Forte@Sun.COM }, 4827836SJohn.Forte@Sun.COM { 4837836SJohn.Forte@Sun.COM FC_PKT_PORT_OFFLINE, 4847836SJohn.Forte@Sun.COM "Port Offline", 4857836SJohn.Forte@Sun.COM NULL, 4867836SJohn.Forte@Sun.COM NULL, 4877836SJohn.Forte@Sun.COM NULL 4887836SJohn.Forte@Sun.COM }, 4897836SJohn.Forte@Sun.COM { 4907836SJohn.Forte@Sun.COM FC_PKT_ELS_IN_PROGRESS, 4917836SJohn.Forte@Sun.COM "ELS is in Progress", 4927836SJohn.Forte@Sun.COM NULL, 4937836SJohn.Forte@Sun.COM NULL, 4947836SJohn.Forte@Sun.COM NULL 4957836SJohn.Forte@Sun.COM } 4967836SJohn.Forte@Sun.COM }; 4977836SJohn.Forte@Sun.COM 4987836SJohn.Forte@Sun.COM int 4997836SJohn.Forte@Sun.COM _init() 5007836SJohn.Forte@Sun.COM { 5017836SJohn.Forte@Sun.COM int rval; 5027836SJohn.Forte@Sun.COM 5037836SJohn.Forte@Sun.COM rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL); 5047836SJohn.Forte@Sun.COM rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL); 5057836SJohn.Forte@Sun.COM mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL); 5067836SJohn.Forte@Sun.COM mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL); 5077836SJohn.Forte@Sun.COM 5087836SJohn.Forte@Sun.COM fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) * 5097836SJohn.Forte@Sun.COM fctl_nwwn_table_size, KM_SLEEP); 5107836SJohn.Forte@Sun.COM 5117836SJohn.Forte@Sun.COM fctl_ulp_modules = NULL; 5127836SJohn.Forte@Sun.COM fctl_fca_portlist = NULL; 5137836SJohn.Forte@Sun.COM 5147836SJohn.Forte@Sun.COM fctl_job_cache = kmem_cache_create("fctl_cache", 5157836SJohn.Forte@Sun.COM sizeof (job_request_t), 8, fctl_cache_constructor, 5167836SJohn.Forte@Sun.COM fctl_cache_destructor, NULL, NULL, NULL, 0); 5177836SJohn.Forte@Sun.COM 5187836SJohn.Forte@Sun.COM if (fctl_job_cache == NULL) { 5197836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 5207836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 5217836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 5227836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 5237836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 5247836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 5257836SJohn.Forte@Sun.COM return (ENOMEM); 5267836SJohn.Forte@Sun.COM } 5277836SJohn.Forte@Sun.COM 5287836SJohn.Forte@Sun.COM if ((rval = mod_install(&modlinkage)) != 0) { 5297836SJohn.Forte@Sun.COM kmem_cache_destroy(fctl_job_cache); 5307836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 5317836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 5327836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 5337836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 5347836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 5357836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 5367836SJohn.Forte@Sun.COM } 5377836SJohn.Forte@Sun.COM 5387836SJohn.Forte@Sun.COM return (rval); 5397836SJohn.Forte@Sun.COM } 5407836SJohn.Forte@Sun.COM 5417836SJohn.Forte@Sun.COM 5427836SJohn.Forte@Sun.COM /* 5437836SJohn.Forte@Sun.COM * The mod_uninstall code doesn't call _fini when 5447836SJohn.Forte@Sun.COM * there is living dependent module on fctl. So 5457836SJohn.Forte@Sun.COM * there is no need to be extra careful here ? 5467836SJohn.Forte@Sun.COM */ 5477836SJohn.Forte@Sun.COM int 5487836SJohn.Forte@Sun.COM _fini() 5497836SJohn.Forte@Sun.COM { 5507836SJohn.Forte@Sun.COM int rval; 5517836SJohn.Forte@Sun.COM 5527836SJohn.Forte@Sun.COM if ((rval = mod_remove(&modlinkage)) != 0) { 5537836SJohn.Forte@Sun.COM return (rval); 5547836SJohn.Forte@Sun.COM } 5557836SJohn.Forte@Sun.COM 5567836SJohn.Forte@Sun.COM kmem_cache_destroy(fctl_job_cache); 5577836SJohn.Forte@Sun.COM kmem_free(fctl_nwwn_hash_table, 5587836SJohn.Forte@Sun.COM sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size); 5597836SJohn.Forte@Sun.COM mutex_destroy(&fctl_nwwn_hash_mutex); 5607836SJohn.Forte@Sun.COM mutex_destroy(&fctl_port_lock); 5617836SJohn.Forte@Sun.COM rw_destroy(&fctl_ulp_lock); 5627836SJohn.Forte@Sun.COM rw_destroy(&fctl_mod_ports_lock); 5637836SJohn.Forte@Sun.COM 5647836SJohn.Forte@Sun.COM return (rval); 5657836SJohn.Forte@Sun.COM } 5667836SJohn.Forte@Sun.COM 5677836SJohn.Forte@Sun.COM 5687836SJohn.Forte@Sun.COM int 5697836SJohn.Forte@Sun.COM _info(struct modinfo *modinfo_p) 5707836SJohn.Forte@Sun.COM { 5717836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfo_p)); 5727836SJohn.Forte@Sun.COM } 5737836SJohn.Forte@Sun.COM 5747836SJohn.Forte@Sun.COM 5757836SJohn.Forte@Sun.COM /* ARGSUSED */ 5767836SJohn.Forte@Sun.COM static int 5777836SJohn.Forte@Sun.COM fctl_cache_constructor(void *buf, void *cdarg, int kmflag) 5787836SJohn.Forte@Sun.COM { 5797836SJohn.Forte@Sun.COM job_request_t *job = (job_request_t *)buf; 5807836SJohn.Forte@Sun.COM 5817836SJohn.Forte@Sun.COM mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL); 5827836SJohn.Forte@Sun.COM sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL); 5837836SJohn.Forte@Sun.COM sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL); 5847836SJohn.Forte@Sun.COM 5857836SJohn.Forte@Sun.COM return (0); 5867836SJohn.Forte@Sun.COM } 5877836SJohn.Forte@Sun.COM 5887836SJohn.Forte@Sun.COM 5897836SJohn.Forte@Sun.COM /* ARGSUSED */ 5907836SJohn.Forte@Sun.COM static void 5917836SJohn.Forte@Sun.COM fctl_cache_destructor(void *buf, void *cdarg) 5927836SJohn.Forte@Sun.COM { 5937836SJohn.Forte@Sun.COM job_request_t *job = (job_request_t *)buf; 5947836SJohn.Forte@Sun.COM 5957836SJohn.Forte@Sun.COM sema_destroy(&job->job_fctl_sema); 5967836SJohn.Forte@Sun.COM sema_destroy(&job->job_port_sema); 5977836SJohn.Forte@Sun.COM mutex_destroy(&job->job_mutex); 5987836SJohn.Forte@Sun.COM } 5997836SJohn.Forte@Sun.COM 6007836SJohn.Forte@Sun.COM 6017836SJohn.Forte@Sun.COM /* 6027836SJohn.Forte@Sun.COM * fc_ulp_add: 6037836SJohn.Forte@Sun.COM * Add a ULP module 6047836SJohn.Forte@Sun.COM * 6057836SJohn.Forte@Sun.COM * Return Codes: 6067836SJohn.Forte@Sun.COM * FC_ULP_SAMEMODULE 6077836SJohn.Forte@Sun.COM * FC_SUCCESS 6087836SJohn.Forte@Sun.COM * FC_FAILURE 6097836SJohn.Forte@Sun.COM * 61010264SZhong.Wang@Sun.COM * fc_ulp_add prints a warning message if there is already a 6117836SJohn.Forte@Sun.COM * similar ULP type attached and this is unlikely to change as 61210264SZhong.Wang@Sun.COM * we trudge along. Further, this function returns a failure 6137836SJohn.Forte@Sun.COM * code if the same module attempts to add more than once for 6147836SJohn.Forte@Sun.COM * the same FC-4 type. 6157836SJohn.Forte@Sun.COM */ 6167836SJohn.Forte@Sun.COM int 6177836SJohn.Forte@Sun.COM fc_ulp_add(fc_ulp_modinfo_t *ulp_info) 6187836SJohn.Forte@Sun.COM { 6197836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 6207836SJohn.Forte@Sun.COM fc_ulp_module_t *prev; 62110264SZhong.Wang@Sun.COM job_request_t *job; 6227836SJohn.Forte@Sun.COM fc_ulp_list_t *new; 62310264SZhong.Wang@Sun.COM fc_fca_port_t *fca_port; 6247836SJohn.Forte@Sun.COM int ntry = 0; 6257836SJohn.Forte@Sun.COM 6267836SJohn.Forte@Sun.COM ASSERT(ulp_info != NULL); 6277836SJohn.Forte@Sun.COM 6287836SJohn.Forte@Sun.COM /* 6297836SJohn.Forte@Sun.COM * Make sure ulp_rev matches fctl version. 6307836SJohn.Forte@Sun.COM * Whenever non-private data structure or non-static interface changes, 6317836SJohn.Forte@Sun.COM * we should use an increased FCTL_ULP_MODREV_# number here and in all 6327836SJohn.Forte@Sun.COM * ulps to prevent version mismatch. 6337836SJohn.Forte@Sun.COM */ 6347836SJohn.Forte@Sun.COM if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) { 6357836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: ULP %s version mismatch;" 6367836SJohn.Forte@Sun.COM " ULP %s would not be loaded", ulp_info->ulp_name, 6377836SJohn.Forte@Sun.COM ulp_info->ulp_name); 6387836SJohn.Forte@Sun.COM return (FC_BADULP); 6397836SJohn.Forte@Sun.COM } 6407836SJohn.Forte@Sun.COM 6417836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), KM_SLEEP); 6427836SJohn.Forte@Sun.COM ASSERT(new != NULL); 6437836SJohn.Forte@Sun.COM 6447836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 6457836SJohn.Forte@Sun.COM new->ulp_info = ulp_info; 6467836SJohn.Forte@Sun.COM if (fctl_ulp_list != NULL) { 6477836SJohn.Forte@Sun.COM new->ulp_next = fctl_ulp_list; 6487836SJohn.Forte@Sun.COM } 6497836SJohn.Forte@Sun.COM fctl_ulp_list = new; 6507836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 6517836SJohn.Forte@Sun.COM 6527836SJohn.Forte@Sun.COM while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) { 6537836SJohn.Forte@Sun.COM delay(drv_usectohz(1000000)); 6547836SJohn.Forte@Sun.COM if (ntry++ > FC_ULP_ADD_RETRY_COUNT) { 65510264SZhong.Wang@Sun.COM fc_ulp_list_t *list; 65610264SZhong.Wang@Sun.COM fc_ulp_list_t *last; 6577836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 6587836SJohn.Forte@Sun.COM for (last = NULL, list = fctl_ulp_list; list != NULL; 6597836SJohn.Forte@Sun.COM list = list->ulp_next) { 6607836SJohn.Forte@Sun.COM if (list->ulp_info == ulp_info) { 6617836SJohn.Forte@Sun.COM break; 6627836SJohn.Forte@Sun.COM } 6637836SJohn.Forte@Sun.COM last = list; 6647836SJohn.Forte@Sun.COM } 6657836SJohn.Forte@Sun.COM 6667836SJohn.Forte@Sun.COM if (list) { 6677836SJohn.Forte@Sun.COM if (last) { 6687836SJohn.Forte@Sun.COM last->ulp_next = list->ulp_next; 6697836SJohn.Forte@Sun.COM } else { 6707836SJohn.Forte@Sun.COM fctl_ulp_list = list->ulp_next; 6717836SJohn.Forte@Sun.COM } 6727836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 6737836SJohn.Forte@Sun.COM } 6747836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 6757836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: ULP %s unable to load", 6767836SJohn.Forte@Sun.COM ulp_info->ulp_name); 6777836SJohn.Forte@Sun.COM return (FC_FAILURE); 6787836SJohn.Forte@Sun.COM } 6797836SJohn.Forte@Sun.COM } 6807836SJohn.Forte@Sun.COM 6817836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) { 6827836SJohn.Forte@Sun.COM ASSERT(mod->mod_info != NULL); 6837836SJohn.Forte@Sun.COM 6847836SJohn.Forte@Sun.COM if (ulp_info == mod->mod_info && 6857836SJohn.Forte@Sun.COM ulp_info->ulp_type == mod->mod_info->ulp_type) { 6867836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 6877836SJohn.Forte@Sun.COM return (FC_ULP_SAMEMODULE); 6887836SJohn.Forte@Sun.COM } 6897836SJohn.Forte@Sun.COM 6907836SJohn.Forte@Sun.COM if (ulp_info->ulp_type == mod->mod_info->ulp_type) { 6917836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name, 6927836SJohn.Forte@Sun.COM ulp_info->ulp_type); 6937836SJohn.Forte@Sun.COM } 6947836SJohn.Forte@Sun.COM prev = mod; 6957836SJohn.Forte@Sun.COM } 6967836SJohn.Forte@Sun.COM 6977836SJohn.Forte@Sun.COM mod = kmem_zalloc(sizeof (*mod), KM_SLEEP); 6987836SJohn.Forte@Sun.COM mod->mod_info = ulp_info; 6997836SJohn.Forte@Sun.COM mod->mod_next = NULL; 7007836SJohn.Forte@Sun.COM 7017836SJohn.Forte@Sun.COM if (prev) { 7027836SJohn.Forte@Sun.COM prev->mod_next = mod; 7037836SJohn.Forte@Sun.COM } else { 7047836SJohn.Forte@Sun.COM fctl_ulp_modules = mod; 7057836SJohn.Forte@Sun.COM } 7067836SJohn.Forte@Sun.COM 7077836SJohn.Forte@Sun.COM /* 7087836SJohn.Forte@Sun.COM * Schedule a job to each port's job_handler 7097836SJohn.Forte@Sun.COM * thread to attach their ports with this ULP. 7107836SJohn.Forte@Sun.COM */ 7117836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 7127836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 7137836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 7147836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC, 7157836SJohn.Forte@Sun.COM NULL, NULL, KM_SLEEP); 7167836SJohn.Forte@Sun.COM 7177836SJohn.Forte@Sun.COM fctl_enque_job(fca_port->port_handle, job); 7187836SJohn.Forte@Sun.COM } 7197836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 7207836SJohn.Forte@Sun.COM 7217836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 7227836SJohn.Forte@Sun.COM 7237836SJohn.Forte@Sun.COM return (FC_SUCCESS); 7247836SJohn.Forte@Sun.COM } 7257836SJohn.Forte@Sun.COM 7267836SJohn.Forte@Sun.COM 7277836SJohn.Forte@Sun.COM /* 7287836SJohn.Forte@Sun.COM * fc_ulp_remove 7297836SJohn.Forte@Sun.COM * Remove a ULP module 7307836SJohn.Forte@Sun.COM * 7317836SJohn.Forte@Sun.COM * A misbehaving ULP may call this routine while I/Os are in progress. 7327836SJohn.Forte@Sun.COM * Currently there is no mechanism to detect it to fail such a request. 7337836SJohn.Forte@Sun.COM * 7347836SJohn.Forte@Sun.COM * Return Codes: 7357836SJohn.Forte@Sun.COM * FC_SUCCESS 7367836SJohn.Forte@Sun.COM * FC_FAILURE 7377836SJohn.Forte@Sun.COM */ 7387836SJohn.Forte@Sun.COM int 7397836SJohn.Forte@Sun.COM fc_ulp_remove(fc_ulp_modinfo_t *ulp_info) 7407836SJohn.Forte@Sun.COM { 7417836SJohn.Forte@Sun.COM fc_ulp_module_t *mod; 7427836SJohn.Forte@Sun.COM fc_ulp_list_t *list; 7437836SJohn.Forte@Sun.COM fc_ulp_list_t *last; 7447836SJohn.Forte@Sun.COM fc_ulp_module_t *prev; 7457836SJohn.Forte@Sun.COM 7467836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 7477836SJohn.Forte@Sun.COM 7487836SJohn.Forte@Sun.COM for (last = NULL, list = fctl_ulp_list; list != NULL; 7497836SJohn.Forte@Sun.COM list = list->ulp_next) { 7507836SJohn.Forte@Sun.COM if (list->ulp_info == ulp_info) { 7517836SJohn.Forte@Sun.COM break; 7527836SJohn.Forte@Sun.COM } 7537836SJohn.Forte@Sun.COM last = list; 7547836SJohn.Forte@Sun.COM } 7557836SJohn.Forte@Sun.COM 7567836SJohn.Forte@Sun.COM if (list) { 7577836SJohn.Forte@Sun.COM if (last) { 7587836SJohn.Forte@Sun.COM last->ulp_next = list->ulp_next; 7597836SJohn.Forte@Sun.COM } else { 7607836SJohn.Forte@Sun.COM fctl_ulp_list = list->ulp_next; 7617836SJohn.Forte@Sun.COM } 7627836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 7637836SJohn.Forte@Sun.COM } 7647836SJohn.Forte@Sun.COM 7657836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 7667836SJohn.Forte@Sun.COM 7677836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_WRITER); 7687836SJohn.Forte@Sun.COM 7697836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules, prev = NULL; mod != NULL; 7707836SJohn.Forte@Sun.COM mod = mod->mod_next) { 7717836SJohn.Forte@Sun.COM if (mod->mod_info == ulp_info) { 7727836SJohn.Forte@Sun.COM break; 7737836SJohn.Forte@Sun.COM } 7747836SJohn.Forte@Sun.COM prev = mod; 7757836SJohn.Forte@Sun.COM } 7767836SJohn.Forte@Sun.COM 7777836SJohn.Forte@Sun.COM if (mod) { 7787836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 7797836SJohn.Forte@Sun.COM 7807836SJohn.Forte@Sun.COM if (prev) { 7817836SJohn.Forte@Sun.COM prev->mod_next = mod->mod_next; 7827836SJohn.Forte@Sun.COM } else { 7837836SJohn.Forte@Sun.COM fctl_ulp_modules = mod->mod_next; 7847836SJohn.Forte@Sun.COM } 7857836SJohn.Forte@Sun.COM 7867836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 7877836SJohn.Forte@Sun.COM 7887836SJohn.Forte@Sun.COM while ((next = mod->mod_ports) != NULL) { 7897836SJohn.Forte@Sun.COM mod->mod_ports = next->port_next; 7907836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(next); 7917836SJohn.Forte@Sun.COM } 7927836SJohn.Forte@Sun.COM 7937836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 7947836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 7957836SJohn.Forte@Sun.COM 7967836SJohn.Forte@Sun.COM kmem_free(mod, sizeof (*mod)); 7977836SJohn.Forte@Sun.COM 7987836SJohn.Forte@Sun.COM return (FC_SUCCESS); 7997836SJohn.Forte@Sun.COM } 8007836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 8017836SJohn.Forte@Sun.COM 8027836SJohn.Forte@Sun.COM return (FC_FAILURE); 8037836SJohn.Forte@Sun.COM } 8047836SJohn.Forte@Sun.COM 8057836SJohn.Forte@Sun.COM 8067836SJohn.Forte@Sun.COM /* 8077836SJohn.Forte@Sun.COM * The callers typically cache allocate the packet, complete the 8087836SJohn.Forte@Sun.COM * DMA setup for pkt_cmd and pkt_resp fields of the packet and 8097836SJohn.Forte@Sun.COM * call this function to see if the FCA is interested in doing 8107836SJohn.Forte@Sun.COM * its own intialization. For example, socal may like to initialize 8117836SJohn.Forte@Sun.COM * the soc_hdr which is pointed to by the pkt_fca_private field 8127836SJohn.Forte@Sun.COM * and sitting right below fc_packet_t in memory. 8137836SJohn.Forte@Sun.COM * 8147836SJohn.Forte@Sun.COM * The caller is required to ensure that pkt_pd is populated with the 8157836SJohn.Forte@Sun.COM * handle that it was given when the transport notified it about the 8167836SJohn.Forte@Sun.COM * device this packet is associated with. If there is no associated 81710264SZhong.Wang@Sun.COM * device, pkt_pd must be set to NULL. A non-NULL pkt_pd will cause an 8187836SJohn.Forte@Sun.COM * increment of the reference count for said pd. When the packet is freed, 8197836SJohn.Forte@Sun.COM * the reference count will be decremented. This reference count, in 8207836SJohn.Forte@Sun.COM * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd 8217836SJohn.Forte@Sun.COM * will not wink out of existence while there is a packet outstanding. 8227836SJohn.Forte@Sun.COM * 8237836SJohn.Forte@Sun.COM * This function and fca_init_pkt must not perform any operations that 8247836SJohn.Forte@Sun.COM * would result in a call back to the ULP, as the ULP may be required 8257836SJohn.Forte@Sun.COM * to hold a mutex across this call to ensure that the pd in question 8267836SJohn.Forte@Sun.COM * won't go away prior the call to fc_ulp_transport. 8277836SJohn.Forte@Sun.COM * 8287836SJohn.Forte@Sun.COM * ULPs are responsible for using the handles they are given during state 8297836SJohn.Forte@Sun.COM * change callback processing in a manner that ensures consistency. That 8307836SJohn.Forte@Sun.COM * is, they must be aware that they could be processing a state change 8317836SJohn.Forte@Sun.COM * notification that tells them the device associated with a particular 8327836SJohn.Forte@Sun.COM * handle has gone away at the same time they are being asked to 8337836SJohn.Forte@Sun.COM * initialize a packet using that handle. ULPs must therefore ensure 8347836SJohn.Forte@Sun.COM * that their state change processing and packet initialization code 8357836SJohn.Forte@Sun.COM * paths are sufficiently synchronized to avoid the use of an 8367836SJohn.Forte@Sun.COM * invalidated handle in any fc_packet_t struct that is passed to the 8377836SJohn.Forte@Sun.COM * fc_ulp_init_packet() function. 8387836SJohn.Forte@Sun.COM */ 8397836SJohn.Forte@Sun.COM int 8407836SJohn.Forte@Sun.COM fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep) 8417836SJohn.Forte@Sun.COM { 8427836SJohn.Forte@Sun.COM int rval; 8437836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 8447836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 8457836SJohn.Forte@Sun.COM 8467836SJohn.Forte@Sun.COM ASSERT(pkt != NULL); 8477836SJohn.Forte@Sun.COM 8487836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 8497836SJohn.Forte@Sun.COM 8507836SJohn.Forte@Sun.COM /* Call the FCA driver's fca_init_pkt entry point function. */ 8517836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep); 8527836SJohn.Forte@Sun.COM 8537836SJohn.Forte@Sun.COM if ((rval == FC_SUCCESS) && (pd != NULL)) { 8547836SJohn.Forte@Sun.COM /* 8557836SJohn.Forte@Sun.COM * A !NULL pd here must still be a valid 8567836SJohn.Forte@Sun.COM * reference to the fc_remote_port_t. 8577836SJohn.Forte@Sun.COM */ 8587836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 8597836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 8607836SJohn.Forte@Sun.COM pd->pd_ref_count++; 8617836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 8627836SJohn.Forte@Sun.COM } 8637836SJohn.Forte@Sun.COM 8647836SJohn.Forte@Sun.COM return (rval); 8657836SJohn.Forte@Sun.COM } 8667836SJohn.Forte@Sun.COM 8677836SJohn.Forte@Sun.COM 8687836SJohn.Forte@Sun.COM /* 8697836SJohn.Forte@Sun.COM * This function is called before destroying the cache allocated 8707836SJohn.Forte@Sun.COM * fc_packet to free up (and uninitialize) any resource specially 8717836SJohn.Forte@Sun.COM * allocated by the FCA driver during tran_init_pkt(). 8727836SJohn.Forte@Sun.COM * 8737836SJohn.Forte@Sun.COM * If the pkt_pd field in the given fc_packet_t struct is not NULL, then 8747836SJohn.Forte@Sun.COM * the pd_ref_count reference count is decremented for the indicated 8757836SJohn.Forte@Sun.COM * fc_remote_port_t struct. 8767836SJohn.Forte@Sun.COM */ 8777836SJohn.Forte@Sun.COM int 8787836SJohn.Forte@Sun.COM fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt) 8797836SJohn.Forte@Sun.COM { 8807836SJohn.Forte@Sun.COM int rval; 8817836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 8827836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 8837836SJohn.Forte@Sun.COM 8847836SJohn.Forte@Sun.COM ASSERT(pkt != NULL); 8857836SJohn.Forte@Sun.COM 8867836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 8877836SJohn.Forte@Sun.COM 8887836SJohn.Forte@Sun.COM /* Call the FCA driver's fca_un_init_pkt entry point function */ 8897836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt); 8907836SJohn.Forte@Sun.COM 8917836SJohn.Forte@Sun.COM if ((rval == FC_SUCCESS) && (pd != NULL)) { 8927836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 8937836SJohn.Forte@Sun.COM 8947836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count > 0); 8957836SJohn.Forte@Sun.COM pd->pd_ref_count--; 8967836SJohn.Forte@Sun.COM 8977836SJohn.Forte@Sun.COM /* 8987836SJohn.Forte@Sun.COM * If at this point the state of this fc_remote_port_t 8997836SJohn.Forte@Sun.COM * struct is PORT_DEVICE_INVALID, it probably means somebody 9007836SJohn.Forte@Sun.COM * is cleaning up old (e.g. retried) packets. If the 9017836SJohn.Forte@Sun.COM * pd_ref_count has also dropped to zero, it's time to 9027836SJohn.Forte@Sun.COM * deallocate this fc_remote_port_t struct. 9037836SJohn.Forte@Sun.COM */ 9047836SJohn.Forte@Sun.COM if (pd->pd_state == PORT_DEVICE_INVALID && 9057836SJohn.Forte@Sun.COM pd->pd_ref_count == 0) { 9067836SJohn.Forte@Sun.COM fc_remote_node_t *node = pd->pd_remote_nodep; 9077836SJohn.Forte@Sun.COM 9087836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 9097836SJohn.Forte@Sun.COM 9107836SJohn.Forte@Sun.COM /* 9117836SJohn.Forte@Sun.COM * Also deallocate the associated fc_remote_node_t 9127836SJohn.Forte@Sun.COM * struct if it has no other associated 9137836SJohn.Forte@Sun.COM * fc_remote_port_t structs. 9147836SJohn.Forte@Sun.COM */ 9157836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) == 0) && 9167836SJohn.Forte@Sun.COM (node != NULL)) { 9177836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 9187836SJohn.Forte@Sun.COM } 9197836SJohn.Forte@Sun.COM return (rval); 9207836SJohn.Forte@Sun.COM } 9217836SJohn.Forte@Sun.COM 9227836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 9237836SJohn.Forte@Sun.COM } 9247836SJohn.Forte@Sun.COM 9257836SJohn.Forte@Sun.COM return (rval); 9267836SJohn.Forte@Sun.COM } 9277836SJohn.Forte@Sun.COM 9287836SJohn.Forte@Sun.COM 9297836SJohn.Forte@Sun.COM int 9307836SJohn.Forte@Sun.COM fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len, 9317836SJohn.Forte@Sun.COM int flag) 9327836SJohn.Forte@Sun.COM { 9337836SJohn.Forte@Sun.COM int job_code; 9347836SJohn.Forte@Sun.COM fc_local_port_t *port; 9357836SJohn.Forte@Sun.COM job_request_t *job; 9367836SJohn.Forte@Sun.COM fc_portmap_t *tmp_map; 9377836SJohn.Forte@Sun.COM uint32_t tmp_len; 9387836SJohn.Forte@Sun.COM fc_portmap_t *change_list = NULL; 9397836SJohn.Forte@Sun.COM uint32_t listlen = 0; 9407836SJohn.Forte@Sun.COM 9417836SJohn.Forte@Sun.COM port = port_handle; 9427836SJohn.Forte@Sun.COM 9437836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 9447836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 9457836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 9467836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 9477836SJohn.Forte@Sun.COM } 9487836SJohn.Forte@Sun.COM 9497836SJohn.Forte@Sun.COM if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) { 9507836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 9517836SJohn.Forte@Sun.COM return (FC_OFFLINE); 9527836SJohn.Forte@Sun.COM } 9537836SJohn.Forte@Sun.COM 9547836SJohn.Forte@Sun.COM if (port->fp_dev_count && (port->fp_dev_count == 9557836SJohn.Forte@Sun.COM port->fp_total_devices)) { 9567836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 9577836SJohn.Forte@Sun.COM fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0); 9587836SJohn.Forte@Sun.COM if (listlen > *len) { 9597836SJohn.Forte@Sun.COM tmp_map = (fc_portmap_t *)kmem_zalloc( 9607836SJohn.Forte@Sun.COM listlen * sizeof (fc_portmap_t), KM_NOSLEEP); 9617836SJohn.Forte@Sun.COM if (tmp_map == NULL) { 9627836SJohn.Forte@Sun.COM return (FC_NOMEM); 9637836SJohn.Forte@Sun.COM } 9647836SJohn.Forte@Sun.COM if (*map) { 9657836SJohn.Forte@Sun.COM kmem_free(*map, (*len) * sizeof (fc_portmap_t)); 9667836SJohn.Forte@Sun.COM } 9677836SJohn.Forte@Sun.COM *map = tmp_map; 9687836SJohn.Forte@Sun.COM } 9697836SJohn.Forte@Sun.COM if (change_list) { 9707836SJohn.Forte@Sun.COM bcopy(change_list, *map, 9717836SJohn.Forte@Sun.COM listlen * sizeof (fc_portmap_t)); 9727836SJohn.Forte@Sun.COM kmem_free(change_list, listlen * sizeof (fc_portmap_t)); 9737836SJohn.Forte@Sun.COM } 9747836SJohn.Forte@Sun.COM *len = listlen; 9757836SJohn.Forte@Sun.COM } else { 9767836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 9777836SJohn.Forte@Sun.COM 9787836SJohn.Forte@Sun.COM switch (flag) { 9797836SJohn.Forte@Sun.COM case FC_ULP_PLOGI_DONTCARE: 9807836SJohn.Forte@Sun.COM job_code = JOB_PORT_GETMAP; 9817836SJohn.Forte@Sun.COM break; 9827836SJohn.Forte@Sun.COM 9837836SJohn.Forte@Sun.COM case FC_ULP_PLOGI_PRESERVE: 9847836SJohn.Forte@Sun.COM job_code = JOB_PORT_GETMAP_PLOGI_ALL; 9857836SJohn.Forte@Sun.COM break; 9867836SJohn.Forte@Sun.COM 9877836SJohn.Forte@Sun.COM default: 9887836SJohn.Forte@Sun.COM return (FC_INVALID_REQUEST); 9897836SJohn.Forte@Sun.COM } 9907836SJohn.Forte@Sun.COM /* 9917836SJohn.Forte@Sun.COM * Submit a job request to the job handler 9927836SJohn.Forte@Sun.COM * thread to get the map and wait 9937836SJohn.Forte@Sun.COM */ 9947836SJohn.Forte@Sun.COM job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP); 9957836SJohn.Forte@Sun.COM job->job_private = (opaque_t)map; 9967836SJohn.Forte@Sun.COM job->job_arg = (opaque_t)len; 9977836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 9987836SJohn.Forte@Sun.COM 9997836SJohn.Forte@Sun.COM fctl_jobwait(job); 10007836SJohn.Forte@Sun.COM /* 10017836SJohn.Forte@Sun.COM * The result of the last I/O operation is 10027836SJohn.Forte@Sun.COM * in job_code. We don't care to look at it 10037836SJohn.Forte@Sun.COM * Rather we look at the number of devices 10047836SJohn.Forte@Sun.COM * that are found to fill out the map for 10057836SJohn.Forte@Sun.COM * ULPs. 10067836SJohn.Forte@Sun.COM */ 10077836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 10087836SJohn.Forte@Sun.COM } 10097836SJohn.Forte@Sun.COM 10107836SJohn.Forte@Sun.COM /* 10117836SJohn.Forte@Sun.COM * If we're here, we're returning a map to the caller, which means 10127836SJohn.Forte@Sun.COM * we'd better make sure every pd in that map has the 10137836SJohn.Forte@Sun.COM * PD_GIVEN_TO_ULPS flag set. 10147836SJohn.Forte@Sun.COM */ 10157836SJohn.Forte@Sun.COM 10167836SJohn.Forte@Sun.COM tmp_len = *len; 10177836SJohn.Forte@Sun.COM tmp_map = *map; 10187836SJohn.Forte@Sun.COM 10197836SJohn.Forte@Sun.COM while (tmp_len-- != 0) { 10207836SJohn.Forte@Sun.COM if (tmp_map->map_state != PORT_DEVICE_INVALID) { 10217836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 10227836SJohn.Forte@Sun.COM (fc_remote_port_t *)tmp_map->map_pd; 10237836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 10247836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 10257836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 10267836SJohn.Forte@Sun.COM } 10277836SJohn.Forte@Sun.COM tmp_map++; 10287836SJohn.Forte@Sun.COM } 10297836SJohn.Forte@Sun.COM 10307836SJohn.Forte@Sun.COM return (FC_SUCCESS); 10317836SJohn.Forte@Sun.COM } 10327836SJohn.Forte@Sun.COM 10337836SJohn.Forte@Sun.COM 10347836SJohn.Forte@Sun.COM int 10357836SJohn.Forte@Sun.COM fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen) 10367836SJohn.Forte@Sun.COM { 10377836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 103810264SZhong.Wang@Sun.COM int job_flags; 10397836SJohn.Forte@Sun.COM uint32_t count; 10407836SJohn.Forte@Sun.COM fc_packet_t **tmp_array; 104110264SZhong.Wang@Sun.COM job_request_t *job; 104210264SZhong.Wang@Sun.COM fc_local_port_t *port = port_handle; 10437836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 10447836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop; 10457836SJohn.Forte@Sun.COM 10467836SJohn.Forte@Sun.COM /* 10477836SJohn.Forte@Sun.COM * If the port is OFFLINE, or if the port driver is 10487836SJohn.Forte@Sun.COM * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 10497836SJohn.Forte@Sun.COM * PLOGI operations 10507836SJohn.Forte@Sun.COM */ 10517836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 10527836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 10537836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 10547836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 10557836SJohn.Forte@Sun.COM } 10567836SJohn.Forte@Sun.COM 10577836SJohn.Forte@Sun.COM if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 10587836SJohn.Forte@Sun.COM (port->fp_soft_state & 10597836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 10607836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 10617836SJohn.Forte@Sun.COM return (FC_OFFLINE); 10627836SJohn.Forte@Sun.COM } 10637836SJohn.Forte@Sun.COM 10647836SJohn.Forte@Sun.COM /* 10657836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 10667836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 10677836SJohn.Forte@Sun.COM */ 10687836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 10697836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 10707836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 10717836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 10727836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 10737836SJohn.Forte@Sun.COM } 10747836SJohn.Forte@Sun.COM 10757836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 10767836SJohn.Forte@Sun.COM 10777836SJohn.Forte@Sun.COM tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP); 10787836SJohn.Forte@Sun.COM for (count = 0; count < listlen; count++) { 10797836SJohn.Forte@Sun.COM tmp_array[count] = ulp_pkt[count]; 10807836SJohn.Forte@Sun.COM } 10817836SJohn.Forte@Sun.COM 10827836SJohn.Forte@Sun.COM job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR) 10837836SJohn.Forte@Sun.COM ? 0 : JOB_TYPE_FCTL_ASYNC; 10847836SJohn.Forte@Sun.COM 10857836SJohn.Forte@Sun.COM #ifdef DEBUG 10867836SJohn.Forte@Sun.COM { 10877836SJohn.Forte@Sun.COM int next; 10887836SJohn.Forte@Sun.COM int count; 10897836SJohn.Forte@Sun.COM int polled; 10907836SJohn.Forte@Sun.COM 10917836SJohn.Forte@Sun.COM polled = ((ulp_pkt[0]->pkt_tran_flags) & 10927836SJohn.Forte@Sun.COM FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 10937836SJohn.Forte@Sun.COM 10947836SJohn.Forte@Sun.COM for (count = 0; count < listlen; count++) { 10957836SJohn.Forte@Sun.COM next = ((ulp_pkt[count]->pkt_tran_flags) 10967836SJohn.Forte@Sun.COM & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC; 10977836SJohn.Forte@Sun.COM ASSERT(next == polled); 10987836SJohn.Forte@Sun.COM } 10997836SJohn.Forte@Sun.COM } 11007836SJohn.Forte@Sun.COM #endif 11017836SJohn.Forte@Sun.COM 11027836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP); 11037836SJohn.Forte@Sun.COM job->job_ulp_pkts = tmp_array; 11047836SJohn.Forte@Sun.COM job->job_ulp_listlen = listlen; 11057836SJohn.Forte@Sun.COM 11067836SJohn.Forte@Sun.COM while (listlen--) { 11077836SJohn.Forte@Sun.COM fc_packet_t *pkt; 11087836SJohn.Forte@Sun.COM 11097836SJohn.Forte@Sun.COM pkt = tmp_array[listlen]; 11107836SJohn.Forte@Sun.COM if (pkt->pkt_pd == NULL) { 11117836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_SUCCESS; 11127836SJohn.Forte@Sun.COM continue; 11137836SJohn.Forte@Sun.COM } 11147836SJohn.Forte@Sun.COM 11157836SJohn.Forte@Sun.COM mutex_enter(&pkt->pkt_pd->pd_mutex); 11167836SJohn.Forte@Sun.COM if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS || 11177836SJohn.Forte@Sun.COM pkt->pkt_pd->pd_flags == PD_ELS_MARK) { 11187836SJohn.Forte@Sun.COM /* 11197836SJohn.Forte@Sun.COM * Set the packet state and let the port 11207836SJohn.Forte@Sun.COM * driver call the completion routine 11217836SJohn.Forte@Sun.COM * from its thread 11227836SJohn.Forte@Sun.COM */ 11237836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 11247836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS; 11257836SJohn.Forte@Sun.COM continue; 11267836SJohn.Forte@Sun.COM } 11277836SJohn.Forte@Sun.COM 11287836SJohn.Forte@Sun.COM if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID || 11297836SJohn.Forte@Sun.COM pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) { 11307836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 11317836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_LOCAL_RJT; 11327836SJohn.Forte@Sun.COM continue; 11337836SJohn.Forte@Sun.COM } 11347836SJohn.Forte@Sun.COM mutex_exit(&pkt->pkt_pd->pd_mutex); 11357836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_SUCCESS; 11367836SJohn.Forte@Sun.COM } 11377836SJohn.Forte@Sun.COM 11387836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 11397836SJohn.Forte@Sun.COM 11407836SJohn.Forte@Sun.COM if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) { 11417836SJohn.Forte@Sun.COM fctl_jobwait(job); 11427836SJohn.Forte@Sun.COM rval = job->job_result; 11437836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 11447836SJohn.Forte@Sun.COM } 11457836SJohn.Forte@Sun.COM 11467836SJohn.Forte@Sun.COM return (rval); 11477836SJohn.Forte@Sun.COM } 11487836SJohn.Forte@Sun.COM 11497836SJohn.Forte@Sun.COM 11507836SJohn.Forte@Sun.COM opaque_t 11517836SJohn.Forte@Sun.COM fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error, 11527836SJohn.Forte@Sun.COM int create) 11537836SJohn.Forte@Sun.COM { 115410264SZhong.Wang@Sun.COM fc_local_port_t *port; 11557836SJohn.Forte@Sun.COM job_request_t *job; 115610264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 11577836SJohn.Forte@Sun.COM 11587836SJohn.Forte@Sun.COM port = port_handle; 11597836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, pwwn); 11607836SJohn.Forte@Sun.COM 11617836SJohn.Forte@Sun.COM if (pd != NULL) { 11627836SJohn.Forte@Sun.COM *error = FC_SUCCESS; 11637836SJohn.Forte@Sun.COM /* 11647836SJohn.Forte@Sun.COM * A ULP now knows about this pd, so mark it 11657836SJohn.Forte@Sun.COM */ 11667836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 11677836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 11687836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 11697836SJohn.Forte@Sun.COM return (pd); 11707836SJohn.Forte@Sun.COM } 11717836SJohn.Forte@Sun.COM 11727836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 11737836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(port->fp_topology) && create) { 11747836SJohn.Forte@Sun.COM uint32_t d_id; 117510264SZhong.Wang@Sun.COM fctl_ns_req_t *ns_cmd; 11767836SJohn.Forte@Sun.COM 11777836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 11787836SJohn.Forte@Sun.COM 11797836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 11807836SJohn.Forte@Sun.COM 11817836SJohn.Forte@Sun.COM if (job == NULL) { 11827836SJohn.Forte@Sun.COM *error = FC_NOMEM; 11837836SJohn.Forte@Sun.COM return (pd); 11847836SJohn.Forte@Sun.COM } 11857836SJohn.Forte@Sun.COM 11867836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t), 11877836SJohn.Forte@Sun.COM sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t), 11887836SJohn.Forte@Sun.COM 0, KM_SLEEP); 11897836SJohn.Forte@Sun.COM 11907836SJohn.Forte@Sun.COM if (ns_cmd == NULL) { 11917836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 11927836SJohn.Forte@Sun.COM *error = FC_NOMEM; 11937836SJohn.Forte@Sun.COM return (pd); 11947836SJohn.Forte@Sun.COM } 11957836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = NS_GID_PN; 11967836SJohn.Forte@Sun.COM ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn; 11977836SJohn.Forte@Sun.COM 11987836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 11997836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 12007836SJohn.Forte@Sun.COM job->job_counter = 1; 12017836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 12027836SJohn.Forte@Sun.COM fctl_jobwait(job); 12037836SJohn.Forte@Sun.COM 12047836SJohn.Forte@Sun.COM if (job->job_result != FC_SUCCESS) { 12057836SJohn.Forte@Sun.COM *error = job->job_result; 12067836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 12077836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 12087836SJohn.Forte@Sun.COM return (pd); 12097836SJohn.Forte@Sun.COM } 12107836SJohn.Forte@Sun.COM d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id; 12117836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 12127836SJohn.Forte@Sun.COM 12137836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t), 12147836SJohn.Forte@Sun.COM sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE, 12157836SJohn.Forte@Sun.COM KM_SLEEP); 12167836SJohn.Forte@Sun.COM ASSERT(ns_cmd != NULL); 12177836SJohn.Forte@Sun.COM 12187836SJohn.Forte@Sun.COM ns_cmd->ns_gan_max = 1; 12197836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = NS_GA_NXT; 12207836SJohn.Forte@Sun.COM ns_cmd->ns_gan_sid = FCTL_GAN_START_ID; 12217836SJohn.Forte@Sun.COM ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1; 12227836SJohn.Forte@Sun.COM ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0; 12237836SJohn.Forte@Sun.COM 12247836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 12257836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 12267836SJohn.Forte@Sun.COM job->job_counter = 1; 12277836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 12287836SJohn.Forte@Sun.COM fctl_jobwait(job); 12297836SJohn.Forte@Sun.COM 12307836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 12317836SJohn.Forte@Sun.COM if (job->job_result != FC_SUCCESS) { 12327836SJohn.Forte@Sun.COM *error = job->job_result; 12337836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 12347836SJohn.Forte@Sun.COM return (pd); 12357836SJohn.Forte@Sun.COM } 12367836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 12377836SJohn.Forte@Sun.COM 12387836SJohn.Forte@Sun.COM /* 12397836SJohn.Forte@Sun.COM * Check if the port device is created now. 12407836SJohn.Forte@Sun.COM */ 12417836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, pwwn); 12427836SJohn.Forte@Sun.COM 12437836SJohn.Forte@Sun.COM if (pd == NULL) { 12447836SJohn.Forte@Sun.COM *error = FC_FAILURE; 12457836SJohn.Forte@Sun.COM } else { 12467836SJohn.Forte@Sun.COM *error = FC_SUCCESS; 12477836SJohn.Forte@Sun.COM 12487836SJohn.Forte@Sun.COM /* 12497836SJohn.Forte@Sun.COM * A ULP now knows about this pd, so mark it 12507836SJohn.Forte@Sun.COM */ 12517836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 12527836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_GIVEN_TO_ULPS; 12537836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 12547836SJohn.Forte@Sun.COM } 12557836SJohn.Forte@Sun.COM } else { 12567836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 12577836SJohn.Forte@Sun.COM *error = FC_FAILURE; 12587836SJohn.Forte@Sun.COM } 12597836SJohn.Forte@Sun.COM 12607836SJohn.Forte@Sun.COM return (pd); 12617836SJohn.Forte@Sun.COM } 12627836SJohn.Forte@Sun.COM 12637836SJohn.Forte@Sun.COM 12647836SJohn.Forte@Sun.COM /* 12657836SJohn.Forte@Sun.COM * If a NS object exists in the host and query is performed 12667836SJohn.Forte@Sun.COM * on that object, we should retrieve it from our basket 12677836SJohn.Forte@Sun.COM * and return it right here, there by saving a request going 12687836SJohn.Forte@Sun.COM * all the up to the Name Server. 12697836SJohn.Forte@Sun.COM */ 12707836SJohn.Forte@Sun.COM int 12717836SJohn.Forte@Sun.COM fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req) 12727836SJohn.Forte@Sun.COM { 127310264SZhong.Wang@Sun.COM int rval; 12747836SJohn.Forte@Sun.COM int fabric; 12757836SJohn.Forte@Sun.COM job_request_t *job; 12767836SJohn.Forte@Sun.COM fctl_ns_req_t *ns_cmd; 12777836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 12787836SJohn.Forte@Sun.COM 12797836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 12807836SJohn.Forte@Sun.COM fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0; 12817836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 12827836SJohn.Forte@Sun.COM 12837836SJohn.Forte@Sun.COM /* 12847836SJohn.Forte@Sun.COM * Name server query can't be performed for devices not in Fabric 12857836SJohn.Forte@Sun.COM */ 12867836SJohn.Forte@Sun.COM if (!fabric && pd) { 12877836SJohn.Forte@Sun.COM return (FC_BADOBJECT); 12887836SJohn.Forte@Sun.COM } 12897836SJohn.Forte@Sun.COM 12907836SJohn.Forte@Sun.COM if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) { 12917836SJohn.Forte@Sun.COM if (pd == NULL) { 12927836SJohn.Forte@Sun.COM rval = fctl_update_host_ns_values(port, ns_req); 12937836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 12947836SJohn.Forte@Sun.COM return (rval); 12957836SJohn.Forte@Sun.COM } 12967836SJohn.Forte@Sun.COM } else { 12977836SJohn.Forte@Sun.COM /* 12987836SJohn.Forte@Sun.COM * Guess what, FC-GS-2 currently prohibits (not 12997836SJohn.Forte@Sun.COM * in the strongest language though) setting of 13007836SJohn.Forte@Sun.COM * NS object values by other ports. But we might 13017836SJohn.Forte@Sun.COM * get that changed to at least accommodate setting 13027836SJohn.Forte@Sun.COM * symbolic node/port names - But if disks/tapes 13037836SJohn.Forte@Sun.COM * were going to provide a method to set these 13047836SJohn.Forte@Sun.COM * values directly (which in turn might register 13057836SJohn.Forte@Sun.COM * with the NS when they come up; yep, for that 13067836SJohn.Forte@Sun.COM * to happen the disks will have to be very well 13077836SJohn.Forte@Sun.COM * behaved Fabric citizen) we won't need to 13087836SJohn.Forte@Sun.COM * register the symbolic port/node names for 13097836SJohn.Forte@Sun.COM * other ports too (rather send down SCSI commands 13107836SJohn.Forte@Sun.COM * to the devices to set the names) 13117836SJohn.Forte@Sun.COM * 13127836SJohn.Forte@Sun.COM * Be that as it may, let's continue to fail 13137836SJohn.Forte@Sun.COM * registration requests for other ports. period. 13147836SJohn.Forte@Sun.COM */ 13157836SJohn.Forte@Sun.COM return (FC_BADOBJECT); 13167836SJohn.Forte@Sun.COM } 13177836SJohn.Forte@Sun.COM 13187836SJohn.Forte@Sun.COM if (!fabric) { 13197836SJohn.Forte@Sun.COM return (FC_SUCCESS); 13207836SJohn.Forte@Sun.COM } 13217836SJohn.Forte@Sun.COM } else if (!fabric) { 13227836SJohn.Forte@Sun.COM return (fctl_retrieve_host_ns_values(port, ns_req)); 13237836SJohn.Forte@Sun.COM } 13247836SJohn.Forte@Sun.COM 13257836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP); 13267836SJohn.Forte@Sun.COM ASSERT(job != NULL); 13277836SJohn.Forte@Sun.COM 13287836SJohn.Forte@Sun.COM ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len, 13297836SJohn.Forte@Sun.COM ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP); 13307836SJohn.Forte@Sun.COM ASSERT(ns_cmd != NULL); 13317836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_code = ns_req->ns_cmd; 13327836SJohn.Forte@Sun.COM bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf, 13337836SJohn.Forte@Sun.COM ns_req->ns_req_len); 13347836SJohn.Forte@Sun.COM 13357836SJohn.Forte@Sun.COM job->job_private = (void *)ns_cmd; 13367836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 13377836SJohn.Forte@Sun.COM fctl_jobwait(job); 13387836SJohn.Forte@Sun.COM rval = job->job_result; 13397836SJohn.Forte@Sun.COM 13407836SJohn.Forte@Sun.COM if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) { 13417836SJohn.Forte@Sun.COM bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload, 13427836SJohn.Forte@Sun.COM ns_cmd->ns_data_len); 13437836SJohn.Forte@Sun.COM } 13447836SJohn.Forte@Sun.COM bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr, 13457836SJohn.Forte@Sun.COM sizeof (fc_ct_header_t)); 13467836SJohn.Forte@Sun.COM 13477836SJohn.Forte@Sun.COM fctl_free_ns_cmd(ns_cmd); 13487836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 13497836SJohn.Forte@Sun.COM 13507836SJohn.Forte@Sun.COM return (rval); 13517836SJohn.Forte@Sun.COM } 13527836SJohn.Forte@Sun.COM 13537836SJohn.Forte@Sun.COM 13547836SJohn.Forte@Sun.COM int 13557836SJohn.Forte@Sun.COM fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt) 13567836SJohn.Forte@Sun.COM { 13577836SJohn.Forte@Sun.COM int rval; 135810264SZhong.Wang@Sun.COM fc_local_port_t *port; 13597836SJohn.Forte@Sun.COM fc_remote_port_t *pd, *newpd; 13607836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 13617836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 13627836SJohn.Forte@Sun.COM 13637836SJohn.Forte@Sun.COM port = port_handle; 13647836SJohn.Forte@Sun.COM 13657836SJohn.Forte@Sun.COM if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) { 13667836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_transport( 13677836SJohn.Forte@Sun.COM port->fp_fca_handle, pkt)); 13687836SJohn.Forte@Sun.COM } 13697836SJohn.Forte@Sun.COM 13707836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 13717836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 13727836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 13737836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 13747836SJohn.Forte@Sun.COM } 13757836SJohn.Forte@Sun.COM 13767836SJohn.Forte@Sun.COM /* A locus of race conditions */ 13777836SJohn.Forte@Sun.COM if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) || 13787836SJohn.Forte@Sun.COM (port->fp_soft_state & 13797836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 13807836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 13817836SJohn.Forte@Sun.COM return (FC_OFFLINE); 13827836SJohn.Forte@Sun.COM } 13837836SJohn.Forte@Sun.COM 13847836SJohn.Forte@Sun.COM /* 13857836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 13867836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 13877836SJohn.Forte@Sun.COM */ 13887836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 13897836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 13907836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 13917836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 13927836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 13937836SJohn.Forte@Sun.COM } 13947836SJohn.Forte@Sun.COM 13957836SJohn.Forte@Sun.COM pd = pkt->pkt_pd; 13967836SJohn.Forte@Sun.COM if (pd) { 13977836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 13987836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 13997836SJohn.Forte@Sun.COM 14007836SJohn.Forte@Sun.COM newpd = fctl_get_remote_port_by_pwwn_mutex_held(port, 14017836SJohn.Forte@Sun.COM &pd->pd_port_name); 14027836SJohn.Forte@Sun.COM 14037836SJohn.Forte@Sun.COM /* 14047836SJohn.Forte@Sun.COM * The remote port (pd) in the packet is no longer 14057836SJohn.Forte@Sun.COM * usable, as the old pd still exists we can use the 14067836SJohn.Forte@Sun.COM * WWN to check if we have a current pd for the device 14077836SJohn.Forte@Sun.COM * we want. Either way we continue with the old logic 14087836SJohn.Forte@Sun.COM * whether we have a new pd or not, as the new pd 14097836SJohn.Forte@Sun.COM * could be bad, or have become unusable. 14107836SJohn.Forte@Sun.COM */ 14117836SJohn.Forte@Sun.COM if ((newpd) && (newpd != pd)) { 14127836SJohn.Forte@Sun.COM 14137836SJohn.Forte@Sun.COM /* 14147836SJohn.Forte@Sun.COM * There is a better remote port (pd) to try, 14157836SJohn.Forte@Sun.COM * so we need to fix the reference counts, etc. 14167836SJohn.Forte@Sun.COM */ 14177836SJohn.Forte@Sun.COM mutex_enter(&newpd->pd_mutex); 14187836SJohn.Forte@Sun.COM newpd->pd_ref_count++; 14197836SJohn.Forte@Sun.COM pkt->pkt_pd = newpd; 14207836SJohn.Forte@Sun.COM mutex_exit(&newpd->pd_mutex); 14217836SJohn.Forte@Sun.COM 14227836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 14237836SJohn.Forte@Sun.COM pd->pd_ref_count--; 14247836SJohn.Forte@Sun.COM if ((pd->pd_state == PORT_DEVICE_INVALID) && 14257836SJohn.Forte@Sun.COM (pd->pd_ref_count == 0)) { 14267836SJohn.Forte@Sun.COM fc_remote_node_t *node = 14277836SJohn.Forte@Sun.COM pd->pd_remote_nodep; 14287836SJohn.Forte@Sun.COM 14297836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 14307836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14317836SJohn.Forte@Sun.COM 14327836SJohn.Forte@Sun.COM /* 14337836SJohn.Forte@Sun.COM * This will create another PD hole 14347836SJohn.Forte@Sun.COM * where we have a reference to a pd, 14357836SJohn.Forte@Sun.COM * but someone else could remove it. 14367836SJohn.Forte@Sun.COM */ 14377836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) 14387836SJohn.Forte@Sun.COM == 0) && (node != NULL)) { 14397836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 14407836SJohn.Forte@Sun.COM } 14417836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 14427836SJohn.Forte@Sun.COM } else { 14437836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 14447836SJohn.Forte@Sun.COM } 14457836SJohn.Forte@Sun.COM pd = newpd; 14467836SJohn.Forte@Sun.COM } 14477836SJohn.Forte@Sun.COM } 14487836SJohn.Forte@Sun.COM 14497836SJohn.Forte@Sun.COM if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 14507836SJohn.Forte@Sun.COM rval = (pd->pd_state == PORT_DEVICE_VALID) ? 14517836SJohn.Forte@Sun.COM FC_LOGINREQ : FC_BADDEV; 14527836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14537836SJohn.Forte@Sun.COM return (rval); 14547836SJohn.Forte@Sun.COM } 14557836SJohn.Forte@Sun.COM 14567836SJohn.Forte@Sun.COM if (pd->pd_flags != PD_IDLE) { 14577836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14587836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY); 14597836SJohn.Forte@Sun.COM } 14607836SJohn.Forte@Sun.COM 14617836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 14627836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 14637836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14647836SJohn.Forte@Sun.COM return (FC_BADDEV); 14657836SJohn.Forte@Sun.COM } 14667836SJohn.Forte@Sun.COM 14677836SJohn.Forte@Sun.COM } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) { 14687836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14697836SJohn.Forte@Sun.COM return (FC_BADPACKET); 14707836SJohn.Forte@Sun.COM } 14717836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14727836SJohn.Forte@Sun.COM 14737836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt)); 14747836SJohn.Forte@Sun.COM } 14757836SJohn.Forte@Sun.COM 14767836SJohn.Forte@Sun.COM 14777836SJohn.Forte@Sun.COM int 14787836SJohn.Forte@Sun.COM fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt) 14797836SJohn.Forte@Sun.COM { 14807836SJohn.Forte@Sun.COM int rval; 148110264SZhong.Wang@Sun.COM fc_local_port_t *port = port_handle; 14827836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 14837836SJohn.Forte@Sun.COM fc_ulp_rscn_info_t *rscnp = 14847836SJohn.Forte@Sun.COM (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop; 14857836SJohn.Forte@Sun.COM 14867836SJohn.Forte@Sun.COM /* 14877836SJohn.Forte@Sun.COM * If the port is OFFLINE, or if the port driver is 14887836SJohn.Forte@Sun.COM * being SUSPENDED/PM_SUSPENDED/DETACHED, block all 14897836SJohn.Forte@Sun.COM * ELS operations 14907836SJohn.Forte@Sun.COM */ 14917836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 14927836SJohn.Forte@Sun.COM if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) || 14937836SJohn.Forte@Sun.COM (port->fp_soft_state & 14947836SJohn.Forte@Sun.COM (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) { 14957836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 14967836SJohn.Forte@Sun.COM return (FC_OFFLINE); 14977836SJohn.Forte@Sun.COM } 14987836SJohn.Forte@Sun.COM 14997836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 15007836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 15017836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 15027836SJohn.Forte@Sun.COM } 15037836SJohn.Forte@Sun.COM 15047836SJohn.Forte@Sun.COM /* 15057836SJohn.Forte@Sun.COM * If the rscn count in the packet is not the same as the rscn count 15067836SJohn.Forte@Sun.COM * in the fc_local_port_t, then one or more new RSCNs has occurred. 15077836SJohn.Forte@Sun.COM */ 15087836SJohn.Forte@Sun.COM if ((rscnp != NULL) && 15097836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) && 15107836SJohn.Forte@Sun.COM (rscnp->ulp_rscn_count != port->fp_rscn_count)) { 15117836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 15127836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY_NEW_RSCN); 15137836SJohn.Forte@Sun.COM } 15147836SJohn.Forte@Sun.COM 15157836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 15167836SJohn.Forte@Sun.COM 15177836SJohn.Forte@Sun.COM if ((pd = pkt->pkt_pd) != NULL) { 15187836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 15197836SJohn.Forte@Sun.COM if (pd->pd_state != PORT_DEVICE_LOGGED_IN) { 15207836SJohn.Forte@Sun.COM rval = (pd->pd_state == PORT_DEVICE_VALID) ? 15217836SJohn.Forte@Sun.COM FC_LOGINREQ : FC_BADDEV; 15227836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 15237836SJohn.Forte@Sun.COM return (rval); 15247836SJohn.Forte@Sun.COM } 15257836SJohn.Forte@Sun.COM 15267836SJohn.Forte@Sun.COM if (pd->pd_flags != PD_IDLE) { 15277836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 15287836SJohn.Forte@Sun.COM return (FC_DEVICE_BUSY); 15297836SJohn.Forte@Sun.COM } 15307836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD || 15317836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 15327836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 15337836SJohn.Forte@Sun.COM return (FC_BADDEV); 15347836SJohn.Forte@Sun.COM } 15357836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 15367836SJohn.Forte@Sun.COM } 15377836SJohn.Forte@Sun.COM 15387836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt)); 15397836SJohn.Forte@Sun.COM } 15407836SJohn.Forte@Sun.COM 15417836SJohn.Forte@Sun.COM 15427836SJohn.Forte@Sun.COM int 15437836SJohn.Forte@Sun.COM fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size, 15447836SJohn.Forte@Sun.COM uint32_t type, uint64_t *tokens) 15457836SJohn.Forte@Sun.COM { 15467836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 15477836SJohn.Forte@Sun.COM 15487836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle, 15497836SJohn.Forte@Sun.COM tokens, size, count, type)); 15507836SJohn.Forte@Sun.COM } 15517836SJohn.Forte@Sun.COM 15527836SJohn.Forte@Sun.COM 15537836SJohn.Forte@Sun.COM int 15547836SJohn.Forte@Sun.COM fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens) 15557836SJohn.Forte@Sun.COM { 15567836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 15577836SJohn.Forte@Sun.COM 15587836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle, 15597836SJohn.Forte@Sun.COM count, tokens)); 15607836SJohn.Forte@Sun.COM } 15617836SJohn.Forte@Sun.COM 15627836SJohn.Forte@Sun.COM 15637836SJohn.Forte@Sun.COM int 15647836SJohn.Forte@Sun.COM fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens) 15657836SJohn.Forte@Sun.COM { 15667836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 15677836SJohn.Forte@Sun.COM 15687836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 15697836SJohn.Forte@Sun.COM count, tokens)); 15707836SJohn.Forte@Sun.COM } 15717836SJohn.Forte@Sun.COM 15727836SJohn.Forte@Sun.COM 15737836SJohn.Forte@Sun.COM int 15747836SJohn.Forte@Sun.COM fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags) 15757836SJohn.Forte@Sun.COM { 15767836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 15777836SJohn.Forte@Sun.COM 15787836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags)); 15797836SJohn.Forte@Sun.COM } 15807836SJohn.Forte@Sun.COM 15817836SJohn.Forte@Sun.COM 15827836SJohn.Forte@Sun.COM /* 15837836SJohn.Forte@Sun.COM * Submit an asynchronous request to the job handler if the sleep 15847836SJohn.Forte@Sun.COM * flag is set to KM_NOSLEEP, as such calls could have been made 15857836SJohn.Forte@Sun.COM * in interrupt contexts, and the goal is to avoid busy waiting, 15867836SJohn.Forte@Sun.COM * blocking on a conditional variable, a semaphore or any of the 15877836SJohn.Forte@Sun.COM * synchronization primitives. A noticeable draw back with this 15887836SJohn.Forte@Sun.COM * asynchronous request is that an FC_SUCCESS is returned long 15897836SJohn.Forte@Sun.COM * before the reset is complete (successful or not). 15907836SJohn.Forte@Sun.COM */ 15917836SJohn.Forte@Sun.COM int 15927836SJohn.Forte@Sun.COM fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep) 15937836SJohn.Forte@Sun.COM { 15947836SJohn.Forte@Sun.COM int rval; 15957836SJohn.Forte@Sun.COM fc_local_port_t *port; 15967836SJohn.Forte@Sun.COM job_request_t *job; 15977836SJohn.Forte@Sun.COM 15987836SJohn.Forte@Sun.COM port = port_handle; 15997836SJohn.Forte@Sun.COM /* 16007836SJohn.Forte@Sun.COM * Many a times, this function is called from interrupt 16017836SJohn.Forte@Sun.COM * contexts and there have been several dead locks and 16027836SJohn.Forte@Sun.COM * hangs - One of the simplest work arounds is to fib 16037836SJohn.Forte@Sun.COM * if a RESET is in progress. 16047836SJohn.Forte@Sun.COM */ 16057836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 16067836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) { 16077836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16087836SJohn.Forte@Sun.COM return (FC_SUCCESS); 16097836SJohn.Forte@Sun.COM } 16107836SJohn.Forte@Sun.COM 16117836SJohn.Forte@Sun.COM /* 16127836SJohn.Forte@Sun.COM * Ward off this reset if a state change is in progress. 16137836SJohn.Forte@Sun.COM */ 16147836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 16157836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16167836SJohn.Forte@Sun.COM return (FC_STATEC_BUSY); 16177836SJohn.Forte@Sun.COM } 16187836SJohn.Forte@Sun.COM port->fp_soft_state |= FP_SOFT_IN_LINK_RESET; 16197836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16207836SJohn.Forte@Sun.COM 16217836SJohn.Forte@Sun.COM if (fctl_busy_port(port) != 0) { 16227836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 16237836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 16247836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16257836SJohn.Forte@Sun.COM return (FC_FAILURE); 16267836SJohn.Forte@Sun.COM } 16277836SJohn.Forte@Sun.COM 16287836SJohn.Forte@Sun.COM if (sleep == KM_SLEEP) { 16297836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep); 16307836SJohn.Forte@Sun.COM ASSERT(job != NULL); 16317836SJohn.Forte@Sun.COM 16327836SJohn.Forte@Sun.COM job->job_private = (void *)pwwn; 16337836SJohn.Forte@Sun.COM job->job_counter = 1; 16347836SJohn.Forte@Sun.COM fctl_enque_job(port, job); 16357836SJohn.Forte@Sun.COM fctl_jobwait(job); 16367836SJohn.Forte@Sun.COM 16377836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 16387836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 16397836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16407836SJohn.Forte@Sun.COM 16417836SJohn.Forte@Sun.COM fctl_idle_port(port); 16427836SJohn.Forte@Sun.COM 16437836SJohn.Forte@Sun.COM rval = job->job_result; 16447836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 16457836SJohn.Forte@Sun.COM } else { 16467836SJohn.Forte@Sun.COM job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC, 16477836SJohn.Forte@Sun.COM fctl_link_reset_done, port, sleep); 16487836SJohn.Forte@Sun.COM if (job == NULL) { 16497836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 16507836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 16517836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 16527836SJohn.Forte@Sun.COM fctl_idle_port(port); 16537836SJohn.Forte@Sun.COM return (FC_NOMEM); 16547836SJohn.Forte@Sun.COM } 16557836SJohn.Forte@Sun.COM job->job_private = (void *)pwwn; 16567836SJohn.Forte@Sun.COM job->job_counter = 1; 16577836SJohn.Forte@Sun.COM fctl_priority_enque_job(port, job); 16587836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 16597836SJohn.Forte@Sun.COM } 16607836SJohn.Forte@Sun.COM 16617836SJohn.Forte@Sun.COM return (rval); 16627836SJohn.Forte@Sun.COM } 16637836SJohn.Forte@Sun.COM 16647836SJohn.Forte@Sun.COM 16657836SJohn.Forte@Sun.COM int 16667836SJohn.Forte@Sun.COM fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd) 16677836SJohn.Forte@Sun.COM { 16687836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 16697836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 16707836SJohn.Forte@Sun.COM 16717836SJohn.Forte@Sun.COM switch (cmd) { 16727836SJohn.Forte@Sun.COM case FC_RESET_PORT: 16737836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 16747836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_LINK_RESET); 16757836SJohn.Forte@Sun.COM break; 16767836SJohn.Forte@Sun.COM 16777836SJohn.Forte@Sun.COM case FC_RESET_ADAPTER: 16787836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 16797836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_RESET); 16807836SJohn.Forte@Sun.COM break; 16817836SJohn.Forte@Sun.COM 16827836SJohn.Forte@Sun.COM case FC_RESET_DUMP: 16837836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 16847836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_CORE); 16857836SJohn.Forte@Sun.COM break; 16867836SJohn.Forte@Sun.COM 16877836SJohn.Forte@Sun.COM case FC_RESET_CRASH: 16887836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_reset( 16897836SJohn.Forte@Sun.COM port->fp_fca_handle, FC_FCA_RESET_CORE); 16907836SJohn.Forte@Sun.COM break; 16917836SJohn.Forte@Sun.COM 16927836SJohn.Forte@Sun.COM default: 16937836SJohn.Forte@Sun.COM rval = FC_FAILURE; 16947836SJohn.Forte@Sun.COM } 16957836SJohn.Forte@Sun.COM 16967836SJohn.Forte@Sun.COM return (rval); 16977836SJohn.Forte@Sun.COM } 16987836SJohn.Forte@Sun.COM 16997836SJohn.Forte@Sun.COM 17007836SJohn.Forte@Sun.COM int 17017836SJohn.Forte@Sun.COM fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params) 17027836SJohn.Forte@Sun.COM { 17037836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 17047836SJohn.Forte@Sun.COM 17057836SJohn.Forte@Sun.COM /* Copy the login parameters */ 17067836SJohn.Forte@Sun.COM *login_params = port->fp_service_params; 17077836SJohn.Forte@Sun.COM return (FC_SUCCESS); 17087836SJohn.Forte@Sun.COM } 17097836SJohn.Forte@Sun.COM 17107836SJohn.Forte@Sun.COM 17117836SJohn.Forte@Sun.COM int 17127836SJohn.Forte@Sun.COM fc_ulp_get_port_instance(opaque_t port_handle) 17137836SJohn.Forte@Sun.COM { 17147836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 17157836SJohn.Forte@Sun.COM 17167836SJohn.Forte@Sun.COM return (port->fp_instance); 17177836SJohn.Forte@Sun.COM } 17187836SJohn.Forte@Sun.COM 17197836SJohn.Forte@Sun.COM 17207836SJohn.Forte@Sun.COM opaque_t 17217836SJohn.Forte@Sun.COM fc_ulp_get_port_handle(int port_instance) 17227836SJohn.Forte@Sun.COM { 17237836SJohn.Forte@Sun.COM opaque_t port_handle = NULL; 172410264SZhong.Wang@Sun.COM fc_fca_port_t *cur; 17257836SJohn.Forte@Sun.COM 17267836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 17277836SJohn.Forte@Sun.COM for (cur = fctl_fca_portlist; cur; cur = cur->port_next) { 17287836SJohn.Forte@Sun.COM if (cur->port_handle->fp_instance == port_instance) { 17297836SJohn.Forte@Sun.COM port_handle = (opaque_t)cur->port_handle; 17307836SJohn.Forte@Sun.COM break; 17317836SJohn.Forte@Sun.COM } 17327836SJohn.Forte@Sun.COM } 17337836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 17347836SJohn.Forte@Sun.COM 17357836SJohn.Forte@Sun.COM return (port_handle); 17367836SJohn.Forte@Sun.COM } 17377836SJohn.Forte@Sun.COM 17387836SJohn.Forte@Sun.COM 17397836SJohn.Forte@Sun.COM int 17407836SJohn.Forte@Sun.COM fc_ulp_error(int fc_errno, char **errmsg) 17417836SJohn.Forte@Sun.COM { 17427836SJohn.Forte@Sun.COM return (fctl_error(fc_errno, errmsg)); 17437836SJohn.Forte@Sun.COM } 17447836SJohn.Forte@Sun.COM 17457836SJohn.Forte@Sun.COM 17467836SJohn.Forte@Sun.COM int 17477836SJohn.Forte@Sun.COM fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason, 17487836SJohn.Forte@Sun.COM char **action, char **expln) 17497836SJohn.Forte@Sun.COM { 17507836SJohn.Forte@Sun.COM return (fctl_pkt_error(pkt, state, reason, action, expln)); 17517836SJohn.Forte@Sun.COM } 17527836SJohn.Forte@Sun.COM 17537836SJohn.Forte@Sun.COM 17547836SJohn.Forte@Sun.COM /* 17557836SJohn.Forte@Sun.COM * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE 17567836SJohn.Forte@Sun.COM */ 17577836SJohn.Forte@Sun.COM int 17587836SJohn.Forte@Sun.COM fc_ulp_is_name_present(caddr_t ulp_name) 17597836SJohn.Forte@Sun.COM { 17607836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 17617836SJohn.Forte@Sun.COM fc_ulp_list_t *list; 17627836SJohn.Forte@Sun.COM 17637836SJohn.Forte@Sun.COM mutex_enter(&fctl_ulp_list_mutex); 17647836SJohn.Forte@Sun.COM for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) { 17657836SJohn.Forte@Sun.COM if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) { 17667836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 17677836SJohn.Forte@Sun.COM break; 17687836SJohn.Forte@Sun.COM } 17697836SJohn.Forte@Sun.COM } 17707836SJohn.Forte@Sun.COM mutex_exit(&fctl_ulp_list_mutex); 17717836SJohn.Forte@Sun.COM 17727836SJohn.Forte@Sun.COM return (rval); 17737836SJohn.Forte@Sun.COM } 17747836SJohn.Forte@Sun.COM 17757836SJohn.Forte@Sun.COM 17767836SJohn.Forte@Sun.COM /* 17777836SJohn.Forte@Sun.COM * Return port WWN for a port Identifier 17787836SJohn.Forte@Sun.COM */ 17797836SJohn.Forte@Sun.COM int 17807836SJohn.Forte@Sun.COM fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn) 17817836SJohn.Forte@Sun.COM { 17827836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 17837836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 17847836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 17857836SJohn.Forte@Sun.COM 17867836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_did(port, d_id.port_id); 17877836SJohn.Forte@Sun.COM if (pd != NULL) { 17887836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 17897836SJohn.Forte@Sun.COM *pwwn = pd->pd_port_name; 17907836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 17917836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 17927836SJohn.Forte@Sun.COM } 17937836SJohn.Forte@Sun.COM 17947836SJohn.Forte@Sun.COM return (rval); 17957836SJohn.Forte@Sun.COM } 17967836SJohn.Forte@Sun.COM 17977836SJohn.Forte@Sun.COM 17987836SJohn.Forte@Sun.COM /* 17997836SJohn.Forte@Sun.COM * Return a port map for a port WWN 18007836SJohn.Forte@Sun.COM */ 18017836SJohn.Forte@Sun.COM int 18027836SJohn.Forte@Sun.COM fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map) 18037836SJohn.Forte@Sun.COM { 18047836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 18057836SJohn.Forte@Sun.COM fc_remote_node_t *node; 180610264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 18077836SJohn.Forte@Sun.COM 18087836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, bytes); 18097836SJohn.Forte@Sun.COM if (pd == NULL) { 18107836SJohn.Forte@Sun.COM return (FC_FAILURE); 18117836SJohn.Forte@Sun.COM } 18127836SJohn.Forte@Sun.COM 18137836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 18147836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 18157836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 18167836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 18177836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 18187836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 18197836SJohn.Forte@Sun.COM map->map_flags = 0; 18207836SJohn.Forte@Sun.COM 18217836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 18227836SJohn.Forte@Sun.COM 18237836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 18247836SJohn.Forte@Sun.COM 18257836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 18267836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 18277836SJohn.Forte@Sun.COM 18287836SJohn.Forte@Sun.COM if (node) { 18297836SJohn.Forte@Sun.COM mutex_enter(&node->fd_mutex); 18307836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 18317836SJohn.Forte@Sun.COM mutex_exit(&node->fd_mutex); 18327836SJohn.Forte@Sun.COM } 18337836SJohn.Forte@Sun.COM map->map_pd = pd; 18347836SJohn.Forte@Sun.COM 18357836SJohn.Forte@Sun.COM return (FC_SUCCESS); 18367836SJohn.Forte@Sun.COM } 18377836SJohn.Forte@Sun.COM 18387836SJohn.Forte@Sun.COM 18397836SJohn.Forte@Sun.COM opaque_t 18407836SJohn.Forte@Sun.COM fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id) 18417836SJohn.Forte@Sun.COM { 18427836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 18437836SJohn.Forte@Sun.COM 18447836SJohn.Forte@Sun.COM if (port->fp_fca_tran->fca_get_device == NULL) { 18457836SJohn.Forte@Sun.COM return (NULL); 18467836SJohn.Forte@Sun.COM } 18477836SJohn.Forte@Sun.COM 18487836SJohn.Forte@Sun.COM return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id)); 18497836SJohn.Forte@Sun.COM } 18507836SJohn.Forte@Sun.COM 18517836SJohn.Forte@Sun.COM 18527836SJohn.Forte@Sun.COM int 18537836SJohn.Forte@Sun.COM fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd) 18547836SJohn.Forte@Sun.COM { 18557836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 18567836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 18577836SJohn.Forte@Sun.COM 18587836SJohn.Forte@Sun.COM if (port->fp_fca_tran->fca_notify) { 18597836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 18607836SJohn.Forte@Sun.COM switch (cmd) { 18617836SJohn.Forte@Sun.COM case FC_NOTIFY_TARGET_MODE: 18627836SJohn.Forte@Sun.COM port->fp_options |= FP_TARGET_MODE; 18637836SJohn.Forte@Sun.COM break; 18647836SJohn.Forte@Sun.COM case FC_NOTIFY_NO_TARGET_MODE: 18657836SJohn.Forte@Sun.COM port->fp_options &= ~FP_TARGET_MODE; 18667836SJohn.Forte@Sun.COM break; 18677836SJohn.Forte@Sun.COM } 18687836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 18697836SJohn.Forte@Sun.COM rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd); 18707836SJohn.Forte@Sun.COM } 18717836SJohn.Forte@Sun.COM 18727836SJohn.Forte@Sun.COM return (rval); 18737836SJohn.Forte@Sun.COM } 18747836SJohn.Forte@Sun.COM 18757836SJohn.Forte@Sun.COM 18767836SJohn.Forte@Sun.COM void 18777836SJohn.Forte@Sun.COM fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 18787836SJohn.Forte@Sun.COM { 18797836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 18807836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 18817836SJohn.Forte@Sun.COM 18827836SJohn.Forte@Sun.COM if (pd) { 18837836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 18847836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_DISABLE_RELOGIN; 18857836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 18867836SJohn.Forte@Sun.COM } 18877836SJohn.Forte@Sun.COM } 18887836SJohn.Forte@Sun.COM 18897836SJohn.Forte@Sun.COM 18907836SJohn.Forte@Sun.COM void 18917836SJohn.Forte@Sun.COM fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn) 18927836SJohn.Forte@Sun.COM { 18937836SJohn.Forte@Sun.COM fc_remote_port_t *pd = 18947836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn); 18957836SJohn.Forte@Sun.COM 18967836SJohn.Forte@Sun.COM if (pd) { 18977836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 18987836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN; 18997836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 19007836SJohn.Forte@Sun.COM } 19017836SJohn.Forte@Sun.COM } 19027836SJohn.Forte@Sun.COM 19037836SJohn.Forte@Sun.COM 19047836SJohn.Forte@Sun.COM /* 19057836SJohn.Forte@Sun.COM * fc_fca_init 190610264SZhong.Wang@Sun.COM * Overload the FCA bus_ops vector in its dev_ops with 19077836SJohn.Forte@Sun.COM * fctl_fca_busops to handle all the INITchilds for "sf" 19087836SJohn.Forte@Sun.COM * in one common place. 19097836SJohn.Forte@Sun.COM * 19107836SJohn.Forte@Sun.COM * Should be called from FCA _init routine. 19117836SJohn.Forte@Sun.COM */ 19127836SJohn.Forte@Sun.COM void 19137836SJohn.Forte@Sun.COM fc_fca_init(struct dev_ops *fca_devops_p) 19147836SJohn.Forte@Sun.COM { 19157836SJohn.Forte@Sun.COM #ifndef __lock_lint 19167836SJohn.Forte@Sun.COM fca_devops_p->devo_bus_ops = &fctl_fca_busops; 19177836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 19187836SJohn.Forte@Sun.COM } 19197836SJohn.Forte@Sun.COM 19207836SJohn.Forte@Sun.COM 19217836SJohn.Forte@Sun.COM /* 19227836SJohn.Forte@Sun.COM * fc_fca_attach 19237836SJohn.Forte@Sun.COM */ 19247836SJohn.Forte@Sun.COM int 19257836SJohn.Forte@Sun.COM fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran) 19267836SJohn.Forte@Sun.COM { 19277836SJohn.Forte@Sun.COM /* 19287836SJohn.Forte@Sun.COM * When we are in a position to offer downward compatibility 19297836SJohn.Forte@Sun.COM * we should change the following check to allow lower revision 19307836SJohn.Forte@Sun.COM * of FCAs; But we aren't there right now. 19317836SJohn.Forte@Sun.COM */ 19327836SJohn.Forte@Sun.COM if (tran->fca_version != FCTL_FCA_MODREV_5) { 19337836SJohn.Forte@Sun.COM const char *name = ddi_driver_name(fca_dip); 19347836SJohn.Forte@Sun.COM 19357836SJohn.Forte@Sun.COM ASSERT(name != NULL); 19367836SJohn.Forte@Sun.COM 19377836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl: FCA %s version mismatch" 19387836SJohn.Forte@Sun.COM " please upgrade %s", name, name); 19397836SJohn.Forte@Sun.COM return (DDI_FAILURE); 19407836SJohn.Forte@Sun.COM } 19417836SJohn.Forte@Sun.COM 19427836SJohn.Forte@Sun.COM ddi_set_driver_private(fca_dip, (caddr_t)tran); 19437836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 19447836SJohn.Forte@Sun.COM } 19457836SJohn.Forte@Sun.COM 19467836SJohn.Forte@Sun.COM 19477836SJohn.Forte@Sun.COM /* 19487836SJohn.Forte@Sun.COM * fc_fca_detach 19497836SJohn.Forte@Sun.COM */ 19507836SJohn.Forte@Sun.COM int 19517836SJohn.Forte@Sun.COM fc_fca_detach(dev_info_t *fca_dip) 19527836SJohn.Forte@Sun.COM { 19537836SJohn.Forte@Sun.COM ddi_set_driver_private(fca_dip, NULL); 19547836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 19557836SJohn.Forte@Sun.COM } 19567836SJohn.Forte@Sun.COM 19577836SJohn.Forte@Sun.COM 19587836SJohn.Forte@Sun.COM /* 19597836SJohn.Forte@Sun.COM * Check if the frame is a Link response Frame; Handle all cases (P_RJT, 19607836SJohn.Forte@Sun.COM * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic 19617836SJohn.Forte@Sun.COM * Link Service responses such as BA_RJT and Extended Link Service response 19627836SJohn.Forte@Sun.COM * such as LS_RJT. If the response is a Link_Data Frame or something that 19637836SJohn.Forte@Sun.COM * this function doesn't understand return FC_FAILURE; Otherwise, fill out 19647836SJohn.Forte@Sun.COM * various fields (state, action, reason, expln) from the response gotten 19657836SJohn.Forte@Sun.COM * in the packet and return FC_SUCCESS. 19667836SJohn.Forte@Sun.COM */ 19677836SJohn.Forte@Sun.COM int 19687836SJohn.Forte@Sun.COM fc_fca_update_errors(fc_packet_t *pkt) 19697836SJohn.Forte@Sun.COM { 19707836SJohn.Forte@Sun.COM int ret = FC_SUCCESS; 19717836SJohn.Forte@Sun.COM 19727836SJohn.Forte@Sun.COM switch (pkt->pkt_resp_fhdr.r_ctl) { 19737836SJohn.Forte@Sun.COM case R_CTL_P_RJT: { 19747836SJohn.Forte@Sun.COM uint32_t prjt; 19757836SJohn.Forte@Sun.COM 19767836SJohn.Forte@Sun.COM prjt = pkt->pkt_resp_fhdr.ro; 19777836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_NPORT_RJT; 19787836SJohn.Forte@Sun.COM pkt->pkt_action = (prjt & 0xFF000000) >> 24; 19797836SJohn.Forte@Sun.COM pkt->pkt_reason = (prjt & 0xFF0000) >> 16; 19807836SJohn.Forte@Sun.COM break; 19817836SJohn.Forte@Sun.COM } 19827836SJohn.Forte@Sun.COM 19837836SJohn.Forte@Sun.COM case R_CTL_F_RJT: { 19847836SJohn.Forte@Sun.COM uint32_t frjt; 19857836SJohn.Forte@Sun.COM 19867836SJohn.Forte@Sun.COM frjt = pkt->pkt_resp_fhdr.ro; 19877836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_FABRIC_RJT; 19887836SJohn.Forte@Sun.COM pkt->pkt_action = (frjt & 0xFF000000) >> 24; 19897836SJohn.Forte@Sun.COM pkt->pkt_reason = (frjt & 0xFF0000) >> 16; 19907836SJohn.Forte@Sun.COM break; 19917836SJohn.Forte@Sun.COM } 19927836SJohn.Forte@Sun.COM 19937836SJohn.Forte@Sun.COM case R_CTL_P_BSY: { 19947836SJohn.Forte@Sun.COM uint32_t pbsy; 19957836SJohn.Forte@Sun.COM 19967836SJohn.Forte@Sun.COM pbsy = pkt->pkt_resp_fhdr.ro; 19977836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_NPORT_BSY; 19987836SJohn.Forte@Sun.COM pkt->pkt_action = (pbsy & 0xFF000000) >> 24; 19997836SJohn.Forte@Sun.COM pkt->pkt_reason = (pbsy & 0xFF0000) >> 16; 20007836SJohn.Forte@Sun.COM break; 20017836SJohn.Forte@Sun.COM } 20027836SJohn.Forte@Sun.COM 20037836SJohn.Forte@Sun.COM case R_CTL_F_BSY_LC: 20047836SJohn.Forte@Sun.COM case R_CTL_F_BSY_DF: { 20057836SJohn.Forte@Sun.COM uchar_t fbsy; 20067836SJohn.Forte@Sun.COM 20077836SJohn.Forte@Sun.COM fbsy = pkt->pkt_resp_fhdr.type; 20087836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_FABRIC_BSY; 20097836SJohn.Forte@Sun.COM pkt->pkt_reason = (fbsy & 0xF0) >> 4; 20107836SJohn.Forte@Sun.COM break; 20117836SJohn.Forte@Sun.COM } 20127836SJohn.Forte@Sun.COM 20137836SJohn.Forte@Sun.COM case R_CTL_LS_BA_RJT: { 20147836SJohn.Forte@Sun.COM uint32_t brjt; 20157836SJohn.Forte@Sun.COM 20167836SJohn.Forte@Sun.COM brjt = *(uint32_t *)pkt->pkt_resp; 20177836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_BA_RJT; 20187836SJohn.Forte@Sun.COM pkt->pkt_reason = (brjt & 0xFF0000) >> 16; 20197836SJohn.Forte@Sun.COM pkt->pkt_expln = (brjt & 0xFF00) >> 8; 20207836SJohn.Forte@Sun.COM break; 20217836SJohn.Forte@Sun.COM } 20227836SJohn.Forte@Sun.COM 20237836SJohn.Forte@Sun.COM case R_CTL_ELS_RSP: { 20247836SJohn.Forte@Sun.COM la_els_rjt_t *lsrjt; 20257836SJohn.Forte@Sun.COM 20267836SJohn.Forte@Sun.COM lsrjt = (la_els_rjt_t *)pkt->pkt_resp; 20277836SJohn.Forte@Sun.COM if (lsrjt->ls_code.ls_code == LA_ELS_RJT) { 20287836SJohn.Forte@Sun.COM pkt->pkt_state = FC_PKT_LS_RJT; 20297836SJohn.Forte@Sun.COM pkt->pkt_reason = lsrjt->reason; 20307836SJohn.Forte@Sun.COM pkt->pkt_action = lsrjt->action; 20317836SJohn.Forte@Sun.COM break; 20327836SJohn.Forte@Sun.COM } 20337836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 20347836SJohn.Forte@Sun.COM } 20357836SJohn.Forte@Sun.COM 20367836SJohn.Forte@Sun.COM default: 20377836SJohn.Forte@Sun.COM ret = FC_FAILURE; 20387836SJohn.Forte@Sun.COM break; 20397836SJohn.Forte@Sun.COM } 20407836SJohn.Forte@Sun.COM 20417836SJohn.Forte@Sun.COM return (ret); 20427836SJohn.Forte@Sun.COM } 20437836SJohn.Forte@Sun.COM 20447836SJohn.Forte@Sun.COM 20457836SJohn.Forte@Sun.COM int 20467836SJohn.Forte@Sun.COM fc_fca_error(int fc_errno, char **errmsg) 20477836SJohn.Forte@Sun.COM { 20487836SJohn.Forte@Sun.COM return (fctl_error(fc_errno, errmsg)); 20497836SJohn.Forte@Sun.COM } 20507836SJohn.Forte@Sun.COM 20517836SJohn.Forte@Sun.COM 20527836SJohn.Forte@Sun.COM int 20537836SJohn.Forte@Sun.COM fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason, 20547836SJohn.Forte@Sun.COM char **action, char **expln) 20557836SJohn.Forte@Sun.COM { 20567836SJohn.Forte@Sun.COM return (fctl_pkt_error(pkt, state, reason, action, expln)); 20577836SJohn.Forte@Sun.COM } 20587836SJohn.Forte@Sun.COM 20597836SJohn.Forte@Sun.COM 20607836SJohn.Forte@Sun.COM /* 20617836SJohn.Forte@Sun.COM * WWN to string goodie. Unpredictable results will happen 20627836SJohn.Forte@Sun.COM * if enough memory isn't supplied in str argument. If you 20637836SJohn.Forte@Sun.COM * are wondering how much does this routine need, it is just 20647836SJohn.Forte@Sun.COM * (2 * WWN size + 1). So for a WWN size of 8 bytes the str 20657836SJohn.Forte@Sun.COM * argument should have atleast 17 bytes allocated. 20667836SJohn.Forte@Sun.COM */ 20677836SJohn.Forte@Sun.COM void 20687836SJohn.Forte@Sun.COM fc_wwn_to_str(la_wwn_t *wwn, caddr_t str) 20697836SJohn.Forte@Sun.COM { 20707836SJohn.Forte@Sun.COM int count; 20717836SJohn.Forte@Sun.COM 20727836SJohn.Forte@Sun.COM for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) { 20737836SJohn.Forte@Sun.COM (void) sprintf(str, "%02x", wwn->raw_wwn[count]); 20747836SJohn.Forte@Sun.COM } 20757836SJohn.Forte@Sun.COM *str = '\0'; 20767836SJohn.Forte@Sun.COM } 20777836SJohn.Forte@Sun.COM 207810264SZhong.Wang@Sun.COM #define FC_ATOB(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : \ 207910264SZhong.Wang@Sun.COM ((x) >= 'a' && (x) <= 'f') ? \ 20807836SJohn.Forte@Sun.COM ((x) - 'a' + 10) : ((x) - 'A' + 10)) 20817836SJohn.Forte@Sun.COM 20827836SJohn.Forte@Sun.COM void 20837836SJohn.Forte@Sun.COM fc_str_to_wwn(caddr_t str, la_wwn_t *wwn) 20847836SJohn.Forte@Sun.COM { 20857836SJohn.Forte@Sun.COM int count = 0; 20867836SJohn.Forte@Sun.COM uchar_t byte; 20877836SJohn.Forte@Sun.COM 20887836SJohn.Forte@Sun.COM while (*str) { 20897836SJohn.Forte@Sun.COM byte = FC_ATOB(*str); 20907836SJohn.Forte@Sun.COM str++; 20917836SJohn.Forte@Sun.COM byte = byte << 4 | FC_ATOB(*str); 20927836SJohn.Forte@Sun.COM str++; 20937836SJohn.Forte@Sun.COM wwn->raw_wwn[count++] = byte; 20947836SJohn.Forte@Sun.COM } 20957836SJohn.Forte@Sun.COM } 20967836SJohn.Forte@Sun.COM 20977836SJohn.Forte@Sun.COM /* 20987836SJohn.Forte@Sun.COM * FCA driver's intercepted bus control operations. 20997836SJohn.Forte@Sun.COM */ 21007836SJohn.Forte@Sun.COM static int 21017836SJohn.Forte@Sun.COM fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 210210264SZhong.Wang@Sun.COM ddi_ctl_enum_t op, void *arg, void *result) 21037836SJohn.Forte@Sun.COM { 21047836SJohn.Forte@Sun.COM switch (op) { 21057836SJohn.Forte@Sun.COM case DDI_CTLOPS_REPORTDEV: 21067836SJohn.Forte@Sun.COM break; 21077836SJohn.Forte@Sun.COM 21087836SJohn.Forte@Sun.COM case DDI_CTLOPS_IOMIN: 21097836SJohn.Forte@Sun.COM break; 21107836SJohn.Forte@Sun.COM 21117836SJohn.Forte@Sun.COM case DDI_CTLOPS_INITCHILD: 21127836SJohn.Forte@Sun.COM return (fctl_initchild(fca_dip, (dev_info_t *)arg)); 21137836SJohn.Forte@Sun.COM 21147836SJohn.Forte@Sun.COM case DDI_CTLOPS_UNINITCHILD: 21157836SJohn.Forte@Sun.COM return (fctl_uninitchild(fca_dip, (dev_info_t *)arg)); 21167836SJohn.Forte@Sun.COM 21177836SJohn.Forte@Sun.COM default: 21187836SJohn.Forte@Sun.COM return (ddi_ctlops(fca_dip, rip, op, arg, result)); 21197836SJohn.Forte@Sun.COM } 21207836SJohn.Forte@Sun.COM 21217836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 21227836SJohn.Forte@Sun.COM } 21237836SJohn.Forte@Sun.COM 21247836SJohn.Forte@Sun.COM 21257836SJohn.Forte@Sun.COM /* 21267836SJohn.Forte@Sun.COM * FCAs indicate the maximum number of ports supported in their 21277836SJohn.Forte@Sun.COM * tran structure. Fail the INITCHILD if the child port number 21287836SJohn.Forte@Sun.COM * is any greater than the maximum number of ports supported 21297836SJohn.Forte@Sun.COM * by the FCA. 21307836SJohn.Forte@Sun.COM */ 21317836SJohn.Forte@Sun.COM static int 21327836SJohn.Forte@Sun.COM fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip) 21337836SJohn.Forte@Sun.COM { 213410264SZhong.Wang@Sun.COM int rval; 213510264SZhong.Wang@Sun.COM int port_no; 213610264SZhong.Wang@Sun.COM int port_len; 213710264SZhong.Wang@Sun.COM char name[20]; 213810264SZhong.Wang@Sun.COM fc_fca_tran_t *tran; 21397836SJohn.Forte@Sun.COM dev_info_t *dip; 21407836SJohn.Forte@Sun.COM int portprop; 21417836SJohn.Forte@Sun.COM 21427836SJohn.Forte@Sun.COM port_len = sizeof (port_no); 21437836SJohn.Forte@Sun.COM 21447836SJohn.Forte@Sun.COM /* physical port do not has this property */ 21457836SJohn.Forte@Sun.COM portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip, 21467836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 21477836SJohn.Forte@Sun.COM "phyport-instance", -1); 21487836SJohn.Forte@Sun.COM 21497836SJohn.Forte@Sun.COM if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) { 21507836SJohn.Forte@Sun.COM /* 21517836SJohn.Forte@Sun.COM * Clear any addr bindings created by fcode interpreter 21527836SJohn.Forte@Sun.COM * in devi_last_addr so that a ndi_devi_find should never 21537836SJohn.Forte@Sun.COM * return this fcode node. 21547836SJohn.Forte@Sun.COM */ 21557836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 21567836SJohn.Forte@Sun.COM return (DDI_FAILURE); 21577836SJohn.Forte@Sun.COM } 21587836SJohn.Forte@Sun.COM 21597836SJohn.Forte@Sun.COM rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF, 21607836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port", 21617836SJohn.Forte@Sun.COM (caddr_t)&port_no, &port_len); 21627836SJohn.Forte@Sun.COM 21637836SJohn.Forte@Sun.COM if (rval != DDI_SUCCESS) { 21647836SJohn.Forte@Sun.COM return (DDI_FAILURE); 21657836SJohn.Forte@Sun.COM } 21667836SJohn.Forte@Sun.COM 21677836SJohn.Forte@Sun.COM tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip); 21687836SJohn.Forte@Sun.COM ASSERT(tran != NULL); 21697836SJohn.Forte@Sun.COM 21707836SJohn.Forte@Sun.COM (void) sprintf((char *)name, "%x,0", port_no); 21717836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, name); 21727836SJohn.Forte@Sun.COM 21737836SJohn.Forte@Sun.COM dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 21747836SJohn.Forte@Sun.COM 21757836SJohn.Forte@Sun.COM /* 21767836SJohn.Forte@Sun.COM * Even though we never initialize FCode nodes of fp, such a node 21777836SJohn.Forte@Sun.COM * could still be there after a DR operation. There will only be 21787836SJohn.Forte@Sun.COM * one FCode node, so if this is the one, clear it and issue a 21797836SJohn.Forte@Sun.COM * ndi_devi_find again. 21807836SJohn.Forte@Sun.COM */ 21817836SJohn.Forte@Sun.COM if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) { 21827836SJohn.Forte@Sun.COM ddi_set_name_addr(dip, NULL); 21837836SJohn.Forte@Sun.COM dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name); 21847836SJohn.Forte@Sun.COM } 21857836SJohn.Forte@Sun.COM 21867836SJohn.Forte@Sun.COM if ((portprop == -1) && dip && (dip != port_dip)) { 21877836SJohn.Forte@Sun.COM /* 21887836SJohn.Forte@Sun.COM * Here we have a duplicate .conf entry. Clear the addr 21897836SJohn.Forte@Sun.COM * set previously and return failure. 21907836SJohn.Forte@Sun.COM */ 21917836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 21927836SJohn.Forte@Sun.COM return (DDI_FAILURE); 21937836SJohn.Forte@Sun.COM } 21947836SJohn.Forte@Sun.COM 21957836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 21967836SJohn.Forte@Sun.COM } 21977836SJohn.Forte@Sun.COM 21987836SJohn.Forte@Sun.COM 21997836SJohn.Forte@Sun.COM /* ARGSUSED */ 22007836SJohn.Forte@Sun.COM static int 22017836SJohn.Forte@Sun.COM fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip) 22027836SJohn.Forte@Sun.COM { 22037836SJohn.Forte@Sun.COM ddi_set_name_addr(port_dip, NULL); 22047836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 22057836SJohn.Forte@Sun.COM } 22067836SJohn.Forte@Sun.COM 22077836SJohn.Forte@Sun.COM 22087836SJohn.Forte@Sun.COM static dev_info_t * 22097836SJohn.Forte@Sun.COM fctl_findchild(dev_info_t *pdip, char *cname, char *caddr) 22107836SJohn.Forte@Sun.COM { 22117836SJohn.Forte@Sun.COM dev_info_t *dip; 22127836SJohn.Forte@Sun.COM char *addr; 22137836SJohn.Forte@Sun.COM 22147836SJohn.Forte@Sun.COM ASSERT(cname != NULL && caddr != NULL); 22157836SJohn.Forte@Sun.COM /* ASSERT(DEVI_BUSY_OWNED(pdip)); */ 22167836SJohn.Forte@Sun.COM 22177836SJohn.Forte@Sun.COM for (dip = ddi_get_child(pdip); dip != NULL; 22187836SJohn.Forte@Sun.COM dip = ddi_get_next_sibling(dip)) { 221910264SZhong.Wang@Sun.COM if (strcmp(cname, ddi_node_name(dip)) != 0) { 22207836SJohn.Forte@Sun.COM continue; 222110264SZhong.Wang@Sun.COM } 22227836SJohn.Forte@Sun.COM 22237836SJohn.Forte@Sun.COM if ((addr = ddi_get_name_addr(dip)) == NULL) { 22247836SJohn.Forte@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 22257836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 22267836SJohn.Forte@Sun.COM "bus-addr", &addr) == DDI_PROP_SUCCESS) { 22277836SJohn.Forte@Sun.COM if (strcmp(caddr, addr) == 0) { 22287836SJohn.Forte@Sun.COM ddi_prop_free(addr); 22297836SJohn.Forte@Sun.COM return (dip); 22307836SJohn.Forte@Sun.COM } 22317836SJohn.Forte@Sun.COM ddi_prop_free(addr); 22327836SJohn.Forte@Sun.COM } 22337836SJohn.Forte@Sun.COM } else { 223410264SZhong.Wang@Sun.COM if (strcmp(caddr, addr) == 0) { 22357836SJohn.Forte@Sun.COM return (dip); 223610264SZhong.Wang@Sun.COM } 22377836SJohn.Forte@Sun.COM } 22387836SJohn.Forte@Sun.COM } 22397836SJohn.Forte@Sun.COM 22407836SJohn.Forte@Sun.COM return (NULL); 22417836SJohn.Forte@Sun.COM } 22427836SJohn.Forte@Sun.COM 22437836SJohn.Forte@Sun.COM int 22447836SJohn.Forte@Sun.COM fctl_check_npiv_portindex(dev_info_t *dip, int vindex) 22457836SJohn.Forte@Sun.COM { 22467836SJohn.Forte@Sun.COM int i, instance; 22477836SJohn.Forte@Sun.COM fc_local_port_t *port; 22487836SJohn.Forte@Sun.COM 22497836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 22507836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 22517836SJohn.Forte@Sun.COM if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) { 22527836SJohn.Forte@Sun.COM return (0); 22537836SJohn.Forte@Sun.COM } 22547836SJohn.Forte@Sun.COM 22557836SJohn.Forte@Sun.COM i = vindex-1; 22567836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 22577836SJohn.Forte@Sun.COM if (port->fp_npiv_portindex[i] == 0) { 22587836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 22597836SJohn.Forte@Sun.COM return (vindex); 22607836SJohn.Forte@Sun.COM } 22617836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 22627836SJohn.Forte@Sun.COM return (0); 22637836SJohn.Forte@Sun.COM } 22647836SJohn.Forte@Sun.COM 22657836SJohn.Forte@Sun.COM int 22667836SJohn.Forte@Sun.COM fctl_get_npiv_portindex(dev_info_t *dip) 22677836SJohn.Forte@Sun.COM { 22687836SJohn.Forte@Sun.COM int i, instance; 22697836SJohn.Forte@Sun.COM fc_local_port_t *port; 22707836SJohn.Forte@Sun.COM 22717836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 22727836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 22737836SJohn.Forte@Sun.COM if (!port) { 22747836SJohn.Forte@Sun.COM return (0); 22757836SJohn.Forte@Sun.COM } 22767836SJohn.Forte@Sun.COM 22777836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 22787836SJohn.Forte@Sun.COM for (i = 0; i < FC_NPIV_MAX_PORT; i++) { 22797836SJohn.Forte@Sun.COM if (port->fp_npiv_portindex[i] == 0) { 22807836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 22817836SJohn.Forte@Sun.COM return (i+1); 22827836SJohn.Forte@Sun.COM } 22837836SJohn.Forte@Sun.COM } 22847836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 22857836SJohn.Forte@Sun.COM return (0); 22867836SJohn.Forte@Sun.COM } 22877836SJohn.Forte@Sun.COM 22887836SJohn.Forte@Sun.COM 22897836SJohn.Forte@Sun.COM void 22907836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(dev_info_t *dip, int index) 22917836SJohn.Forte@Sun.COM { 22927836SJohn.Forte@Sun.COM int instance; 22937836SJohn.Forte@Sun.COM fc_local_port_t *port; 22947836SJohn.Forte@Sun.COM 22957836SJohn.Forte@Sun.COM instance = ddi_get_instance(dip); 22967836SJohn.Forte@Sun.COM port = (fc_local_port_t *)fc_ulp_get_port_handle(instance); 22977836SJohn.Forte@Sun.COM if (!port) { 22987836SJohn.Forte@Sun.COM return; 22997836SJohn.Forte@Sun.COM } 23007836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 23017836SJohn.Forte@Sun.COM port->fp_npiv_portindex[index - 1] = 1; 23027836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 23037836SJohn.Forte@Sun.COM } 23047836SJohn.Forte@Sun.COM 23057836SJohn.Forte@Sun.COM 23067836SJohn.Forte@Sun.COM int 23077836SJohn.Forte@Sun.COM fctl_fca_create_npivport(dev_info_t *parent, 23087836SJohn.Forte@Sun.COM dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex) 23097836SJohn.Forte@Sun.COM { 23107836SJohn.Forte@Sun.COM int rval = 0, devstrlen; 231110264SZhong.Wang@Sun.COM char *devname, *cname, *caddr, *devstr; 23127836SJohn.Forte@Sun.COM dev_info_t *child = NULL; 23137836SJohn.Forte@Sun.COM int portnum; 23147836SJohn.Forte@Sun.COM 23157836SJohn.Forte@Sun.COM if (*vindex == 0) { 23167836SJohn.Forte@Sun.COM portnum = fctl_get_npiv_portindex(phydip); 23177836SJohn.Forte@Sun.COM *vindex = portnum; 23187836SJohn.Forte@Sun.COM } else { 23197836SJohn.Forte@Sun.COM portnum = fctl_check_npiv_portindex(phydip, *vindex); 23207836SJohn.Forte@Sun.COM } 23217836SJohn.Forte@Sun.COM 23227836SJohn.Forte@Sun.COM if (portnum == 0) { 23237836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 23247836SJohn.Forte@Sun.COM "Cann't find valid port index, fail to create devnode"); 23257836SJohn.Forte@Sun.COM return (NDI_FAILURE); 23267836SJohn.Forte@Sun.COM } 23277836SJohn.Forte@Sun.COM 23287836SJohn.Forte@Sun.COM devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 23297836SJohn.Forte@Sun.COM (void) sprintf(devname, "fp@%x,0", portnum); 23307836SJohn.Forte@Sun.COM devstrlen = strlen(devname) + 1; 23317836SJohn.Forte@Sun.COM devstr = i_ddi_strdup(devname, KM_SLEEP); 23327836SJohn.Forte@Sun.COM i_ddi_parse_name(devstr, &cname, &caddr, NULL); 23337836SJohn.Forte@Sun.COM 23347836SJohn.Forte@Sun.COM if (fctl_findchild(parent, cname, caddr) != NULL) { 23357836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23367836SJohn.Forte@Sun.COM goto freememory; 23377836SJohn.Forte@Sun.COM } 23387836SJohn.Forte@Sun.COM 23397836SJohn.Forte@Sun.COM ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child); 23407836SJohn.Forte@Sun.COM if (child == NULL) { 23417836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 23427836SJohn.Forte@Sun.COM "fctl_create_npiv_port fail to create new devinfo"); 23437836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23447836SJohn.Forte@Sun.COM goto freememory; 23457836SJohn.Forte@Sun.COM } 23467836SJohn.Forte@Sun.COM 23477836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 23487836SJohn.Forte@Sun.COM "bus-addr", caddr) != DDI_PROP_SUCCESS) { 23497836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed", 23507836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 23517836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 23527836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23537836SJohn.Forte@Sun.COM goto freememory; 23547836SJohn.Forte@Sun.COM } 23557836SJohn.Forte@Sun.COM 23567836SJohn.Forte@Sun.COM if (strlen(nname) != 0) { 23577836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 23587836SJohn.Forte@Sun.COM "node-name", nname) != DDI_PROP_SUCCESS) { 23597836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 23607836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23617836SJohn.Forte@Sun.COM goto freememory; 23627836SJohn.Forte@Sun.COM } 23637836SJohn.Forte@Sun.COM } 23647836SJohn.Forte@Sun.COM 23657836SJohn.Forte@Sun.COM if (strlen(pname) != 0) { 23667836SJohn.Forte@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 23677836SJohn.Forte@Sun.COM "port-name", pname) != DDI_PROP_SUCCESS) { 23687836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 23697836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23707836SJohn.Forte@Sun.COM goto freememory; 23717836SJohn.Forte@Sun.COM } 23727836SJohn.Forte@Sun.COM } 23737836SJohn.Forte@Sun.COM 23747836SJohn.Forte@Sun.COM if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 23757836SJohn.Forte@Sun.COM "port", portnum) != DDI_PROP_SUCCESS) { 23767836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed", 23777836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 23787836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 23797836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23807836SJohn.Forte@Sun.COM goto freememory; 23817836SJohn.Forte@Sun.COM } 23827836SJohn.Forte@Sun.COM 23837836SJohn.Forte@Sun.COM if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 23847836SJohn.Forte@Sun.COM "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) { 23857836SJohn.Forte@Sun.COM cmn_err(CE_WARN, 23867836SJohn.Forte@Sun.COM "fp%d: prop_update phyport-instance %s@%s failed", 23877836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname, caddr); 23887836SJohn.Forte@Sun.COM (void) ndi_devi_free(child); 23897836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23907836SJohn.Forte@Sun.COM goto freememory; 23917836SJohn.Forte@Sun.COM } 23927836SJohn.Forte@Sun.COM 23937836SJohn.Forte@Sun.COM rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); 23947836SJohn.Forte@Sun.COM if (rval != NDI_SUCCESS) { 23957836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fp%d: online_driver %s failed", 23967836SJohn.Forte@Sun.COM ddi_get_instance(parent), cname); 23977836SJohn.Forte@Sun.COM rval = NDI_FAILURE; 23987836SJohn.Forte@Sun.COM goto freememory; 23997836SJohn.Forte@Sun.COM } 24007836SJohn.Forte@Sun.COM 24017836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(phydip, portnum); 24027836SJohn.Forte@Sun.COM freememory: 24037836SJohn.Forte@Sun.COM kmem_free(devstr, devstrlen); 24047836SJohn.Forte@Sun.COM kmem_free(devname, MAXNAMELEN); 24057836SJohn.Forte@Sun.COM 24067836SJohn.Forte@Sun.COM return (rval); 24077836SJohn.Forte@Sun.COM } 24087836SJohn.Forte@Sun.COM 24097836SJohn.Forte@Sun.COM 24107836SJohn.Forte@Sun.COM void 24117836SJohn.Forte@Sun.COM fctl_add_port(fc_local_port_t *port) 24127836SJohn.Forte@Sun.COM { 24137836SJohn.Forte@Sun.COM fc_fca_port_t *new; 24147836SJohn.Forte@Sun.COM 24157836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), KM_SLEEP); 24167836SJohn.Forte@Sun.COM 24177836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 24187836SJohn.Forte@Sun.COM new->port_handle = port; 24197836SJohn.Forte@Sun.COM new->port_next = fctl_fca_portlist; 24207836SJohn.Forte@Sun.COM fctl_fca_portlist = new; 24217836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 24227836SJohn.Forte@Sun.COM } 24237836SJohn.Forte@Sun.COM 24247836SJohn.Forte@Sun.COM 24257836SJohn.Forte@Sun.COM void 24267836SJohn.Forte@Sun.COM fctl_remove_port(fc_local_port_t *port) 24277836SJohn.Forte@Sun.COM { 242810264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 242910264SZhong.Wang@Sun.COM fc_fca_port_t *prev; 243010264SZhong.Wang@Sun.COM fc_fca_port_t *list; 24317836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 24327836SJohn.Forte@Sun.COM 24337836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_WRITER); 24347836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 24357836SJohn.Forte@Sun.COM 24367836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 24377836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 24387836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 24397836SJohn.Forte@Sun.COM continue; 24407836SJohn.Forte@Sun.COM } 24417836SJohn.Forte@Sun.COM 24427836SJohn.Forte@Sun.COM #ifndef __lock_lint 24437836SJohn.Forte@Sun.COM ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0); 24447836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 24457836SJohn.Forte@Sun.COM 24467836SJohn.Forte@Sun.COM (void) fctl_remove_ulp_port(mod, port); 24477836SJohn.Forte@Sun.COM } 24487836SJohn.Forte@Sun.COM 24497836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 24507836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 24517836SJohn.Forte@Sun.COM 24527836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 24537836SJohn.Forte@Sun.COM 24547836SJohn.Forte@Sun.COM list = fctl_fca_portlist; 24557836SJohn.Forte@Sun.COM prev = NULL; 24567836SJohn.Forte@Sun.COM while (list != NULL) { 24577836SJohn.Forte@Sun.COM if (list->port_handle == port) { 24587836SJohn.Forte@Sun.COM if (prev == NULL) { 24597836SJohn.Forte@Sun.COM fctl_fca_portlist = list->port_next; 24607836SJohn.Forte@Sun.COM } else { 24617836SJohn.Forte@Sun.COM prev->port_next = list->port_next; 24627836SJohn.Forte@Sun.COM } 24637836SJohn.Forte@Sun.COM kmem_free(list, sizeof (*list)); 24647836SJohn.Forte@Sun.COM break; 24657836SJohn.Forte@Sun.COM } 24667836SJohn.Forte@Sun.COM prev = list; 24677836SJohn.Forte@Sun.COM list = list->port_next; 24687836SJohn.Forte@Sun.COM } 24697836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 24707836SJohn.Forte@Sun.COM } 24717836SJohn.Forte@Sun.COM 24727836SJohn.Forte@Sun.COM 24737836SJohn.Forte@Sun.COM void 24747836SJohn.Forte@Sun.COM fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd, 24757836SJohn.Forte@Sun.COM struct modlinkage *linkage) 24767836SJohn.Forte@Sun.COM { 24777836SJohn.Forte@Sun.COM int rval; 24787836SJohn.Forte@Sun.COM uint32_t s_id; 24797836SJohn.Forte@Sun.COM uint32_t state; 248010264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 248110264SZhong.Wang@Sun.COM fc_ulp_port_info_t info; 24827836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 24837836SJohn.Forte@Sun.COM 24847836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 24857836SJohn.Forte@Sun.COM 24867836SJohn.Forte@Sun.COM info.port_linkage = linkage; 24877836SJohn.Forte@Sun.COM info.port_dip = port->fp_port_dip; 24887836SJohn.Forte@Sun.COM info.port_handle = (opaque_t)port; 24897836SJohn.Forte@Sun.COM info.port_dma_behavior = port->fp_dma_behavior; 24907836SJohn.Forte@Sun.COM info.port_fcp_dma = port->fp_fcp_dma; 24917836SJohn.Forte@Sun.COM info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 24927836SJohn.Forte@Sun.COM info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 24937836SJohn.Forte@Sun.COM info.port_reset_action = port->fp_reset_action; 24947836SJohn.Forte@Sun.COM 24957836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 24967836SJohn.Forte@Sun.COM 24977836SJohn.Forte@Sun.COM /* 24987836SJohn.Forte@Sun.COM * It is still possible that another thread could have gotten 24997836SJohn.Forte@Sun.COM * into the detach process before we got here. 25007836SJohn.Forte@Sun.COM */ 25017836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_IN_DETACH) { 25027836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 25037836SJohn.Forte@Sun.COM return; 25047836SJohn.Forte@Sun.COM } 25057836SJohn.Forte@Sun.COM 25067836SJohn.Forte@Sun.COM s_id = port->fp_port_id.port_id; 25077836SJohn.Forte@Sun.COM if (port->fp_statec_busy) { 25087836SJohn.Forte@Sun.COM info.port_state = port->fp_bind_state; 25097836SJohn.Forte@Sun.COM } else { 25107836SJohn.Forte@Sun.COM info.port_state = port->fp_state; 25117836SJohn.Forte@Sun.COM } 25127836SJohn.Forte@Sun.COM 25137836SJohn.Forte@Sun.COM switch (state = FC_PORT_STATE_MASK(info.port_state)) { 25147836SJohn.Forte@Sun.COM case FC_STATE_LOOP: 25157836SJohn.Forte@Sun.COM case FC_STATE_NAMESERVICE: 25167836SJohn.Forte@Sun.COM info.port_state &= ~state; 25177836SJohn.Forte@Sun.COM info.port_state |= FC_STATE_ONLINE; 25187836SJohn.Forte@Sun.COM break; 25197836SJohn.Forte@Sun.COM 25207836SJohn.Forte@Sun.COM default: 25217836SJohn.Forte@Sun.COM break; 25227836SJohn.Forte@Sun.COM } 25237836SJohn.Forte@Sun.COM ASSERT((info.port_state & FC_STATE_LOOP) == 0); 25247836SJohn.Forte@Sun.COM 25257836SJohn.Forte@Sun.COM info.port_flags = port->fp_topology; 25267836SJohn.Forte@Sun.COM info.port_pwwn = port->fp_service_params.nport_ww_name; 25277836SJohn.Forte@Sun.COM info.port_nwwn = port->fp_service_params.node_ww_name; 25287836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 25297836SJohn.Forte@Sun.COM 25307836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 25317836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_WRITER); 25327836SJohn.Forte@Sun.COM 25337836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 253410264SZhong.Wang@Sun.COM if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) && 253510264SZhong.Wang@Sun.COM (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) { 253610264SZhong.Wang@Sun.COM /* 253710264SZhong.Wang@Sun.COM * We don't support IP over FC on FCOE HBA 253810264SZhong.Wang@Sun.COM */ 253910264SZhong.Wang@Sun.COM continue; 254010264SZhong.Wang@Sun.COM } 254110264SZhong.Wang@Sun.COM 25427836SJohn.Forte@Sun.COM if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 25437836SJohn.Forte@Sun.COM ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP); 25447836SJohn.Forte@Sun.COM ASSERT(ulp_port != NULL); 25457836SJohn.Forte@Sun.COM 25467836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 254710264SZhong.Wang@Sun.COM ulp_port->port_statec = ((info.port_state & 25487836SJohn.Forte@Sun.COM FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE : 254910264SZhong.Wang@Sun.COM FC_ULP_STATEC_OFFLINE); 25507836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 25517836SJohn.Forte@Sun.COM } 25527836SJohn.Forte@Sun.COM } 25537836SJohn.Forte@Sun.COM 25547836SJohn.Forte@Sun.COM rw_downgrade(&fctl_mod_ports_lock); 25557836SJohn.Forte@Sun.COM 25567836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 255710264SZhong.Wang@Sun.COM if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) && 255810264SZhong.Wang@Sun.COM (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) { 255910264SZhong.Wang@Sun.COM /* 256010264SZhong.Wang@Sun.COM * We don't support IP over FC on FCOE HBA 256110264SZhong.Wang@Sun.COM */ 256210264SZhong.Wang@Sun.COM continue; 256310264SZhong.Wang@Sun.COM } 256410264SZhong.Wang@Sun.COM 25657836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 25667836SJohn.Forte@Sun.COM ASSERT(ulp_port != NULL); 25677836SJohn.Forte@Sun.COM 25687836SJohn.Forte@Sun.COM if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) { 25697836SJohn.Forte@Sun.COM continue; 25707836SJohn.Forte@Sun.COM } 25717836SJohn.Forte@Sun.COM 25727836SJohn.Forte@Sun.COM fctl_init_dma_attr(port, mod, &info); 25737836SJohn.Forte@Sun.COM 25747836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_port_attach( 25757836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, &info, cmd, s_id); 25767836SJohn.Forte@Sun.COM 25777836SJohn.Forte@Sun.COM fctl_post_attach(mod, ulp_port, cmd, rval); 25787836SJohn.Forte@Sun.COM 25797836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH && 25807836SJohn.Forte@Sun.COM strcmp(mod->mod_info->ulp_name, "fcp") == 0) { 25817836SJohn.Forte@Sun.COM ASSERT(ddi_get_driver_private(info.port_dip) != NULL); 25827836SJohn.Forte@Sun.COM } 25837836SJohn.Forte@Sun.COM } 25847836SJohn.Forte@Sun.COM 25857836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 25867836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 25877836SJohn.Forte@Sun.COM } 25887836SJohn.Forte@Sun.COM 25897836SJohn.Forte@Sun.COM 25907836SJohn.Forte@Sun.COM static int 25917836SJohn.Forte@Sun.COM fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd) 25927836SJohn.Forte@Sun.COM { 25937836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 25947836SJohn.Forte@Sun.COM 25957836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 25967836SJohn.Forte@Sun.COM 25977836SJohn.Forte@Sun.COM switch (cmd) { 25987836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 25997836SJohn.Forte@Sun.COM if (ulp_port->port_dstate & ULP_PORT_ATTACH) { 26007836SJohn.Forte@Sun.COM rval = FC_FAILURE; 26017836SJohn.Forte@Sun.COM } 26027836SJohn.Forte@Sun.COM break; 26037836SJohn.Forte@Sun.COM 26047836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 26057836SJohn.Forte@Sun.COM ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0); 26067836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 26077836SJohn.Forte@Sun.COM !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) { 26087836SJohn.Forte@Sun.COM rval = FC_FAILURE; 26097836SJohn.Forte@Sun.COM } 26107836SJohn.Forte@Sun.COM break; 26117836SJohn.Forte@Sun.COM 26127836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 26137836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 26147836SJohn.Forte@Sun.COM !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) { 26157836SJohn.Forte@Sun.COM rval = FC_FAILURE; 26167836SJohn.Forte@Sun.COM } 26177836SJohn.Forte@Sun.COM break; 26187836SJohn.Forte@Sun.COM } 26197836SJohn.Forte@Sun.COM 26207836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 26217836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_BUSY; 26227836SJohn.Forte@Sun.COM } 26237836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 26247836SJohn.Forte@Sun.COM 26257836SJohn.Forte@Sun.COM return (rval); 26267836SJohn.Forte@Sun.COM } 26277836SJohn.Forte@Sun.COM 26287836SJohn.Forte@Sun.COM 26297836SJohn.Forte@Sun.COM static void 26307836SJohn.Forte@Sun.COM fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 26317836SJohn.Forte@Sun.COM fc_attach_cmd_t cmd, int rval) 26327836SJohn.Forte@Sun.COM { 26337836SJohn.Forte@Sun.COM int be_chatty; 26347836SJohn.Forte@Sun.COM 26357836SJohn.Forte@Sun.COM ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME || 26367836SJohn.Forte@Sun.COM cmd == FC_CMD_POWER_UP); 26377836SJohn.Forte@Sun.COM 26387836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 26397836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_BUSY; 26407836SJohn.Forte@Sun.COM 26417836SJohn.Forte@Sun.COM be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1; 26427836SJohn.Forte@Sun.COM 26437836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 26447836SJohn.Forte@Sun.COM caddr_t op; 26457836SJohn.Forte@Sun.COM fc_local_port_t *port = ulp_port->port_handle; 26467836SJohn.Forte@Sun.COM 26477836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 26487836SJohn.Forte@Sun.COM 26497836SJohn.Forte@Sun.COM switch (cmd) { 26507836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 26517836SJohn.Forte@Sun.COM op = "attach"; 26527836SJohn.Forte@Sun.COM break; 26537836SJohn.Forte@Sun.COM 26547836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 26557836SJohn.Forte@Sun.COM op = "resume"; 26567836SJohn.Forte@Sun.COM break; 26577836SJohn.Forte@Sun.COM 26587836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 26597836SJohn.Forte@Sun.COM op = "power up"; 26607836SJohn.Forte@Sun.COM break; 26617836SJohn.Forte@Sun.COM } 26627836SJohn.Forte@Sun.COM 26637836SJohn.Forte@Sun.COM if (be_chatty) { 26647836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 26657836SJohn.Forte@Sun.COM port->fp_instance, op, mod->mod_info->ulp_name); 26667836SJohn.Forte@Sun.COM } 26677836SJohn.Forte@Sun.COM 26687836SJohn.Forte@Sun.COM return; 26697836SJohn.Forte@Sun.COM } 26707836SJohn.Forte@Sun.COM 26717836SJohn.Forte@Sun.COM switch (cmd) { 26727836SJohn.Forte@Sun.COM case FC_CMD_ATTACH: 26737836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_ATTACH; 26747836SJohn.Forte@Sun.COM break; 26757836SJohn.Forte@Sun.COM 26767836SJohn.Forte@Sun.COM case FC_CMD_RESUME: 26777836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_SUSPEND; 26787836SJohn.Forte@Sun.COM break; 26797836SJohn.Forte@Sun.COM 26807836SJohn.Forte@Sun.COM case FC_CMD_POWER_UP: 26817836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN; 26827836SJohn.Forte@Sun.COM break; 26837836SJohn.Forte@Sun.COM } 26847836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 26857836SJohn.Forte@Sun.COM } 26867836SJohn.Forte@Sun.COM 26877836SJohn.Forte@Sun.COM 26887836SJohn.Forte@Sun.COM int 26897836SJohn.Forte@Sun.COM fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd, 26907836SJohn.Forte@Sun.COM struct modlinkage *linkage) 26917836SJohn.Forte@Sun.COM { 26927836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 269310264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 269410264SZhong.Wang@Sun.COM fc_ulp_port_info_t info; 26957836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 26967836SJohn.Forte@Sun.COM 26977836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 26987836SJohn.Forte@Sun.COM 26997836SJohn.Forte@Sun.COM info.port_linkage = linkage; 27007836SJohn.Forte@Sun.COM info.port_dip = port->fp_port_dip; 27017836SJohn.Forte@Sun.COM info.port_handle = (opaque_t)port; 27027836SJohn.Forte@Sun.COM info.port_acc_attr = port->fp_fca_tran->fca_acc_attr; 27037836SJohn.Forte@Sun.COM info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size; 27047836SJohn.Forte@Sun.COM 27057836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 27067836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 27077836SJohn.Forte@Sun.COM 27087836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 27097836SJohn.Forte@Sun.COM if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) { 27107836SJohn.Forte@Sun.COM continue; 27117836SJohn.Forte@Sun.COM } 27127836SJohn.Forte@Sun.COM 27137836SJohn.Forte@Sun.COM if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) { 27147836SJohn.Forte@Sun.COM continue; 27157836SJohn.Forte@Sun.COM } 27167836SJohn.Forte@Sun.COM 27177836SJohn.Forte@Sun.COM fctl_init_dma_attr(port, mod, &info); 27187836SJohn.Forte@Sun.COM 27197836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_port_detach( 27207836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, &info, cmd); 27217836SJohn.Forte@Sun.COM 27227836SJohn.Forte@Sun.COM fctl_post_detach(mod, ulp_port, cmd, rval); 27237836SJohn.Forte@Sun.COM 27247836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 27257836SJohn.Forte@Sun.COM break; 27267836SJohn.Forte@Sun.COM } 27277836SJohn.Forte@Sun.COM 27287836SJohn.Forte@Sun.COM if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name, 27297836SJohn.Forte@Sun.COM "fcp") == 0) { 27307836SJohn.Forte@Sun.COM ASSERT(ddi_get_driver_private(info.port_dip) == NULL); 27317836SJohn.Forte@Sun.COM } 27327836SJohn.Forte@Sun.COM 27337836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 27347836SJohn.Forte@Sun.COM ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE; 27357836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 27367836SJohn.Forte@Sun.COM } 27377836SJohn.Forte@Sun.COM 27387836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 27397836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 27407836SJohn.Forte@Sun.COM 27417836SJohn.Forte@Sun.COM return (rval); 27427836SJohn.Forte@Sun.COM } 27437836SJohn.Forte@Sun.COM 27447836SJohn.Forte@Sun.COM static void 27457836SJohn.Forte@Sun.COM fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod, 274610264SZhong.Wang@Sun.COM fc_ulp_port_info_t *info) 27477836SJohn.Forte@Sun.COM { 27487836SJohn.Forte@Sun.COM 274910264SZhong.Wang@Sun.COM if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) || 275010264SZhong.Wang@Sun.COM (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) { 275110264SZhong.Wang@Sun.COM info->port_cmd_dma_attr = 275210264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcp_cmd_attr; 275310264SZhong.Wang@Sun.COM info->port_data_dma_attr = 275410264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcp_data_attr; 275510264SZhong.Wang@Sun.COM info->port_resp_dma_attr = 275610264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcp_rsp_attr; 275710264SZhong.Wang@Sun.COM } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) { 275810264SZhong.Wang@Sun.COM info->port_cmd_dma_attr = 275910264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcsm_cmd_attr; 276010264SZhong.Wang@Sun.COM info->port_data_dma_attr = 276110264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_attr; 276210264SZhong.Wang@Sun.COM info->port_resp_dma_attr = 276310264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcsm_rsp_attr; 276410264SZhong.Wang@Sun.COM } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) { 276510264SZhong.Wang@Sun.COM info->port_cmd_dma_attr = 276610264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcip_cmd_attr; 276710264SZhong.Wang@Sun.COM info->port_data_dma_attr = 276810264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_attr; 276910264SZhong.Wang@Sun.COM info->port_resp_dma_attr = 277010264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_fcip_rsp_attr; 277110264SZhong.Wang@Sun.COM } else { 277210264SZhong.Wang@Sun.COM info->port_cmd_dma_attr = info->port_data_dma_attr = 277310264SZhong.Wang@Sun.COM info->port_resp_dma_attr = 277410264SZhong.Wang@Sun.COM port->fp_fca_tran->fca_dma_attr; /* default */ 277510264SZhong.Wang@Sun.COM } 27767836SJohn.Forte@Sun.COM } 27777836SJohn.Forte@Sun.COM 27787836SJohn.Forte@Sun.COM static int 27797836SJohn.Forte@Sun.COM fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd) 27807836SJohn.Forte@Sun.COM { 27817836SJohn.Forte@Sun.COM int rval = FC_SUCCESS; 27827836SJohn.Forte@Sun.COM 27837836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 27847836SJohn.Forte@Sun.COM 27857836SJohn.Forte@Sun.COM switch (cmd) { 27867836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 27877836SJohn.Forte@Sun.COM if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) { 27887836SJohn.Forte@Sun.COM rval = FC_FAILURE; 27897836SJohn.Forte@Sun.COM } 27907836SJohn.Forte@Sun.COM break; 27917836SJohn.Forte@Sun.COM 27927836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 27937836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 27947836SJohn.Forte@Sun.COM ulp_port->port_dstate & ULP_PORT_SUSPEND) { 27957836SJohn.Forte@Sun.COM rval = FC_FAILURE; 27967836SJohn.Forte@Sun.COM } 27977836SJohn.Forte@Sun.COM break; 27987836SJohn.Forte@Sun.COM 27997836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 28007836SJohn.Forte@Sun.COM if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) || 28017836SJohn.Forte@Sun.COM ulp_port->port_dstate & ULP_PORT_POWER_DOWN) { 28027836SJohn.Forte@Sun.COM rval = FC_FAILURE; 28037836SJohn.Forte@Sun.COM } 28047836SJohn.Forte@Sun.COM break; 28057836SJohn.Forte@Sun.COM } 28067836SJohn.Forte@Sun.COM 28077836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 28087836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_BUSY; 28097836SJohn.Forte@Sun.COM } 28107836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 28117836SJohn.Forte@Sun.COM 28127836SJohn.Forte@Sun.COM return (rval); 28137836SJohn.Forte@Sun.COM } 28147836SJohn.Forte@Sun.COM 28157836SJohn.Forte@Sun.COM 28167836SJohn.Forte@Sun.COM static void 28177836SJohn.Forte@Sun.COM fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port, 28187836SJohn.Forte@Sun.COM fc_detach_cmd_t cmd, int rval) 28197836SJohn.Forte@Sun.COM { 28207836SJohn.Forte@Sun.COM ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND || 28217836SJohn.Forte@Sun.COM cmd == FC_CMD_POWER_DOWN); 28227836SJohn.Forte@Sun.COM 28237836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 28247836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_BUSY; 28257836SJohn.Forte@Sun.COM 28267836SJohn.Forte@Sun.COM if (rval != FC_SUCCESS) { 28277836SJohn.Forte@Sun.COM caddr_t op; 28287836SJohn.Forte@Sun.COM fc_local_port_t *port = ulp_port->port_handle; 28297836SJohn.Forte@Sun.COM 28307836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 28317836SJohn.Forte@Sun.COM 28327836SJohn.Forte@Sun.COM switch (cmd) { 28337836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 28347836SJohn.Forte@Sun.COM op = "detach"; 28357836SJohn.Forte@Sun.COM break; 28367836SJohn.Forte@Sun.COM 28377836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 28387836SJohn.Forte@Sun.COM op = "suspend"; 28397836SJohn.Forte@Sun.COM break; 28407836SJohn.Forte@Sun.COM 28417836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 28427836SJohn.Forte@Sun.COM op = "power down"; 28437836SJohn.Forte@Sun.COM break; 28447836SJohn.Forte@Sun.COM } 28457836SJohn.Forte@Sun.COM 28467836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): %s failed for %s", 28477836SJohn.Forte@Sun.COM port->fp_instance, op, mod->mod_info->ulp_name); 28487836SJohn.Forte@Sun.COM 28497836SJohn.Forte@Sun.COM return; 28507836SJohn.Forte@Sun.COM } 28517836SJohn.Forte@Sun.COM 28527836SJohn.Forte@Sun.COM switch (cmd) { 28537836SJohn.Forte@Sun.COM case FC_CMD_DETACH: 28547836SJohn.Forte@Sun.COM ulp_port->port_dstate &= ~ULP_PORT_ATTACH; 28557836SJohn.Forte@Sun.COM break; 28567836SJohn.Forte@Sun.COM 28577836SJohn.Forte@Sun.COM case FC_CMD_SUSPEND: 28587836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_SUSPEND; 28597836SJohn.Forte@Sun.COM break; 28607836SJohn.Forte@Sun.COM 28617836SJohn.Forte@Sun.COM case FC_CMD_POWER_DOWN: 28627836SJohn.Forte@Sun.COM ulp_port->port_dstate |= ULP_PORT_POWER_DOWN; 28637836SJohn.Forte@Sun.COM break; 28647836SJohn.Forte@Sun.COM } 28657836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 28667836SJohn.Forte@Sun.COM } 28677836SJohn.Forte@Sun.COM 28687836SJohn.Forte@Sun.COM 28697836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 28707836SJohn.Forte@Sun.COM fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle, 28717836SJohn.Forte@Sun.COM int sleep) 28727836SJohn.Forte@Sun.COM { 28737836SJohn.Forte@Sun.COM fc_ulp_ports_t *last; 28747836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 28757836SJohn.Forte@Sun.COM fc_ulp_ports_t *new; 28767836SJohn.Forte@Sun.COM 28777836SJohn.Forte@Sun.COM ASSERT(RW_READ_HELD(&fctl_ulp_lock)); 28787836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 28797836SJohn.Forte@Sun.COM 28807836SJohn.Forte@Sun.COM last = NULL; 28817836SJohn.Forte@Sun.COM next = ulp_module->mod_ports; 28827836SJohn.Forte@Sun.COM 28837836SJohn.Forte@Sun.COM while (next != NULL) { 28847836SJohn.Forte@Sun.COM last = next; 28857836SJohn.Forte@Sun.COM next = next->port_next; 28867836SJohn.Forte@Sun.COM } 28877836SJohn.Forte@Sun.COM 28887836SJohn.Forte@Sun.COM new = fctl_alloc_ulp_port(sleep); 28897836SJohn.Forte@Sun.COM if (new == NULL) { 28907836SJohn.Forte@Sun.COM return (new); 28917836SJohn.Forte@Sun.COM } 28927836SJohn.Forte@Sun.COM 28937836SJohn.Forte@Sun.COM new->port_handle = port_handle; 28947836SJohn.Forte@Sun.COM if (last == NULL) { 28957836SJohn.Forte@Sun.COM ulp_module->mod_ports = new; 28967836SJohn.Forte@Sun.COM } else { 28977836SJohn.Forte@Sun.COM last->port_next = new; 28987836SJohn.Forte@Sun.COM } 28997836SJohn.Forte@Sun.COM 29007836SJohn.Forte@Sun.COM return (new); 29017836SJohn.Forte@Sun.COM } 29027836SJohn.Forte@Sun.COM 29037836SJohn.Forte@Sun.COM 29047836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 29057836SJohn.Forte@Sun.COM fctl_alloc_ulp_port(int sleep) 29067836SJohn.Forte@Sun.COM { 29077836SJohn.Forte@Sun.COM fc_ulp_ports_t *new; 29087836SJohn.Forte@Sun.COM 29097836SJohn.Forte@Sun.COM new = kmem_zalloc(sizeof (*new), sleep); 29107836SJohn.Forte@Sun.COM if (new == NULL) { 29117836SJohn.Forte@Sun.COM return (new); 29127836SJohn.Forte@Sun.COM } 29137836SJohn.Forte@Sun.COM mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL); 29147836SJohn.Forte@Sun.COM 29157836SJohn.Forte@Sun.COM return (new); 29167836SJohn.Forte@Sun.COM } 29177836SJohn.Forte@Sun.COM 29187836SJohn.Forte@Sun.COM 29197836SJohn.Forte@Sun.COM static int 29207836SJohn.Forte@Sun.COM fctl_remove_ulp_port(struct ulp_module *ulp_module, 29217836SJohn.Forte@Sun.COM fc_local_port_t *port_handle) 29227836SJohn.Forte@Sun.COM { 29237836SJohn.Forte@Sun.COM fc_ulp_ports_t *last; 29247836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 29257836SJohn.Forte@Sun.COM 29267836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_ulp_lock)); 29277836SJohn.Forte@Sun.COM ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock)); 29287836SJohn.Forte@Sun.COM 29297836SJohn.Forte@Sun.COM last = NULL; 29307836SJohn.Forte@Sun.COM next = ulp_module->mod_ports; 29317836SJohn.Forte@Sun.COM 29327836SJohn.Forte@Sun.COM while (next != NULL) { 29337836SJohn.Forte@Sun.COM if (next->port_handle == port_handle) { 29347836SJohn.Forte@Sun.COM if (next->port_dstate & ULP_PORT_ATTACH) { 29357836SJohn.Forte@Sun.COM return (FC_FAILURE); 29367836SJohn.Forte@Sun.COM } 29377836SJohn.Forte@Sun.COM break; 29387836SJohn.Forte@Sun.COM } 29397836SJohn.Forte@Sun.COM last = next; 29407836SJohn.Forte@Sun.COM next = next->port_next; 29417836SJohn.Forte@Sun.COM } 29427836SJohn.Forte@Sun.COM 29437836SJohn.Forte@Sun.COM if (next != NULL) { 29447836SJohn.Forte@Sun.COM ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0); 29457836SJohn.Forte@Sun.COM 29467836SJohn.Forte@Sun.COM if (last == NULL) { 29477836SJohn.Forte@Sun.COM ulp_module->mod_ports = next->port_next; 29487836SJohn.Forte@Sun.COM } else { 29497836SJohn.Forte@Sun.COM last->port_next = next->port_next; 29507836SJohn.Forte@Sun.COM } 29517836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(next); 29527836SJohn.Forte@Sun.COM 29537836SJohn.Forte@Sun.COM return (FC_SUCCESS); 29547836SJohn.Forte@Sun.COM } else { 29557836SJohn.Forte@Sun.COM return (FC_FAILURE); 29567836SJohn.Forte@Sun.COM } 29577836SJohn.Forte@Sun.COM } 29587836SJohn.Forte@Sun.COM 29597836SJohn.Forte@Sun.COM 29607836SJohn.Forte@Sun.COM static void 29617836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(fc_ulp_ports_t *next) 29627836SJohn.Forte@Sun.COM { 29637836SJohn.Forte@Sun.COM mutex_destroy(&next->port_mutex); 29647836SJohn.Forte@Sun.COM kmem_free(next, sizeof (*next)); 29657836SJohn.Forte@Sun.COM } 29667836SJohn.Forte@Sun.COM 29677836SJohn.Forte@Sun.COM 29687836SJohn.Forte@Sun.COM static fc_ulp_ports_t * 29697836SJohn.Forte@Sun.COM fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle) 29707836SJohn.Forte@Sun.COM { 29717836SJohn.Forte@Sun.COM fc_ulp_ports_t *next; 29727836SJohn.Forte@Sun.COM 29737836SJohn.Forte@Sun.COM ASSERT(RW_LOCK_HELD(&fctl_ulp_lock)); 29747836SJohn.Forte@Sun.COM ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock)); 29757836SJohn.Forte@Sun.COM 29767836SJohn.Forte@Sun.COM for (next = ulp_module->mod_ports; next != NULL; 29777836SJohn.Forte@Sun.COM next = next->port_next) { 29787836SJohn.Forte@Sun.COM if (next->port_handle == port_handle) { 29797836SJohn.Forte@Sun.COM return (next); 29807836SJohn.Forte@Sun.COM } 29817836SJohn.Forte@Sun.COM } 29827836SJohn.Forte@Sun.COM 29837836SJohn.Forte@Sun.COM return (NULL); 29847836SJohn.Forte@Sun.COM } 29857836SJohn.Forte@Sun.COM 29867836SJohn.Forte@Sun.COM 29877836SJohn.Forte@Sun.COM /* 29887836SJohn.Forte@Sun.COM * Pass state change notfications on to registered ULPs. 29897836SJohn.Forte@Sun.COM * 29907836SJohn.Forte@Sun.COM * Can issue wakeups to client callers who might be waiting for completions 29917836SJohn.Forte@Sun.COM * on other threads. 29927836SJohn.Forte@Sun.COM * 29937836SJohn.Forte@Sun.COM * Caution: will silently deallocate any fc_remote_port_t and/or 29947836SJohn.Forte@Sun.COM * fc_remote_node_t structs it finds that are not in use. 29957836SJohn.Forte@Sun.COM */ 29967836SJohn.Forte@Sun.COM void 29977836SJohn.Forte@Sun.COM fctl_ulp_statec_cb(void *arg) 29987836SJohn.Forte@Sun.COM { 29997836SJohn.Forte@Sun.COM uint32_t s_id; 30007836SJohn.Forte@Sun.COM uint32_t new_state; 30017836SJohn.Forte@Sun.COM fc_local_port_t *port; 30027836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 300310264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 300410264SZhong.Wang@Sun.COM fc_port_clist_t *clist = (fc_port_clist_t *)arg; 30057836SJohn.Forte@Sun.COM 30067836SJohn.Forte@Sun.COM ASSERT(clist != NULL); 30077836SJohn.Forte@Sun.COM 30087836SJohn.Forte@Sun.COM port = clist->clist_port; 30097836SJohn.Forte@Sun.COM 30107836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 30117836SJohn.Forte@Sun.COM s_id = port->fp_port_id.port_id; 30127836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 30137836SJohn.Forte@Sun.COM 30147836SJohn.Forte@Sun.COM switch (clist->clist_state) { 30157836SJohn.Forte@Sun.COM case FC_STATE_ONLINE: 30167836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_ONLINE; 30177836SJohn.Forte@Sun.COM break; 30187836SJohn.Forte@Sun.COM 30197836SJohn.Forte@Sun.COM case FC_STATE_OFFLINE: 30207836SJohn.Forte@Sun.COM if (clist->clist_len) { 30217836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT; 30227836SJohn.Forte@Sun.COM } else { 30237836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_OFFLINE; 30247836SJohn.Forte@Sun.COM } 30257836SJohn.Forte@Sun.COM break; 30267836SJohn.Forte@Sun.COM 30277836SJohn.Forte@Sun.COM default: 30287836SJohn.Forte@Sun.COM new_state = FC_ULP_STATEC_DONT_CARE; 30297836SJohn.Forte@Sun.COM break; 30307836SJohn.Forte@Sun.COM } 30317836SJohn.Forte@Sun.COM 30327836SJohn.Forte@Sun.COM #ifdef DEBUG 30337836SJohn.Forte@Sun.COM /* 30347836SJohn.Forte@Sun.COM * sanity check for presence of OLD devices in the hash lists 30357836SJohn.Forte@Sun.COM */ 30367836SJohn.Forte@Sun.COM if (clist->clist_size) { 303710264SZhong.Wang@Sun.COM int count; 30387836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 30397836SJohn.Forte@Sun.COM 30407836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 30417836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len; count++) { 30427836SJohn.Forte@Sun.COM if (clist->clist_map[count].map_state == 30437836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID) { 304410264SZhong.Wang@Sun.COM la_wwn_t pwwn; 304510264SZhong.Wang@Sun.COM fc_portid_t d_id; 30467836SJohn.Forte@Sun.COM 30477836SJohn.Forte@Sun.COM pd = clist->clist_map[count].map_pd; 30487836SJohn.Forte@Sun.COM if (pd != NULL) { 30497836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 30507836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 30517836SJohn.Forte@Sun.COM d_id = pd->pd_port_id; 30527836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 30537836SJohn.Forte@Sun.COM 30547836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn(port, 30557836SJohn.Forte@Sun.COM &pwwn); 30567836SJohn.Forte@Sun.COM 30577836SJohn.Forte@Sun.COM ASSERT(pd != clist->clist_map[count]. 30587836SJohn.Forte@Sun.COM map_pd); 30597836SJohn.Forte@Sun.COM 30607836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_did(port, 30617836SJohn.Forte@Sun.COM d_id.port_id); 30627836SJohn.Forte@Sun.COM ASSERT(pd != clist->clist_map[count]. 30637836SJohn.Forte@Sun.COM map_pd); 30647836SJohn.Forte@Sun.COM } 30657836SJohn.Forte@Sun.COM } 30667836SJohn.Forte@Sun.COM } 30677836SJohn.Forte@Sun.COM } 30687836SJohn.Forte@Sun.COM #endif 30697836SJohn.Forte@Sun.COM 30707836SJohn.Forte@Sun.COM /* 30717836SJohn.Forte@Sun.COM * Check for duplicate map entries 30727836SJohn.Forte@Sun.COM */ 30737836SJohn.Forte@Sun.COM if (clist->clist_size) { 307410264SZhong.Wang@Sun.COM int count; 30757836SJohn.Forte@Sun.COM fc_remote_port_t *pd1, *pd2; 30767836SJohn.Forte@Sun.COM 30777836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 30787836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len-1; count++) { 30797836SJohn.Forte@Sun.COM int count2; 30807836SJohn.Forte@Sun.COM 30817836SJohn.Forte@Sun.COM pd1 = clist->clist_map[count].map_pd; 30827836SJohn.Forte@Sun.COM if (pd1 == NULL) { 30837836SJohn.Forte@Sun.COM continue; 30847836SJohn.Forte@Sun.COM } 30857836SJohn.Forte@Sun.COM 30867836SJohn.Forte@Sun.COM for (count2 = count+1; 30877836SJohn.Forte@Sun.COM count2 < clist->clist_len; 30887836SJohn.Forte@Sun.COM count2++) { 30897836SJohn.Forte@Sun.COM 30907836SJohn.Forte@Sun.COM pd2 = clist->clist_map[count2].map_pd; 30917836SJohn.Forte@Sun.COM if (pd2 == NULL) { 30927836SJohn.Forte@Sun.COM continue; 30937836SJohn.Forte@Sun.COM } 30947836SJohn.Forte@Sun.COM 30957836SJohn.Forte@Sun.COM if (pd1 == pd2) { 30967836SJohn.Forte@Sun.COM clist->clist_map[count].map_flags |= 30977836SJohn.Forte@Sun.COM PORT_DEVICE_DUPLICATE_MAP_ENTRY; 30987836SJohn.Forte@Sun.COM break; 30997836SJohn.Forte@Sun.COM } 31007836SJohn.Forte@Sun.COM } 31017836SJohn.Forte@Sun.COM } 31027836SJohn.Forte@Sun.COM } 31037836SJohn.Forte@Sun.COM 31047836SJohn.Forte@Sun.COM 31057836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 31067836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 31077836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 31087836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 31097836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 31107836SJohn.Forte@Sun.COM 31117836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 31127836SJohn.Forte@Sun.COM continue; 31137836SJohn.Forte@Sun.COM } 31147836SJohn.Forte@Sun.COM 31157836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 31167836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 31177836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 31187836SJohn.Forte@Sun.COM continue; 31197836SJohn.Forte@Sun.COM } 31207836SJohn.Forte@Sun.COM 31217836SJohn.Forte@Sun.COM switch (ulp_port->port_statec) { 31227836SJohn.Forte@Sun.COM case FC_ULP_STATEC_DONT_CARE: 31237836SJohn.Forte@Sun.COM if (ulp_port->port_statec != new_state) { 31247836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 31257836SJohn.Forte@Sun.COM } 31267836SJohn.Forte@Sun.COM break; 31277836SJohn.Forte@Sun.COM 31287836SJohn.Forte@Sun.COM case FC_ULP_STATEC_ONLINE: 31297836SJohn.Forte@Sun.COM case FC_ULP_STATEC_OFFLINE: 31307836SJohn.Forte@Sun.COM if (ulp_port->port_statec == new_state) { 31317836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 31327836SJohn.Forte@Sun.COM continue; 31337836SJohn.Forte@Sun.COM } 31347836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 31357836SJohn.Forte@Sun.COM break; 31367836SJohn.Forte@Sun.COM 31377836SJohn.Forte@Sun.COM case FC_ULP_STATEC_OFFLINE_TIMEOUT: 31387836SJohn.Forte@Sun.COM if (ulp_port->port_statec == new_state || 31397836SJohn.Forte@Sun.COM new_state == FC_ULP_STATEC_OFFLINE) { 31407836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 31417836SJohn.Forte@Sun.COM continue; 31427836SJohn.Forte@Sun.COM } 31437836SJohn.Forte@Sun.COM ulp_port->port_statec = new_state; 31447836SJohn.Forte@Sun.COM break; 31457836SJohn.Forte@Sun.COM 31467836SJohn.Forte@Sun.COM default: 31477836SJohn.Forte@Sun.COM ASSERT(0); 31487836SJohn.Forte@Sun.COM break; 31497836SJohn.Forte@Sun.COM } 31507836SJohn.Forte@Sun.COM 31517836SJohn.Forte@Sun.COM mod->mod_info->ulp_statec_callback( 31527836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, (opaque_t)port, 31537836SJohn.Forte@Sun.COM clist->clist_state, clist->clist_flags, 31547836SJohn.Forte@Sun.COM clist->clist_map, clist->clist_len, s_id); 31557836SJohn.Forte@Sun.COM 31567836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 31577836SJohn.Forte@Sun.COM } 31587836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 31597836SJohn.Forte@Sun.COM 31607836SJohn.Forte@Sun.COM if (clist->clist_size) { 316110264SZhong.Wang@Sun.COM int count; 31627836SJohn.Forte@Sun.COM fc_remote_node_t *node; 31637836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 31647836SJohn.Forte@Sun.COM 31657836SJohn.Forte@Sun.COM ASSERT(clist->clist_map != NULL); 31667836SJohn.Forte@Sun.COM for (count = 0; count < clist->clist_len; count++) { 31677836SJohn.Forte@Sun.COM 31687836SJohn.Forte@Sun.COM if ((pd = clist->clist_map[count].map_pd) == NULL) { 31697836SJohn.Forte@Sun.COM continue; 31707836SJohn.Forte@Sun.COM } 31717836SJohn.Forte@Sun.COM 31727836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 31737836SJohn.Forte@Sun.COM 31747836SJohn.Forte@Sun.COM pd->pd_ref_count--; 31757836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 31767836SJohn.Forte@Sun.COM 31777836SJohn.Forte@Sun.COM if (clist->clist_map[count].map_state != 31787836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID) { 31797836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 31807836SJohn.Forte@Sun.COM continue; 31817836SJohn.Forte@Sun.COM } 31827836SJohn.Forte@Sun.COM 31837836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 31847836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS; 31857836SJohn.Forte@Sun.COM 31867836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 31877836SJohn.Forte@Sun.COM 31887836SJohn.Forte@Sun.COM /* 31897836SJohn.Forte@Sun.COM * This fc_remote_port_t is no longer referenced 31907836SJohn.Forte@Sun.COM * by any ULPs. Deallocate it if its pd_ref_count 31917836SJohn.Forte@Sun.COM * has reached zero. 31927836SJohn.Forte@Sun.COM */ 31937836SJohn.Forte@Sun.COM if ((fctl_destroy_remote_port(port, pd) == 0) && 31947836SJohn.Forte@Sun.COM (node != NULL)) { 31957836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 31967836SJohn.Forte@Sun.COM } 31977836SJohn.Forte@Sun.COM } 31987836SJohn.Forte@Sun.COM 31997836SJohn.Forte@Sun.COM kmem_free(clist->clist_map, 32007836SJohn.Forte@Sun.COM sizeof (*(clist->clist_map)) * clist->clist_size); 32017836SJohn.Forte@Sun.COM } 32027836SJohn.Forte@Sun.COM 32037836SJohn.Forte@Sun.COM if (clist->clist_wait) { 32047836SJohn.Forte@Sun.COM mutex_enter(&clist->clist_mutex); 32057836SJohn.Forte@Sun.COM clist->clist_wait = 0; 32067836SJohn.Forte@Sun.COM cv_signal(&clist->clist_cv); 32077836SJohn.Forte@Sun.COM mutex_exit(&clist->clist_mutex); 32087836SJohn.Forte@Sun.COM } else { 32097836SJohn.Forte@Sun.COM kmem_free(clist, sizeof (*clist)); 32107836SJohn.Forte@Sun.COM } 32117836SJohn.Forte@Sun.COM } 32127836SJohn.Forte@Sun.COM 32137836SJohn.Forte@Sun.COM 32147836SJohn.Forte@Sun.COM /* 32157836SJohn.Forte@Sun.COM * Allocate an fc_remote_node_t struct to represent a remote node for the 321610264SZhong.Wang@Sun.COM * given nwwn. This will also add the nwwn to the global nwwn table. 32177836SJohn.Forte@Sun.COM * 32187836SJohn.Forte@Sun.COM * Returns a pointer to the newly-allocated struct. Returns NULL if 32197836SJohn.Forte@Sun.COM * the kmem_zalloc fails or if the enlist_wwn attempt fails. 32207836SJohn.Forte@Sun.COM */ 32217836SJohn.Forte@Sun.COM fc_remote_node_t * 32227836SJohn.Forte@Sun.COM fctl_create_remote_node(la_wwn_t *nwwn, int sleep) 32237836SJohn.Forte@Sun.COM { 32247836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 32257836SJohn.Forte@Sun.COM 32267836SJohn.Forte@Sun.COM if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) { 32277836SJohn.Forte@Sun.COM return (NULL); 32287836SJohn.Forte@Sun.COM } 32297836SJohn.Forte@Sun.COM 32307836SJohn.Forte@Sun.COM mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL); 32317836SJohn.Forte@Sun.COM 32327836SJohn.Forte@Sun.COM rnodep->fd_node_name = *nwwn; 32337836SJohn.Forte@Sun.COM rnodep->fd_flags = FC_REMOTE_NODE_VALID; 32347836SJohn.Forte@Sun.COM rnodep->fd_numports = 1; 32357836SJohn.Forte@Sun.COM 32367836SJohn.Forte@Sun.COM if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) { 32377836SJohn.Forte@Sun.COM mutex_destroy(&rnodep->fd_mutex); 32387836SJohn.Forte@Sun.COM kmem_free(rnodep, sizeof (*rnodep)); 32397836SJohn.Forte@Sun.COM return (NULL); 32407836SJohn.Forte@Sun.COM } 32417836SJohn.Forte@Sun.COM 32427836SJohn.Forte@Sun.COM return (rnodep); 32437836SJohn.Forte@Sun.COM } 32447836SJohn.Forte@Sun.COM 32457836SJohn.Forte@Sun.COM /* 32467836SJohn.Forte@Sun.COM * Deconstruct and free the given fc_remote_node_t struct (remote node struct). 32477836SJohn.Forte@Sun.COM * Silently skips the deconstruct/free if there are any fc_remote_port_t 32487836SJohn.Forte@Sun.COM * (remote port device) structs still referenced by the given 32497836SJohn.Forte@Sun.COM * fc_remote_node_t struct. 32507836SJohn.Forte@Sun.COM */ 32517836SJohn.Forte@Sun.COM void 32527836SJohn.Forte@Sun.COM fctl_destroy_remote_node(fc_remote_node_t *rnodep) 32537836SJohn.Forte@Sun.COM { 32547836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 32557836SJohn.Forte@Sun.COM 32567836SJohn.Forte@Sun.COM /* 32577836SJohn.Forte@Sun.COM * Look at the count and linked list of of remote ports 32587836SJohn.Forte@Sun.COM * (fc_remote_port_t structs); bail if these indicate that 32597836SJohn.Forte@Sun.COM * given fc_remote_node_t may be in use. 32607836SJohn.Forte@Sun.COM */ 32617836SJohn.Forte@Sun.COM if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) { 32627836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 32637836SJohn.Forte@Sun.COM return; 32647836SJohn.Forte@Sun.COM } 32657836SJohn.Forte@Sun.COM 32667836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 32677836SJohn.Forte@Sun.COM 32687836SJohn.Forte@Sun.COM mutex_destroy(&rnodep->fd_mutex); 32697836SJohn.Forte@Sun.COM kmem_free(rnodep, sizeof (*rnodep)); 32707836SJohn.Forte@Sun.COM } 32717836SJohn.Forte@Sun.COM 32727836SJohn.Forte@Sun.COM 32737836SJohn.Forte@Sun.COM /* 32747836SJohn.Forte@Sun.COM * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This 32757836SJohn.Forte@Sun.COM * uses the nwwn in the fd_node_name.raw_wwn of the given struct. 32767836SJohn.Forte@Sun.COM * This only fails if the kmem_zalloc fails. This does not check for a 32777836SJohn.Forte@Sun.COM * unique or pre-existing nwwn in the fctl_nwwn_hash_table[]. 32787836SJohn.Forte@Sun.COM * This is only called from fctl_create_remote_node(). 32797836SJohn.Forte@Sun.COM */ 32807836SJohn.Forte@Sun.COM int 32817836SJohn.Forte@Sun.COM fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep) 32827836SJohn.Forte@Sun.COM { 328310264SZhong.Wang@Sun.COM int index; 328410264SZhong.Wang@Sun.COM fctl_nwwn_elem_t *new; 328510264SZhong.Wang@Sun.COM fctl_nwwn_list_t *head; 32867836SJohn.Forte@Sun.COM 32877836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 32887836SJohn.Forte@Sun.COM 32897836SJohn.Forte@Sun.COM if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) { 32907836SJohn.Forte@Sun.COM return (FC_FAILURE); 32917836SJohn.Forte@Sun.COM } 32927836SJohn.Forte@Sun.COM 32937836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 32947836SJohn.Forte@Sun.COM new->fne_nodep = rnodep; 32957836SJohn.Forte@Sun.COM 32967836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 32977836SJohn.Forte@Sun.COM ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE); 32987836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 32997836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 33007836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 33017836SJohn.Forte@Sun.COM 33027836SJohn.Forte@Sun.COM head = &fctl_nwwn_hash_table[index]; 33037836SJohn.Forte@Sun.COM 33047836SJohn.Forte@Sun.COM /* Link it in at the head of the hash list */ 33057836SJohn.Forte@Sun.COM new->fne_nextp = head->fnl_headp; 33067836SJohn.Forte@Sun.COM head->fnl_headp = new; 33077836SJohn.Forte@Sun.COM 33087836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 33097836SJohn.Forte@Sun.COM 33107836SJohn.Forte@Sun.COM return (FC_SUCCESS); 33117836SJohn.Forte@Sun.COM } 33127836SJohn.Forte@Sun.COM 33137836SJohn.Forte@Sun.COM 33147836SJohn.Forte@Sun.COM /* 33157836SJohn.Forte@Sun.COM * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[]. 33167836SJohn.Forte@Sun.COM * This uses the nwwn in the fd_node_name.raw_wwn of the given struct. 33177836SJohn.Forte@Sun.COM */ 33187836SJohn.Forte@Sun.COM void 33197836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(fc_remote_node_t *rnodep) 33207836SJohn.Forte@Sun.COM { 332110264SZhong.Wang@Sun.COM int index; 332210264SZhong.Wang@Sun.COM fctl_nwwn_list_t *head; 332310264SZhong.Wang@Sun.COM fctl_nwwn_elem_t *elem; 332410264SZhong.Wang@Sun.COM fctl_nwwn_elem_t *prev; 33257836SJohn.Forte@Sun.COM 33267836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex)); 33277836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&rnodep->fd_mutex)); 33287836SJohn.Forte@Sun.COM 33297836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn), 33307836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 33317836SJohn.Forte@Sun.COM 33327836SJohn.Forte@Sun.COM head = &fctl_nwwn_hash_table[index]; 33337836SJohn.Forte@Sun.COM elem = head->fnl_headp; 33347836SJohn.Forte@Sun.COM prev = NULL; 33357836SJohn.Forte@Sun.COM 33367836SJohn.Forte@Sun.COM while (elem != NULL) { 33377836SJohn.Forte@Sun.COM if (elem->fne_nodep == rnodep) { 33387836SJohn.Forte@Sun.COM /* 33397836SJohn.Forte@Sun.COM * Found it -- unlink it from the list & decrement 33407836SJohn.Forte@Sun.COM * the count for the hash chain. 33417836SJohn.Forte@Sun.COM */ 33427836SJohn.Forte@Sun.COM if (prev == NULL) { 33437836SJohn.Forte@Sun.COM head->fnl_headp = elem->fne_nextp; 33447836SJohn.Forte@Sun.COM } else { 33457836SJohn.Forte@Sun.COM prev->fne_nextp = elem->fne_nextp; 33467836SJohn.Forte@Sun.COM } 33477836SJohn.Forte@Sun.COM break; 33487836SJohn.Forte@Sun.COM } 33497836SJohn.Forte@Sun.COM prev = elem; 33507836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 33517836SJohn.Forte@Sun.COM } 33527836SJohn.Forte@Sun.COM 33537836SJohn.Forte@Sun.COM if (elem != NULL) { 33547836SJohn.Forte@Sun.COM kmem_free(elem, sizeof (*elem)); 33557836SJohn.Forte@Sun.COM } 33567836SJohn.Forte@Sun.COM } 33577836SJohn.Forte@Sun.COM 33587836SJohn.Forte@Sun.COM 33597836SJohn.Forte@Sun.COM /* 33607836SJohn.Forte@Sun.COM * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 33617836SJohn.Forte@Sun.COM * Looks in the global fctl_nwwn_hash_table[]. Identical to the 33627836SJohn.Forte@Sun.COM * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment 33637836SJohn.Forte@Sun.COM * the fc_count reference count in the f_device_t before returning. 33647836SJohn.Forte@Sun.COM * 33657836SJohn.Forte@Sun.COM * This function is called by: fctl_create_remote_port_t(). 33667836SJohn.Forte@Sun.COM * 33677836SJohn.Forte@Sun.COM * OLD COMMENT: 33687836SJohn.Forte@Sun.COM * Note: The calling thread needs to make sure it isn't holding any device 33697836SJohn.Forte@Sun.COM * mutex (more so the fc_remote_node_t that could potentially have this wwn). 33707836SJohn.Forte@Sun.COM */ 33717836SJohn.Forte@Sun.COM fc_remote_node_t * 33727836SJohn.Forte@Sun.COM fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn) 33737836SJohn.Forte@Sun.COM { 337410264SZhong.Wang@Sun.COM int index; 337510264SZhong.Wang@Sun.COM fctl_nwwn_elem_t *elem; 33767836SJohn.Forte@Sun.COM fc_remote_node_t *next; 337710264SZhong.Wang@Sun.COM fc_remote_node_t *rnodep = NULL; 33787836SJohn.Forte@Sun.COM 33797836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 33807836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 33817836SJohn.Forte@Sun.COM ASSERT(index >= 0 && index < fctl_nwwn_table_size); 33827836SJohn.Forte@Sun.COM 33837836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 33847836SJohn.Forte@Sun.COM elem = fctl_nwwn_hash_table[index].fnl_headp; 33857836SJohn.Forte@Sun.COM while (elem != NULL) { 33867836SJohn.Forte@Sun.COM next = elem->fne_nodep; 33877836SJohn.Forte@Sun.COM if (next != NULL) { 33887836SJohn.Forte@Sun.COM mutex_enter(&next->fd_mutex); 33897836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 33907836SJohn.Forte@Sun.COM rnodep = next; 33917836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 33927836SJohn.Forte@Sun.COM break; 33937836SJohn.Forte@Sun.COM } 33947836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 33957836SJohn.Forte@Sun.COM } 33967836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 33977836SJohn.Forte@Sun.COM } 33987836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 33997836SJohn.Forte@Sun.COM 34007836SJohn.Forte@Sun.COM return (rnodep); 34017836SJohn.Forte@Sun.COM } 34027836SJohn.Forte@Sun.COM 34037836SJohn.Forte@Sun.COM 34047836SJohn.Forte@Sun.COM /* 34057836SJohn.Forte@Sun.COM * Returns a reference to an fc_remote_node_t struct for the given node_wwn. 34067836SJohn.Forte@Sun.COM * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports 34077836SJohn.Forte@Sun.COM * reference count in the f_device_t before returning. 34087836SJohn.Forte@Sun.COM * 34097836SJohn.Forte@Sun.COM * This function is only called by fctl_create_remote_port_t(). 34107836SJohn.Forte@Sun.COM */ 34117836SJohn.Forte@Sun.COM fc_remote_node_t * 34127836SJohn.Forte@Sun.COM fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn) 34137836SJohn.Forte@Sun.COM { 341410264SZhong.Wang@Sun.COM int index; 341510264SZhong.Wang@Sun.COM fctl_nwwn_elem_t *elem; 34167836SJohn.Forte@Sun.COM fc_remote_node_t *next; 341710264SZhong.Wang@Sun.COM fc_remote_node_t *rnodep = NULL; 34187836SJohn.Forte@Sun.COM 34197836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn), 34207836SJohn.Forte@Sun.COM fctl_nwwn_table_size); 34217836SJohn.Forte@Sun.COM ASSERT(index >= 0 && index < fctl_nwwn_table_size); 34227836SJohn.Forte@Sun.COM 34237836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 34247836SJohn.Forte@Sun.COM elem = fctl_nwwn_hash_table[index].fnl_headp; 34257836SJohn.Forte@Sun.COM while (elem != NULL) { 34267836SJohn.Forte@Sun.COM next = elem->fne_nodep; 34277836SJohn.Forte@Sun.COM if (next != NULL) { 34287836SJohn.Forte@Sun.COM mutex_enter(&next->fd_mutex); 34297836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) { 34307836SJohn.Forte@Sun.COM rnodep = next; 34317836SJohn.Forte@Sun.COM rnodep->fd_numports++; 34327836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 34337836SJohn.Forte@Sun.COM break; 34347836SJohn.Forte@Sun.COM } 34357836SJohn.Forte@Sun.COM mutex_exit(&next->fd_mutex); 34367836SJohn.Forte@Sun.COM } 34377836SJohn.Forte@Sun.COM elem = elem->fne_nextp; 34387836SJohn.Forte@Sun.COM } 34397836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 34407836SJohn.Forte@Sun.COM 34417836SJohn.Forte@Sun.COM return (rnodep); 34427836SJohn.Forte@Sun.COM } 34437836SJohn.Forte@Sun.COM 34447836SJohn.Forte@Sun.COM 34457836SJohn.Forte@Sun.COM /* 34467836SJohn.Forte@Sun.COM * Allocate and initialize an fc_remote_port_t struct & returns a pointer to 344710264SZhong.Wang@Sun.COM * the newly allocated struct. Only fails if the kmem_zalloc() fails. 34487836SJohn.Forte@Sun.COM */ 34497836SJohn.Forte@Sun.COM fc_remote_port_t * 34507836SJohn.Forte@Sun.COM fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn, 34517836SJohn.Forte@Sun.COM uint32_t d_id, uchar_t recepient, int sleep) 34527836SJohn.Forte@Sun.COM { 34537836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 34547836SJohn.Forte@Sun.COM 34557836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 34567836SJohn.Forte@Sun.COM ASSERT(FC_IS_REAL_DEVICE(d_id)); 34577836SJohn.Forte@Sun.COM 34587836SJohn.Forte@Sun.COM if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) { 34597836SJohn.Forte@Sun.COM return (NULL); 34607836SJohn.Forte@Sun.COM } 34617836SJohn.Forte@Sun.COM fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT, 34627836SJohn.Forte@Sun.COM FC_LOGO_TOLERANCE_TIME_LIMIT); 34637836SJohn.Forte@Sun.COM 34647836SJohn.Forte@Sun.COM mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL); 34657836SJohn.Forte@Sun.COM 34667836SJohn.Forte@Sun.COM pd->pd_port_id.port_id = d_id; 34677836SJohn.Forte@Sun.COM pd->pd_port_name = *port_wwn; 34687836SJohn.Forte@Sun.COM pd->pd_port = port; 34697836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 34707836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NEW; 34717836SJohn.Forte@Sun.COM pd->pd_recepient = recepient; 34727836SJohn.Forte@Sun.COM 34737836SJohn.Forte@Sun.COM return (pd); 34747836SJohn.Forte@Sun.COM } 34757836SJohn.Forte@Sun.COM 34767836SJohn.Forte@Sun.COM 34777836SJohn.Forte@Sun.COM /* 34787836SJohn.Forte@Sun.COM * Deconstruct and free the given fc_remote_port_t struct (unconditionally). 34797836SJohn.Forte@Sun.COM */ 34807836SJohn.Forte@Sun.COM void 34817836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(fc_remote_port_t *pd) 34827836SJohn.Forte@Sun.COM { 34837836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 34847836SJohn.Forte@Sun.COM 34857836SJohn.Forte@Sun.COM fctl_tc_destructor(&pd->pd_logo_tc); 34867836SJohn.Forte@Sun.COM mutex_destroy(&pd->pd_mutex); 34877836SJohn.Forte@Sun.COM kmem_free(pd, sizeof (*pd)); 34887836SJohn.Forte@Sun.COM } 34897836SJohn.Forte@Sun.COM 34907836SJohn.Forte@Sun.COM /* 34917836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t onto the linked list of remote port 34927836SJohn.Forte@Sun.COM * devices associated with the given fc_remote_node_t. Does NOT add the 34937836SJohn.Forte@Sun.COM * fc_remote_port_t to the list if already exists on the list. 34947836SJohn.Forte@Sun.COM */ 34957836SJohn.Forte@Sun.COM void 34967836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep, 34977836SJohn.Forte@Sun.COM fc_remote_port_t *pd) 34987836SJohn.Forte@Sun.COM { 34997836SJohn.Forte@Sun.COM fc_remote_port_t *last; 35007836SJohn.Forte@Sun.COM fc_remote_port_t *ports; 35017836SJohn.Forte@Sun.COM 35027836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 35037836SJohn.Forte@Sun.COM 35047836SJohn.Forte@Sun.COM last = NULL; 35057836SJohn.Forte@Sun.COM for (ports = rnodep->fd_portlistp; ports != NULL; 35067836SJohn.Forte@Sun.COM ports = ports->pd_port_next) { 35077836SJohn.Forte@Sun.COM if (ports == pd) { 35087836SJohn.Forte@Sun.COM /* 35097836SJohn.Forte@Sun.COM * The given fc_remote_port_t is already on the linked 35107836SJohn.Forte@Sun.COM * list chain for the given remote node, so bail now. 35117836SJohn.Forte@Sun.COM */ 35127836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 35137836SJohn.Forte@Sun.COM return; 35147836SJohn.Forte@Sun.COM } 35157836SJohn.Forte@Sun.COM last = ports; 35167836SJohn.Forte@Sun.COM } 35177836SJohn.Forte@Sun.COM 35187836SJohn.Forte@Sun.COM /* Add the fc_remote_port_t to the tail of the linked list */ 35197836SJohn.Forte@Sun.COM if (last != NULL) { 35207836SJohn.Forte@Sun.COM last->pd_port_next = pd; 35217836SJohn.Forte@Sun.COM } else { 35227836SJohn.Forte@Sun.COM rnodep->fd_portlistp = pd; 35237836SJohn.Forte@Sun.COM } 35247836SJohn.Forte@Sun.COM pd->pd_port_next = NULL; 35257836SJohn.Forte@Sun.COM 35267836SJohn.Forte@Sun.COM /* 35277836SJohn.Forte@Sun.COM * Link the fc_remote_port_t back to the associated fc_remote_node_t. 35287836SJohn.Forte@Sun.COM */ 35297836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 35307836SJohn.Forte@Sun.COM pd->pd_remote_nodep = rnodep; 35317836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 35327836SJohn.Forte@Sun.COM 35337836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 35347836SJohn.Forte@Sun.COM } 35357836SJohn.Forte@Sun.COM 35367836SJohn.Forte@Sun.COM 35377836SJohn.Forte@Sun.COM /* 35387836SJohn.Forte@Sun.COM * Remove the specified fc_remote_port_t from the linked list of remote ports 35397836SJohn.Forte@Sun.COM * for the given fc_remote_node_t. 35407836SJohn.Forte@Sun.COM * 35417836SJohn.Forte@Sun.COM * Returns a count of the _remaining_ fc_remote_port_t structs on the linked 35427836SJohn.Forte@Sun.COM * list of the fc_remote_node_t. 35437836SJohn.Forte@Sun.COM * 35447836SJohn.Forte@Sun.COM * The fd_numports on the given fc_remote_node_t is decremented, and if 35457836SJohn.Forte@Sun.COM * it hits zero then this function also removes the fc_remote_node_t from the 35467836SJohn.Forte@Sun.COM * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries 35477836SJohn.Forte@Sun.COM * are removed from the fctl_nwwn_hash_table[]. 35487836SJohn.Forte@Sun.COM */ 35497836SJohn.Forte@Sun.COM int 35507836SJohn.Forte@Sun.COM fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep, 35517836SJohn.Forte@Sun.COM fc_remote_port_t *pd) 35527836SJohn.Forte@Sun.COM { 35537836SJohn.Forte@Sun.COM int rcount = 0; 355410264SZhong.Wang@Sun.COM fc_remote_port_t *last; 355510264SZhong.Wang@Sun.COM fc_remote_port_t *ports; 35567836SJohn.Forte@Sun.COM 35577836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&rnodep->fd_mutex)); 35587836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 35597836SJohn.Forte@Sun.COM 35607836SJohn.Forte@Sun.COM last = NULL; 35617836SJohn.Forte@Sun.COM 35627836SJohn.Forte@Sun.COM mutex_enter(&fctl_nwwn_hash_mutex); 35637836SJohn.Forte@Sun.COM 35647836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 35657836SJohn.Forte@Sun.COM 35667836SJohn.Forte@Sun.COM /* 35677836SJohn.Forte@Sun.COM * Go thru the linked list of fc_remote_port_t structs for the given 35687836SJohn.Forte@Sun.COM * fc_remote_node_t; try to find the specified fc_remote_port_t (pd). 35697836SJohn.Forte@Sun.COM */ 35707836SJohn.Forte@Sun.COM ports = rnodep->fd_portlistp; 35717836SJohn.Forte@Sun.COM while (ports != NULL) { 35727836SJohn.Forte@Sun.COM if (ports == pd) { 35737836SJohn.Forte@Sun.COM break; /* Found the requested fc_remote_port_t */ 35747836SJohn.Forte@Sun.COM } 35757836SJohn.Forte@Sun.COM last = ports; 35767836SJohn.Forte@Sun.COM ports = ports->pd_port_next; 35777836SJohn.Forte@Sun.COM } 35787836SJohn.Forte@Sun.COM 35797836SJohn.Forte@Sun.COM if (ports) { 35807836SJohn.Forte@Sun.COM rcount = --rnodep->fd_numports; 35817836SJohn.Forte@Sun.COM if (rcount == 0) { 35827836SJohn.Forte@Sun.COM /* Note: this is only ever called from here */ 35837836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(rnodep); 35847836SJohn.Forte@Sun.COM } 35857836SJohn.Forte@Sun.COM if (last) { 35867836SJohn.Forte@Sun.COM last->pd_port_next = pd->pd_port_next; 35877836SJohn.Forte@Sun.COM } else { 35887836SJohn.Forte@Sun.COM rnodep->fd_portlistp = pd->pd_port_next; 35897836SJohn.Forte@Sun.COM } 35907836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 35917836SJohn.Forte@Sun.COM pd->pd_remote_nodep = NULL; 35927836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 35937836SJohn.Forte@Sun.COM } 35947836SJohn.Forte@Sun.COM 35957836SJohn.Forte@Sun.COM pd->pd_port_next = NULL; 35967836SJohn.Forte@Sun.COM 35977836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 35987836SJohn.Forte@Sun.COM mutex_exit(&fctl_nwwn_hash_mutex); 35997836SJohn.Forte@Sun.COM 36007836SJohn.Forte@Sun.COM return (rcount); 36017836SJohn.Forte@Sun.COM } 36027836SJohn.Forte@Sun.COM 36037836SJohn.Forte@Sun.COM 36047836SJohn.Forte@Sun.COM /* 36057836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t struct to the d_id table in the given 36067836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 36077836SJohn.Forte@Sun.COM * fc_remote_port_t. 36087836SJohn.Forte@Sun.COM * 36097836SJohn.Forte@Sun.COM * No memory allocs are required, so this never fails, but it does use the 36107836SJohn.Forte@Sun.COM * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list. 36117836SJohn.Forte@Sun.COM * (There does not seem to be a way to tell the caller that a duplicate 36127836SJohn.Forte@Sun.COM * exists.) 36137836SJohn.Forte@Sun.COM */ 36147836SJohn.Forte@Sun.COM void 36157836SJohn.Forte@Sun.COM fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 36167836SJohn.Forte@Sun.COM { 36177836SJohn.Forte@Sun.COM struct d_id_hash *head; 36187836SJohn.Forte@Sun.COM 36197836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 36207836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 36217836SJohn.Forte@Sun.COM 36227836SJohn.Forte@Sun.COM if (pd->pd_aux_flags & PD_IN_DID_QUEUE) { 36237836SJohn.Forte@Sun.COM return; 36247836SJohn.Forte@Sun.COM } 36257836SJohn.Forte@Sun.COM 36267836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id, 36277836SJohn.Forte@Sun.COM did_table_size)]; 36287836SJohn.Forte@Sun.COM 36297836SJohn.Forte@Sun.COM #ifdef DEBUG 36307836SJohn.Forte@Sun.COM { 36317836SJohn.Forte@Sun.COM int index; 363210264SZhong.Wang@Sun.COM fc_remote_port_t *tmp_pd; 36337836SJohn.Forte@Sun.COM struct d_id_hash *tmp_head; 36347836SJohn.Forte@Sun.COM 36357836SJohn.Forte@Sun.COM /* 36367836SJohn.Forte@Sun.COM * Search down in each bucket for a duplicate pd 36377836SJohn.Forte@Sun.COM * Also search for duplicate D_IDs 36387836SJohn.Forte@Sun.COM * This DEBUG code will force an ASSERT if a duplicate 36397836SJohn.Forte@Sun.COM * is ever found. 36407836SJohn.Forte@Sun.COM */ 36417836SJohn.Forte@Sun.COM for (index = 0; index < did_table_size; index++) { 36427836SJohn.Forte@Sun.COM tmp_head = &port->fp_did_table[index]; 36437836SJohn.Forte@Sun.COM 36447836SJohn.Forte@Sun.COM tmp_pd = tmp_head->d_id_head; 36457836SJohn.Forte@Sun.COM while (tmp_pd != NULL) { 36467836SJohn.Forte@Sun.COM ASSERT(tmp_pd != pd); 36477836SJohn.Forte@Sun.COM 36487836SJohn.Forte@Sun.COM if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 36497836SJohn.Forte@Sun.COM tmp_pd->pd_type != PORT_DEVICE_OLD) { 36507836SJohn.Forte@Sun.COM ASSERT(tmp_pd->pd_port_id.port_id != 36517836SJohn.Forte@Sun.COM pd->pd_port_id.port_id); 36527836SJohn.Forte@Sun.COM } 36537836SJohn.Forte@Sun.COM 36547836SJohn.Forte@Sun.COM tmp_pd = tmp_pd->pd_did_hnext; 36557836SJohn.Forte@Sun.COM } 36567836SJohn.Forte@Sun.COM } 36577836SJohn.Forte@Sun.COM } 36587836SJohn.Forte@Sun.COM 36597836SJohn.Forte@Sun.COM bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack)); 36607836SJohn.Forte@Sun.COM pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH); 36617836SJohn.Forte@Sun.COM #endif 36627836SJohn.Forte@Sun.COM 36637836SJohn.Forte@Sun.COM pd->pd_did_hnext = head->d_id_head; 36647836SJohn.Forte@Sun.COM head->d_id_head = pd; 36657836SJohn.Forte@Sun.COM 36667836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_IN_DID_QUEUE; 36677836SJohn.Forte@Sun.COM head->d_id_count++; 36687836SJohn.Forte@Sun.COM } 36697836SJohn.Forte@Sun.COM 36707836SJohn.Forte@Sun.COM 36717836SJohn.Forte@Sun.COM /* 36727836SJohn.Forte@Sun.COM * Remove the given fc_remote_port_t struct from the d_id table in the given 36737836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_id.port_id in the 36747836SJohn.Forte@Sun.COM * fc_remote_port_t. 36757836SJohn.Forte@Sun.COM * 36767836SJohn.Forte@Sun.COM * Does nothing if the requested fc_remote_port_t was not found. 36777836SJohn.Forte@Sun.COM */ 36787836SJohn.Forte@Sun.COM void 36797836SJohn.Forte@Sun.COM fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd) 36807836SJohn.Forte@Sun.COM { 36817836SJohn.Forte@Sun.COM uint32_t d_id; 368210264SZhong.Wang@Sun.COM struct d_id_hash *head; 368310264SZhong.Wang@Sun.COM fc_remote_port_t *pd_next; 368410264SZhong.Wang@Sun.COM fc_remote_port_t *last; 36857836SJohn.Forte@Sun.COM 36867836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 36877836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 36887836SJohn.Forte@Sun.COM 36897836SJohn.Forte@Sun.COM d_id = pd->pd_port_id.port_id; 36907836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 36917836SJohn.Forte@Sun.COM 36927836SJohn.Forte@Sun.COM pd_next = head->d_id_head; 36937836SJohn.Forte@Sun.COM last = NULL; 36947836SJohn.Forte@Sun.COM while (pd_next != NULL) { 36957836SJohn.Forte@Sun.COM if (pd == pd_next) { 36967836SJohn.Forte@Sun.COM break; /* Found the given fc_remote_port_t */ 36977836SJohn.Forte@Sun.COM } 36987836SJohn.Forte@Sun.COM last = pd_next; 36997836SJohn.Forte@Sun.COM pd_next = pd_next->pd_did_hnext; 37007836SJohn.Forte@Sun.COM } 37017836SJohn.Forte@Sun.COM 37027836SJohn.Forte@Sun.COM if (pd_next) { 37037836SJohn.Forte@Sun.COM /* 37047836SJohn.Forte@Sun.COM * Found the given fc_remote_port_t; now remove it from the 37057836SJohn.Forte@Sun.COM * d_id list. 37067836SJohn.Forte@Sun.COM */ 37077836SJohn.Forte@Sun.COM head->d_id_count--; 37087836SJohn.Forte@Sun.COM if (last == NULL) { 37097836SJohn.Forte@Sun.COM head->d_id_head = pd->pd_did_hnext; 37107836SJohn.Forte@Sun.COM } else { 37117836SJohn.Forte@Sun.COM last->pd_did_hnext = pd->pd_did_hnext; 37127836SJohn.Forte@Sun.COM } 37137836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 37147836SJohn.Forte@Sun.COM pd->pd_did_hnext = NULL; 37157836SJohn.Forte@Sun.COM } 37167836SJohn.Forte@Sun.COM } 37177836SJohn.Forte@Sun.COM 37187836SJohn.Forte@Sun.COM 37197836SJohn.Forte@Sun.COM /* 37207836SJohn.Forte@Sun.COM * Add the given fc_remote_port_t struct to the pwwn table in the given 37217836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 37227836SJohn.Forte@Sun.COM * in the fc_remote_port_t. 37237836SJohn.Forte@Sun.COM * 37247836SJohn.Forte@Sun.COM * No memory allocs are required, so this never fails. 37257836SJohn.Forte@Sun.COM */ 37267836SJohn.Forte@Sun.COM void 37277836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 37287836SJohn.Forte@Sun.COM { 37297836SJohn.Forte@Sun.COM int index; 37307836SJohn.Forte@Sun.COM struct pwwn_hash *head; 37317836SJohn.Forte@Sun.COM 37327836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 37337836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 37347836SJohn.Forte@Sun.COM 37357836SJohn.Forte@Sun.COM ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE); 37367836SJohn.Forte@Sun.COM 37377836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn), 37387836SJohn.Forte@Sun.COM pwwn_table_size); 37397836SJohn.Forte@Sun.COM 37407836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 37417836SJohn.Forte@Sun.COM 37427836SJohn.Forte@Sun.COM #ifdef DEBUG 37437836SJohn.Forte@Sun.COM { 37447836SJohn.Forte@Sun.COM int index; 374510264SZhong.Wang@Sun.COM fc_remote_port_t *tmp_pd; 37467836SJohn.Forte@Sun.COM struct pwwn_hash *tmp_head; 37477836SJohn.Forte@Sun.COM 37487836SJohn.Forte@Sun.COM /* 37497836SJohn.Forte@Sun.COM * Search down in each bucket for a duplicate pd 37507836SJohn.Forte@Sun.COM * Search also for a duplicate WWN 37517836SJohn.Forte@Sun.COM * Throw an ASSERT if any duplicate is found. 37527836SJohn.Forte@Sun.COM */ 37537836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 37547836SJohn.Forte@Sun.COM tmp_head = &port->fp_pwwn_table[index]; 37557836SJohn.Forte@Sun.COM 37567836SJohn.Forte@Sun.COM tmp_pd = tmp_head->pwwn_head; 37577836SJohn.Forte@Sun.COM while (tmp_pd != NULL) { 37587836SJohn.Forte@Sun.COM ASSERT(tmp_pd != pd); 37597836SJohn.Forte@Sun.COM 37607836SJohn.Forte@Sun.COM if (tmp_pd->pd_state != PORT_DEVICE_INVALID && 37617836SJohn.Forte@Sun.COM tmp_pd->pd_type != PORT_DEVICE_OLD) { 37627836SJohn.Forte@Sun.COM ASSERT(fctl_wwn_cmp( 37637836SJohn.Forte@Sun.COM &tmp_pd->pd_port_name, 37647836SJohn.Forte@Sun.COM &pd->pd_port_name) != 0); 37657836SJohn.Forte@Sun.COM } 37667836SJohn.Forte@Sun.COM 37677836SJohn.Forte@Sun.COM tmp_pd = tmp_pd->pd_wwn_hnext; 37687836SJohn.Forte@Sun.COM } 37697836SJohn.Forte@Sun.COM } 37707836SJohn.Forte@Sun.COM } 37717836SJohn.Forte@Sun.COM 37727836SJohn.Forte@Sun.COM bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack)); 37737836SJohn.Forte@Sun.COM pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH); 37747836SJohn.Forte@Sun.COM #endif /* DEBUG */ 37757836SJohn.Forte@Sun.COM 37767836SJohn.Forte@Sun.COM pd->pd_wwn_hnext = head->pwwn_head; 37777836SJohn.Forte@Sun.COM head->pwwn_head = pd; 37787836SJohn.Forte@Sun.COM 37797836SJohn.Forte@Sun.COM head->pwwn_count++; 37807836SJohn.Forte@Sun.COM /* 37817836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 37827836SJohn.Forte@Sun.COM * pwwn_table 37837836SJohn.Forte@Sun.COM */ 37847836SJohn.Forte@Sun.COM port->fp_dev_count++; 37857836SJohn.Forte@Sun.COM } 37867836SJohn.Forte@Sun.COM 37877836SJohn.Forte@Sun.COM 37887836SJohn.Forte@Sun.COM /* 37897836SJohn.Forte@Sun.COM * Remove the given fc_remote_port_t struct from the pwwn table in the given 37907836SJohn.Forte@Sun.COM * fc_local_port_t struct. Hashes based upon the pd->pd_port_name.raw_wwn 37917836SJohn.Forte@Sun.COM * in the fc_remote_port_t. 37927836SJohn.Forte@Sun.COM * 37937836SJohn.Forte@Sun.COM * Does nothing if the requested fc_remote_port_t was not found. 37947836SJohn.Forte@Sun.COM */ 37957836SJohn.Forte@Sun.COM void 37967836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd) 37977836SJohn.Forte@Sun.COM { 37987836SJohn.Forte@Sun.COM int index; 37997836SJohn.Forte@Sun.COM la_wwn_t pwwn; 380010264SZhong.Wang@Sun.COM struct pwwn_hash *head; 380110264SZhong.Wang@Sun.COM fc_remote_port_t *pd_next; 380210264SZhong.Wang@Sun.COM fc_remote_port_t *last; 38037836SJohn.Forte@Sun.COM 38047836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 38057836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 38067836SJohn.Forte@Sun.COM 38077836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 38087836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size); 38097836SJohn.Forte@Sun.COM 38107836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 38117836SJohn.Forte@Sun.COM 38127836SJohn.Forte@Sun.COM last = NULL; 38137836SJohn.Forte@Sun.COM pd_next = head->pwwn_head; 38147836SJohn.Forte@Sun.COM while (pd_next != NULL) { 38157836SJohn.Forte@Sun.COM if (pd_next == pd) { 38167836SJohn.Forte@Sun.COM break; /* Found the given fc_remote_port_t */ 38177836SJohn.Forte@Sun.COM } 38187836SJohn.Forte@Sun.COM last = pd_next; 38197836SJohn.Forte@Sun.COM pd_next = pd_next->pd_wwn_hnext; 38207836SJohn.Forte@Sun.COM } 38217836SJohn.Forte@Sun.COM 38227836SJohn.Forte@Sun.COM if (pd_next) { 38237836SJohn.Forte@Sun.COM /* 38247836SJohn.Forte@Sun.COM * Found the given fc_remote_port_t; now remove it from the 38257836SJohn.Forte@Sun.COM * pwwn list. 38267836SJohn.Forte@Sun.COM */ 38277836SJohn.Forte@Sun.COM head->pwwn_count--; 38287836SJohn.Forte@Sun.COM /* 38297836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 38307836SJohn.Forte@Sun.COM * pwwn_table 38317836SJohn.Forte@Sun.COM */ 38327836SJohn.Forte@Sun.COM port->fp_dev_count--; 38337836SJohn.Forte@Sun.COM if (last == NULL) { 38347836SJohn.Forte@Sun.COM head->pwwn_head = pd->pd_wwn_hnext; 38357836SJohn.Forte@Sun.COM } else { 38367836SJohn.Forte@Sun.COM last->pd_wwn_hnext = pd->pd_wwn_hnext; 38377836SJohn.Forte@Sun.COM } 38387836SJohn.Forte@Sun.COM pd->pd_wwn_hnext = NULL; 38397836SJohn.Forte@Sun.COM } 38407836SJohn.Forte@Sun.COM } 38417836SJohn.Forte@Sun.COM 38427836SJohn.Forte@Sun.COM 38437836SJohn.Forte@Sun.COM /* 38447836SJohn.Forte@Sun.COM * Looks in the d_id table of the specified fc_local_port_t for the 38457836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon 38467836SJohn.Forte@Sun.COM * the given d_id. 38477836SJohn.Forte@Sun.COM * Returns a pointer to the fc_remote_port_t struct, but does not update any 38487836SJohn.Forte@Sun.COM * reference counts or otherwise indicate that the fc_remote_port_t is in 38497836SJohn.Forte@Sun.COM * use. 38507836SJohn.Forte@Sun.COM */ 38517836SJohn.Forte@Sun.COM fc_remote_port_t * 38527836SJohn.Forte@Sun.COM fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 38537836SJohn.Forte@Sun.COM { 385410264SZhong.Wang@Sun.COM struct d_id_hash *head; 385510264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 38567836SJohn.Forte@Sun.COM 38577836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 38587836SJohn.Forte@Sun.COM 38597836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 38607836SJohn.Forte@Sun.COM 38617836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 38627836SJohn.Forte@Sun.COM 38637836SJohn.Forte@Sun.COM pd = head->d_id_head; 38647836SJohn.Forte@Sun.COM while (pd != NULL) { 38657836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 38667836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id) { 38677836SJohn.Forte@Sun.COM /* Match found -- break out of the loop */ 38687836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 38697836SJohn.Forte@Sun.COM break; 38707836SJohn.Forte@Sun.COM } 38717836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 38727836SJohn.Forte@Sun.COM pd = pd->pd_did_hnext; 38737836SJohn.Forte@Sun.COM } 38747836SJohn.Forte@Sun.COM 38757836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 38767836SJohn.Forte@Sun.COM 38777836SJohn.Forte@Sun.COM return (pd); 38787836SJohn.Forte@Sun.COM } 38797836SJohn.Forte@Sun.COM 38807836SJohn.Forte@Sun.COM 38817836SJohn.Forte@Sun.COM #ifndef __lock_lint /* uncomment when there is a consumer */ 38827836SJohn.Forte@Sun.COM 38837836SJohn.Forte@Sun.COM void 38847836SJohn.Forte@Sun.COM fc_ulp_hold_remote_port(opaque_t port_handle) 38857836SJohn.Forte@Sun.COM { 38867836SJohn.Forte@Sun.COM fc_remote_port_t *pd = port_handle; 38877836SJohn.Forte@Sun.COM 38887836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 38897836SJohn.Forte@Sun.COM pd->pd_ref_count++; 38907836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 38917836SJohn.Forte@Sun.COM } 38927836SJohn.Forte@Sun.COM 38937836SJohn.Forte@Sun.COM /* 38947836SJohn.Forte@Sun.COM * Looks in the d_id table of the specified fc_local_port_t for the 38957836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon 38967836SJohn.Forte@Sun.COM * the given d_id. Returns a pointer to the fc_remote_port_t struct. 38977836SJohn.Forte@Sun.COM * 38987836SJohn.Forte@Sun.COM * Increments pd_ref_count in the fc_remote_port_t if the 38997836SJohn.Forte@Sun.COM * fc_remote_port_t is found at the given d_id. 39007836SJohn.Forte@Sun.COM * 39017836SJohn.Forte@Sun.COM * The fc_remote_port_t is ignored (treated as non-existent) if either 39027836SJohn.Forte@Sun.COM * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 39037836SJohn.Forte@Sun.COM */ 39047836SJohn.Forte@Sun.COM fc_remote_port_t * 39057836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id) 39067836SJohn.Forte@Sun.COM { 390710264SZhong.Wang@Sun.COM struct d_id_hash *head; 390810264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 39097836SJohn.Forte@Sun.COM 39107836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 39117836SJohn.Forte@Sun.COM 39127836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 39137836SJohn.Forte@Sun.COM 39147836SJohn.Forte@Sun.COM head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)]; 39157836SJohn.Forte@Sun.COM 39167836SJohn.Forte@Sun.COM pd = head->d_id_head; 39177836SJohn.Forte@Sun.COM while (pd != NULL) { 39187836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 39197836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id && pd->pd_state != 39207836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) { 39217836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 39227836SJohn.Forte@Sun.COM pd->pd_ref_count++; 39237836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39247836SJohn.Forte@Sun.COM break; 39257836SJohn.Forte@Sun.COM } 39267836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39277836SJohn.Forte@Sun.COM pd = pd->pd_did_hnext; 39287836SJohn.Forte@Sun.COM } 39297836SJohn.Forte@Sun.COM 39307836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 39317836SJohn.Forte@Sun.COM 39327836SJohn.Forte@Sun.COM return (pd); 39337836SJohn.Forte@Sun.COM } 39347836SJohn.Forte@Sun.COM 39357836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 39367836SJohn.Forte@Sun.COM 39377836SJohn.Forte@Sun.COM /* 39387836SJohn.Forte@Sun.COM * Looks in the pwwn table of the specified fc_local_port_t for the 39397836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given pwwn. Hashes based upon the 39407836SJohn.Forte@Sun.COM * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct, 39417836SJohn.Forte@Sun.COM * but does not update any reference counts or otherwise indicate that 39427836SJohn.Forte@Sun.COM * the fc_remote_port_t is in use. 39437836SJohn.Forte@Sun.COM */ 39447836SJohn.Forte@Sun.COM fc_remote_port_t * 39457836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 39467836SJohn.Forte@Sun.COM { 39477836SJohn.Forte@Sun.COM int index; 394810264SZhong.Wang@Sun.COM struct pwwn_hash *head; 394910264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 39507836SJohn.Forte@Sun.COM 39517836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 39527836SJohn.Forte@Sun.COM 39537836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 39547836SJohn.Forte@Sun.COM 39557836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 39567836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 39577836SJohn.Forte@Sun.COM 39587836SJohn.Forte@Sun.COM pd = head->pwwn_head; 39597836SJohn.Forte@Sun.COM while (pd != NULL) { 39607836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 39617836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 39627836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39637836SJohn.Forte@Sun.COM break; 39647836SJohn.Forte@Sun.COM } 39657836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39667836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 39677836SJohn.Forte@Sun.COM } 39687836SJohn.Forte@Sun.COM 39697836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 39707836SJohn.Forte@Sun.COM 39717836SJohn.Forte@Sun.COM return (pd); 39727836SJohn.Forte@Sun.COM } 39737836SJohn.Forte@Sun.COM 39747836SJohn.Forte@Sun.COM 39757836SJohn.Forte@Sun.COM /* 39767836SJohn.Forte@Sun.COM * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that 39777836SJohn.Forte@Sun.COM * the caller already hold the fp_mutex in the fc_local_port_t struct. 39787836SJohn.Forte@Sun.COM */ 39797836SJohn.Forte@Sun.COM fc_remote_port_t * 39807836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn) 39817836SJohn.Forte@Sun.COM { 39827836SJohn.Forte@Sun.COM int index; 398310264SZhong.Wang@Sun.COM struct pwwn_hash *head; 398410264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 39857836SJohn.Forte@Sun.COM 39867836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 39877836SJohn.Forte@Sun.COM 39887836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 39897836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 39907836SJohn.Forte@Sun.COM 39917836SJohn.Forte@Sun.COM pd = head->pwwn_head; 39927836SJohn.Forte@Sun.COM while (pd != NULL) { 39937836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 39947836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) { 39957836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39967836SJohn.Forte@Sun.COM break; 39977836SJohn.Forte@Sun.COM } 39987836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 39997836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 40007836SJohn.Forte@Sun.COM } 40017836SJohn.Forte@Sun.COM 40027836SJohn.Forte@Sun.COM return (pd); 40037836SJohn.Forte@Sun.COM } 40047836SJohn.Forte@Sun.COM 40057836SJohn.Forte@Sun.COM 40067836SJohn.Forte@Sun.COM /* 40077836SJohn.Forte@Sun.COM * Looks in the pwwn table of the specified fc_local_port_t for the 40087836SJohn.Forte@Sun.COM * fc_remote_port_t that matches the given d_id. Hashes based upon the 40097836SJohn.Forte@Sun.COM * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct. 40107836SJohn.Forte@Sun.COM * 40117836SJohn.Forte@Sun.COM * Increments pd_ref_count in the fc_remote_port_t if the 40127836SJohn.Forte@Sun.COM * fc_remote_port_t is found at the given pwwn. 40137836SJohn.Forte@Sun.COM * 40147836SJohn.Forte@Sun.COM * The fc_remote_port_t is ignored (treated as non-existent) if either 40157836SJohn.Forte@Sun.COM * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD. 40167836SJohn.Forte@Sun.COM */ 40177836SJohn.Forte@Sun.COM fc_remote_port_t * 40187836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn) 40197836SJohn.Forte@Sun.COM { 40207836SJohn.Forte@Sun.COM int index; 402110264SZhong.Wang@Sun.COM struct pwwn_hash *head; 402210264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 40237836SJohn.Forte@Sun.COM 40247836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 40257836SJohn.Forte@Sun.COM 40267836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 40277836SJohn.Forte@Sun.COM 40287836SJohn.Forte@Sun.COM index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size); 40297836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 40307836SJohn.Forte@Sun.COM 40317836SJohn.Forte@Sun.COM pd = head->pwwn_head; 40327836SJohn.Forte@Sun.COM while (pd != NULL) { 40337836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 40347836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 && 40357836SJohn.Forte@Sun.COM pd->pd_state != PORT_DEVICE_INVALID && 40367836SJohn.Forte@Sun.COM pd->pd_type != PORT_DEVICE_OLD) { 40377836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count >= 0); 40387836SJohn.Forte@Sun.COM pd->pd_ref_count++; 40397836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 40407836SJohn.Forte@Sun.COM break; 40417836SJohn.Forte@Sun.COM } 40427836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 40437836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 40447836SJohn.Forte@Sun.COM } 40457836SJohn.Forte@Sun.COM 40467836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 40477836SJohn.Forte@Sun.COM 40487836SJohn.Forte@Sun.COM return (pd); 40497836SJohn.Forte@Sun.COM } 40507836SJohn.Forte@Sun.COM 40517836SJohn.Forte@Sun.COM 40527836SJohn.Forte@Sun.COM /* 40537836SJohn.Forte@Sun.COM * Unconditionally decrement pd_ref_count in the given fc_remote_port_t 40547836SJohn.Forte@Sun.COM * struct. 40557836SJohn.Forte@Sun.COM * 40567836SJohn.Forte@Sun.COM * If pd_ref_count reaches zero, then this function will see if the 40577836SJohn.Forte@Sun.COM * fc_remote_port_t has been marked for deallocation. If so (and also if there 40587836SJohn.Forte@Sun.COM * are no other potential operations in progress, as indicated by the 40597836SJohn.Forte@Sun.COM * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then 40607836SJohn.Forte@Sun.COM * fctl_destroy_remote_port_t() is called to deconstruct/free the given 40617836SJohn.Forte@Sun.COM * fc_remote_port_t (which will also remove it from the d_id and pwwn tables 406210264SZhong.Wang@Sun.COM * on the associated fc_local_port_t). If the associated fc_remote_node_t is no 40637836SJohn.Forte@Sun.COM * longer in use, then it too is deconstructed/freed. 40647836SJohn.Forte@Sun.COM */ 40657836SJohn.Forte@Sun.COM void 40667836SJohn.Forte@Sun.COM fctl_release_remote_port(fc_remote_port_t *pd) 40677836SJohn.Forte@Sun.COM { 40687836SJohn.Forte@Sun.COM int remove = 0; 406910264SZhong.Wang@Sun.COM fc_remote_node_t *node; 407010264SZhong.Wang@Sun.COM fc_local_port_t *port; 40717836SJohn.Forte@Sun.COM 40727836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 40737836SJohn.Forte@Sun.COM port = pd->pd_port; 40747836SJohn.Forte@Sun.COM 40757836SJohn.Forte@Sun.COM ASSERT(pd->pd_ref_count > 0); 40767836SJohn.Forte@Sun.COM pd->pd_ref_count--; 40777836SJohn.Forte@Sun.COM if (pd->pd_ref_count == 0 && 40787836SJohn.Forte@Sun.COM (pd->pd_aux_flags & PD_NEEDS_REMOVAL) && 40797836SJohn.Forte@Sun.COM (pd->pd_flags != PD_ELS_IN_PROGRESS) && 40807836SJohn.Forte@Sun.COM (pd->pd_flags != PD_ELS_MARK)) { 40817836SJohn.Forte@Sun.COM remove = 1; 40827836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL; 40837836SJohn.Forte@Sun.COM } 40847836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 40857836SJohn.Forte@Sun.COM ASSERT(node != NULL); 40867836SJohn.Forte@Sun.COM 40877836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 40887836SJohn.Forte@Sun.COM 40897836SJohn.Forte@Sun.COM if (remove) { 40907836SJohn.Forte@Sun.COM /* 40917836SJohn.Forte@Sun.COM * The fc_remote_port_t struct has to go away now, so call the 40927836SJohn.Forte@Sun.COM * cleanup function to get it off the various lists and remove 40937836SJohn.Forte@Sun.COM * references to it in any other associated structs. 40947836SJohn.Forte@Sun.COM */ 40957836SJohn.Forte@Sun.COM if (fctl_destroy_remote_port(port, pd) == 0) { 40967836SJohn.Forte@Sun.COM /* 40977836SJohn.Forte@Sun.COM * No more fc_remote_port_t references found in the 40987836SJohn.Forte@Sun.COM * associated fc_remote_node_t, so deallocate the 40997836SJohn.Forte@Sun.COM * fc_remote_node_t (if it even exists). 41007836SJohn.Forte@Sun.COM */ 41017836SJohn.Forte@Sun.COM if (node) { 41027836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 41037836SJohn.Forte@Sun.COM } 41047836SJohn.Forte@Sun.COM } 41057836SJohn.Forte@Sun.COM } 41067836SJohn.Forte@Sun.COM } 41077836SJohn.Forte@Sun.COM 41087836SJohn.Forte@Sun.COM 41097836SJohn.Forte@Sun.COM void 41107836SJohn.Forte@Sun.COM fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len, 41117836SJohn.Forte@Sun.COM int whole_map, int justcopy, int orphan) 41127836SJohn.Forte@Sun.COM { 41137836SJohn.Forte@Sun.COM int index; 41147836SJohn.Forte@Sun.COM int listlen; 41157836SJohn.Forte@Sun.COM int full_list; 41167836SJohn.Forte@Sun.COM int initiator; 41177836SJohn.Forte@Sun.COM uint32_t topology; 411810264SZhong.Wang@Sun.COM struct pwwn_hash *head; 411910264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 412010264SZhong.Wang@Sun.COM fc_remote_port_t *old_pd; 41217836SJohn.Forte@Sun.COM fc_remote_port_t *last_pd; 41227836SJohn.Forte@Sun.COM fc_portmap_t *listptr; 41237836SJohn.Forte@Sun.COM 41247836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 41257836SJohn.Forte@Sun.COM 41267836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 41277836SJohn.Forte@Sun.COM 41287836SJohn.Forte@Sun.COM topology = port->fp_topology; 41297836SJohn.Forte@Sun.COM 41307836SJohn.Forte@Sun.COM if (orphan) { 41317836SJohn.Forte@Sun.COM ASSERT(!FC_IS_TOP_SWITCH(topology)); 41327836SJohn.Forte@Sun.COM } 41337836SJohn.Forte@Sun.COM 41347836SJohn.Forte@Sun.COM for (full_list = listlen = index = 0; 41357836SJohn.Forte@Sun.COM index < pwwn_table_size; index++) { 41367836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 41377836SJohn.Forte@Sun.COM pd = head->pwwn_head; 41387836SJohn.Forte@Sun.COM while (pd != NULL) { 41397836SJohn.Forte@Sun.COM full_list++; 41407836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 41417836SJohn.Forte@Sun.COM if (pd->pd_type != PORT_DEVICE_NOCHANGE) { 41427836SJohn.Forte@Sun.COM listlen++; 41437836SJohn.Forte@Sun.COM } 41447836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 41457836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 41467836SJohn.Forte@Sun.COM } 41477836SJohn.Forte@Sun.COM } 41487836SJohn.Forte@Sun.COM 41497836SJohn.Forte@Sun.COM if (whole_map == 0) { 41507836SJohn.Forte@Sun.COM if (listlen == 0 && *len == 0) { 41517836SJohn.Forte@Sun.COM *map = NULL; 41527836SJohn.Forte@Sun.COM *len = listlen; 41537836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 41547836SJohn.Forte@Sun.COM return; 41557836SJohn.Forte@Sun.COM } 41567836SJohn.Forte@Sun.COM } else { 41577836SJohn.Forte@Sun.COM if (full_list == 0 && *len == 0) { 41587836SJohn.Forte@Sun.COM *map = NULL; 41597836SJohn.Forte@Sun.COM *len = full_list; 41607836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 41617836SJohn.Forte@Sun.COM return; 41627836SJohn.Forte@Sun.COM } 41637836SJohn.Forte@Sun.COM } 41647836SJohn.Forte@Sun.COM 41657836SJohn.Forte@Sun.COM if (*len == 0) { 41667836SJohn.Forte@Sun.COM ASSERT(*map == NULL); 41677836SJohn.Forte@Sun.COM if (whole_map == 0) { 41687836SJohn.Forte@Sun.COM listptr = *map = kmem_zalloc( 41697836SJohn.Forte@Sun.COM sizeof (*listptr) * listlen, KM_SLEEP); 41707836SJohn.Forte@Sun.COM *len = listlen; 41717836SJohn.Forte@Sun.COM } else { 41727836SJohn.Forte@Sun.COM listptr = *map = kmem_zalloc( 41737836SJohn.Forte@Sun.COM sizeof (*listptr) * full_list, KM_SLEEP); 41747836SJohn.Forte@Sun.COM *len = full_list; 41757836SJohn.Forte@Sun.COM } 41767836SJohn.Forte@Sun.COM } else { 41777836SJohn.Forte@Sun.COM /* 41787836SJohn.Forte@Sun.COM * By design this routine mandates the callers to 41797836SJohn.Forte@Sun.COM * ask for a whole map when they specify the length 41807836SJohn.Forte@Sun.COM * and the listptr. 41817836SJohn.Forte@Sun.COM */ 41827836SJohn.Forte@Sun.COM ASSERT(whole_map == 1); 41837836SJohn.Forte@Sun.COM if (*len < full_list) { 41847836SJohn.Forte@Sun.COM *len = full_list; 41857836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 41867836SJohn.Forte@Sun.COM return; 41877836SJohn.Forte@Sun.COM } 41887836SJohn.Forte@Sun.COM listptr = *map; 41897836SJohn.Forte@Sun.COM *len = full_list; 41907836SJohn.Forte@Sun.COM } 41917836SJohn.Forte@Sun.COM 41927836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 41937836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 41947836SJohn.Forte@Sun.COM last_pd = NULL; 41957836SJohn.Forte@Sun.COM pd = head->pwwn_head; 41967836SJohn.Forte@Sun.COM while (pd != NULL) { 41977836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 41987836SJohn.Forte@Sun.COM if ((whole_map == 0 && 41997836SJohn.Forte@Sun.COM pd->pd_type == PORT_DEVICE_NOCHANGE) || 42007836SJohn.Forte@Sun.COM pd->pd_state == PORT_DEVICE_INVALID) { 42017836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 42027836SJohn.Forte@Sun.COM last_pd = pd; 42037836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 42047836SJohn.Forte@Sun.COM continue; 42057836SJohn.Forte@Sun.COM } 42067836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 42077836SJohn.Forte@Sun.COM 42087836SJohn.Forte@Sun.COM fctl_copy_portmap(listptr, pd); 42097836SJohn.Forte@Sun.COM 42107836SJohn.Forte@Sun.COM if (justcopy) { 42117836SJohn.Forte@Sun.COM last_pd = pd; 42127836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 42137836SJohn.Forte@Sun.COM listptr++; 42147836SJohn.Forte@Sun.COM continue; 42157836SJohn.Forte@Sun.COM } 42167836SJohn.Forte@Sun.COM 42177836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 42187836SJohn.Forte@Sun.COM ASSERT(pd->pd_state != PORT_DEVICE_INVALID); 42197836SJohn.Forte@Sun.COM if (pd->pd_type == PORT_DEVICE_OLD) { 42207836SJohn.Forte@Sun.COM listptr->map_pd = pd; 42217836SJohn.Forte@Sun.COM listptr->map_state = pd->pd_state = 42227836SJohn.Forte@Sun.COM PORT_DEVICE_INVALID; 42237836SJohn.Forte@Sun.COM /* 42247836SJohn.Forte@Sun.COM * Remove this from the PWWN hash table. 42257836SJohn.Forte@Sun.COM */ 42267836SJohn.Forte@Sun.COM old_pd = pd; 42277836SJohn.Forte@Sun.COM pd = old_pd->pd_wwn_hnext; 42287836SJohn.Forte@Sun.COM 42297836SJohn.Forte@Sun.COM if (last_pd == NULL) { 42307836SJohn.Forte@Sun.COM ASSERT(old_pd == head->pwwn_head); 42317836SJohn.Forte@Sun.COM 42327836SJohn.Forte@Sun.COM head->pwwn_head = pd; 42337836SJohn.Forte@Sun.COM } else { 42347836SJohn.Forte@Sun.COM last_pd->pd_wwn_hnext = pd; 42357836SJohn.Forte@Sun.COM } 42367836SJohn.Forte@Sun.COM head->pwwn_count--; 42377836SJohn.Forte@Sun.COM /* 42387836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size 42397836SJohn.Forte@Sun.COM * of the pwwn_table 42407836SJohn.Forte@Sun.COM */ 42417836SJohn.Forte@Sun.COM port->fp_dev_count--; 42427836SJohn.Forte@Sun.COM old_pd->pd_wwn_hnext = NULL; 42437836SJohn.Forte@Sun.COM 42447836SJohn.Forte@Sun.COM if (port->fp_topology == FC_TOP_PRIVATE_LOOP && 42457836SJohn.Forte@Sun.COM port->fp_statec_busy && !orphan) { 42467836SJohn.Forte@Sun.COM fctl_check_alpa_list(port, old_pd); 42477836SJohn.Forte@Sun.COM } 42487836SJohn.Forte@Sun.COM 42497836SJohn.Forte@Sun.COM /* 42507836SJohn.Forte@Sun.COM * Remove if the port device has stealthily 42517836SJohn.Forte@Sun.COM * present in the D_ID hash table 42527836SJohn.Forte@Sun.COM */ 42537836SJohn.Forte@Sun.COM fctl_delist_did_table(port, old_pd); 42547836SJohn.Forte@Sun.COM 42557836SJohn.Forte@Sun.COM ASSERT(old_pd->pd_remote_nodep != NULL); 42567836SJohn.Forte@Sun.COM 42577836SJohn.Forte@Sun.COM initiator = (old_pd->pd_recepient == 42587836SJohn.Forte@Sun.COM PD_PLOGI_INITIATOR) ? 1 : 0; 42597836SJohn.Forte@Sun.COM 42607836SJohn.Forte@Sun.COM mutex_exit(&old_pd->pd_mutex); 42617836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 42627836SJohn.Forte@Sun.COM 42637836SJohn.Forte@Sun.COM if (orphan) { 42647836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(port, old_pd); 42657836SJohn.Forte@Sun.COM 42667836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 42677836SJohn.Forte@Sun.COM KM_NOSLEEP); 42687836SJohn.Forte@Sun.COM } 42697836SJohn.Forte@Sun.COM 42707836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(topology) && initiator) { 42717836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 42727836SJohn.Forte@Sun.COM KM_NOSLEEP); 42737836SJohn.Forte@Sun.COM } 42747836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 42757836SJohn.Forte@Sun.COM } else { 42767836SJohn.Forte@Sun.COM listptr->map_pd = pd; 42777836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 42787836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 42797836SJohn.Forte@Sun.COM last_pd = pd; 42807836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 42817836SJohn.Forte@Sun.COM } 42827836SJohn.Forte@Sun.COM listptr++; 42837836SJohn.Forte@Sun.COM } 42847836SJohn.Forte@Sun.COM } 42857836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 42867836SJohn.Forte@Sun.COM } 42877836SJohn.Forte@Sun.COM 42887836SJohn.Forte@Sun.COM 42897836SJohn.Forte@Sun.COM job_request_t * 42907836SJohn.Forte@Sun.COM fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t), 42917836SJohn.Forte@Sun.COM opaque_t arg, int sleep) 42927836SJohn.Forte@Sun.COM { 42937836SJohn.Forte@Sun.COM job_request_t *job; 42947836SJohn.Forte@Sun.COM 42957836SJohn.Forte@Sun.COM job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep); 42967836SJohn.Forte@Sun.COM if (job != NULL) { 42977836SJohn.Forte@Sun.COM job->job_result = FC_SUCCESS; 42987836SJohn.Forte@Sun.COM job->job_code = job_code; 42997836SJohn.Forte@Sun.COM job->job_flags = job_flags; 43007836SJohn.Forte@Sun.COM job->job_cb_arg = arg; 43017836SJohn.Forte@Sun.COM job->job_comp = comp; 43027836SJohn.Forte@Sun.COM job->job_private = NULL; 43037836SJohn.Forte@Sun.COM job->job_ulp_pkts = NULL; 43047836SJohn.Forte@Sun.COM job->job_ulp_listlen = 0; 43057836SJohn.Forte@Sun.COM #ifndef __lock_lint 43067836SJohn.Forte@Sun.COM job->job_counter = 0; 43077836SJohn.Forte@Sun.COM job->job_next = NULL; 43087836SJohn.Forte@Sun.COM #endif /* __lock_lint */ 43097836SJohn.Forte@Sun.COM } 43107836SJohn.Forte@Sun.COM 43117836SJohn.Forte@Sun.COM return (job); 43127836SJohn.Forte@Sun.COM } 43137836SJohn.Forte@Sun.COM 43147836SJohn.Forte@Sun.COM 43157836SJohn.Forte@Sun.COM void 43167836SJohn.Forte@Sun.COM fctl_dealloc_job(job_request_t *job) 43177836SJohn.Forte@Sun.COM { 43187836SJohn.Forte@Sun.COM kmem_cache_free(fctl_job_cache, (void *)job); 43197836SJohn.Forte@Sun.COM } 43207836SJohn.Forte@Sun.COM 43217836SJohn.Forte@Sun.COM 43227836SJohn.Forte@Sun.COM void 43237836SJohn.Forte@Sun.COM fctl_enque_job(fc_local_port_t *port, job_request_t *job) 43247836SJohn.Forte@Sun.COM { 43257836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 43267836SJohn.Forte@Sun.COM 43277836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 43287836SJohn.Forte@Sun.COM 43297836SJohn.Forte@Sun.COM if (port->fp_job_tail == NULL) { 43307836SJohn.Forte@Sun.COM ASSERT(port->fp_job_head == NULL); 43317836SJohn.Forte@Sun.COM port->fp_job_head = port->fp_job_tail = job; 43327836SJohn.Forte@Sun.COM } else { 43337836SJohn.Forte@Sun.COM port->fp_job_tail->job_next = job; 43347836SJohn.Forte@Sun.COM port->fp_job_tail = job; 43357836SJohn.Forte@Sun.COM } 43367836SJohn.Forte@Sun.COM job->job_next = NULL; 43377836SJohn.Forte@Sun.COM 43387836SJohn.Forte@Sun.COM cv_signal(&port->fp_cv); 43397836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 43407836SJohn.Forte@Sun.COM } 43417836SJohn.Forte@Sun.COM 43427836SJohn.Forte@Sun.COM 43437836SJohn.Forte@Sun.COM job_request_t * 43447836SJohn.Forte@Sun.COM fctl_deque_job(fc_local_port_t *port) 43457836SJohn.Forte@Sun.COM { 43467836SJohn.Forte@Sun.COM job_request_t *job; 43477836SJohn.Forte@Sun.COM 43487836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 43497836SJohn.Forte@Sun.COM 43507836SJohn.Forte@Sun.COM if (port->fp_job_head == NULL) { 43517836SJohn.Forte@Sun.COM ASSERT(port->fp_job_tail == NULL); 43527836SJohn.Forte@Sun.COM job = NULL; 43537836SJohn.Forte@Sun.COM } else { 43547836SJohn.Forte@Sun.COM job = port->fp_job_head; 43557836SJohn.Forte@Sun.COM if (job->job_next == NULL) { 43567836SJohn.Forte@Sun.COM ASSERT(job == port->fp_job_tail); 43577836SJohn.Forte@Sun.COM port->fp_job_tail = NULL; 43587836SJohn.Forte@Sun.COM } 43597836SJohn.Forte@Sun.COM port->fp_job_head = job->job_next; 43607836SJohn.Forte@Sun.COM } 43617836SJohn.Forte@Sun.COM 43627836SJohn.Forte@Sun.COM return (job); 43637836SJohn.Forte@Sun.COM } 43647836SJohn.Forte@Sun.COM 43657836SJohn.Forte@Sun.COM 43667836SJohn.Forte@Sun.COM void 43677836SJohn.Forte@Sun.COM fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job) 43687836SJohn.Forte@Sun.COM { 43697836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 43707836SJohn.Forte@Sun.COM 43717836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 43727836SJohn.Forte@Sun.COM if (port->fp_job_tail == NULL) { 43737836SJohn.Forte@Sun.COM ASSERT(port->fp_job_head == NULL); 43747836SJohn.Forte@Sun.COM port->fp_job_head = port->fp_job_tail = job; 43757836SJohn.Forte@Sun.COM job->job_next = NULL; 43767836SJohn.Forte@Sun.COM } else { 43777836SJohn.Forte@Sun.COM job->job_next = port->fp_job_head; 43787836SJohn.Forte@Sun.COM port->fp_job_head = job; 43797836SJohn.Forte@Sun.COM } 43807836SJohn.Forte@Sun.COM cv_signal(&port->fp_cv); 43817836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 43827836SJohn.Forte@Sun.COM } 43837836SJohn.Forte@Sun.COM 43847836SJohn.Forte@Sun.COM 43857836SJohn.Forte@Sun.COM void 43867836SJohn.Forte@Sun.COM fctl_jobwait(job_request_t *job) 43877836SJohn.Forte@Sun.COM { 43887836SJohn.Forte@Sun.COM ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC)); 43897836SJohn.Forte@Sun.COM sema_p(&job->job_fctl_sema); 43907836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&job->job_mutex)); 43917836SJohn.Forte@Sun.COM } 43927836SJohn.Forte@Sun.COM 43937836SJohn.Forte@Sun.COM 43947836SJohn.Forte@Sun.COM void 43957836SJohn.Forte@Sun.COM fctl_jobdone(job_request_t *job) 43967836SJohn.Forte@Sun.COM { 43977836SJohn.Forte@Sun.COM if (job->job_flags & JOB_TYPE_FCTL_ASYNC) { 43987836SJohn.Forte@Sun.COM if (job->job_comp) { 43997836SJohn.Forte@Sun.COM job->job_comp(job->job_cb_arg, job->job_result); 44007836SJohn.Forte@Sun.COM } 44017836SJohn.Forte@Sun.COM fctl_dealloc_job(job); 44027836SJohn.Forte@Sun.COM } else { 44037836SJohn.Forte@Sun.COM sema_v(&job->job_fctl_sema); 44047836SJohn.Forte@Sun.COM } 44057836SJohn.Forte@Sun.COM } 44067836SJohn.Forte@Sun.COM 44077836SJohn.Forte@Sun.COM 44087836SJohn.Forte@Sun.COM /* 440910264SZhong.Wang@Sun.COM * Compare two WWNs. 441010264SZhong.Wang@Sun.COM * The NAA can't be omitted for comparison. 44117836SJohn.Forte@Sun.COM * 44127836SJohn.Forte@Sun.COM * Return Values: 44137836SJohn.Forte@Sun.COM * if src == dst return 0 44147836SJohn.Forte@Sun.COM * if src > dst return 1 44157836SJohn.Forte@Sun.COM * if src < dst return -1 44167836SJohn.Forte@Sun.COM */ 44177836SJohn.Forte@Sun.COM int 44187836SJohn.Forte@Sun.COM fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst) 44197836SJohn.Forte@Sun.COM { 442010264SZhong.Wang@Sun.COM uint8_t *l, *r; 442110264SZhong.Wang@Sun.COM int i; 442210264SZhong.Wang@Sun.COM uint64_t wl, wr; 442310264SZhong.Wang@Sun.COM 442410264SZhong.Wang@Sun.COM l = (uint8_t *)src; 442510264SZhong.Wang@Sun.COM r = (uint8_t *)dst; 442610264SZhong.Wang@Sun.COM 442710264SZhong.Wang@Sun.COM for (i = 0, wl = 0; i < 8; i++) { 442810264SZhong.Wang@Sun.COM wl <<= 8; 442910264SZhong.Wang@Sun.COM wl |= l[i]; 443010264SZhong.Wang@Sun.COM } 443110264SZhong.Wang@Sun.COM for (i = 0, wr = 0; i < 8; i++) { 443210264SZhong.Wang@Sun.COM wr <<= 8; 443310264SZhong.Wang@Sun.COM wr |= r[i]; 443410264SZhong.Wang@Sun.COM } 443510264SZhong.Wang@Sun.COM 443610264SZhong.Wang@Sun.COM if (wl > wr) { 443710264SZhong.Wang@Sun.COM return (1); 443810264SZhong.Wang@Sun.COM } else if (wl == wr) { 443910264SZhong.Wang@Sun.COM return (0); 444010264SZhong.Wang@Sun.COM } else { 444110264SZhong.Wang@Sun.COM return (-1); 444210264SZhong.Wang@Sun.COM } 44437836SJohn.Forte@Sun.COM } 44447836SJohn.Forte@Sun.COM 44457836SJohn.Forte@Sun.COM 44467836SJohn.Forte@Sun.COM /* 44477836SJohn.Forte@Sun.COM * ASCII to Integer goodie with support for base 16, 10, 2 and 8 44487836SJohn.Forte@Sun.COM */ 44497836SJohn.Forte@Sun.COM int 44507836SJohn.Forte@Sun.COM fctl_atoi(char *s, int base) 44517836SJohn.Forte@Sun.COM { 44527836SJohn.Forte@Sun.COM int val; 44537836SJohn.Forte@Sun.COM int ch; 44547836SJohn.Forte@Sun.COM 44557836SJohn.Forte@Sun.COM for (val = 0; *s != '\0'; s++) { 44567836SJohn.Forte@Sun.COM switch (base) { 44577836SJohn.Forte@Sun.COM case 16: 44587836SJohn.Forte@Sun.COM if (*s >= '0' && *s <= '9') { 44597836SJohn.Forte@Sun.COM ch = *s - '0'; 44607836SJohn.Forte@Sun.COM } else if (*s >= 'a' && *s <= 'f') { 44617836SJohn.Forte@Sun.COM ch = *s - 'a' + 10; 44627836SJohn.Forte@Sun.COM } else if (*s >= 'A' && *s <= 'F') { 44637836SJohn.Forte@Sun.COM ch = *s - 'A' + 10; 44647836SJohn.Forte@Sun.COM } else { 44657836SJohn.Forte@Sun.COM return (-1); 44667836SJohn.Forte@Sun.COM } 44677836SJohn.Forte@Sun.COM break; 44687836SJohn.Forte@Sun.COM 44697836SJohn.Forte@Sun.COM case 10: 44707836SJohn.Forte@Sun.COM if (*s < '0' || *s > '9') { 44717836SJohn.Forte@Sun.COM return (-1); 44727836SJohn.Forte@Sun.COM } 44737836SJohn.Forte@Sun.COM ch = *s - '0'; 44747836SJohn.Forte@Sun.COM break; 44757836SJohn.Forte@Sun.COM 44767836SJohn.Forte@Sun.COM case 2: 44777836SJohn.Forte@Sun.COM if (*s < '0' || *s > '1') { 44787836SJohn.Forte@Sun.COM return (-1); 44797836SJohn.Forte@Sun.COM } 44807836SJohn.Forte@Sun.COM ch = *s - '0'; 44817836SJohn.Forte@Sun.COM break; 44827836SJohn.Forte@Sun.COM 44837836SJohn.Forte@Sun.COM case 8: 44847836SJohn.Forte@Sun.COM if (*s < '0' || *s > '7') { 44857836SJohn.Forte@Sun.COM return (-1); 44867836SJohn.Forte@Sun.COM } 44877836SJohn.Forte@Sun.COM ch = *s - '0'; 44887836SJohn.Forte@Sun.COM break; 44897836SJohn.Forte@Sun.COM 44907836SJohn.Forte@Sun.COM default: 44917836SJohn.Forte@Sun.COM return (-1); 44927836SJohn.Forte@Sun.COM } 44937836SJohn.Forte@Sun.COM val = (val * base) + ch; 44947836SJohn.Forte@Sun.COM } 44957836SJohn.Forte@Sun.COM return (val); 44967836SJohn.Forte@Sun.COM } 44977836SJohn.Forte@Sun.COM 44987836SJohn.Forte@Sun.COM 44997836SJohn.Forte@Sun.COM /* 45007836SJohn.Forte@Sun.COM * Create the fc_remote_port_t struct for the given port_wwn and d_id. 45017836SJohn.Forte@Sun.COM * 45027836SJohn.Forte@Sun.COM * If the struct already exists (and is "valid"), then use it. Before using 45037836SJohn.Forte@Sun.COM * it, the code below also checks: (a) if the d_id has changed, and (b) if 45047836SJohn.Forte@Sun.COM * the device is maked as PORT_DEVICE_OLD. 45057836SJohn.Forte@Sun.COM * 45067836SJohn.Forte@Sun.COM * If no fc_remote_node_t struct exists for the given node_wwn, then that 45077836SJohn.Forte@Sun.COM * struct is also created (and linked with the fc_remote_port_t). 45087836SJohn.Forte@Sun.COM * 45097836SJohn.Forte@Sun.COM * The given fc_local_port_t struct is updated with the info on the new 45107836SJohn.Forte@Sun.COM * struct(s). The d_id and pwwn hash tables in the port_wwn are updated. 45117836SJohn.Forte@Sun.COM * The global node_hash_table[] is updated (if necessary). 45127836SJohn.Forte@Sun.COM */ 45137836SJohn.Forte@Sun.COM fc_remote_port_t * 45147836SJohn.Forte@Sun.COM fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn, 45157836SJohn.Forte@Sun.COM la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep) 45167836SJohn.Forte@Sun.COM { 45177836SJohn.Forte@Sun.COM int invalid = 0; 45187836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 451910264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 45207836SJohn.Forte@Sun.COM 45217836SJohn.Forte@Sun.COM rnodep = fctl_get_remote_node_by_nwwn(node_wwn); 45227836SJohn.Forte@Sun.COM if (rnodep) { 45237836SJohn.Forte@Sun.COM /* 45247836SJohn.Forte@Sun.COM * We found an fc_remote_node_t for the remote node -- see if 45257836SJohn.Forte@Sun.COM * anyone has marked it as going away or gone. 45267836SJohn.Forte@Sun.COM */ 45277836SJohn.Forte@Sun.COM mutex_enter(&rnodep->fd_mutex); 45287836SJohn.Forte@Sun.COM invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0; 45297836SJohn.Forte@Sun.COM mutex_exit(&rnodep->fd_mutex); 45307836SJohn.Forte@Sun.COM } 45317836SJohn.Forte@Sun.COM if (rnodep == NULL || invalid) { 45327836SJohn.Forte@Sun.COM /* 45337836SJohn.Forte@Sun.COM * No valid remote node struct found -- create it. 45347836SJohn.Forte@Sun.COM * Note: this is the only place that this func is called. 45357836SJohn.Forte@Sun.COM */ 45367836SJohn.Forte@Sun.COM rnodep = fctl_create_remote_node(node_wwn, sleep); 45377836SJohn.Forte@Sun.COM if (rnodep == NULL) { 45387836SJohn.Forte@Sun.COM return (NULL); 45397836SJohn.Forte@Sun.COM } 45407836SJohn.Forte@Sun.COM } 45417836SJohn.Forte@Sun.COM 45427836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 45437836SJohn.Forte@Sun.COM 45447836SJohn.Forte@Sun.COM /* 45457836SJohn.Forte@Sun.COM * See if there already is an fc_remote_port_t struct in existence 454610264SZhong.Wang@Sun.COM * on the specified fc_local_port_t for the given pwwn. If so, then 45477836SJohn.Forte@Sun.COM * grab a reference to it. The 'held' here just means that fp_mutex 45487836SJohn.Forte@Sun.COM * is held by the caller -- no reference counts are updated. 45497836SJohn.Forte@Sun.COM */ 45507836SJohn.Forte@Sun.COM pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn); 45517836SJohn.Forte@Sun.COM if (pd) { 45527836SJohn.Forte@Sun.COM /* 45537836SJohn.Forte@Sun.COM * An fc_remote_port_t struct was found -- see if anyone has 45547836SJohn.Forte@Sun.COM * marked it as "invalid", which means that it is in the 45557836SJohn.Forte@Sun.COM * process of going away & we don't want to use it. 45567836SJohn.Forte@Sun.COM */ 45577836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 45587836SJohn.Forte@Sun.COM invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0; 45597836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 45607836SJohn.Forte@Sun.COM } 45617836SJohn.Forte@Sun.COM 45627836SJohn.Forte@Sun.COM if (pd == NULL || invalid) { 45637836SJohn.Forte@Sun.COM /* 45647836SJohn.Forte@Sun.COM * No fc_remote_port_t was found (or the existing one is 45657836SJohn.Forte@Sun.COM * marked as "invalid".) Allocate a new one and use that. 45667836SJohn.Forte@Sun.COM * This call will also update the d_id and pwwn hash tables 45677836SJohn.Forte@Sun.COM * in the given fc_local_port_t struct with the newly allocated 45687836SJohn.Forte@Sun.COM * fc_remote_port_t. 45697836SJohn.Forte@Sun.COM */ 45707836SJohn.Forte@Sun.COM if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id, 45717836SJohn.Forte@Sun.COM recepient, sleep)) == NULL) { 45727836SJohn.Forte@Sun.COM /* Just give up if the allocation fails. */ 45737836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 45747836SJohn.Forte@Sun.COM fctl_destroy_remote_node(rnodep); 45757836SJohn.Forte@Sun.COM return (pd); 45767836SJohn.Forte@Sun.COM } 45777836SJohn.Forte@Sun.COM 45787836SJohn.Forte@Sun.COM /* 45797836SJohn.Forte@Sun.COM * Add the new fc_remote_port_t struct to the d_id and pwwn 45807836SJohn.Forte@Sun.COM * hash tables on the associated fc_local_port_t struct. 45817836SJohn.Forte@Sun.COM */ 45827836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 45837836SJohn.Forte@Sun.COM pd->pd_remote_nodep = rnodep; 45847836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 45857836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(port, pd); 45867836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 45877836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 45887836SJohn.Forte@Sun.COM 45897836SJohn.Forte@Sun.COM /* 45907836SJohn.Forte@Sun.COM * Retrieve a pointer to the fc_remote_node_t (i.e., remote 45917836SJohn.Forte@Sun.COM * node) specified by the given node_wwn. This looks in the 45927836SJohn.Forte@Sun.COM * global fctl_nwwn_hash_table[]. The fd_numports reference 45937836SJohn.Forte@Sun.COM * count in the fc_remote_node_t struct is incremented. 45947836SJohn.Forte@Sun.COM */ 45957836SJohn.Forte@Sun.COM rnodep = fctl_lock_remote_node_by_nwwn(node_wwn); 45967836SJohn.Forte@Sun.COM 45977836SJohn.Forte@Sun.COM } else { 45987836SJohn.Forte@Sun.COM /* 45997836SJohn.Forte@Sun.COM * An existing and valid fc_remote_port_t struct already 46007836SJohn.Forte@Sun.COM * exists on the fc_local_port_t for the given pwwn. 46017836SJohn.Forte@Sun.COM */ 46027836SJohn.Forte@Sun.COM 46037836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 46047836SJohn.Forte@Sun.COM ASSERT(pd->pd_remote_nodep != NULL); 46057836SJohn.Forte@Sun.COM 46067836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id != d_id) { 46077836SJohn.Forte@Sun.COM /* 46087836SJohn.Forte@Sun.COM * A very unlikely occurance in a well 46097836SJohn.Forte@Sun.COM * behaved environment. 46107836SJohn.Forte@Sun.COM */ 46117836SJohn.Forte@Sun.COM 46127836SJohn.Forte@Sun.COM /* 46137836SJohn.Forte@Sun.COM * The existing fc_remote_port_t has a different 46147836SJohn.Forte@Sun.COM * d_id than what we were given. This code will 46157836SJohn.Forte@Sun.COM * update the existing one with the one that was 46167836SJohn.Forte@Sun.COM * just given. 46177836SJohn.Forte@Sun.COM */ 46187836SJohn.Forte@Sun.COM char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1]; 46197836SJohn.Forte@Sun.COM uint32_t old_id; 46207836SJohn.Forte@Sun.COM 46217836SJohn.Forte@Sun.COM fc_wwn_to_str(port_wwn, string); 46227836SJohn.Forte@Sun.COM 46237836SJohn.Forte@Sun.COM old_id = pd->pd_port_id.port_id; 46247836SJohn.Forte@Sun.COM 46257836SJohn.Forte@Sun.COM fctl_delist_did_table(port, pd); 46267836SJohn.Forte@Sun.COM 46277836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device" 46287836SJohn.Forte@Sun.COM " with PWWN %s changed. New D_ID = %x," 46297836SJohn.Forte@Sun.COM " OLD D_ID = %x", port->fp_instance, string, 46307836SJohn.Forte@Sun.COM d_id, old_id); 46317836SJohn.Forte@Sun.COM 46327836SJohn.Forte@Sun.COM pd->pd_port_id.port_id = d_id; 46337836SJohn.Forte@Sun.COM 46347836SJohn.Forte@Sun.COM /* 46357836SJohn.Forte@Sun.COM * Looks like we have to presume here that the 46367836SJohn.Forte@Sun.COM * remote port could be something entirely different 46377836SJohn.Forte@Sun.COM * from what was previously existing & valid at this 46387836SJohn.Forte@Sun.COM * pwwn. 46397836SJohn.Forte@Sun.COM */ 46407836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_CHANGED; 46417836SJohn.Forte@Sun.COM 46427836SJohn.Forte@Sun.COM /* Record (update) the new d_id for the remote port */ 46437836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 46447836SJohn.Forte@Sun.COM 46457836SJohn.Forte@Sun.COM } else if (pd->pd_type == PORT_DEVICE_OLD) { 46467836SJohn.Forte@Sun.COM /* 46477836SJohn.Forte@Sun.COM * OK at least the old & new d_id's match. So for 46487836SJohn.Forte@Sun.COM * PORT_DEVICE_OLD, this assumes that the remote 46497836SJohn.Forte@Sun.COM * port had disappeared but now has come back. 46507836SJohn.Forte@Sun.COM * Update the pd_type and pd_state to put the 46517836SJohn.Forte@Sun.COM * remote port back into service. 46527836SJohn.Forte@Sun.COM */ 46537836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 46547836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 46557836SJohn.Forte@Sun.COM 46567836SJohn.Forte@Sun.COM fctl_enlist_did_table(port, pd); 46577836SJohn.Forte@Sun.COM 46587836SJohn.Forte@Sun.COM } else { 46597836SJohn.Forte@Sun.COM /* 46607836SJohn.Forte@Sun.COM * OK the old & new d_id's match, and the remote 46617836SJohn.Forte@Sun.COM * port struct is not marked as PORT_DEVICE_OLD, so 46627836SJohn.Forte@Sun.COM * presume that it's still the same device and is 466310264SZhong.Wang@Sun.COM * still in good shape. Also this presumes that we 46647836SJohn.Forte@Sun.COM * do not need to update d_id or pwwn hash tables. 46657836SJohn.Forte@Sun.COM */ 46667836SJohn.Forte@Sun.COM /* sanitize device values */ 46677836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_NOCHANGE; 46687836SJohn.Forte@Sun.COM pd->pd_state = PORT_DEVICE_VALID; 46697836SJohn.Forte@Sun.COM } 46707836SJohn.Forte@Sun.COM 46717836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 46727836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 46737836SJohn.Forte@Sun.COM 46747836SJohn.Forte@Sun.COM if (rnodep != pd->pd_remote_nodep) { 46757836SJohn.Forte@Sun.COM if ((rnodep != NULL) && 46767836SJohn.Forte@Sun.COM (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name, 46777836SJohn.Forte@Sun.COM node_wwn) != 0)) { 46787836SJohn.Forte@Sun.COM /* 46797836SJohn.Forte@Sun.COM * Rut-roh, there is an fc_remote_node_t remote 46807836SJohn.Forte@Sun.COM * node struct for the given node_wwn, but the 46817836SJohn.Forte@Sun.COM * fc_remote_port_t remote port struct doesn't 46827836SJohn.Forte@Sun.COM * know about it. This just prints a warning 46837836SJohn.Forte@Sun.COM * message & fails the fc_remote_port_t 46847836SJohn.Forte@Sun.COM * allocation (possible leak here?). 46857836SJohn.Forte@Sun.COM */ 46867836SJohn.Forte@Sun.COM char ww1_name[17]; 46877836SJohn.Forte@Sun.COM char ww2_name[17]; 46887836SJohn.Forte@Sun.COM 46897836SJohn.Forte@Sun.COM fc_wwn_to_str( 46907836SJohn.Forte@Sun.COM &pd->pd_remote_nodep->fd_node_name, 46917836SJohn.Forte@Sun.COM ww1_name); 46927836SJohn.Forte@Sun.COM fc_wwn_to_str(node_wwn, ww2_name); 46937836SJohn.Forte@Sun.COM 46947836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: " 46957836SJohn.Forte@Sun.COM "Expected %s Got %s", port->fp_instance, 46967836SJohn.Forte@Sun.COM ww1_name, ww2_name); 46977836SJohn.Forte@Sun.COM } 46987836SJohn.Forte@Sun.COM 46997836SJohn.Forte@Sun.COM return (NULL); 47007836SJohn.Forte@Sun.COM } 47017836SJohn.Forte@Sun.COM } 47027836SJohn.Forte@Sun.COM 47037836SJohn.Forte@Sun.COM /* 470410264SZhong.Wang@Sun.COM * Add the fc_remote_port_t onto the linked list of remote port 47057836SJohn.Forte@Sun.COM * devices associated with the given fc_remote_node_t (remote node). 47067836SJohn.Forte@Sun.COM */ 47077836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(rnodep, pd); 47087836SJohn.Forte@Sun.COM 47097836SJohn.Forte@Sun.COM return (pd); 47107836SJohn.Forte@Sun.COM } 47117836SJohn.Forte@Sun.COM 47127836SJohn.Forte@Sun.COM 47137836SJohn.Forte@Sun.COM /* 47147836SJohn.Forte@Sun.COM * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes 47157836SJohn.Forte@Sun.COM * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any 47167836SJohn.Forte@Sun.COM * references to the fc_remote_port_t from the d_id and pwwn tables in the 47177836SJohn.Forte@Sun.COM * given fc_local_port_t. Deallocates the given fc_remote_port_t. 47187836SJohn.Forte@Sun.COM * 47197836SJohn.Forte@Sun.COM * Returns a count of the number of remaining fc_remote_port_t structs 47207836SJohn.Forte@Sun.COM * associated with the fc_remote_node_t struct. 47217836SJohn.Forte@Sun.COM * 47227836SJohn.Forte@Sun.COM * If pd_ref_count in the given fc_remote_port_t is nonzero, then this 47237836SJohn.Forte@Sun.COM * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the 47247836SJohn.Forte@Sun.COM * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about 472510264SZhong.Wang@Sun.COM * the cleanup. The function then also returns '1' 47267836SJohn.Forte@Sun.COM * instead of the actual number of remaining fc_remote_port_t structs 47277836SJohn.Forte@Sun.COM * 47287836SJohn.Forte@Sun.COM * If there are no more remote ports on the remote node, return 0. 47297836SJohn.Forte@Sun.COM * Otherwise, return non-zero. 47307836SJohn.Forte@Sun.COM */ 47317836SJohn.Forte@Sun.COM int 47327836SJohn.Forte@Sun.COM fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd) 47337836SJohn.Forte@Sun.COM { 473410264SZhong.Wang@Sun.COM fc_remote_node_t *rnodep; 47357836SJohn.Forte@Sun.COM int rcount = 0; 47367836SJohn.Forte@Sun.COM 47377836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 47387836SJohn.Forte@Sun.COM 47397836SJohn.Forte@Sun.COM /* 47407836SJohn.Forte@Sun.COM * If pd_ref_count > 0, we can't pull the rug out from any 47417836SJohn.Forte@Sun.COM * current users of this fc_remote_port_t. We'll mark it as old 47427836SJohn.Forte@Sun.COM * and in need of removal. The same goes for any fc_remote_port_t 47437836SJohn.Forte@Sun.COM * that has a reference handle(s) in a ULP(s) but for which the ULP(s) 47447836SJohn.Forte@Sun.COM * have not yet been notified that the handle is no longer valid 47457836SJohn.Forte@Sun.COM * (i.e., PD_GIVEN_TO_ULPS is set). 47467836SJohn.Forte@Sun.COM */ 47477836SJohn.Forte@Sun.COM if ((pd->pd_ref_count > 0) || 47487836SJohn.Forte@Sun.COM (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) { 47497836SJohn.Forte@Sun.COM pd->pd_aux_flags |= PD_NEEDS_REMOVAL; 47507836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_OLD; 47517836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 47527836SJohn.Forte@Sun.COM return (1); 47537836SJohn.Forte@Sun.COM } 47547836SJohn.Forte@Sun.COM 47557836SJohn.Forte@Sun.COM pd->pd_type = PORT_DEVICE_OLD; 47567836SJohn.Forte@Sun.COM 47577836SJohn.Forte@Sun.COM rnodep = pd->pd_remote_nodep; 47587836SJohn.Forte@Sun.COM 47597836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 47607836SJohn.Forte@Sun.COM 47617836SJohn.Forte@Sun.COM if (rnodep != NULL) { 47627836SJohn.Forte@Sun.COM /* 47637836SJohn.Forte@Sun.COM * Remove the fc_remote_port_t from the linked list of remote 47647836SJohn.Forte@Sun.COM * ports for the given fc_remote_node_t. This is only called 47657836SJohn.Forte@Sun.COM * here and in fctl_destroy_all_remote_ports(). 47667836SJohn.Forte@Sun.COM */ 47677836SJohn.Forte@Sun.COM rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd); 47687836SJohn.Forte@Sun.COM } 47697836SJohn.Forte@Sun.COM 47707836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 47717836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 47727836SJohn.Forte@Sun.COM 47737836SJohn.Forte@Sun.COM fctl_delist_did_table(port, pd); 47747836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(port, pd); 47757836SJohn.Forte@Sun.COM 47767836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 47777836SJohn.Forte@Sun.COM 47787836SJohn.Forte@Sun.COM /* 47797836SJohn.Forte@Sun.COM * Deconstruct & free the fc_remote_port_t. This is only called 47807836SJohn.Forte@Sun.COM * here and in fctl_destroy_all_remote_ports(). 47817836SJohn.Forte@Sun.COM */ 47827836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(pd); 47837836SJohn.Forte@Sun.COM 47847836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 47857836SJohn.Forte@Sun.COM 47867836SJohn.Forte@Sun.COM return (rcount); 47877836SJohn.Forte@Sun.COM } 47887836SJohn.Forte@Sun.COM 47897836SJohn.Forte@Sun.COM 47907836SJohn.Forte@Sun.COM /* 47917836SJohn.Forte@Sun.COM * This goes thru the d_id table on the given fc_local_port_t. 47927836SJohn.Forte@Sun.COM * For each fc_remote_port_t found, this will: 47937836SJohn.Forte@Sun.COM * 47947836SJohn.Forte@Sun.COM * - Remove the fc_remote_port_t from the linked list of remote ports for 479510264SZhong.Wang@Sun.COM * the associated fc_remote_node_t. If the linked list goes empty, then this 47967836SJohn.Forte@Sun.COM * tries to deconstruct & free the fc_remote_node_t (that also removes the 47977836SJohn.Forte@Sun.COM * fc_remote_node_t from the global fctl_nwwn_hash_table[]). 47987836SJohn.Forte@Sun.COM * 47997836SJohn.Forte@Sun.COM * - Remove the fc_remote_port_t from the pwwn list on the given 48007836SJohn.Forte@Sun.COM * fc_local_port_t. 48017836SJohn.Forte@Sun.COM * 48027836SJohn.Forte@Sun.COM * - Deconstruct and free the fc_remote_port_t. 48037836SJohn.Forte@Sun.COM * 48047836SJohn.Forte@Sun.COM * - Removes the link to the fc_remote_port_t in the d_id table. Note, this 48057836SJohn.Forte@Sun.COM * does not appear to correctle decrement the d_id_count tho. 48067836SJohn.Forte@Sun.COM */ 48077836SJohn.Forte@Sun.COM void 48087836SJohn.Forte@Sun.COM fctl_destroy_all_remote_ports(fc_local_port_t *port) 48097836SJohn.Forte@Sun.COM { 48107836SJohn.Forte@Sun.COM int index; 48117836SJohn.Forte@Sun.COM fc_remote_port_t *pd; 48127836SJohn.Forte@Sun.COM fc_remote_node_t *rnodep; 481310264SZhong.Wang@Sun.COM struct d_id_hash *head; 48147836SJohn.Forte@Sun.COM 48157836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 48167836SJohn.Forte@Sun.COM 48177836SJohn.Forte@Sun.COM for (index = 0; index < did_table_size; index++) { 48187836SJohn.Forte@Sun.COM 48197836SJohn.Forte@Sun.COM head = &port->fp_did_table[index]; 48207836SJohn.Forte@Sun.COM 48217836SJohn.Forte@Sun.COM while (head->d_id_head != NULL) { 48227836SJohn.Forte@Sun.COM pd = head->d_id_head; 48237836SJohn.Forte@Sun.COM 48247836SJohn.Forte@Sun.COM /* 48257836SJohn.Forte@Sun.COM * See if this remote port (fc_remote_port_t) has a 48267836SJohn.Forte@Sun.COM * reference to a remote node (fc_remote_node_t) in its 48277836SJohn.Forte@Sun.COM * pd->pd_remote_nodep pointer. 48287836SJohn.Forte@Sun.COM */ 48297836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 48307836SJohn.Forte@Sun.COM rnodep = pd->pd_remote_nodep; 48317836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 48327836SJohn.Forte@Sun.COM 48337836SJohn.Forte@Sun.COM if (rnodep != NULL) { 48347836SJohn.Forte@Sun.COM /* 48357836SJohn.Forte@Sun.COM * An fc_remote_node_t reference exists. Remove 48367836SJohn.Forte@Sun.COM * the fc_remote_port_t from the linked list of 48377836SJohn.Forte@Sun.COM * remote ports for fc_remote_node_t. 48387836SJohn.Forte@Sun.COM */ 48397836SJohn.Forte@Sun.COM if (fctl_unlink_remote_port_from_remote_node( 48407836SJohn.Forte@Sun.COM rnodep, pd) == 0) { 48417836SJohn.Forte@Sun.COM /* 48427836SJohn.Forte@Sun.COM * The fd_numports reference count 48437836SJohn.Forte@Sun.COM * in the fc_remote_node_t has come 48447836SJohn.Forte@Sun.COM * back as zero, so we can free the 48457836SJohn.Forte@Sun.COM * fc_remote_node_t. This also means 48467836SJohn.Forte@Sun.COM * that the fc_remote_node_t was 48477836SJohn.Forte@Sun.COM * removed from the 48487836SJohn.Forte@Sun.COM * fctl_nwwn_hash_table[]. 48497836SJohn.Forte@Sun.COM * 48507836SJohn.Forte@Sun.COM * This will silently skip the 48517836SJohn.Forte@Sun.COM * kmem_free() if either the 48527836SJohn.Forte@Sun.COM * fd_numports is nonzero or 48537836SJohn.Forte@Sun.COM * the fd_port is not NULL in 48547836SJohn.Forte@Sun.COM * the fc_remote_node_t. 48557836SJohn.Forte@Sun.COM */ 48567836SJohn.Forte@Sun.COM fctl_destroy_remote_node(rnodep); 48577836SJohn.Forte@Sun.COM } 48587836SJohn.Forte@Sun.COM } 48597836SJohn.Forte@Sun.COM 48607836SJohn.Forte@Sun.COM /* 48617836SJohn.Forte@Sun.COM * Clean up the entry in the fc_local_port_t's pwwn 48627836SJohn.Forte@Sun.COM * table for the given fc_remote_port_t (i.e., the pd). 48637836SJohn.Forte@Sun.COM */ 48647836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 48657836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(port, pd); 48667836SJohn.Forte@Sun.COM pd->pd_aux_flags &= ~PD_IN_DID_QUEUE; 48677836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 48687836SJohn.Forte@Sun.COM 48697836SJohn.Forte@Sun.COM /* 48707836SJohn.Forte@Sun.COM * Remove the current entry from the d_id list. 48717836SJohn.Forte@Sun.COM */ 48727836SJohn.Forte@Sun.COM head->d_id_head = pd->pd_did_hnext; 48737836SJohn.Forte@Sun.COM 48747836SJohn.Forte@Sun.COM /* 48757836SJohn.Forte@Sun.COM * Deconstruct & free the fc_remote_port_t (pd) 48767836SJohn.Forte@Sun.COM * Note: this is only called here and in 48777836SJohn.Forte@Sun.COM * fctl_destroy_remote_port_t(). 48787836SJohn.Forte@Sun.COM */ 48797836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(pd); 48807836SJohn.Forte@Sun.COM } 48817836SJohn.Forte@Sun.COM } 48827836SJohn.Forte@Sun.COM 48837836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 48847836SJohn.Forte@Sun.COM } 48857836SJohn.Forte@Sun.COM 48867836SJohn.Forte@Sun.COM 48877836SJohn.Forte@Sun.COM int 48887836SJohn.Forte@Sun.COM fctl_is_wwn_zero(la_wwn_t *wwn) 48897836SJohn.Forte@Sun.COM { 48907836SJohn.Forte@Sun.COM int count; 48917836SJohn.Forte@Sun.COM 48927836SJohn.Forte@Sun.COM for (count = 0; count < sizeof (la_wwn_t); count++) { 48937836SJohn.Forte@Sun.COM if (wwn->raw_wwn[count] != 0) { 48947836SJohn.Forte@Sun.COM return (FC_FAILURE); 48957836SJohn.Forte@Sun.COM } 48967836SJohn.Forte@Sun.COM } 48977836SJohn.Forte@Sun.COM 48987836SJohn.Forte@Sun.COM return (FC_SUCCESS); 48997836SJohn.Forte@Sun.COM } 49007836SJohn.Forte@Sun.COM 49017836SJohn.Forte@Sun.COM 49027836SJohn.Forte@Sun.COM void 49037836SJohn.Forte@Sun.COM fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type) 49047836SJohn.Forte@Sun.COM { 49057836SJohn.Forte@Sun.COM int data_cb; 49067836SJohn.Forte@Sun.COM int check_type; 49077836SJohn.Forte@Sun.COM int rval; 49087836SJohn.Forte@Sun.COM uint32_t claimed; 490910264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 49107836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 49117836SJohn.Forte@Sun.COM 49127836SJohn.Forte@Sun.COM claimed = 0; 49137836SJohn.Forte@Sun.COM check_type = 1; 49147836SJohn.Forte@Sun.COM 49157836SJohn.Forte@Sun.COM switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) { 49167836SJohn.Forte@Sun.COM case R_CTL_DEVICE_DATA: 49177836SJohn.Forte@Sun.COM data_cb = 1; 49187836SJohn.Forte@Sun.COM break; 49197836SJohn.Forte@Sun.COM 49207836SJohn.Forte@Sun.COM case R_CTL_EXTENDED_SVC: 49217836SJohn.Forte@Sun.COM check_type = 0; 49227836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 49237836SJohn.Forte@Sun.COM 49247836SJohn.Forte@Sun.COM case R_CTL_FC4_SVC: 49257836SJohn.Forte@Sun.COM data_cb = 0; 49267836SJohn.Forte@Sun.COM break; 49277836SJohn.Forte@Sun.COM 49287836SJohn.Forte@Sun.COM default: 49297836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 49307836SJohn.Forte@Sun.COM ASSERT(port->fp_active_ubs > 0); 49317836SJohn.Forte@Sun.COM if (--(port->fp_active_ubs) == 0) { 49327836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 49337836SJohn.Forte@Sun.COM } 49347836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 49357836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 49367836SJohn.Forte@Sun.COM 1, &buf->ub_token); 49377836SJohn.Forte@Sun.COM return; 49387836SJohn.Forte@Sun.COM } 49397836SJohn.Forte@Sun.COM 49407836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 49417836SJohn.Forte@Sun.COM for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 49427836SJohn.Forte@Sun.COM if (check_type && mod->mod_info->ulp_type != type) { 49437836SJohn.Forte@Sun.COM continue; 49447836SJohn.Forte@Sun.COM } 49457836SJohn.Forte@Sun.COM 49467836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 49477836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 49487836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 49497836SJohn.Forte@Sun.COM 49507836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 49517836SJohn.Forte@Sun.COM continue; 49527836SJohn.Forte@Sun.COM } 49537836SJohn.Forte@Sun.COM 49547836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 49557836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) { 49567836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 49577836SJohn.Forte@Sun.COM continue; 49587836SJohn.Forte@Sun.COM } 49597836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 49607836SJohn.Forte@Sun.COM 49617836SJohn.Forte@Sun.COM if (data_cb == 1) { 49627836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_data_callback( 49637836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, 49647836SJohn.Forte@Sun.COM (opaque_t)port, buf, claimed); 49657836SJohn.Forte@Sun.COM } else { 49667836SJohn.Forte@Sun.COM rval = mod->mod_info->ulp_els_callback( 49677836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, 49687836SJohn.Forte@Sun.COM (opaque_t)port, buf, claimed); 49697836SJohn.Forte@Sun.COM } 49707836SJohn.Forte@Sun.COM 49717836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS && claimed == 0) { 49727836SJohn.Forte@Sun.COM claimed = 1; 49737836SJohn.Forte@Sun.COM } 49747836SJohn.Forte@Sun.COM } 49757836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 49767836SJohn.Forte@Sun.COM 49777836SJohn.Forte@Sun.COM if (claimed == 0) { 49787836SJohn.Forte@Sun.COM /* 49797836SJohn.Forte@Sun.COM * We should actually RJT since nobody claimed it. 49807836SJohn.Forte@Sun.COM */ 49817836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 49827836SJohn.Forte@Sun.COM ASSERT(port->fp_active_ubs > 0); 49837836SJohn.Forte@Sun.COM if (--(port->fp_active_ubs) == 0) { 49847836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 49857836SJohn.Forte@Sun.COM } 49867836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 49877836SJohn.Forte@Sun.COM port->fp_fca_tran->fca_ub_release(port->fp_fca_handle, 49887836SJohn.Forte@Sun.COM 1, &buf->ub_token); 49897836SJohn.Forte@Sun.COM 49907836SJohn.Forte@Sun.COM } else { 49917836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 49927836SJohn.Forte@Sun.COM if (--port->fp_active_ubs == 0) { 49937836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB; 49947836SJohn.Forte@Sun.COM } 49957836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 49967836SJohn.Forte@Sun.COM } 49977836SJohn.Forte@Sun.COM } 49987836SJohn.Forte@Sun.COM 49997836SJohn.Forte@Sun.COM 50007836SJohn.Forte@Sun.COM /* 50017836SJohn.Forte@Sun.COM * Both fd_mutex and pd_mutex are held (in that order) coming in to this func 50027836SJohn.Forte@Sun.COM * 50037836SJohn.Forte@Sun.COM * With all these mutexes held, we should make sure this function does not eat 50047836SJohn.Forte@Sun.COM * up much time. 50057836SJohn.Forte@Sun.COM */ 50067836SJohn.Forte@Sun.COM void 50077836SJohn.Forte@Sun.COM fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd) 50087836SJohn.Forte@Sun.COM { 50097836SJohn.Forte@Sun.COM fc_remote_node_t *node; 50107836SJohn.Forte@Sun.COM 50117836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 50127836SJohn.Forte@Sun.COM 50137836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 50147836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 50157836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 50167836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 50177836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 50187836SJohn.Forte@Sun.COM map->map_flags = 0; 50197836SJohn.Forte@Sun.COM 50207836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 50217836SJohn.Forte@Sun.COM 50227836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 50237836SJohn.Forte@Sun.COM 50247836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 50257836SJohn.Forte@Sun.COM 50267836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&node->fd_mutex)); 50277836SJohn.Forte@Sun.COM 50287836SJohn.Forte@Sun.COM if (node) { 50297836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 50307836SJohn.Forte@Sun.COM } 50317836SJohn.Forte@Sun.COM map->map_pd = pd; 50327836SJohn.Forte@Sun.COM } 50337836SJohn.Forte@Sun.COM 50347836SJohn.Forte@Sun.COM void 50357836SJohn.Forte@Sun.COM fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd) 50367836SJohn.Forte@Sun.COM { 50377836SJohn.Forte@Sun.COM fc_remote_node_t *node; 50387836SJohn.Forte@Sun.COM 50397836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&pd->pd_mutex)); 50407836SJohn.Forte@Sun.COM 50417836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 50427836SJohn.Forte@Sun.COM map->map_pwwn = pd->pd_port_name; 50437836SJohn.Forte@Sun.COM map->map_did = pd->pd_port_id; 50447836SJohn.Forte@Sun.COM map->map_hard_addr = pd->pd_hard_addr; 50457836SJohn.Forte@Sun.COM map->map_state = pd->pd_state; 50467836SJohn.Forte@Sun.COM map->map_type = pd->pd_type; 50477836SJohn.Forte@Sun.COM map->map_flags = 0; 50487836SJohn.Forte@Sun.COM 50497836SJohn.Forte@Sun.COM ASSERT(map->map_type <= PORT_DEVICE_DELETE); 50507836SJohn.Forte@Sun.COM 50517836SJohn.Forte@Sun.COM bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types)); 50527836SJohn.Forte@Sun.COM 50537836SJohn.Forte@Sun.COM node = pd->pd_remote_nodep; 50547836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 50557836SJohn.Forte@Sun.COM 50567836SJohn.Forte@Sun.COM if (node) { 50577836SJohn.Forte@Sun.COM mutex_enter(&node->fd_mutex); 50587836SJohn.Forte@Sun.COM map->map_nwwn = node->fd_node_name; 50597836SJohn.Forte@Sun.COM mutex_exit(&node->fd_mutex); 50607836SJohn.Forte@Sun.COM } 50617836SJohn.Forte@Sun.COM map->map_pd = pd; 50627836SJohn.Forte@Sun.COM } 50637836SJohn.Forte@Sun.COM 50647836SJohn.Forte@Sun.COM 50657836SJohn.Forte@Sun.COM static int 50667836SJohn.Forte@Sun.COM fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 50677836SJohn.Forte@Sun.COM { 506810264SZhong.Wang@Sun.COM int rval = FC_SUCCESS; 50697836SJohn.Forte@Sun.COM 50707836SJohn.Forte@Sun.COM switch (ns_req->ns_cmd) { 50717836SJohn.Forte@Sun.COM case NS_RFT_ID: { 50727836SJohn.Forte@Sun.COM int count; 50737836SJohn.Forte@Sun.COM uint32_t *src; 50747836SJohn.Forte@Sun.COM uint32_t *dst; 507510264SZhong.Wang@Sun.COM ns_rfc_type_t *rfc; 50767836SJohn.Forte@Sun.COM 50777836SJohn.Forte@Sun.COM rfc = (ns_rfc_type_t *)ns_req->ns_req_payload; 50787836SJohn.Forte@Sun.COM 50797836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 50807836SJohn.Forte@Sun.COM src = (uint32_t *)port->fp_fc4_types; 50817836SJohn.Forte@Sun.COM dst = (uint32_t *)rfc->rfc_types; 50827836SJohn.Forte@Sun.COM 50837836SJohn.Forte@Sun.COM for (count = 0; count < 8; count++) { 50847836SJohn.Forte@Sun.COM *src++ |= *dst++; 50857836SJohn.Forte@Sun.COM } 50867836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 50877836SJohn.Forte@Sun.COM 50887836SJohn.Forte@Sun.COM break; 50897836SJohn.Forte@Sun.COM } 50907836SJohn.Forte@Sun.COM 50917836SJohn.Forte@Sun.COM case NS_RSPN_ID: { 50927836SJohn.Forte@Sun.COM ns_spn_t *spn; 50937836SJohn.Forte@Sun.COM 50947836SJohn.Forte@Sun.COM spn = (ns_spn_t *)ns_req->ns_req_payload; 50957836SJohn.Forte@Sun.COM 50967836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 50977836SJohn.Forte@Sun.COM port->fp_sym_port_namelen = spn->spn_len; 50987836SJohn.Forte@Sun.COM if (spn->spn_len) { 50997836SJohn.Forte@Sun.COM bcopy((caddr_t)spn + sizeof (ns_spn_t), 51007836SJohn.Forte@Sun.COM port->fp_sym_port_name, spn->spn_len); 51017836SJohn.Forte@Sun.COM } 51027836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51037836SJohn.Forte@Sun.COM 51047836SJohn.Forte@Sun.COM break; 51057836SJohn.Forte@Sun.COM } 51067836SJohn.Forte@Sun.COM 51077836SJohn.Forte@Sun.COM case NS_RSNN_NN: { 51087836SJohn.Forte@Sun.COM ns_snn_t *snn; 51097836SJohn.Forte@Sun.COM 51107836SJohn.Forte@Sun.COM snn = (ns_snn_t *)ns_req->ns_req_payload; 51117836SJohn.Forte@Sun.COM 51127836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51137836SJohn.Forte@Sun.COM port->fp_sym_node_namelen = snn->snn_len; 51147836SJohn.Forte@Sun.COM if (snn->snn_len) { 51157836SJohn.Forte@Sun.COM bcopy((caddr_t)snn + sizeof (ns_snn_t), 51167836SJohn.Forte@Sun.COM port->fp_sym_node_name, snn->snn_len); 51177836SJohn.Forte@Sun.COM } 51187836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51197836SJohn.Forte@Sun.COM 51207836SJohn.Forte@Sun.COM break; 51217836SJohn.Forte@Sun.COM } 51227836SJohn.Forte@Sun.COM 51237836SJohn.Forte@Sun.COM case NS_RIP_NN: { 51247836SJohn.Forte@Sun.COM ns_rip_t *rip; 51257836SJohn.Forte@Sun.COM 51267836SJohn.Forte@Sun.COM rip = (ns_rip_t *)ns_req->ns_req_payload; 51277836SJohn.Forte@Sun.COM 51287836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51297836SJohn.Forte@Sun.COM bcopy(rip->rip_ip_addr, port->fp_ip_addr, 51307836SJohn.Forte@Sun.COM sizeof (rip->rip_ip_addr)); 51317836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51327836SJohn.Forte@Sun.COM 51337836SJohn.Forte@Sun.COM break; 51347836SJohn.Forte@Sun.COM } 51357836SJohn.Forte@Sun.COM 51367836SJohn.Forte@Sun.COM case NS_RIPA_NN: { 51377836SJohn.Forte@Sun.COM ns_ipa_t *ipa; 51387836SJohn.Forte@Sun.COM 51397836SJohn.Forte@Sun.COM ipa = (ns_ipa_t *)ns_req->ns_req_payload; 51407836SJohn.Forte@Sun.COM 51417836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51427836SJohn.Forte@Sun.COM bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value)); 51437836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51447836SJohn.Forte@Sun.COM 51457836SJohn.Forte@Sun.COM break; 51467836SJohn.Forte@Sun.COM } 51477836SJohn.Forte@Sun.COM 51487836SJohn.Forte@Sun.COM default: 51497836SJohn.Forte@Sun.COM rval = FC_BADOBJECT; 51507836SJohn.Forte@Sun.COM break; 51517836SJohn.Forte@Sun.COM } 51527836SJohn.Forte@Sun.COM 51537836SJohn.Forte@Sun.COM return (rval); 51547836SJohn.Forte@Sun.COM } 51557836SJohn.Forte@Sun.COM 51567836SJohn.Forte@Sun.COM 51577836SJohn.Forte@Sun.COM static int 51587836SJohn.Forte@Sun.COM fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req) 51597836SJohn.Forte@Sun.COM { 516010264SZhong.Wang@Sun.COM int rval = FC_SUCCESS; 51617836SJohn.Forte@Sun.COM 51627836SJohn.Forte@Sun.COM switch (ns_req->ns_cmd) { 51637836SJohn.Forte@Sun.COM case NS_GFT_ID: { 51647836SJohn.Forte@Sun.COM ns_rfc_type_t *rfc; 51657836SJohn.Forte@Sun.COM 51667836SJohn.Forte@Sun.COM rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload; 51677836SJohn.Forte@Sun.COM 51687836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51697836SJohn.Forte@Sun.COM bcopy(port->fp_fc4_types, rfc->rfc_types, 51707836SJohn.Forte@Sun.COM sizeof (rfc->rfc_types)); 51717836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51727836SJohn.Forte@Sun.COM break; 51737836SJohn.Forte@Sun.COM } 51747836SJohn.Forte@Sun.COM 51757836SJohn.Forte@Sun.COM case NS_GSPN_ID: { 51767836SJohn.Forte@Sun.COM ns_spn_t *spn; 51777836SJohn.Forte@Sun.COM 51787836SJohn.Forte@Sun.COM spn = (ns_spn_t *)ns_req->ns_resp_payload; 51797836SJohn.Forte@Sun.COM 51807836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51817836SJohn.Forte@Sun.COM spn->spn_len = port->fp_sym_port_namelen; 51827836SJohn.Forte@Sun.COM if (spn->spn_len) { 51837836SJohn.Forte@Sun.COM bcopy(port->fp_sym_port_name, (caddr_t)spn + 51847836SJohn.Forte@Sun.COM sizeof (ns_spn_t), spn->spn_len); 51857836SJohn.Forte@Sun.COM } 51867836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 51877836SJohn.Forte@Sun.COM 51887836SJohn.Forte@Sun.COM break; 51897836SJohn.Forte@Sun.COM } 51907836SJohn.Forte@Sun.COM 51917836SJohn.Forte@Sun.COM case NS_GSNN_NN: { 51927836SJohn.Forte@Sun.COM ns_snn_t *snn; 51937836SJohn.Forte@Sun.COM 51947836SJohn.Forte@Sun.COM snn = (ns_snn_t *)ns_req->ns_resp_payload; 51957836SJohn.Forte@Sun.COM 51967836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 51977836SJohn.Forte@Sun.COM snn->snn_len = port->fp_sym_node_namelen; 51987836SJohn.Forte@Sun.COM if (snn->snn_len) { 51997836SJohn.Forte@Sun.COM bcopy(port->fp_sym_node_name, (caddr_t)snn + 52007836SJohn.Forte@Sun.COM sizeof (ns_snn_t), snn->snn_len); 52017836SJohn.Forte@Sun.COM } 52027836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 52037836SJohn.Forte@Sun.COM 52047836SJohn.Forte@Sun.COM break; 52057836SJohn.Forte@Sun.COM } 52067836SJohn.Forte@Sun.COM 52077836SJohn.Forte@Sun.COM case NS_GIP_NN: { 52087836SJohn.Forte@Sun.COM ns_rip_t *rip; 52097836SJohn.Forte@Sun.COM 52107836SJohn.Forte@Sun.COM rip = (ns_rip_t *)ns_req->ns_resp_payload; 52117836SJohn.Forte@Sun.COM 52127836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 52137836SJohn.Forte@Sun.COM bcopy(port->fp_ip_addr, rip->rip_ip_addr, 52147836SJohn.Forte@Sun.COM sizeof (rip->rip_ip_addr)); 52157836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 52167836SJohn.Forte@Sun.COM 52177836SJohn.Forte@Sun.COM break; 52187836SJohn.Forte@Sun.COM } 52197836SJohn.Forte@Sun.COM 52207836SJohn.Forte@Sun.COM case NS_GIPA_NN: { 52217836SJohn.Forte@Sun.COM ns_ipa_t *ipa; 52227836SJohn.Forte@Sun.COM 52237836SJohn.Forte@Sun.COM ipa = (ns_ipa_t *)ns_req->ns_resp_payload; 52247836SJohn.Forte@Sun.COM 52257836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 52267836SJohn.Forte@Sun.COM bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value)); 52277836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 52287836SJohn.Forte@Sun.COM 52297836SJohn.Forte@Sun.COM break; 52307836SJohn.Forte@Sun.COM } 52317836SJohn.Forte@Sun.COM 52327836SJohn.Forte@Sun.COM default: 52337836SJohn.Forte@Sun.COM rval = FC_BADOBJECT; 52347836SJohn.Forte@Sun.COM break; 52357836SJohn.Forte@Sun.COM } 52367836SJohn.Forte@Sun.COM 52377836SJohn.Forte@Sun.COM return (rval); 52387836SJohn.Forte@Sun.COM } 52397836SJohn.Forte@Sun.COM 52407836SJohn.Forte@Sun.COM 52417836SJohn.Forte@Sun.COM fctl_ns_req_t * 52427836SJohn.Forte@Sun.COM fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len, 52437836SJohn.Forte@Sun.COM uint32_t ns_flags, int sleep) 52447836SJohn.Forte@Sun.COM { 52457836SJohn.Forte@Sun.COM fctl_ns_req_t *ns_cmd; 52467836SJohn.Forte@Sun.COM 52477836SJohn.Forte@Sun.COM ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep); 52487836SJohn.Forte@Sun.COM if (ns_cmd == NULL) { 52497836SJohn.Forte@Sun.COM return (NULL); 52507836SJohn.Forte@Sun.COM } 52517836SJohn.Forte@Sun.COM 52527836SJohn.Forte@Sun.COM if (cmd_len) { 52537836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep); 52547836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_buf == NULL) { 52557836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 52567836SJohn.Forte@Sun.COM return (NULL); 52577836SJohn.Forte@Sun.COM } 52587836SJohn.Forte@Sun.COM ns_cmd->ns_cmd_size = cmd_len; 52597836SJohn.Forte@Sun.COM } 52607836SJohn.Forte@Sun.COM 52617836SJohn.Forte@Sun.COM ns_cmd->ns_resp_size = resp_len; 52627836SJohn.Forte@Sun.COM 52637836SJohn.Forte@Sun.COM if (data_len) { 52647836SJohn.Forte@Sun.COM ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep); 52657836SJohn.Forte@Sun.COM if (ns_cmd->ns_data_buf == NULL) { 52667836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_buf && cmd_len) { 52677836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_cmd_buf, cmd_len); 52687836SJohn.Forte@Sun.COM } 52697836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 52707836SJohn.Forte@Sun.COM return (NULL); 52717836SJohn.Forte@Sun.COM } 52727836SJohn.Forte@Sun.COM ns_cmd->ns_data_len = data_len; 52737836SJohn.Forte@Sun.COM } 52747836SJohn.Forte@Sun.COM ns_cmd->ns_flags = ns_flags; 52757836SJohn.Forte@Sun.COM 52767836SJohn.Forte@Sun.COM return (ns_cmd); 52777836SJohn.Forte@Sun.COM } 52787836SJohn.Forte@Sun.COM 52797836SJohn.Forte@Sun.COM 52807836SJohn.Forte@Sun.COM void 52817836SJohn.Forte@Sun.COM fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd) 52827836SJohn.Forte@Sun.COM { 52837836SJohn.Forte@Sun.COM if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) { 52847836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size); 52857836SJohn.Forte@Sun.COM } 52867836SJohn.Forte@Sun.COM if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) { 52877836SJohn.Forte@Sun.COM kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len); 52887836SJohn.Forte@Sun.COM } 52897836SJohn.Forte@Sun.COM kmem_free(ns_cmd, sizeof (*ns_cmd)); 52907836SJohn.Forte@Sun.COM } 52917836SJohn.Forte@Sun.COM 52927836SJohn.Forte@Sun.COM 52937836SJohn.Forte@Sun.COM int 52947836SJohn.Forte@Sun.COM fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd, 52957836SJohn.Forte@Sun.COM intptr_t data, int mode, cred_t *credp, int *rval) 52967836SJohn.Forte@Sun.COM { 52977836SJohn.Forte@Sun.COM int ret; 52987836SJohn.Forte@Sun.COM int save; 529910264SZhong.Wang@Sun.COM uint32_t claimed; 530010264SZhong.Wang@Sun.COM fc_ulp_module_t *mod; 53017836SJohn.Forte@Sun.COM fc_ulp_ports_t *ulp_port; 53027836SJohn.Forte@Sun.COM 53037836SJohn.Forte@Sun.COM save = *rval; 53047836SJohn.Forte@Sun.COM *rval = ENOTTY; 53057836SJohn.Forte@Sun.COM 53067836SJohn.Forte@Sun.COM rw_enter(&fctl_ulp_lock, RW_READER); 53077836SJohn.Forte@Sun.COM for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) { 53087836SJohn.Forte@Sun.COM rw_enter(&fctl_mod_ports_lock, RW_READER); 53097836SJohn.Forte@Sun.COM ulp_port = fctl_get_ulp_port(mod, port); 53107836SJohn.Forte@Sun.COM rw_exit(&fctl_mod_ports_lock); 53117836SJohn.Forte@Sun.COM 53127836SJohn.Forte@Sun.COM if (ulp_port == NULL) { 53137836SJohn.Forte@Sun.COM continue; 53147836SJohn.Forte@Sun.COM } 53157836SJohn.Forte@Sun.COM 53167836SJohn.Forte@Sun.COM mutex_enter(&ulp_port->port_mutex); 53177836SJohn.Forte@Sun.COM if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) || 53187836SJohn.Forte@Sun.COM mod->mod_info->ulp_port_ioctl == NULL) { 53197836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 53207836SJohn.Forte@Sun.COM continue; 53217836SJohn.Forte@Sun.COM } 53227836SJohn.Forte@Sun.COM mutex_exit(&ulp_port->port_mutex); 53237836SJohn.Forte@Sun.COM 53247836SJohn.Forte@Sun.COM ret = mod->mod_info->ulp_port_ioctl( 53257836SJohn.Forte@Sun.COM mod->mod_info->ulp_handle, (opaque_t)port, 53267836SJohn.Forte@Sun.COM dev, cmd, data, mode, credp, rval, claimed); 53277836SJohn.Forte@Sun.COM 53287836SJohn.Forte@Sun.COM if (ret == FC_SUCCESS && claimed == 0) { 53297836SJohn.Forte@Sun.COM claimed = 1; 53307836SJohn.Forte@Sun.COM } 53317836SJohn.Forte@Sun.COM } 53327836SJohn.Forte@Sun.COM rw_exit(&fctl_ulp_lock); 53337836SJohn.Forte@Sun.COM 53347836SJohn.Forte@Sun.COM ret = *rval; 53357836SJohn.Forte@Sun.COM *rval = save; 53367836SJohn.Forte@Sun.COM 53377836SJohn.Forte@Sun.COM return (ret); 53387836SJohn.Forte@Sun.COM } 53397836SJohn.Forte@Sun.COM 53407836SJohn.Forte@Sun.COM /* 53417836SJohn.Forte@Sun.COM * raise power if necessary, and set the port busy 53427836SJohn.Forte@Sun.COM * 53437836SJohn.Forte@Sun.COM * this may cause power to be raised, so no power related locks should 53447836SJohn.Forte@Sun.COM * be held 53457836SJohn.Forte@Sun.COM */ 53467836SJohn.Forte@Sun.COM int 53477836SJohn.Forte@Sun.COM fc_ulp_busy_port(opaque_t port_handle) 53487836SJohn.Forte@Sun.COM { 53497836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 53507836SJohn.Forte@Sun.COM 53517836SJohn.Forte@Sun.COM return (fctl_busy_port(port)); 53527836SJohn.Forte@Sun.COM } 53537836SJohn.Forte@Sun.COM 53547836SJohn.Forte@Sun.COM void 53557836SJohn.Forte@Sun.COM fc_ulp_idle_port(opaque_t port_handle) 53567836SJohn.Forte@Sun.COM { 53577836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 53587836SJohn.Forte@Sun.COM fctl_idle_port(port); 53597836SJohn.Forte@Sun.COM } 53607836SJohn.Forte@Sun.COM 53617836SJohn.Forte@Sun.COM void 53627836SJohn.Forte@Sun.COM fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd) 53637836SJohn.Forte@Sun.COM { 53647836SJohn.Forte@Sun.COM fctl_copy_portmap(map, (fc_remote_port_t *)pd); 53657836SJohn.Forte@Sun.COM } 53667836SJohn.Forte@Sun.COM 53677836SJohn.Forte@Sun.COM 53687836SJohn.Forte@Sun.COM int 53697836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_num(opaque_t port_handle) 53707836SJohn.Forte@Sun.COM { 53717836SJohn.Forte@Sun.COM int portsnum = 0; 53727836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 53737836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 53747836SJohn.Forte@Sun.COM 53757836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 53767836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 53777836SJohn.Forte@Sun.COM if (!tmpport) { 53787836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 53797836SJohn.Forte@Sun.COM return (portsnum); 53807836SJohn.Forte@Sun.COM } 53817836SJohn.Forte@Sun.COM while (tmpport != port) { 53827836SJohn.Forte@Sun.COM portsnum ++; 53837836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 53847836SJohn.Forte@Sun.COM } 53857836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 53867836SJohn.Forte@Sun.COM return (portsnum); 53877836SJohn.Forte@Sun.COM } 53887836SJohn.Forte@Sun.COM 53897836SJohn.Forte@Sun.COM fc_local_port_t * 53907836SJohn.Forte@Sun.COM fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn) 53917836SJohn.Forte@Sun.COM { 53927836SJohn.Forte@Sun.COM fc_fca_port_t *fca_port; 53937836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = phyport; 53947836SJohn.Forte@Sun.COM 53957836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 53967836SJohn.Forte@Sun.COM 53977836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 53987836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 53997836SJohn.Forte@Sun.COM tmpPort = fca_port->port_handle; 54007836SJohn.Forte@Sun.COM if (tmpPort == NULL) { 54017836SJohn.Forte@Sun.COM continue; 54027836SJohn.Forte@Sun.COM } 54037836SJohn.Forte@Sun.COM mutex_enter(&tmpPort->fp_mutex); 54047836SJohn.Forte@Sun.COM if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn, 54057836SJohn.Forte@Sun.COM pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) { 54067836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 54077836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 54087836SJohn.Forte@Sun.COM return (tmpPort); 54097836SJohn.Forte@Sun.COM } 54107836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 54117836SJohn.Forte@Sun.COM } 54127836SJohn.Forte@Sun.COM 54137836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 54147836SJohn.Forte@Sun.COM 54157836SJohn.Forte@Sun.COM return (NULL); 54167836SJohn.Forte@Sun.COM } 54177836SJohn.Forte@Sun.COM 54187836SJohn.Forte@Sun.COM int 54197836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList) 54207836SJohn.Forte@Sun.COM { 54217836SJohn.Forte@Sun.COM int portsnum = 0; 54227836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 54237836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 54247836SJohn.Forte@Sun.COM 54257836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 54267836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 54277836SJohn.Forte@Sun.COM if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 54287836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 54297836SJohn.Forte@Sun.COM return (portsnum); 54307836SJohn.Forte@Sun.COM } 54317836SJohn.Forte@Sun.COM 54327836SJohn.Forte@Sun.COM while (tmpport != port) { 54337836SJohn.Forte@Sun.COM (void) ddi_pathname(tmpport->fp_port_dip, 54347836SJohn.Forte@Sun.COM &pathList[MAXPATHLEN * portsnum]); 54357836SJohn.Forte@Sun.COM portsnum ++; 54367836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 54377836SJohn.Forte@Sun.COM } 54387836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 54397836SJohn.Forte@Sun.COM 54407836SJohn.Forte@Sun.COM return (portsnum); 54417836SJohn.Forte@Sun.COM } 54427836SJohn.Forte@Sun.COM 54437836SJohn.Forte@Sun.COM 54447836SJohn.Forte@Sun.COM fc_local_port_t * 54457836SJohn.Forte@Sun.COM fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn) 54467836SJohn.Forte@Sun.COM { 54477836SJohn.Forte@Sun.COM fc_local_port_t *tmpport; 54487836SJohn.Forte@Sun.COM 54497836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 54507836SJohn.Forte@Sun.COM tmpport = port->fp_port_next; 54517836SJohn.Forte@Sun.COM if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) { 54527836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 54537836SJohn.Forte@Sun.COM return (NULL); 54547836SJohn.Forte@Sun.COM } 54557836SJohn.Forte@Sun.COM 54567836SJohn.Forte@Sun.COM while (tmpport != port) { 54577836SJohn.Forte@Sun.COM if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn, 54587836SJohn.Forte@Sun.COM pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) && 54597836SJohn.Forte@Sun.COM (tmpport->fp_npiv_state == 0)) { 54607836SJohn.Forte@Sun.COM tmpport->fp_npiv_state = FC_NPIV_DELETING; 54617836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 54627836SJohn.Forte@Sun.COM return (tmpport); 54637836SJohn.Forte@Sun.COM } 54647836SJohn.Forte@Sun.COM tmpport = tmpport->fp_port_next; 54657836SJohn.Forte@Sun.COM } 54667836SJohn.Forte@Sun.COM 54677836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 54687836SJohn.Forte@Sun.COM return (NULL); 54697836SJohn.Forte@Sun.COM } 54707836SJohn.Forte@Sun.COM 54717836SJohn.Forte@Sun.COM /* 54727836SJohn.Forte@Sun.COM * Get the list of Adapters. On multi-ported adapters, 54737836SJohn.Forte@Sun.COM * only ONE port on the adapter will be returned. 54747836SJohn.Forte@Sun.COM * pathList should be (count * MAXPATHLEN) long. 54757836SJohn.Forte@Sun.COM * The return value will be set to the number of 547610264SZhong.Wang@Sun.COM * HBAs that were found on the system. If the value 54777836SJohn.Forte@Sun.COM * is greater than count, the routine should be retried 54787836SJohn.Forte@Sun.COM * with a larger buffer. 54797836SJohn.Forte@Sun.COM */ 54807836SJohn.Forte@Sun.COM int 54817836SJohn.Forte@Sun.COM fc_ulp_get_adapter_paths(char *pathList, int count) 54827836SJohn.Forte@Sun.COM { 548310264SZhong.Wang@Sun.COM fc_fca_port_t *fca_port; 54847836SJohn.Forte@Sun.COM int in = 0, out = 0, check, skip, maxPorts = 0; 54857836SJohn.Forte@Sun.COM fc_local_port_t **portList; 54867836SJohn.Forte@Sun.COM fc_local_port_t *new_port, *stored_port; 54877836SJohn.Forte@Sun.COM fca_hba_fru_details_t *new_fru, *stored_fru; 54887836SJohn.Forte@Sun.COM 54897836SJohn.Forte@Sun.COM ASSERT(pathList != NULL); 54907836SJohn.Forte@Sun.COM 54917836SJohn.Forte@Sun.COM /* First figure out how many ports we have */ 54927836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 54937836SJohn.Forte@Sun.COM 54947836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 54957836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 54967836SJohn.Forte@Sun.COM maxPorts ++; 54977836SJohn.Forte@Sun.COM } 54987836SJohn.Forte@Sun.COM 54997836SJohn.Forte@Sun.COM /* Now allocate a buffer to store all the pointers for comparisons */ 55007836SJohn.Forte@Sun.COM portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP); 55017836SJohn.Forte@Sun.COM 55027836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 55037836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 55047836SJohn.Forte@Sun.COM skip = 0; 55057836SJohn.Forte@Sun.COM 55067836SJohn.Forte@Sun.COM /* Lock the new port for subsequent comparisons */ 55077836SJohn.Forte@Sun.COM new_port = fca_port->port_handle; 55087836SJohn.Forte@Sun.COM mutex_enter(&new_port->fp_mutex); 55097836SJohn.Forte@Sun.COM new_fru = &new_port->fp_hba_port_attrs.hba_fru_details; 55107836SJohn.Forte@Sun.COM 55117836SJohn.Forte@Sun.COM /* Filter out secondary ports from the list */ 55127836SJohn.Forte@Sun.COM for (check = 0; check < out; check++) { 551310264SZhong.Wang@Sun.COM if (portList[check] == NULL) { 551410264SZhong.Wang@Sun.COM continue; 551510264SZhong.Wang@Sun.COM } 551610264SZhong.Wang@Sun.COM /* Guard against duplicates (should never happen) */ 551710264SZhong.Wang@Sun.COM if (portList[check] == fca_port->port_handle) { 551810264SZhong.Wang@Sun.COM /* Same port */ 551910264SZhong.Wang@Sun.COM skip = 1; 552010264SZhong.Wang@Sun.COM break; 552110264SZhong.Wang@Sun.COM } 552210264SZhong.Wang@Sun.COM 552310264SZhong.Wang@Sun.COM /* Lock the already stored port for comparison */ 552410264SZhong.Wang@Sun.COM stored_port = portList[check]; 552510264SZhong.Wang@Sun.COM mutex_enter(&stored_port->fp_mutex); 552610264SZhong.Wang@Sun.COM stored_fru = 552710264SZhong.Wang@Sun.COM &stored_port->fp_hba_port_attrs.hba_fru_details; 552810264SZhong.Wang@Sun.COM 552910264SZhong.Wang@Sun.COM /* Are these ports on the same HBA? */ 553010264SZhong.Wang@Sun.COM if (new_fru->high == stored_fru->high && 553110264SZhong.Wang@Sun.COM new_fru->low == stored_fru->low) { 553210264SZhong.Wang@Sun.COM /* Now double check driver */ 553310264SZhong.Wang@Sun.COM if (strncmp( 553410264SZhong.Wang@Sun.COM new_port->fp_hba_port_attrs.driver_name, 553510264SZhong.Wang@Sun.COM stored_port->fp_hba_port_attrs.driver_name, 553610264SZhong.Wang@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 553710264SZhong.Wang@Sun.COM /* we don't need to grow the list */ 553810264SZhong.Wang@Sun.COM skip = 1; 553910264SZhong.Wang@Sun.COM /* looking at a lower port index? */ 554010264SZhong.Wang@Sun.COM if (new_fru->port_index < 554110264SZhong.Wang@Sun.COM stored_fru->port_index) { 554210264SZhong.Wang@Sun.COM /* Replace the port in list */ 554310264SZhong.Wang@Sun.COM mutex_exit( 554410264SZhong.Wang@Sun.COM &stored_port->fp_mutex); 554510264SZhong.Wang@Sun.COM if (new_port->fp_npiv_type == 554610264SZhong.Wang@Sun.COM FC_NPIV_PORT) { 554710264SZhong.Wang@Sun.COM break; 554810264SZhong.Wang@Sun.COM } 554910264SZhong.Wang@Sun.COM portList[check] = new_port; 555010264SZhong.Wang@Sun.COM break; 555110264SZhong.Wang@Sun.COM } /* Else, just skip this port */ 55527836SJohn.Forte@Sun.COM } 555310264SZhong.Wang@Sun.COM } 555410264SZhong.Wang@Sun.COM 555510264SZhong.Wang@Sun.COM mutex_exit(&stored_port->fp_mutex); 555610264SZhong.Wang@Sun.COM } 555710264SZhong.Wang@Sun.COM mutex_exit(&new_port->fp_mutex); 555810264SZhong.Wang@Sun.COM 555910264SZhong.Wang@Sun.COM if (!skip) { 556010264SZhong.Wang@Sun.COM /* 556110264SZhong.Wang@Sun.COM * Either this is the first port for this HBA, or 556210264SZhong.Wang@Sun.COM * it's a secondary port and we haven't stored the 556310264SZhong.Wang@Sun.COM * primary/first port for that HBA. In the latter case, 556410264SZhong.Wang@Sun.COM * will just filter it out as we proceed to loop. 556510264SZhong.Wang@Sun.COM */ 556610264SZhong.Wang@Sun.COM if (fca_port->port_handle->fp_npiv_type == 556710264SZhong.Wang@Sun.COM FC_NPIV_PORT) { 556810264SZhong.Wang@Sun.COM continue; 556910264SZhong.Wang@Sun.COM } else { 557010264SZhong.Wang@Sun.COM portList[out++] = fca_port->port_handle; 557110264SZhong.Wang@Sun.COM } 557210264SZhong.Wang@Sun.COM } 55737836SJohn.Forte@Sun.COM } 55747836SJohn.Forte@Sun.COM 55757836SJohn.Forte@Sun.COM if (out <= count) { 557610264SZhong.Wang@Sun.COM for (in = 0; in < out; in++) { 557710264SZhong.Wang@Sun.COM (void) ddi_pathname(portList[in]->fp_port_dip, 557810264SZhong.Wang@Sun.COM &pathList[MAXPATHLEN * in]); 557910264SZhong.Wang@Sun.COM } 55807836SJohn.Forte@Sun.COM } 55817836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 55827836SJohn.Forte@Sun.COM kmem_free(portList, sizeof (*portList) * maxPorts); 55837836SJohn.Forte@Sun.COM return (out); 55847836SJohn.Forte@Sun.COM } 55857836SJohn.Forte@Sun.COM 55867836SJohn.Forte@Sun.COM uint32_t 55877836SJohn.Forte@Sun.COM fc_ulp_get_rscn_count(opaque_t port_handle) 55887836SJohn.Forte@Sun.COM { 55897836SJohn.Forte@Sun.COM uint32_t count; 55907836SJohn.Forte@Sun.COM fc_local_port_t *port; 55917836SJohn.Forte@Sun.COM 55927836SJohn.Forte@Sun.COM port = (fc_local_port_t *)port_handle; 55937836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 55947836SJohn.Forte@Sun.COM count = port->fp_rscn_count; 55957836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 55967836SJohn.Forte@Sun.COM 55977836SJohn.Forte@Sun.COM return (count); 55987836SJohn.Forte@Sun.COM } 55997836SJohn.Forte@Sun.COM 56007836SJohn.Forte@Sun.COM 56017836SJohn.Forte@Sun.COM /* 56027836SJohn.Forte@Sun.COM * This function is a very similar to fctl_add_orphan except that it expects 56037836SJohn.Forte@Sun.COM * that the fp_mutex and pd_mutex of the pd passed in are held coming in. 56047836SJohn.Forte@Sun.COM * 56057836SJohn.Forte@Sun.COM * Note that there is a lock hierarchy here (fp_mutex should be held first) but 56067836SJohn.Forte@Sun.COM * since this function could be called with a different pd's pd_mutex held, we 56077836SJohn.Forte@Sun.COM * should take care not to release fp_mutex in this function. 56087836SJohn.Forte@Sun.COM */ 56097836SJohn.Forte@Sun.COM int 56107836SJohn.Forte@Sun.COM fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd) 56117836SJohn.Forte@Sun.COM { 56127836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 56137836SJohn.Forte@Sun.COM la_wwn_t pwwn; 561410264SZhong.Wang@Sun.COM fc_orphan_t *orp; 56157836SJohn.Forte@Sun.COM fc_orphan_t *orphan; 56167836SJohn.Forte@Sun.COM 56177836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 56187836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&pd->pd_mutex)); 56197836SJohn.Forte@Sun.COM 56207836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 56217836SJohn.Forte@Sun.COM 56227836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 56237836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 56247836SJohn.Forte@Sun.COM return (FC_SUCCESS); 56257836SJohn.Forte@Sun.COM } 56267836SJohn.Forte@Sun.COM } 56277836SJohn.Forte@Sun.COM 56287836SJohn.Forte@Sun.COM orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP); 56297836SJohn.Forte@Sun.COM if (orphan) { 56307836SJohn.Forte@Sun.COM orphan->orp_pwwn = pwwn; 56317836SJohn.Forte@Sun.COM orphan->orp_tstamp = ddi_get_lbolt(); 56327836SJohn.Forte@Sun.COM 56337836SJohn.Forte@Sun.COM if (port->fp_orphan_list) { 56347836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_count > 0); 56357836SJohn.Forte@Sun.COM orphan->orp_next = port->fp_orphan_list; 56367836SJohn.Forte@Sun.COM } 56377836SJohn.Forte@Sun.COM port->fp_orphan_list = orphan; 56387836SJohn.Forte@Sun.COM port->fp_orphan_count++; 56397836SJohn.Forte@Sun.COM 56407836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 56417836SJohn.Forte@Sun.COM } 56427836SJohn.Forte@Sun.COM 56437836SJohn.Forte@Sun.COM return (rval); 56447836SJohn.Forte@Sun.COM } 56457836SJohn.Forte@Sun.COM 56467836SJohn.Forte@Sun.COM int 56477836SJohn.Forte@Sun.COM fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep) 56487836SJohn.Forte@Sun.COM { 56497836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 56507836SJohn.Forte@Sun.COM la_wwn_t pwwn; 565110264SZhong.Wang@Sun.COM fc_orphan_t *orp; 56527836SJohn.Forte@Sun.COM fc_orphan_t *orphan; 56537836SJohn.Forte@Sun.COM 56547836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 56557836SJohn.Forte@Sun.COM 56567836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 56577836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 56587836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 56597836SJohn.Forte@Sun.COM 56607836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 56617836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 56627836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 56637836SJohn.Forte@Sun.COM return (FC_SUCCESS); 56647836SJohn.Forte@Sun.COM } 56657836SJohn.Forte@Sun.COM } 56667836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 56677836SJohn.Forte@Sun.COM 56687836SJohn.Forte@Sun.COM orphan = kmem_zalloc(sizeof (*orphan), sleep); 56697836SJohn.Forte@Sun.COM if (orphan != NULL) { 56707836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 56717836SJohn.Forte@Sun.COM 56727836SJohn.Forte@Sun.COM orphan->orp_pwwn = pwwn; 56737836SJohn.Forte@Sun.COM orphan->orp_tstamp = ddi_get_lbolt(); 56747836SJohn.Forte@Sun.COM 56757836SJohn.Forte@Sun.COM if (port->fp_orphan_list) { 56767836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_count > 0); 56777836SJohn.Forte@Sun.COM orphan->orp_next = port->fp_orphan_list; 56787836SJohn.Forte@Sun.COM } 56797836SJohn.Forte@Sun.COM port->fp_orphan_list = orphan; 56807836SJohn.Forte@Sun.COM port->fp_orphan_count++; 56817836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 56827836SJohn.Forte@Sun.COM 56837836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 56847836SJohn.Forte@Sun.COM } 56857836SJohn.Forte@Sun.COM 56867836SJohn.Forte@Sun.COM return (rval); 56877836SJohn.Forte@Sun.COM } 56887836SJohn.Forte@Sun.COM 56897836SJohn.Forte@Sun.COM 56907836SJohn.Forte@Sun.COM int 56917836SJohn.Forte@Sun.COM fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn) 56927836SJohn.Forte@Sun.COM { 56937836SJohn.Forte@Sun.COM int rval = FC_FAILURE; 56947836SJohn.Forte@Sun.COM fc_orphan_t *prev = NULL; 569510264SZhong.Wang@Sun.COM fc_orphan_t *orp; 56967836SJohn.Forte@Sun.COM 56977836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 56987836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 56997836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) { 57007836SJohn.Forte@Sun.COM if (prev) { 57017836SJohn.Forte@Sun.COM prev->orp_next = orp->orp_next; 57027836SJohn.Forte@Sun.COM } else { 57037836SJohn.Forte@Sun.COM ASSERT(port->fp_orphan_list == orp); 57047836SJohn.Forte@Sun.COM port->fp_orphan_list = orp->orp_next; 57057836SJohn.Forte@Sun.COM } 57067836SJohn.Forte@Sun.COM port->fp_orphan_count--; 57077836SJohn.Forte@Sun.COM rval = FC_SUCCESS; 57087836SJohn.Forte@Sun.COM break; 57097836SJohn.Forte@Sun.COM } 57107836SJohn.Forte@Sun.COM prev = orp; 57117836SJohn.Forte@Sun.COM } 57127836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 57137836SJohn.Forte@Sun.COM 57147836SJohn.Forte@Sun.COM if (rval == FC_SUCCESS) { 57157836SJohn.Forte@Sun.COM kmem_free(orp, sizeof (*orp)); 57167836SJohn.Forte@Sun.COM } 57177836SJohn.Forte@Sun.COM 57187836SJohn.Forte@Sun.COM return (rval); 57197836SJohn.Forte@Sun.COM } 57207836SJohn.Forte@Sun.COM 57217836SJohn.Forte@Sun.COM 57227836SJohn.Forte@Sun.COM static void 57237836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd) 57247836SJohn.Forte@Sun.COM { 572510264SZhong.Wang@Sun.COM char ww_name[17]; 572610264SZhong.Wang@Sun.COM la_wwn_t pwwn; 572710264SZhong.Wang@Sun.COM fc_orphan_t *orp; 57287836SJohn.Forte@Sun.COM 57297836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 57307836SJohn.Forte@Sun.COM 57317836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 57327836SJohn.Forte@Sun.COM pwwn = pd->pd_port_name; 57337836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 57347836SJohn.Forte@Sun.COM 57357836SJohn.Forte@Sun.COM for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) { 57367836SJohn.Forte@Sun.COM if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) { 57377836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 57387836SJohn.Forte@Sun.COM return; 57397836SJohn.Forte@Sun.COM } 57407836SJohn.Forte@Sun.COM } 57417836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 57427836SJohn.Forte@Sun.COM 57437836SJohn.Forte@Sun.COM fc_wwn_to_str(&pwwn, ww_name); 57447836SJohn.Forte@Sun.COM 57457836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s" 57467836SJohn.Forte@Sun.COM " disappeared from fabric", port->fp_instance, 57477836SJohn.Forte@Sun.COM pd->pd_port_id.port_id, ww_name); 57487836SJohn.Forte@Sun.COM } 57497836SJohn.Forte@Sun.COM 57507836SJohn.Forte@Sun.COM 57517836SJohn.Forte@Sun.COM /* ARGSUSED */ 57527836SJohn.Forte@Sun.COM static void 57537836SJohn.Forte@Sun.COM fctl_link_reset_done(opaque_t port_handle, uchar_t result) 57547836SJohn.Forte@Sun.COM { 57557836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 57567836SJohn.Forte@Sun.COM 57577836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 57587836SJohn.Forte@Sun.COM port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET; 57597836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 57607836SJohn.Forte@Sun.COM 57617836SJohn.Forte@Sun.COM fctl_idle_port(port); 57627836SJohn.Forte@Sun.COM } 57637836SJohn.Forte@Sun.COM 57647836SJohn.Forte@Sun.COM 57657836SJohn.Forte@Sun.COM static int 57667836SJohn.Forte@Sun.COM fctl_error(int fc_errno, char **errmsg) 57677836SJohn.Forte@Sun.COM { 57687836SJohn.Forte@Sun.COM int count; 57697836SJohn.Forte@Sun.COM 57707836SJohn.Forte@Sun.COM for (count = 0; count < sizeof (fc_errlist) / 57717836SJohn.Forte@Sun.COM sizeof (fc_errlist[0]); count++) { 57727836SJohn.Forte@Sun.COM if (fc_errlist[count].fc_errno == fc_errno) { 57737836SJohn.Forte@Sun.COM *errmsg = fc_errlist[count].fc_errname; 57747836SJohn.Forte@Sun.COM return (FC_SUCCESS); 57757836SJohn.Forte@Sun.COM } 57767836SJohn.Forte@Sun.COM } 57777836SJohn.Forte@Sun.COM *errmsg = fctl_undefined; 57787836SJohn.Forte@Sun.COM 57797836SJohn.Forte@Sun.COM return (FC_FAILURE); 57807836SJohn.Forte@Sun.COM } 57817836SJohn.Forte@Sun.COM 57827836SJohn.Forte@Sun.COM 57837836SJohn.Forte@Sun.COM /* 57847836SJohn.Forte@Sun.COM * Return number of successful translations. 57857836SJohn.Forte@Sun.COM * Anybody with some userland programming experience would have 57867836SJohn.Forte@Sun.COM * figured it by now that the return value exactly resembles that 57877836SJohn.Forte@Sun.COM * of scanf(3c). This function returns a count of successful 57887836SJohn.Forte@Sun.COM * translations. It could range from 0 (no match for state, reason, 57897836SJohn.Forte@Sun.COM * action, expln) to 4 (successful matches for all state, reason, 57907836SJohn.Forte@Sun.COM * action, expln) and where translation isn't successful into a 57917836SJohn.Forte@Sun.COM * friendlier message the relevent field is set to "Undefined" 57927836SJohn.Forte@Sun.COM */ 57937836SJohn.Forte@Sun.COM static int 57947836SJohn.Forte@Sun.COM fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason, 57957836SJohn.Forte@Sun.COM char **action, char **expln) 57967836SJohn.Forte@Sun.COM { 57977836SJohn.Forte@Sun.COM int ret; 579810264SZhong.Wang@Sun.COM int len; 57997836SJohn.Forte@Sun.COM int index; 58007836SJohn.Forte@Sun.COM fc_pkt_error_t *error; 58017836SJohn.Forte@Sun.COM fc_pkt_reason_t *reason_b; /* Base pointer */ 58027836SJohn.Forte@Sun.COM fc_pkt_action_t *action_b; /* Base pointer */ 58037836SJohn.Forte@Sun.COM fc_pkt_expln_t *expln_b; /* Base pointer */ 58047836SJohn.Forte@Sun.COM 58057836SJohn.Forte@Sun.COM ret = 0; 58067836SJohn.Forte@Sun.COM *state = *reason = *action = *expln = fctl_undefined; 58077836SJohn.Forte@Sun.COM 58087836SJohn.Forte@Sun.COM len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0]; 58097836SJohn.Forte@Sun.COM for (index = 0; index < len; index++) { 58107836SJohn.Forte@Sun.COM error = fc_pkt_errlist + index; 58117836SJohn.Forte@Sun.COM if (pkt->pkt_state == error->pkt_state) { 58127836SJohn.Forte@Sun.COM *state = error->pkt_msg; 58137836SJohn.Forte@Sun.COM ret++; 58147836SJohn.Forte@Sun.COM 58157836SJohn.Forte@Sun.COM reason_b = error->pkt_reason; 58167836SJohn.Forte@Sun.COM action_b = error->pkt_action; 58177836SJohn.Forte@Sun.COM expln_b = error->pkt_expln; 58187836SJohn.Forte@Sun.COM 58197836SJohn.Forte@Sun.COM while (reason_b != NULL && 58207836SJohn.Forte@Sun.COM reason_b->reason_val != FC_REASON_INVALID) { 58217836SJohn.Forte@Sun.COM if (reason_b->reason_val == pkt->pkt_reason) { 58227836SJohn.Forte@Sun.COM *reason = reason_b->reason_msg; 58237836SJohn.Forte@Sun.COM ret++; 58247836SJohn.Forte@Sun.COM break; 58257836SJohn.Forte@Sun.COM } 58267836SJohn.Forte@Sun.COM reason_b++; 58277836SJohn.Forte@Sun.COM } 58287836SJohn.Forte@Sun.COM 58297836SJohn.Forte@Sun.COM while (action_b != NULL && 58307836SJohn.Forte@Sun.COM action_b->action_val != FC_ACTION_INVALID) { 58317836SJohn.Forte@Sun.COM if (action_b->action_val == pkt->pkt_action) { 58327836SJohn.Forte@Sun.COM *action = action_b->action_msg; 58337836SJohn.Forte@Sun.COM ret++; 58347836SJohn.Forte@Sun.COM break; 58357836SJohn.Forte@Sun.COM } 58367836SJohn.Forte@Sun.COM action_b++; 58377836SJohn.Forte@Sun.COM } 58387836SJohn.Forte@Sun.COM 58397836SJohn.Forte@Sun.COM while (expln_b != NULL && 58407836SJohn.Forte@Sun.COM expln_b->expln_val != FC_EXPLN_INVALID) { 58417836SJohn.Forte@Sun.COM if (expln_b->expln_val == pkt->pkt_expln) { 58427836SJohn.Forte@Sun.COM *expln = expln_b->expln_msg; 58437836SJohn.Forte@Sun.COM ret++; 58447836SJohn.Forte@Sun.COM break; 58457836SJohn.Forte@Sun.COM } 58467836SJohn.Forte@Sun.COM expln_b++; 58477836SJohn.Forte@Sun.COM } 58487836SJohn.Forte@Sun.COM break; 58497836SJohn.Forte@Sun.COM } 58507836SJohn.Forte@Sun.COM } 58517836SJohn.Forte@Sun.COM 58527836SJohn.Forte@Sun.COM return (ret); 58537836SJohn.Forte@Sun.COM } 58547836SJohn.Forte@Sun.COM 58557836SJohn.Forte@Sun.COM 58567836SJohn.Forte@Sun.COM /* 58577836SJohn.Forte@Sun.COM * Remove all port devices that are marked OLD, remove 58587836SJohn.Forte@Sun.COM * corresponding node devices (fc_remote_node_t) 58597836SJohn.Forte@Sun.COM */ 58607836SJohn.Forte@Sun.COM void 58617836SJohn.Forte@Sun.COM fctl_remove_oldies(fc_local_port_t *port) 58627836SJohn.Forte@Sun.COM { 58637836SJohn.Forte@Sun.COM int index; 58647836SJohn.Forte@Sun.COM int initiator; 58657836SJohn.Forte@Sun.COM fc_remote_node_t *node; 586610264SZhong.Wang@Sun.COM struct pwwn_hash *head; 586710264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 586810264SZhong.Wang@Sun.COM fc_remote_port_t *old_pd; 58697836SJohn.Forte@Sun.COM fc_remote_port_t *last_pd; 58707836SJohn.Forte@Sun.COM 58717836SJohn.Forte@Sun.COM /* 58727836SJohn.Forte@Sun.COM * Nuke all OLD devices 58737836SJohn.Forte@Sun.COM */ 58747836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 58757836SJohn.Forte@Sun.COM 58767836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 58777836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 58787836SJohn.Forte@Sun.COM last_pd = NULL; 58797836SJohn.Forte@Sun.COM pd = head->pwwn_head; 58807836SJohn.Forte@Sun.COM 58817836SJohn.Forte@Sun.COM while (pd != NULL) { 58827836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 58837836SJohn.Forte@Sun.COM if (pd->pd_type != PORT_DEVICE_OLD) { 58847836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 58857836SJohn.Forte@Sun.COM last_pd = pd; 58867836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 58877836SJohn.Forte@Sun.COM continue; 58887836SJohn.Forte@Sun.COM } 58897836SJohn.Forte@Sun.COM 58907836SJohn.Forte@Sun.COM /* 58917836SJohn.Forte@Sun.COM * Remove this from the PWWN hash table 58927836SJohn.Forte@Sun.COM */ 58937836SJohn.Forte@Sun.COM old_pd = pd; 58947836SJohn.Forte@Sun.COM pd = old_pd->pd_wwn_hnext; 58957836SJohn.Forte@Sun.COM 58967836SJohn.Forte@Sun.COM if (last_pd == NULL) { 58977836SJohn.Forte@Sun.COM ASSERT(old_pd == head->pwwn_head); 58987836SJohn.Forte@Sun.COM head->pwwn_head = pd; 58997836SJohn.Forte@Sun.COM } else { 59007836SJohn.Forte@Sun.COM last_pd->pd_wwn_hnext = pd; 59017836SJohn.Forte@Sun.COM } 59027836SJohn.Forte@Sun.COM head->pwwn_count--; 59037836SJohn.Forte@Sun.COM /* 59047836SJohn.Forte@Sun.COM * Make sure we tie fp_dev_count to the size of the 59057836SJohn.Forte@Sun.COM * pwwn_table 59067836SJohn.Forte@Sun.COM */ 59077836SJohn.Forte@Sun.COM port->fp_dev_count--; 59087836SJohn.Forte@Sun.COM old_pd->pd_wwn_hnext = NULL; 59097836SJohn.Forte@Sun.COM 59107836SJohn.Forte@Sun.COM fctl_delist_did_table(port, old_pd); 59117836SJohn.Forte@Sun.COM node = old_pd->pd_remote_nodep; 59127836SJohn.Forte@Sun.COM ASSERT(node != NULL); 59137836SJohn.Forte@Sun.COM 59147836SJohn.Forte@Sun.COM initiator = (old_pd->pd_recepient == 59157836SJohn.Forte@Sun.COM PD_PLOGI_INITIATOR) ? 1 : 0; 59167836SJohn.Forte@Sun.COM 59177836SJohn.Forte@Sun.COM mutex_exit(&old_pd->pd_mutex); 59187836SJohn.Forte@Sun.COM 59197836SJohn.Forte@Sun.COM if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) { 59207836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 59217836SJohn.Forte@Sun.COM 59227836SJohn.Forte@Sun.COM (void) fctl_add_orphan(port, old_pd, 59237836SJohn.Forte@Sun.COM KM_NOSLEEP); 59247836SJohn.Forte@Sun.COM } else { 59257836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 59267836SJohn.Forte@Sun.COM } 59277836SJohn.Forte@Sun.COM 59287836SJohn.Forte@Sun.COM if (fctl_destroy_remote_port(port, old_pd) == 0) { 59297836SJohn.Forte@Sun.COM if (node) { 59307836SJohn.Forte@Sun.COM fctl_destroy_remote_node(node); 59317836SJohn.Forte@Sun.COM } 59327836SJohn.Forte@Sun.COM } 59337836SJohn.Forte@Sun.COM 59347836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 59357836SJohn.Forte@Sun.COM } 59367836SJohn.Forte@Sun.COM } 59377836SJohn.Forte@Sun.COM 59387836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 59397836SJohn.Forte@Sun.COM } 59407836SJohn.Forte@Sun.COM 59417836SJohn.Forte@Sun.COM 59427836SJohn.Forte@Sun.COM static void 59437836SJohn.Forte@Sun.COM fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd) 59447836SJohn.Forte@Sun.COM { 59457836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 59467836SJohn.Forte@Sun.COM ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 59477836SJohn.Forte@Sun.COM 59487836SJohn.Forte@Sun.COM if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) { 59497836SJohn.Forte@Sun.COM return; 59507836SJohn.Forte@Sun.COM } 59517836SJohn.Forte@Sun.COM 59527836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map", 59537836SJohn.Forte@Sun.COM port->fp_instance, pd->pd_port_id.port_id); 59547836SJohn.Forte@Sun.COM } 59557836SJohn.Forte@Sun.COM 59567836SJohn.Forte@Sun.COM 59577836SJohn.Forte@Sun.COM static int 59587836SJohn.Forte@Sun.COM fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa) 59597836SJohn.Forte@Sun.COM { 59607836SJohn.Forte@Sun.COM int index; 59617836SJohn.Forte@Sun.COM 59627836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 59637836SJohn.Forte@Sun.COM ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP); 59647836SJohn.Forte@Sun.COM 59657836SJohn.Forte@Sun.COM for (index = 0; index < port->fp_lilp_map.lilp_length; index++) { 59667836SJohn.Forte@Sun.COM if (port->fp_lilp_map.lilp_alpalist[index] == alpa) { 59677836SJohn.Forte@Sun.COM return (FC_SUCCESS); 59687836SJohn.Forte@Sun.COM } 59697836SJohn.Forte@Sun.COM } 59707836SJohn.Forte@Sun.COM 59717836SJohn.Forte@Sun.COM return (FC_FAILURE); 59727836SJohn.Forte@Sun.COM } 59737836SJohn.Forte@Sun.COM 59747836SJohn.Forte@Sun.COM 59757836SJohn.Forte@Sun.COM fc_remote_port_t * 59767836SJohn.Forte@Sun.COM fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id) 59777836SJohn.Forte@Sun.COM { 59787836SJohn.Forte@Sun.COM int index; 59797836SJohn.Forte@Sun.COM struct pwwn_hash *head; 598010264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 59817836SJohn.Forte@Sun.COM 59827836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 59837836SJohn.Forte@Sun.COM 59847836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 59857836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 59867836SJohn.Forte@Sun.COM pd = head->pwwn_head; 59877836SJohn.Forte@Sun.COM 59887836SJohn.Forte@Sun.COM while (pd != NULL) { 59897836SJohn.Forte@Sun.COM mutex_enter(&pd->pd_mutex); 59907836SJohn.Forte@Sun.COM if (pd->pd_port_id.port_id == d_id) { 59917836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 59927836SJohn.Forte@Sun.COM return (pd); 59937836SJohn.Forte@Sun.COM } 59947836SJohn.Forte@Sun.COM mutex_exit(&pd->pd_mutex); 59957836SJohn.Forte@Sun.COM pd = pd->pd_wwn_hnext; 59967836SJohn.Forte@Sun.COM } 59977836SJohn.Forte@Sun.COM } 59987836SJohn.Forte@Sun.COM 59997836SJohn.Forte@Sun.COM return (pd); 60007836SJohn.Forte@Sun.COM } 60017836SJohn.Forte@Sun.COM 60027836SJohn.Forte@Sun.COM 60037836SJohn.Forte@Sun.COM /* 60047836SJohn.Forte@Sun.COM * trace debugging 60057836SJohn.Forte@Sun.COM */ 60067836SJohn.Forte@Sun.COM void 60077836SJohn.Forte@Sun.COM fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel, 60087836SJohn.Forte@Sun.COM int errno, const char *fmt, ...) 60097836SJohn.Forte@Sun.COM { 601010264SZhong.Wang@Sun.COM char buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */ 60117836SJohn.Forte@Sun.COM char *bufptr = buf; 60127836SJohn.Forte@Sun.COM va_list ap; 60137836SJohn.Forte@Sun.COM int cnt = 0; 60147836SJohn.Forte@Sun.COM 60157836SJohn.Forte@Sun.COM if ((dlevel & dflag) == 0) { 60167836SJohn.Forte@Sun.COM return; 60177836SJohn.Forte@Sun.COM } 60187836SJohn.Forte@Sun.COM 60197836SJohn.Forte@Sun.COM if (name) { 60207836SJohn.Forte@Sun.COM cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::", 602110264SZhong.Wang@Sun.COM logq->il_id++, name); 60227836SJohn.Forte@Sun.COM } else { 60237836SJohn.Forte@Sun.COM cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::", 602410264SZhong.Wang@Sun.COM logq->il_id++); 60257836SJohn.Forte@Sun.COM } 60267836SJohn.Forte@Sun.COM 60277836SJohn.Forte@Sun.COM if (cnt < FC_MAX_TRACE_BUF_LEN) { 60287836SJohn.Forte@Sun.COM va_start(ap, fmt); 60297836SJohn.Forte@Sun.COM cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 603010264SZhong.Wang@Sun.COM fmt, ap); 60317836SJohn.Forte@Sun.COM va_end(ap); 60327836SJohn.Forte@Sun.COM } 60337836SJohn.Forte@Sun.COM 60347836SJohn.Forte@Sun.COM if (cnt > FC_MAX_TRACE_BUF_LEN) { 60357836SJohn.Forte@Sun.COM cnt = FC_MAX_TRACE_BUF_LEN; 60367836SJohn.Forte@Sun.COM } 60377836SJohn.Forte@Sun.COM if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) { 60387836SJohn.Forte@Sun.COM cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt, 603910264SZhong.Wang@Sun.COM "error=0x%x\n", errno); 60407836SJohn.Forte@Sun.COM } 60417836SJohn.Forte@Sun.COM (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n"); 60427836SJohn.Forte@Sun.COM 60437836SJohn.Forte@Sun.COM if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) { 60447836SJohn.Forte@Sun.COM fc_trace_logmsg(logq, buf, dlevel); 60457836SJohn.Forte@Sun.COM } 60467836SJohn.Forte@Sun.COM 60477836SJohn.Forte@Sun.COM /* 60487836SJohn.Forte@Sun.COM * We do not want to print the log numbers that appear as 60497836SJohn.Forte@Sun.COM * random numbers at the console and messages files, to 60507836SJohn.Forte@Sun.COM * the user. 60517836SJohn.Forte@Sun.COM */ 60527836SJohn.Forte@Sun.COM if ((bufptr = strchr(buf, '>')) == NULL) { 60537836SJohn.Forte@Sun.COM /* 60547836SJohn.Forte@Sun.COM * We would have added the a string with "=>" above and so, 60557836SJohn.Forte@Sun.COM * ideally, we should not get here at all. But, if we do, 60567836SJohn.Forte@Sun.COM * we'll just use the full buf. 60577836SJohn.Forte@Sun.COM */ 60587836SJohn.Forte@Sun.COM bufptr = buf; 60597836SJohn.Forte@Sun.COM } else { 60607836SJohn.Forte@Sun.COM bufptr++; 60617836SJohn.Forte@Sun.COM } 60627836SJohn.Forte@Sun.COM 60637836SJohn.Forte@Sun.COM switch (dlevel & FC_TRACE_LOG_MASK) { 60647836SJohn.Forte@Sun.COM case FC_TRACE_LOG_CONSOLE: 60657836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "%s", bufptr); 60667836SJohn.Forte@Sun.COM break; 60677836SJohn.Forte@Sun.COM 60687836SJohn.Forte@Sun.COM case FC_TRACE_LOG_CONSOLE_MSG: 60697836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "%s", bufptr); 60707836SJohn.Forte@Sun.COM break; 60717836SJohn.Forte@Sun.COM 60727836SJohn.Forte@Sun.COM case FC_TRACE_LOG_MSG: 60737836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!%s", bufptr); 60747836SJohn.Forte@Sun.COM break; 60757836SJohn.Forte@Sun.COM 60767836SJohn.Forte@Sun.COM default: 60777836SJohn.Forte@Sun.COM break; 60787836SJohn.Forte@Sun.COM } 60797836SJohn.Forte@Sun.COM } 60807836SJohn.Forte@Sun.COM 60817836SJohn.Forte@Sun.COM 60827836SJohn.Forte@Sun.COM /* 60837836SJohn.Forte@Sun.COM * This function can block 60847836SJohn.Forte@Sun.COM */ 60857836SJohn.Forte@Sun.COM fc_trace_logq_t * 60867836SJohn.Forte@Sun.COM fc_trace_alloc_logq(int maxsize) 60877836SJohn.Forte@Sun.COM { 60887836SJohn.Forte@Sun.COM fc_trace_logq_t *logq; 60897836SJohn.Forte@Sun.COM 60907836SJohn.Forte@Sun.COM logq = kmem_zalloc(sizeof (*logq), KM_SLEEP); 60917836SJohn.Forte@Sun.COM 60927836SJohn.Forte@Sun.COM mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL); 60937836SJohn.Forte@Sun.COM logq->il_hiwat = maxsize; 60947836SJohn.Forte@Sun.COM logq->il_flags |= FC_TRACE_LOGQ_V2; 60957836SJohn.Forte@Sun.COM 60967836SJohn.Forte@Sun.COM return (logq); 60977836SJohn.Forte@Sun.COM } 60987836SJohn.Forte@Sun.COM 60997836SJohn.Forte@Sun.COM 61007836SJohn.Forte@Sun.COM void 61017836SJohn.Forte@Sun.COM fc_trace_free_logq(fc_trace_logq_t *logq) 61027836SJohn.Forte@Sun.COM { 61037836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 61047836SJohn.Forte@Sun.COM while (logq->il_msgh) { 61057836SJohn.Forte@Sun.COM fc_trace_freemsg(logq); 61067836SJohn.Forte@Sun.COM } 61077836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 61087836SJohn.Forte@Sun.COM 61097836SJohn.Forte@Sun.COM mutex_destroy(&logq->il_lock); 61107836SJohn.Forte@Sun.COM kmem_free(logq, sizeof (*logq)); 61117836SJohn.Forte@Sun.COM } 61127836SJohn.Forte@Sun.COM 61137836SJohn.Forte@Sun.COM 61147836SJohn.Forte@Sun.COM /* ARGSUSED */ 61157836SJohn.Forte@Sun.COM void 61167836SJohn.Forte@Sun.COM fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level) 61177836SJohn.Forte@Sun.COM { 61187836SJohn.Forte@Sun.COM int qfull = 0; 61197836SJohn.Forte@Sun.COM fc_trace_dmsg_t *dmsg; 61207836SJohn.Forte@Sun.COM 61217836SJohn.Forte@Sun.COM dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP); 61227836SJohn.Forte@Sun.COM if (dmsg == NULL) { 61237836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 61247836SJohn.Forte@Sun.COM logq->il_afail++; 61257836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 61267836SJohn.Forte@Sun.COM 61277836SJohn.Forte@Sun.COM return; 61287836SJohn.Forte@Sun.COM } 61297836SJohn.Forte@Sun.COM 61307836SJohn.Forte@Sun.COM gethrestime(&dmsg->id_time); 61317836SJohn.Forte@Sun.COM 61327836SJohn.Forte@Sun.COM dmsg->id_size = strlen(buf) + 1; 61337836SJohn.Forte@Sun.COM dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP); 61347836SJohn.Forte@Sun.COM if (dmsg->id_buf == NULL) { 61357836SJohn.Forte@Sun.COM kmem_free(dmsg, sizeof (*dmsg)); 61367836SJohn.Forte@Sun.COM 61377836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 61387836SJohn.Forte@Sun.COM logq->il_afail++; 61397836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 61407836SJohn.Forte@Sun.COM 61417836SJohn.Forte@Sun.COM return; 61427836SJohn.Forte@Sun.COM } 61437836SJohn.Forte@Sun.COM bcopy(buf, dmsg->id_buf, strlen(buf)); 61447836SJohn.Forte@Sun.COM dmsg->id_buf[strlen(buf)] = '\0'; 61457836SJohn.Forte@Sun.COM 61467836SJohn.Forte@Sun.COM mutex_enter(&logq->il_lock); 61477836SJohn.Forte@Sun.COM 61487836SJohn.Forte@Sun.COM logq->il_size += dmsg->id_size; 61497836SJohn.Forte@Sun.COM if (logq->il_size >= logq->il_hiwat) { 61507836SJohn.Forte@Sun.COM qfull = 1; 61517836SJohn.Forte@Sun.COM } 61527836SJohn.Forte@Sun.COM 61537836SJohn.Forte@Sun.COM if (qfull) { 61547836SJohn.Forte@Sun.COM fc_trace_freemsg(logq); 61557836SJohn.Forte@Sun.COM } 61567836SJohn.Forte@Sun.COM 61577836SJohn.Forte@Sun.COM dmsg->id_next = NULL; 61587836SJohn.Forte@Sun.COM if (logq->il_msgt) { 61597836SJohn.Forte@Sun.COM logq->il_msgt->id_next = dmsg; 61607836SJohn.Forte@Sun.COM } else { 61617836SJohn.Forte@Sun.COM ASSERT(logq->il_msgh == NULL); 61627836SJohn.Forte@Sun.COM logq->il_msgh = dmsg; 61637836SJohn.Forte@Sun.COM } 61647836SJohn.Forte@Sun.COM logq->il_msgt = dmsg; 61657836SJohn.Forte@Sun.COM 61667836SJohn.Forte@Sun.COM mutex_exit(&logq->il_lock); 61677836SJohn.Forte@Sun.COM } 61687836SJohn.Forte@Sun.COM 61697836SJohn.Forte@Sun.COM 61707836SJohn.Forte@Sun.COM static void 61717836SJohn.Forte@Sun.COM fc_trace_freemsg(fc_trace_logq_t *logq) 61727836SJohn.Forte@Sun.COM { 61737836SJohn.Forte@Sun.COM fc_trace_dmsg_t *dmsg; 61747836SJohn.Forte@Sun.COM 61757836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&logq->il_lock)); 61767836SJohn.Forte@Sun.COM 61777836SJohn.Forte@Sun.COM if ((dmsg = logq->il_msgh) != NULL) { 61787836SJohn.Forte@Sun.COM logq->il_msgh = dmsg->id_next; 61797836SJohn.Forte@Sun.COM if (logq->il_msgh == NULL) { 61807836SJohn.Forte@Sun.COM logq->il_msgt = NULL; 61817836SJohn.Forte@Sun.COM } 61827836SJohn.Forte@Sun.COM 61837836SJohn.Forte@Sun.COM logq->il_size -= dmsg->id_size; 61847836SJohn.Forte@Sun.COM kmem_free(dmsg->id_buf, dmsg->id_size); 61857836SJohn.Forte@Sun.COM kmem_free(dmsg, sizeof (*dmsg)); 61867836SJohn.Forte@Sun.COM } else { 61877836SJohn.Forte@Sun.COM ASSERT(logq->il_msgt == NULL); 61887836SJohn.Forte@Sun.COM } 61897836SJohn.Forte@Sun.COM } 61907836SJohn.Forte@Sun.COM 61917836SJohn.Forte@Sun.COM /* 61927836SJohn.Forte@Sun.COM * Used by T11 FC-HBA to fetch discovered ports by index. 61937836SJohn.Forte@Sun.COM * Returns NULL if the index isn't valid. 61947836SJohn.Forte@Sun.COM */ 61957836SJohn.Forte@Sun.COM fc_remote_port_t * 61967836SJohn.Forte@Sun.COM fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index) 61977836SJohn.Forte@Sun.COM { 61987836SJohn.Forte@Sun.COM int outer; 61997836SJohn.Forte@Sun.COM int match = 0; 62007836SJohn.Forte@Sun.COM struct pwwn_hash *head; 620110264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 62027836SJohn.Forte@Sun.COM 62037836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 62047836SJohn.Forte@Sun.COM 62057836SJohn.Forte@Sun.COM for (outer = 0; 620610264SZhong.Wang@Sun.COM outer < pwwn_table_size && match <= index; 620710264SZhong.Wang@Sun.COM outer++) { 620810264SZhong.Wang@Sun.COM head = &port->fp_pwwn_table[outer]; 620910264SZhong.Wang@Sun.COM pd = head->pwwn_head; 62107836SJohn.Forte@Sun.COM if (pd != NULL) match ++; 621110264SZhong.Wang@Sun.COM 621210264SZhong.Wang@Sun.COM while (pd != NULL && match <= index) { 621310264SZhong.Wang@Sun.COM pd = pd->pd_wwn_hnext; 621410264SZhong.Wang@Sun.COM if (pd != NULL) match ++; 621510264SZhong.Wang@Sun.COM } 62167836SJohn.Forte@Sun.COM } 62177836SJohn.Forte@Sun.COM 62187836SJohn.Forte@Sun.COM return (pd); 62197836SJohn.Forte@Sun.COM } 62207836SJohn.Forte@Sun.COM 62217836SJohn.Forte@Sun.COM /* 62227836SJohn.Forte@Sun.COM * Search for a matching Node or Port WWN in the discovered port list 62237836SJohn.Forte@Sun.COM */ 62247836SJohn.Forte@Sun.COM fc_remote_port_t * 62257836SJohn.Forte@Sun.COM fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn) 62267836SJohn.Forte@Sun.COM { 62277836SJohn.Forte@Sun.COM int index; 62287836SJohn.Forte@Sun.COM struct pwwn_hash *head; 622910264SZhong.Wang@Sun.COM fc_remote_port_t *pd; 62307836SJohn.Forte@Sun.COM 62317836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&port->fp_mutex)); 62327836SJohn.Forte@Sun.COM 62337836SJohn.Forte@Sun.COM for (index = 0; index < pwwn_table_size; index++) { 62347836SJohn.Forte@Sun.COM head = &port->fp_pwwn_table[index]; 62357836SJohn.Forte@Sun.COM pd = head->pwwn_head; 62367836SJohn.Forte@Sun.COM 623710264SZhong.Wang@Sun.COM while (pd != NULL) { 623810264SZhong.Wang@Sun.COM mutex_enter(&pd->pd_mutex); 623910264SZhong.Wang@Sun.COM if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn, 624010264SZhong.Wang@Sun.COM sizeof (la_wwn_t)) == 0) { 624110264SZhong.Wang@Sun.COM mutex_exit(&pd->pd_mutex); 624210264SZhong.Wang@Sun.COM return (pd); 624310264SZhong.Wang@Sun.COM } 624410264SZhong.Wang@Sun.COM if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn, 624510264SZhong.Wang@Sun.COM wwn.raw_wwn, sizeof (la_wwn_t)) == 0) { 624610264SZhong.Wang@Sun.COM mutex_exit(&pd->pd_mutex); 624710264SZhong.Wang@Sun.COM return (pd); 624810264SZhong.Wang@Sun.COM } 624910264SZhong.Wang@Sun.COM mutex_exit(&pd->pd_mutex); 625010264SZhong.Wang@Sun.COM pd = pd->pd_wwn_hnext; 625110264SZhong.Wang@Sun.COM } 62527836SJohn.Forte@Sun.COM } 62537836SJohn.Forte@Sun.COM /* No match */ 62547836SJohn.Forte@Sun.COM return (NULL); 62557836SJohn.Forte@Sun.COM } 62567836SJohn.Forte@Sun.COM 62577836SJohn.Forte@Sun.COM 62587836SJohn.Forte@Sun.COM /* 62597836SJohn.Forte@Sun.COM * Count the number of ports on this adapter. 62607836SJohn.Forte@Sun.COM * This routine will walk the port list and count up the number of adapters 62617836SJohn.Forte@Sun.COM * with matching fp_hba_port_attrs.hba_fru_details.high and 62627836SJohn.Forte@Sun.COM * fp_hba_port_attrs.hba_fru_details.low. 62637836SJohn.Forte@Sun.COM * 62647836SJohn.Forte@Sun.COM * port->fp_mutex must not be held. 62657836SJohn.Forte@Sun.COM */ 62667836SJohn.Forte@Sun.COM int 62677836SJohn.Forte@Sun.COM fctl_count_fru_ports(fc_local_port_t *port, int npivflag) 62687836SJohn.Forte@Sun.COM { 62697836SJohn.Forte@Sun.COM fca_hba_fru_details_t *fru; 627010264SZhong.Wang@Sun.COM fc_fca_port_t *fca_port; 62717836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = NULL; 62727836SJohn.Forte@Sun.COM uint32_t count = 1; 62737836SJohn.Forte@Sun.COM 62747836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 62757836SJohn.Forte@Sun.COM 62767836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 62777836SJohn.Forte@Sun.COM fru = &port->fp_hba_port_attrs.hba_fru_details; 62787836SJohn.Forte@Sun.COM 62797836SJohn.Forte@Sun.COM /* Detect FCA drivers that don't support linking HBA ports */ 62807836SJohn.Forte@Sun.COM if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 62817836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 62827836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 62837836SJohn.Forte@Sun.COM return (1); 62847836SJohn.Forte@Sun.COM } 62857836SJohn.Forte@Sun.COM 62867836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 62877836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 628810264SZhong.Wang@Sun.COM tmpPort = fca_port->port_handle; 628910264SZhong.Wang@Sun.COM if (tmpPort == port) { 629010264SZhong.Wang@Sun.COM continue; 629110264SZhong.Wang@Sun.COM } 629210264SZhong.Wang@Sun.COM mutex_enter(&tmpPort->fp_mutex); 62937836SJohn.Forte@Sun.COM 62947836SJohn.Forte@Sun.COM /* 62957836SJohn.Forte@Sun.COM * If an FCA driver returns unique fru->high and fru->low for 62967836SJohn.Forte@Sun.COM * ports on the same card, there is no way for the transport 62977836SJohn.Forte@Sun.COM * layer to determine that the two ports on the same FRU. So, 62987836SJohn.Forte@Sun.COM * the discovery of the ports on a same FRU is limited to what 62997836SJohn.Forte@Sun.COM * the FCA driver can report back. 63007836SJohn.Forte@Sun.COM */ 63017836SJohn.Forte@Sun.COM if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 63027836SJohn.Forte@Sun.COM fru->high && 63037836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.hba_fru_details.low == 63047836SJohn.Forte@Sun.COM fru->low) { 63057836SJohn.Forte@Sun.COM /* Now double check driver */ 63067836SJohn.Forte@Sun.COM if (strncmp(port->fp_hba_port_attrs.driver_name, 63077836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.driver_name, 63087836SJohn.Forte@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 63097836SJohn.Forte@Sun.COM if (!npivflag || 63107836SJohn.Forte@Sun.COM (tmpPort->fp_npiv_type != FC_NPIV_PORT)) { 63117836SJohn.Forte@Sun.COM count++; 63127836SJohn.Forte@Sun.COM } 63137836SJohn.Forte@Sun.COM } /* Else, different FCA driver */ 63147836SJohn.Forte@Sun.COM } /* Else not the same HBA FRU */ 63157836SJohn.Forte@Sun.COM mutex_exit(&tmpPort->fp_mutex); 63167836SJohn.Forte@Sun.COM } 63177836SJohn.Forte@Sun.COM 63187836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 63197836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 63207836SJohn.Forte@Sun.COM 63217836SJohn.Forte@Sun.COM return (count); 63227836SJohn.Forte@Sun.COM } 63237836SJohn.Forte@Sun.COM 63247836SJohn.Forte@Sun.COM fc_fca_port_t * 63257836SJohn.Forte@Sun.COM fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port) 63267836SJohn.Forte@Sun.COM { 63277836SJohn.Forte@Sun.COM fc_fca_port_t *tmp = list, *newentry = NULL; 63287836SJohn.Forte@Sun.COM 63297836SJohn.Forte@Sun.COM newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP); 63307836SJohn.Forte@Sun.COM if (newentry == NULL) { 63317836SJohn.Forte@Sun.COM return (list); 63327836SJohn.Forte@Sun.COM } 63337836SJohn.Forte@Sun.COM newentry->port_handle = port; 63347836SJohn.Forte@Sun.COM 63357836SJohn.Forte@Sun.COM if (tmp == NULL) { 63367836SJohn.Forte@Sun.COM return (newentry); 63377836SJohn.Forte@Sun.COM } 63387836SJohn.Forte@Sun.COM while (tmp->port_next != NULL) tmp = tmp->port_next; 63397836SJohn.Forte@Sun.COM tmp->port_next = newentry; 63407836SJohn.Forte@Sun.COM 63417836SJohn.Forte@Sun.COM return (list); 63427836SJohn.Forte@Sun.COM } 63437836SJohn.Forte@Sun.COM 63447836SJohn.Forte@Sun.COM void 63457836SJohn.Forte@Sun.COM fctl_local_port_list_free(fc_fca_port_t *list) 63467836SJohn.Forte@Sun.COM { 63477836SJohn.Forte@Sun.COM fc_fca_port_t *tmp = list, *nextentry; 63487836SJohn.Forte@Sun.COM 63497836SJohn.Forte@Sun.COM if (tmp == NULL) { 63507836SJohn.Forte@Sun.COM return; 63517836SJohn.Forte@Sun.COM } 63527836SJohn.Forte@Sun.COM 63537836SJohn.Forte@Sun.COM while (tmp != NULL) { 63547836SJohn.Forte@Sun.COM nextentry = tmp->port_next; 63557836SJohn.Forte@Sun.COM kmem_free(tmp, sizeof (*tmp)); 63567836SJohn.Forte@Sun.COM tmp = nextentry; 63577836SJohn.Forte@Sun.COM } 63587836SJohn.Forte@Sun.COM } 63597836SJohn.Forte@Sun.COM 63607836SJohn.Forte@Sun.COM /* 63617836SJohn.Forte@Sun.COM * Fetch another port on the HBA FRU based on index. 63627836SJohn.Forte@Sun.COM * Returns NULL if index not found. 63637836SJohn.Forte@Sun.COM * 63647836SJohn.Forte@Sun.COM * port->fp_mutex must not be held. 63657836SJohn.Forte@Sun.COM */ 63667836SJohn.Forte@Sun.COM fc_local_port_t * 63677836SJohn.Forte@Sun.COM fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index) 63687836SJohn.Forte@Sun.COM { 63697836SJohn.Forte@Sun.COM fca_hba_fru_details_t *fru; 637010264SZhong.Wang@Sun.COM fc_fca_port_t *fca_port; 63717836SJohn.Forte@Sun.COM fc_local_port_t *tmpPort = NULL; 63727836SJohn.Forte@Sun.COM fc_fca_port_t *list = NULL, *tmpEntry; 63737836SJohn.Forte@Sun.COM fc_local_port_t *phyPort, *virPort = NULL; 63747836SJohn.Forte@Sun.COM int index, phyPortNum = 0; 63757836SJohn.Forte@Sun.COM 63767836SJohn.Forte@Sun.COM mutex_enter(&fctl_port_lock); 63777836SJohn.Forte@Sun.COM 63787836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 63797836SJohn.Forte@Sun.COM fru = &port->fp_hba_port_attrs.hba_fru_details; 63807836SJohn.Forte@Sun.COM 63817836SJohn.Forte@Sun.COM /* Are we looking for this port? */ 63827836SJohn.Forte@Sun.COM if (fru->port_index == port_index) { 63837836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 63847836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 63857836SJohn.Forte@Sun.COM return (port); 63867836SJohn.Forte@Sun.COM } 63877836SJohn.Forte@Sun.COM 63887836SJohn.Forte@Sun.COM /* Detect FCA drivers that don't support linking HBA ports */ 63897836SJohn.Forte@Sun.COM if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) { 63907836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 63917836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 63927836SJohn.Forte@Sun.COM return (NULL); 63937836SJohn.Forte@Sun.COM } 63947836SJohn.Forte@Sun.COM 63957836SJohn.Forte@Sun.COM list = fctl_local_port_list_add(list, port); 63967836SJohn.Forte@Sun.COM phyPortNum++; 63977836SJohn.Forte@Sun.COM /* Loop through all known ports */ 63987836SJohn.Forte@Sun.COM for (fca_port = fctl_fca_portlist; fca_port != NULL; 63997836SJohn.Forte@Sun.COM fca_port = fca_port->port_next) { 640010264SZhong.Wang@Sun.COM tmpPort = fca_port->port_handle; 640110264SZhong.Wang@Sun.COM if (tmpPort == port) { 640210264SZhong.Wang@Sun.COM /* Skip the port that was passed in as the argument */ 640310264SZhong.Wang@Sun.COM continue; 640410264SZhong.Wang@Sun.COM } 640510264SZhong.Wang@Sun.COM mutex_enter(&tmpPort->fp_mutex); 640610264SZhong.Wang@Sun.COM 640710264SZhong.Wang@Sun.COM /* See if this port is on the same HBA FRU (fast check) */ 640810264SZhong.Wang@Sun.COM if (tmpPort->fp_hba_port_attrs.hba_fru_details.high == 64097836SJohn.Forte@Sun.COM fru->high && 64107836SJohn.Forte@Sun.COM tmpPort->fp_hba_port_attrs.hba_fru_details.low == 64117836SJohn.Forte@Sun.COM fru->low) { 641210264SZhong.Wang@Sun.COM /* Now double check driver (slower check) */ 641310264SZhong.Wang@Sun.COM if (strncmp(port->fp_hba_port_attrs.driver_name, 641410264SZhong.Wang@Sun.COM tmpPort->fp_hba_port_attrs.driver_name, 641510264SZhong.Wang@Sun.COM FCHBA_DRIVER_NAME_LEN) == 0) { 641610264SZhong.Wang@Sun.COM 641710264SZhong.Wang@Sun.COM fru = 641810264SZhong.Wang@Sun.COM &tmpPort->fp_hba_port_attrs.hba_fru_details; 641910264SZhong.Wang@Sun.COM /* Check for the matching port_index */ 642010264SZhong.Wang@Sun.COM if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) && 642110264SZhong.Wang@Sun.COM (fru->port_index == port_index)) { 642210264SZhong.Wang@Sun.COM /* Found it! */ 642310264SZhong.Wang@Sun.COM mutex_exit(&tmpPort->fp_mutex); 642410264SZhong.Wang@Sun.COM mutex_exit(&port->fp_mutex); 642510264SZhong.Wang@Sun.COM mutex_exit(&fctl_port_lock); 642610264SZhong.Wang@Sun.COM fctl_local_port_list_free(list); 642710264SZhong.Wang@Sun.COM return (tmpPort); 642810264SZhong.Wang@Sun.COM } 642910264SZhong.Wang@Sun.COM if (tmpPort->fp_npiv_type != FC_NPIV_PORT) { 643010264SZhong.Wang@Sun.COM (void) fctl_local_port_list_add(list, 643110264SZhong.Wang@Sun.COM tmpPort); 643210264SZhong.Wang@Sun.COM phyPortNum++; 643310264SZhong.Wang@Sun.COM } 643410264SZhong.Wang@Sun.COM } /* Else, different FCA driver */ 643510264SZhong.Wang@Sun.COM } /* Else not the same HBA FRU */ 643610264SZhong.Wang@Sun.COM mutex_exit(&tmpPort->fp_mutex); 64377836SJohn.Forte@Sun.COM 64387836SJohn.Forte@Sun.COM } 64397836SJohn.Forte@Sun.COM 64407836SJohn.Forte@Sun.COM /* scan all physical port on same chip to find virtual port */ 64417836SJohn.Forte@Sun.COM tmpEntry = list; 64427836SJohn.Forte@Sun.COM index = phyPortNum - 1; 64437836SJohn.Forte@Sun.COM virPort = NULL; 64447836SJohn.Forte@Sun.COM while (index < port_index) { 64457836SJohn.Forte@Sun.COM if (tmpEntry == NULL) { 64467836SJohn.Forte@Sun.COM break; 64477836SJohn.Forte@Sun.COM } 64487836SJohn.Forte@Sun.COM if (virPort == NULL) { 64497836SJohn.Forte@Sun.COM phyPort = tmpEntry->port_handle; 64507836SJohn.Forte@Sun.COM virPort = phyPort->fp_port_next; 64517836SJohn.Forte@Sun.COM if (virPort == NULL) { 64527836SJohn.Forte@Sun.COM tmpEntry = tmpEntry->port_next; 64537836SJohn.Forte@Sun.COM continue; 64547836SJohn.Forte@Sun.COM } 64557836SJohn.Forte@Sun.COM } else { 64567836SJohn.Forte@Sun.COM virPort = virPort->fp_port_next; 64577836SJohn.Forte@Sun.COM } 64587836SJohn.Forte@Sun.COM if (virPort == phyPort) { 64597836SJohn.Forte@Sun.COM tmpEntry = tmpEntry->port_next; 64607836SJohn.Forte@Sun.COM virPort = NULL; 64617836SJohn.Forte@Sun.COM } else { 64627836SJohn.Forte@Sun.COM index++; 64637836SJohn.Forte@Sun.COM } 64647836SJohn.Forte@Sun.COM } 64657836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 64667836SJohn.Forte@Sun.COM mutex_exit(&fctl_port_lock); 64677836SJohn.Forte@Sun.COM 64687836SJohn.Forte@Sun.COM fctl_local_port_list_free(list); 64697836SJohn.Forte@Sun.COM if (virPort) { 64707836SJohn.Forte@Sun.COM return (virPort); 64717836SJohn.Forte@Sun.COM } 64727836SJohn.Forte@Sun.COM return (NULL); 64737836SJohn.Forte@Sun.COM } 64747836SJohn.Forte@Sun.COM 64757836SJohn.Forte@Sun.COM int 64767836SJohn.Forte@Sun.COM fctl_busy_port(fc_local_port_t *port) 64777836SJohn.Forte@Sun.COM { 64787836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 64797836SJohn.Forte@Sun.COM 64807836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 64817836SJohn.Forte@Sun.COM if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) { 64827836SJohn.Forte@Sun.COM /* 64837836SJohn.Forte@Sun.COM * If fctl_busy_port() is called before we've registered our 64847836SJohn.Forte@Sun.COM * PM components, we return success. We need to be aware of 64857836SJohn.Forte@Sun.COM * this because the caller will eventually call fctl_idle_port. 64867836SJohn.Forte@Sun.COM * This wouldn't be a problem except that if we have 64877836SJohn.Forte@Sun.COM * registered our PM components in the meantime, we will 64887836SJohn.Forte@Sun.COM * then be idling a component that was never busied. PM 648910264SZhong.Wang@Sun.COM * will be very unhappy if we do this. Thus, we keep 64907836SJohn.Forte@Sun.COM * track of this with port->fp_pm_busy_nocomp. 64917836SJohn.Forte@Sun.COM */ 64927836SJohn.Forte@Sun.COM port->fp_pm_busy_nocomp++; 64937836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 64947836SJohn.Forte@Sun.COM return (0); 64957836SJohn.Forte@Sun.COM } 64967836SJohn.Forte@Sun.COM port->fp_pm_busy++; 64977836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 64987836SJohn.Forte@Sun.COM 64997836SJohn.Forte@Sun.COM if (pm_busy_component(port->fp_port_dip, 65007836SJohn.Forte@Sun.COM FP_PM_COMPONENT) != DDI_SUCCESS) { 65017836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 65027836SJohn.Forte@Sun.COM port->fp_pm_busy--; 65037836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65047836SJohn.Forte@Sun.COM return (ENXIO); 65057836SJohn.Forte@Sun.COM } 65067836SJohn.Forte@Sun.COM 65077836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 65087836SJohn.Forte@Sun.COM if (port->fp_pm_level == FP_PM_PORT_DOWN) { 65097836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65107836SJohn.Forte@Sun.COM if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT, 65117836SJohn.Forte@Sun.COM FP_PM_PORT_UP) != DDI_SUCCESS) { 65127836SJohn.Forte@Sun.COM 65137836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 65147836SJohn.Forte@Sun.COM port->fp_pm_busy--; 65157836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65167836SJohn.Forte@Sun.COM 65177836SJohn.Forte@Sun.COM (void) pm_idle_component(port->fp_port_dip, 65187836SJohn.Forte@Sun.COM FP_PM_COMPONENT); 65197836SJohn.Forte@Sun.COM return (EIO); 65207836SJohn.Forte@Sun.COM } 65217836SJohn.Forte@Sun.COM return (0); 65227836SJohn.Forte@Sun.COM } 65237836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65247836SJohn.Forte@Sun.COM return (0); 65257836SJohn.Forte@Sun.COM } 65267836SJohn.Forte@Sun.COM 65277836SJohn.Forte@Sun.COM void 65287836SJohn.Forte@Sun.COM fctl_idle_port(fc_local_port_t *port) 65297836SJohn.Forte@Sun.COM { 65307836SJohn.Forte@Sun.COM ASSERT(!MUTEX_HELD(&port->fp_mutex)); 65317836SJohn.Forte@Sun.COM 65327836SJohn.Forte@Sun.COM mutex_enter(&port->fp_mutex); 65337836SJohn.Forte@Sun.COM 65347836SJohn.Forte@Sun.COM /* 65357836SJohn.Forte@Sun.COM * If port->fp_pm_busy_nocomp is > 0, that means somebody had 65367836SJohn.Forte@Sun.COM * called fctl_busy_port prior to us registering our PM components. 65377836SJohn.Forte@Sun.COM * In that case, we just decrement fp_pm_busy_nocomp and return. 65387836SJohn.Forte@Sun.COM */ 65397836SJohn.Forte@Sun.COM 65407836SJohn.Forte@Sun.COM if (port->fp_pm_busy_nocomp > 0) { 65417836SJohn.Forte@Sun.COM port->fp_pm_busy_nocomp--; 65427836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65437836SJohn.Forte@Sun.COM return; 65447836SJohn.Forte@Sun.COM } 65457836SJohn.Forte@Sun.COM 65467836SJohn.Forte@Sun.COM port->fp_pm_busy--; 65477836SJohn.Forte@Sun.COM mutex_exit(&port->fp_mutex); 65487836SJohn.Forte@Sun.COM 65497836SJohn.Forte@Sun.COM (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT); 65507836SJohn.Forte@Sun.COM } 65517836SJohn.Forte@Sun.COM 65527836SJohn.Forte@Sun.COM /* 65537836SJohn.Forte@Sun.COM * Function: fctl_tc_timer 65547836SJohn.Forte@Sun.COM * 65557836SJohn.Forte@Sun.COM * Description: Resets the value of the timed counter. 65567836SJohn.Forte@Sun.COM * 65577836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter 65587836SJohn.Forte@Sun.COM * 65597836SJohn.Forte@Sun.COM * Return Value: Nothing 65607836SJohn.Forte@Sun.COM * 656110264SZhong.Wang@Sun.COM * Context: Kernel context. 65627836SJohn.Forte@Sun.COM */ 65637836SJohn.Forte@Sun.COM static void 656410264SZhong.Wang@Sun.COM fctl_tc_timer(void *arg) 65657836SJohn.Forte@Sun.COM { 65667836SJohn.Forte@Sun.COM timed_counter_t *tc = (timed_counter_t *)arg; 65677836SJohn.Forte@Sun.COM 65687836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 65697836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 65707836SJohn.Forte@Sun.COM 65717836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 65727836SJohn.Forte@Sun.COM if (tc->active) { 65737836SJohn.Forte@Sun.COM tc->active = B_FALSE; 65747836SJohn.Forte@Sun.COM tc->counter = 0; 65757836SJohn.Forte@Sun.COM } 65767836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 65777836SJohn.Forte@Sun.COM } 65787836SJohn.Forte@Sun.COM 65797836SJohn.Forte@Sun.COM /* 65807836SJohn.Forte@Sun.COM * Function: fctl_tc_constructor 65817836SJohn.Forte@Sun.COM * 65827836SJohn.Forte@Sun.COM * Description: Constructs a timed counter. 65837836SJohn.Forte@Sun.COM * 65847836SJohn.Forte@Sun.COM * Arguments: *tc Address where the timed counter will reside. 658510264SZhong.Wang@Sun.COM * max_value Maximum value the counter is allowed to take. 65867836SJohn.Forte@Sun.COM * timer Number of microseconds after which the counter 65877836SJohn.Forte@Sun.COM * will be reset. The timer is started when the 65887836SJohn.Forte@Sun.COM * value of the counter goes from 0 to 1. 65897836SJohn.Forte@Sun.COM * 65907836SJohn.Forte@Sun.COM * Return Value: Nothing 65917836SJohn.Forte@Sun.COM * 659210264SZhong.Wang@Sun.COM * Context: Kernel context. 65937836SJohn.Forte@Sun.COM */ 65947836SJohn.Forte@Sun.COM void 659510264SZhong.Wang@Sun.COM fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer) 65967836SJohn.Forte@Sun.COM { 65977836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 65987836SJohn.Forte@Sun.COM ASSERT(tc->sig != tc); 65997836SJohn.Forte@Sun.COM 66007836SJohn.Forte@Sun.COM bzero(tc, sizeof (*tc)); 66017836SJohn.Forte@Sun.COM mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL); 66027836SJohn.Forte@Sun.COM tc->timer = drv_usectohz(timer); 66037836SJohn.Forte@Sun.COM tc->active = B_FALSE; 66047836SJohn.Forte@Sun.COM tc->maxed_out = B_FALSE; 66057836SJohn.Forte@Sun.COM tc->max_value = max_value; 66067836SJohn.Forte@Sun.COM tc->sig = tc; 66077836SJohn.Forte@Sun.COM } 66087836SJohn.Forte@Sun.COM 66097836SJohn.Forte@Sun.COM /* 66107836SJohn.Forte@Sun.COM * Function: fctl_tc_destructor 66117836SJohn.Forte@Sun.COM * 66127836SJohn.Forte@Sun.COM * Description: Destroyes a timed counter. 66137836SJohn.Forte@Sun.COM * 66147836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to destroy. 66157836SJohn.Forte@Sun.COM * 66167836SJohn.Forte@Sun.COM * Return Value: Nothing 66177836SJohn.Forte@Sun.COM * 661810264SZhong.Wang@Sun.COM * Context: Kernel context. 66197836SJohn.Forte@Sun.COM */ 66207836SJohn.Forte@Sun.COM void 662110264SZhong.Wang@Sun.COM fctl_tc_destructor(timed_counter_t *tc) 66227836SJohn.Forte@Sun.COM { 66237836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 66247836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 66257836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&tc->mutex)); 66267836SJohn.Forte@Sun.COM 66277836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 66287836SJohn.Forte@Sun.COM if (tc->active) { 66297836SJohn.Forte@Sun.COM tc->active = B_FALSE; 6630*11922SSriram.Popuri@sun.com mutex_exit(&tc->mutex); 66317836SJohn.Forte@Sun.COM (void) untimeout(tc->tid); 6632*11922SSriram.Popuri@sun.com mutex_enter(&tc->mutex); 66337836SJohn.Forte@Sun.COM tc->sig = NULL; 66347836SJohn.Forte@Sun.COM } 66357836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 66367836SJohn.Forte@Sun.COM mutex_destroy(&tc->mutex); 66377836SJohn.Forte@Sun.COM } 66387836SJohn.Forte@Sun.COM 66397836SJohn.Forte@Sun.COM /* 66407836SJohn.Forte@Sun.COM * Function: fctl_tc_increment 66417836SJohn.Forte@Sun.COM * 66427836SJohn.Forte@Sun.COM * Description: Increments a timed counter 66437836SJohn.Forte@Sun.COM * 66447836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to increment. 66457836SJohn.Forte@Sun.COM * 66467836SJohn.Forte@Sun.COM * Return Value: B_TRUE Counter reached the max value. 66477836SJohn.Forte@Sun.COM * B_FALSE Counter hasn't reached the max value. 66487836SJohn.Forte@Sun.COM * 664910264SZhong.Wang@Sun.COM * Context: Kernel or interrupt context. 66507836SJohn.Forte@Sun.COM */ 66517836SJohn.Forte@Sun.COM boolean_t 665210264SZhong.Wang@Sun.COM fctl_tc_increment(timed_counter_t *tc) 66537836SJohn.Forte@Sun.COM { 66547836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 66557836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 66567836SJohn.Forte@Sun.COM 66577836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 66587836SJohn.Forte@Sun.COM if (!tc->maxed_out) { 66597836SJohn.Forte@Sun.COM /* Hasn't maxed out yet. */ 66607836SJohn.Forte@Sun.COM ++tc->counter; 66617836SJohn.Forte@Sun.COM if (tc->counter >= tc->max_value) { 66627836SJohn.Forte@Sun.COM /* Just maxed out. */ 66637836SJohn.Forte@Sun.COM tc->maxed_out = B_TRUE; 66647836SJohn.Forte@Sun.COM } 66657836SJohn.Forte@Sun.COM if (!tc->active) { 66667836SJohn.Forte@Sun.COM tc->tid = timeout(fctl_tc_timer, tc, tc->timer); 66677836SJohn.Forte@Sun.COM tc->active = B_TRUE; 66687836SJohn.Forte@Sun.COM } 66697836SJohn.Forte@Sun.COM } 66707836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 66717836SJohn.Forte@Sun.COM 66727836SJohn.Forte@Sun.COM return (tc->maxed_out); 66737836SJohn.Forte@Sun.COM } 66747836SJohn.Forte@Sun.COM 66757836SJohn.Forte@Sun.COM /* 66767836SJohn.Forte@Sun.COM * Function: fctl_tc_reset 66777836SJohn.Forte@Sun.COM * 66787836SJohn.Forte@Sun.COM * Description: Resets a timed counter. The caller of this function has to 66797836SJohn.Forte@Sun.COM * to make sure that while in fctl_tc_reset() fctl_tc_increment() 66807836SJohn.Forte@Sun.COM * is not called. 66817836SJohn.Forte@Sun.COM * 66827836SJohn.Forte@Sun.COM * Arguments: *tc Timed counter to reset. 66837836SJohn.Forte@Sun.COM * 66847836SJohn.Forte@Sun.COM * Return Value: 0 Counter reached the max value. 66857836SJohn.Forte@Sun.COM * Not 0 Counter hasn't reached the max value. 66867836SJohn.Forte@Sun.COM * 668710264SZhong.Wang@Sun.COM * Context: Kernel or interrupt context. 66887836SJohn.Forte@Sun.COM */ 66897836SJohn.Forte@Sun.COM void 669010264SZhong.Wang@Sun.COM fctl_tc_reset(timed_counter_t *tc) 66917836SJohn.Forte@Sun.COM { 66927836SJohn.Forte@Sun.COM ASSERT(tc != NULL); 66937836SJohn.Forte@Sun.COM ASSERT(tc->sig == tc); 66947836SJohn.Forte@Sun.COM 66957836SJohn.Forte@Sun.COM mutex_enter(&tc->mutex); 66967836SJohn.Forte@Sun.COM tc->counter = 0; 66977836SJohn.Forte@Sun.COM tc->maxed_out = B_FALSE; 66987836SJohn.Forte@Sun.COM if (tc->active) { 66997836SJohn.Forte@Sun.COM tc->active = B_FALSE; 67007836SJohn.Forte@Sun.COM (void) untimeout(tc->tid); 67017836SJohn.Forte@Sun.COM } 67027836SJohn.Forte@Sun.COM mutex_exit(&tc->mutex); 67037836SJohn.Forte@Sun.COM } 67047836SJohn.Forte@Sun.COM 67057836SJohn.Forte@Sun.COM void 67067836SJohn.Forte@Sun.COM fc_ulp_log_device_event(opaque_t port_handle, int type) 67077836SJohn.Forte@Sun.COM { 67087836SJohn.Forte@Sun.COM fc_local_port_t *port = port_handle; 67097836SJohn.Forte@Sun.COM nvlist_t *attr_list; 67107836SJohn.Forte@Sun.COM 67117836SJohn.Forte@Sun.COM if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 67127836SJohn.Forte@Sun.COM KM_SLEEP) != DDI_SUCCESS) { 67137836SJohn.Forte@Sun.COM return; 67147836SJohn.Forte@Sun.COM } 67157836SJohn.Forte@Sun.COM 67167836SJohn.Forte@Sun.COM if (nvlist_add_uint32(attr_list, "instance", 67177836SJohn.Forte@Sun.COM port->fp_instance) != DDI_SUCCESS) { 67187836SJohn.Forte@Sun.COM goto error; 67197836SJohn.Forte@Sun.COM } 67207836SJohn.Forte@Sun.COM 67217836SJohn.Forte@Sun.COM if (nvlist_add_byte_array(attr_list, "port-wwn", 67227836SJohn.Forte@Sun.COM port->fp_service_params.nport_ww_name.raw_wwn, 67237836SJohn.Forte@Sun.COM sizeof (la_wwn_t)) != DDI_SUCCESS) { 67247836SJohn.Forte@Sun.COM goto error; 67257836SJohn.Forte@Sun.COM } 67267836SJohn.Forte@Sun.COM 67277836SJohn.Forte@Sun.COM (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC, 67287836SJohn.Forte@Sun.COM (type == FC_ULP_DEVICE_ONLINE) ? 67297836SJohn.Forte@Sun.COM ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE, 67307836SJohn.Forte@Sun.COM attr_list, NULL, DDI_SLEEP); 67317836SJohn.Forte@Sun.COM nvlist_free(attr_list); 67327836SJohn.Forte@Sun.COM return; 67337836SJohn.Forte@Sun.COM 67347836SJohn.Forte@Sun.COM error: 67357836SJohn.Forte@Sun.COM nvlist_free(attr_list); 67367836SJohn.Forte@Sun.COM } 6737