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