xref: /titanic_44/usr/src/uts/common/io/fibre-channel/impl/fctl.c (revision cd21e7c548ae2a3b5e522244bf798f2a6b4ba02d)
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