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