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
_init()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
_fini()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
_info(struct modinfo * modinfo_p)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
fctl_cache_constructor(void * buf,void * cdarg,int kmflag)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
fctl_cache_destructor(void * buf,void * cdarg)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
fc_ulp_add(fc_ulp_modinfo_t * ulp_info)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
fc_ulp_remove(fc_ulp_modinfo_t * ulp_info)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
fc_ulp_init_packet(opaque_t port_handle,fc_packet_t * pkt,int sleep)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
fc_ulp_uninit_packet(opaque_t port_handle,fc_packet_t * pkt)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
fc_ulp_getportmap(opaque_t port_handle,fc_portmap_t ** map,uint32_t * len,int flag)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
fc_ulp_login(opaque_t port_handle,fc_packet_t ** ulp_pkt,uint32_t listlen)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
fc_ulp_get_remote_port(opaque_t port_handle,la_wwn_t * pwwn,int * error,int create)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
fc_ulp_port_ns(opaque_t port_handle,opaque_t pd,fc_ns_cmd_t * ns_req)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
fc_ulp_transport(opaque_t port_handle,fc_packet_t * pkt)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
fc_ulp_issue_els(opaque_t port_handle,fc_packet_t * pkt)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
fc_ulp_uballoc(opaque_t port_handle,uint32_t * count,uint32_t size,uint32_t type,uint64_t * tokens)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
fc_ulp_ubfree(opaque_t port_handle,uint32_t count,uint64_t * tokens)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
fc_ulp_ubrelease(opaque_t port_handle,uint32_t count,uint64_t * tokens)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
fc_ulp_abort(opaque_t port_handle,fc_packet_t * pkt,int flags)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
fc_ulp_linkreset(opaque_t port_handle,la_wwn_t * pwwn,int sleep)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
fc_ulp_port_reset(opaque_t port_handle,uint32_t cmd)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
fc_ulp_get_port_login_params(opaque_t port_handle,la_els_logi_t * login_params)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
fc_ulp_get_port_instance(opaque_t port_handle)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
fc_ulp_get_port_handle(int port_instance)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
fc_ulp_error(int fc_errno,char ** errmsg)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
fc_ulp_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)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
fc_ulp_is_name_present(caddr_t ulp_name)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
fc_ulp_get_pwwn_by_did(opaque_t port_handle,fc_portid_t d_id,la_wwn_t * pwwn)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
fc_ulp_pwwn_to_portmap(opaque_t port_handle,la_wwn_t * bytes,fc_portmap_t * map)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
fc_ulp_get_fca_device(opaque_t port_handle,fc_portid_t d_id)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
fc_ulp_port_notify(opaque_t port_handle,uint32_t cmd)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
fc_ulp_disable_relogin(opaque_t * fc_port,la_wwn_t * pwwn)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
fc_ulp_enable_relogin(opaque_t * fc_port,la_wwn_t * pwwn)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
fc_fca_init(struct dev_ops * fca_devops_p)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
fc_fca_attach(dev_info_t * fca_dip,fc_fca_tran_t * tran)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
fc_fca_detach(dev_info_t * fca_dip)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
fc_fca_update_errors(fc_packet_t * pkt)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
fc_fca_error(int fc_errno,char ** errmsg)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
fc_fca_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)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
fc_wwn_to_str(la_wwn_t * wwn,caddr_t str)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
fc_str_to_wwn(caddr_t str,la_wwn_t * wwn)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
fctl_fca_bus_ctl(dev_info_t * fca_dip,dev_info_t * rip,ddi_ctl_enum_t op,void * arg,void * result)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
fctl_initchild(dev_info_t * fca_dip,dev_info_t * port_dip)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
fctl_uninitchild(dev_info_t * fca_dip,dev_info_t * port_dip)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 *
fctl_findchild(dev_info_t * pdip,char * cname,char * caddr)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
fctl_check_npiv_portindex(dev_info_t * dip,int vindex)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
fctl_get_npiv_portindex(dev_info_t * dip)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
fctl_set_npiv_portindex(dev_info_t * dip,int index)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
fctl_fca_create_npivport(dev_info_t * parent,dev_info_t * phydip,char * nname,char * pname,uint32_t * vindex)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
fctl_add_port(fc_local_port_t * port)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
fctl_remove_port(fc_local_port_t * port)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
fctl_attach_ulps(fc_local_port_t * port,fc_attach_cmd_t cmd,struct modlinkage * linkage)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
fctl_pre_attach(fc_ulp_ports_t * ulp_port,fc_attach_cmd_t cmd)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
fctl_post_attach(fc_ulp_module_t * mod,fc_ulp_ports_t * ulp_port,fc_attach_cmd_t cmd,int rval)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
fctl_detach_ulps(fc_local_port_t * port,fc_detach_cmd_t cmd,struct modlinkage * linkage)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
fctl_init_dma_attr(fc_local_port_t * port,fc_ulp_module_t * mod,fc_ulp_port_info_t * info)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
fctl_pre_detach(fc_ulp_ports_t * ulp_port,fc_detach_cmd_t cmd)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
fctl_post_detach(fc_ulp_module_t * mod,fc_ulp_ports_t * ulp_port,fc_detach_cmd_t cmd,int rval)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 *
fctl_add_ulp_port(fc_ulp_module_t * ulp_module,fc_local_port_t * port_handle,int sleep)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 *
fctl_alloc_ulp_port(int sleep)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
fctl_remove_ulp_port(struct ulp_module * ulp_module,fc_local_port_t * port_handle)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
fctl_dealloc_ulp_port(fc_ulp_ports_t * next)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 *
fctl_get_ulp_port(struct ulp_module * ulp_module,fc_local_port_t * port_handle)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
fctl_ulp_statec_cb(void * arg)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 *
fctl_create_remote_node(la_wwn_t * nwwn,int sleep)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
fctl_destroy_remote_node(fc_remote_node_t * rnodep)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
fctl_enlist_nwwn_table(fc_remote_node_t * rnodep,int sleep)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
fctl_delist_nwwn_table(fc_remote_node_t * rnodep)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 *
fctl_get_remote_node_by_nwwn(la_wwn_t * node_wwn)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 *
fctl_lock_remote_node_by_nwwn(la_wwn_t * node_wwn)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 *
fctl_alloc_remote_port(fc_local_port_t * port,la_wwn_t * port_wwn,uint32_t d_id,uchar_t recepient,int sleep)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
fctl_dealloc_remote_port(fc_remote_port_t * pd)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
fctl_link_remote_port_to_remote_node(fc_remote_node_t * rnodep,fc_remote_port_t * pd)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
fctl_unlink_remote_port_from_remote_node(fc_remote_node_t * rnodep,fc_remote_port_t * pd)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
fctl_enlist_did_table(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_delist_did_table(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_enlist_pwwn_table(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_delist_pwwn_table(fc_local_port_t * port,fc_remote_port_t * pd)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 *
fctl_get_remote_port_by_did(fc_local_port_t * port,uint32_t d_id)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
fc_ulp_hold_remote_port(opaque_t port_handle)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 *
fctl_hold_remote_port_by_did(fc_local_port_t * port,uint32_t d_id)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 *
fctl_get_remote_port_by_pwwn(fc_local_port_t * port,la_wwn_t * pwwn)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 *
fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t * port,la_wwn_t * pwwn)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 *
fctl_hold_remote_port_by_pwwn(fc_local_port_t * port,la_wwn_t * pwwn)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
fctl_release_remote_port(fc_remote_port_t * pd)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
fctl_fillout_map(fc_local_port_t * port,fc_portmap_t ** map,uint32_t * len,int whole_map,int justcopy,int orphan)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 *
fctl_alloc_job(int job_code,int job_flags,void (* comp)(opaque_t,uchar_t),opaque_t arg,int sleep)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
fctl_dealloc_job(job_request_t * job)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
fctl_enque_job(fc_local_port_t * port,job_request_t * job)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 *
fctl_deque_job(fc_local_port_t * port)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
fctl_priority_enque_job(fc_local_port_t * port,job_request_t * job)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
fctl_jobwait(job_request_t * job)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
fctl_jobdone(job_request_t * job)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
fctl_wwn_cmp(la_wwn_t * src,la_wwn_t * dst)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
fctl_atoi(char * s,int base)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 *
fctl_create_remote_port(fc_local_port_t * port,la_wwn_t * node_wwn,la_wwn_t * port_wwn,uint32_t d_id,uchar_t recepient,int sleep)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
fctl_destroy_remote_port(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_destroy_all_remote_ports(fc_local_port_t * port)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
fctl_is_wwn_zero(la_wwn_t * wwn)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
fctl_ulp_unsol_cb(fc_local_port_t * port,fc_unsol_buf_t * buf,uchar_t type)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
fctl_copy_portmap_held(fc_portmap_t * map,fc_remote_port_t * pd)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
fctl_copy_portmap(fc_portmap_t * map,fc_remote_port_t * pd)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
fctl_update_host_ns_values(fc_local_port_t * port,fc_ns_cmd_t * ns_req)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
fctl_retrieve_host_ns_values(fc_local_port_t * port,fc_ns_cmd_t * ns_req)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 *
fctl_alloc_ns_cmd(uint32_t cmd_len,uint32_t resp_len,uint32_t data_len,uint32_t ns_flags,int sleep)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
fctl_free_ns_cmd(fctl_ns_req_t * ns_cmd)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
fctl_ulp_port_ioctl(fc_local_port_t * port,dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)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
fc_ulp_busy_port(opaque_t port_handle)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
fc_ulp_idle_port(opaque_t port_handle)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
fc_ulp_copy_portmap(fc_portmap_t * map,opaque_t pd)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
fc_ulp_get_npiv_port_num(opaque_t port_handle)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 *
fc_get_npiv_port(fc_local_port_t * phyport,la_wwn_t * pwwn)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
fc_ulp_get_npiv_port_list(opaque_t port_handle,char * pathList)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 *
fc_delete_npiv_port(fc_local_port_t * port,la_wwn_t * pwwn)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
fc_ulp_get_adapter_paths(char * pathList,int count)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
fc_ulp_get_rscn_count(opaque_t port_handle)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
fctl_add_orphan_held(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_add_orphan(fc_local_port_t * port,fc_remote_port_t * pd,int sleep)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
fctl_remove_if_orphan(fc_local_port_t * port,la_wwn_t * pwwn)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
fctl_print_if_not_orphan(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_link_reset_done(opaque_t port_handle,uchar_t result)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
fctl_error(int fc_errno,char ** errmsg)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
fctl_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)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
fctl_remove_oldies(fc_local_port_t * port)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
fctl_check_alpa_list(fc_local_port_t * port,fc_remote_port_t * pd)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
fctl_is_alpa_present(fc_local_port_t * port,uchar_t alpa)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 *
fctl_lookup_pd_by_did(fc_local_port_t * port,uint32_t d_id)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
fc_trace_debug(fc_trace_logq_t * logq,caddr_t name,int dflag,int dlevel,int errno,const char * fmt,...)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 *
fc_trace_alloc_logq(int maxsize)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
fc_trace_free_logq(fc_trace_logq_t * logq)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
fc_trace_logmsg(fc_trace_logq_t * logq,caddr_t buf,int level)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
fc_trace_freemsg(fc_trace_logq_t * logq)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 *
fctl_lookup_pd_by_index(fc_local_port_t * port,uint32_t index)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 *
fctl_lookup_pd_by_wwn(fc_local_port_t * port,la_wwn_t wwn)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
fctl_count_fru_ports(fc_local_port_t * port,int npivflag)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 *
fctl_local_port_list_add(fc_fca_port_t * list,fc_local_port_t * port)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
fctl_local_port_list_free(fc_fca_port_t * list)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 *
fctl_get_adapter_port_by_index(fc_local_port_t * port,uint32_t port_index)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
fctl_busy_port(fc_local_port_t * port)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
fctl_idle_port(fc_local_port_t * port)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
fctl_tc_timer(void * arg)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
fctl_tc_constructor(timed_counter_t * tc,uint32_t max_value,clock_t timer)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
fctl_tc_destructor(timed_counter_t * tc)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
fctl_tc_increment(timed_counter_t * tc)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
fctl_tc_reset(timed_counter_t * tc)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
fc_ulp_log_device_event(opaque_t port_handle,int type)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