1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  *
25*7836SJohn.Forte@Sun.COM  * Fibre channel Transport Library (fctl)
26*7836SJohn.Forte@Sun.COM  *
27*7836SJohn.Forte@Sun.COM  * Function naming conventions:
28*7836SJohn.Forte@Sun.COM  *		Functions called from ULPs begin with fc_ulp_
29*7836SJohn.Forte@Sun.COM  *		Functions called from FCAs begin with fc_fca_
30*7836SJohn.Forte@Sun.COM  *		Internal functions begin with fctl_
31*7836SJohn.Forte@Sun.COM  *
32*7836SJohn.Forte@Sun.COM  * Fibre channel packet layout:
33*7836SJohn.Forte@Sun.COM  *        +---------------------+<--------+
34*7836SJohn.Forte@Sun.COM  *        |                     |         |
35*7836SJohn.Forte@Sun.COM  *        | ULP Packet private  |         |
36*7836SJohn.Forte@Sun.COM  *        |                     |         |
37*7836SJohn.Forte@Sun.COM  *        +---------------------+         |
38*7836SJohn.Forte@Sun.COM  *        |                     |---------+
39*7836SJohn.Forte@Sun.COM  *        |  struct  fc_packet  |---------+
40*7836SJohn.Forte@Sun.COM  *        |                     |         |
41*7836SJohn.Forte@Sun.COM  *        +---------------------+<--------+
42*7836SJohn.Forte@Sun.COM  *        |                     |
43*7836SJohn.Forte@Sun.COM  *        | FCA Packet private  |
44*7836SJohn.Forte@Sun.COM  *        |                     |
45*7836SJohn.Forte@Sun.COM  *        +---------------------+
46*7836SJohn.Forte@Sun.COM  *
47*7836SJohn.Forte@Sun.COM  * So you  loved  the  ascii  art ?  It's  strongly  desirable  to  cache
48*7836SJohn.Forte@Sun.COM  * allocate the entire packet in one common  place.  So we define a set a
49*7836SJohn.Forte@Sun.COM  * of rules.  In a  contiguous  block of memory,  the top  portion of the
50*7836SJohn.Forte@Sun.COM  * block points to ulp packet  private  area, next follows the  fc_packet
51*7836SJohn.Forte@Sun.COM  * structure used  extensively by all the consumers and what follows this
52*7836SJohn.Forte@Sun.COM  * is the FCA packet private.  Note that given a packet  structure, it is
53*7836SJohn.Forte@Sun.COM  * possible  to get to the  ULP  and  FCA  Packet  private  fields  using
54*7836SJohn.Forte@Sun.COM  * ulp_private and fca_private fields (which hold pointers) respectively.
55*7836SJohn.Forte@Sun.COM  *
56*7836SJohn.Forte@Sun.COM  * It should be noted with a grain of salt that ULP Packet  private  size
57*7836SJohn.Forte@Sun.COM  * varies  between two different  ULP types, So this poses a challenge to
58*7836SJohn.Forte@Sun.COM  * compute the correct  size of the whole block on a per port basis.  The
59*7836SJohn.Forte@Sun.COM  * transport  layer  doesn't have a problem in dealing with  FCA   packet
60*7836SJohn.Forte@Sun.COM  * private  sizes as it is the sole  manager of ports  underneath.  Since
61*7836SJohn.Forte@Sun.COM  * it's not a good idea to cache allocate  different  sizes of memory for
62*7836SJohn.Forte@Sun.COM  * different ULPs and have the ability to choose from one of these caches
63*7836SJohn.Forte@Sun.COM  * based on ULP type during every packet  allocation,  the transport some
64*7836SJohn.Forte@Sun.COM  * what  wisely (?)  hands off this job of cache  allocation  to the ULPs
65*7836SJohn.Forte@Sun.COM  * themselves.
66*7836SJohn.Forte@Sun.COM  *
67*7836SJohn.Forte@Sun.COM  * That means FCAs need to make their  packet  private size  known to the
68*7836SJohn.Forte@Sun.COM  * transport   to  pass  it  up  to  the   ULPs.  This  is  done   during
69*7836SJohn.Forte@Sun.COM  * fc_fca_attach().  And the transport passes this size up to ULPs during
70*7836SJohn.Forte@Sun.COM  * fc_ulp_port_attach() of each ULP.
71*7836SJohn.Forte@Sun.COM  *
72*7836SJohn.Forte@Sun.COM  * This  leaves  us with  another  possible  question;  How  are  packets
73*7836SJohn.Forte@Sun.COM  * allocated for ELS's started by the transport  itself ?  Well, the port
74*7836SJohn.Forte@Sun.COM  * driver  during  attach  time, cache  allocates  on a per port basis to
75*7836SJohn.Forte@Sun.COM  * handle ELSs too.
76*7836SJohn.Forte@Sun.COM  */
77*7836SJohn.Forte@Sun.COM 
78*7836SJohn.Forte@Sun.COM #include <sys/note.h>
79*7836SJohn.Forte@Sun.COM #include <sys/types.h>
80*7836SJohn.Forte@Sun.COM #include <sys/varargs.h>
81*7836SJohn.Forte@Sun.COM #include <sys/param.h>
82*7836SJohn.Forte@Sun.COM #include <sys/errno.h>
83*7836SJohn.Forte@Sun.COM #include <sys/uio.h>
84*7836SJohn.Forte@Sun.COM #include <sys/buf.h>
85*7836SJohn.Forte@Sun.COM #include <sys/modctl.h>
86*7836SJohn.Forte@Sun.COM #include <sys/open.h>
87*7836SJohn.Forte@Sun.COM #include <sys/kmem.h>
88*7836SJohn.Forte@Sun.COM #include <sys/poll.h>
89*7836SJohn.Forte@Sun.COM #include <sys/conf.h>
90*7836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
91*7836SJohn.Forte@Sun.COM #include <sys/stat.h>
92*7836SJohn.Forte@Sun.COM #include <sys/ddi.h>
93*7836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
94*7836SJohn.Forte@Sun.COM #include <sys/promif.h>
95*7836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
96*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fc.h>
97*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_ulpif.h>
98*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_fcaif.h>
99*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fctl_private.h>
100*7836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_portif.h>
101*7836SJohn.Forte@Sun.COM 
102*7836SJohn.Forte@Sun.COM /* These are referenced by fp.c!  */
103*7836SJohn.Forte@Sun.COM int did_table_size = D_ID_HASH_TABLE_SIZE;
104*7836SJohn.Forte@Sun.COM int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
105*7836SJohn.Forte@Sun.COM 
106*7836SJohn.Forte@Sun.COM static fc_ulp_module_t 	*fctl_ulp_modules;
107*7836SJohn.Forte@Sun.COM static fc_fca_port_t 	*fctl_fca_portlist;
108*7836SJohn.Forte@Sun.COM static fc_ulp_list_t	*fctl_ulp_list;
109*7836SJohn.Forte@Sun.COM 
110*7836SJohn.Forte@Sun.COM static char fctl_greeting[] =
111*7836SJohn.Forte@Sun.COM 	"fctl: %s ULP same type (0x%x) as existing module.\n";
112*7836SJohn.Forte@Sun.COM 
113*7836SJohn.Forte@Sun.COM static char *fctl_undefined = "Undefined";
114*7836SJohn.Forte@Sun.COM 
115*7836SJohn.Forte@Sun.COM /*
116*7836SJohn.Forte@Sun.COM  * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
117*7836SJohn.Forte@Sun.COM  */
118*7836SJohn.Forte@Sun.COM 
119*7836SJohn.Forte@Sun.COM static krwlock_t fctl_ulp_lock;
120*7836SJohn.Forte@Sun.COM 
121*7836SJohn.Forte@Sun.COM /*
122*7836SJohn.Forte@Sun.COM  * The fctl_mod_ports_lock protects the mod_ports element in the
123*7836SJohn.Forte@Sun.COM  * fc_ulp_ports_t structure
124*7836SJohn.Forte@Sun.COM  */
125*7836SJohn.Forte@Sun.COM 
126*7836SJohn.Forte@Sun.COM static krwlock_t fctl_mod_ports_lock;
127*7836SJohn.Forte@Sun.COM 
128*7836SJohn.Forte@Sun.COM /*
129*7836SJohn.Forte@Sun.COM  * fctl_port_lock protects the linked list of local port structures
130*7836SJohn.Forte@Sun.COM  * (fctl_fca_portlist).  When walking the list, this lock must be obtained
131*7836SJohn.Forte@Sun.COM  * prior to any local port locks.
132*7836SJohn.Forte@Sun.COM  */
133*7836SJohn.Forte@Sun.COM 
134*7836SJohn.Forte@Sun.COM static kmutex_t fctl_port_lock;
135*7836SJohn.Forte@Sun.COM static kmutex_t	fctl_ulp_list_mutex;
136*7836SJohn.Forte@Sun.COM 
137*7836SJohn.Forte@Sun.COM static fctl_nwwn_list_t		*fctl_nwwn_hash_table;
138*7836SJohn.Forte@Sun.COM static kmutex_t			fctl_nwwn_hash_mutex;
139*7836SJohn.Forte@Sun.COM int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
140*7836SJohn.Forte@Sun.COM 
141*7836SJohn.Forte@Sun.COM #if	!defined(lint)
142*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
143*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
144*7836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
145*7836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
146*7836SJohn.Forte@Sun.COM     ulp_ports::port_handle))
147*7836SJohn.Forte@Sun.COM _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
148*7836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
149*7836SJohn.Forte@Sun.COM     ulp_ports::port_dstate))
150*7836SJohn.Forte@Sun.COM #endif /* lint */
151*7836SJohn.Forte@Sun.COM 
152*7836SJohn.Forte@Sun.COM #define	FCTL_VERSION		"1.69"
153*7836SJohn.Forte@Sun.COM #define	FCTL_NAME_VERSION	"SunFC Transport v" FCTL_VERSION
154*7836SJohn.Forte@Sun.COM 
155*7836SJohn.Forte@Sun.COM 
156*7836SJohn.Forte@Sun.COM char *fctl_version = FCTL_NAME_VERSION;
157*7836SJohn.Forte@Sun.COM 
158*7836SJohn.Forte@Sun.COM extern struct mod_ops mod_miscops;
159*7836SJohn.Forte@Sun.COM 
160*7836SJohn.Forte@Sun.COM static struct modlmisc modlmisc = {
161*7836SJohn.Forte@Sun.COM 	&mod_miscops,			/* type of module */
162*7836SJohn.Forte@Sun.COM 	FCTL_NAME_VERSION		/* Module name */
163*7836SJohn.Forte@Sun.COM };
164*7836SJohn.Forte@Sun.COM 
165*7836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
166*7836SJohn.Forte@Sun.COM 	MODREV_1, (void *)&modlmisc, NULL
167*7836SJohn.Forte@Sun.COM };
168*7836SJohn.Forte@Sun.COM 
169*7836SJohn.Forte@Sun.COM static struct bus_ops fctl_fca_busops = {
170*7836SJohn.Forte@Sun.COM 	BUSO_REV,
171*7836SJohn.Forte@Sun.COM 	nullbusmap,			/* bus_map */
172*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_get_intrspec */
173*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_add_intrspec */
174*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_remove_intrspec */
175*7836SJohn.Forte@Sun.COM 	i_ddi_map_fault,		/* bus_map_fault */
176*7836SJohn.Forte@Sun.COM 	ddi_dma_map,			/* bus_dma_map */
177*7836SJohn.Forte@Sun.COM 	ddi_dma_allochdl,		/* bus_dma_allochdl */
178*7836SJohn.Forte@Sun.COM 	ddi_dma_freehdl,		/* bus_dma_freehdl */
179*7836SJohn.Forte@Sun.COM 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
180*7836SJohn.Forte@Sun.COM 	ddi_dma_unbindhdl,		/* bus_unbindhdl */
181*7836SJohn.Forte@Sun.COM 	ddi_dma_flush,			/* bus_dma_flush */
182*7836SJohn.Forte@Sun.COM 	ddi_dma_win,			/* bus_dma_win */
183*7836SJohn.Forte@Sun.COM 	ddi_dma_mctl,			/* bus_dma_ctl */
184*7836SJohn.Forte@Sun.COM 	fctl_fca_bus_ctl,		/* bus_ctl */
185*7836SJohn.Forte@Sun.COM 	ddi_bus_prop_op,		/* bus_prop_op */
186*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_get_eventcookie */
187*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_add_eventcall */
188*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_remove_event */
189*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_post_event */
190*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_intr_ctl */
191*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_config */
192*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_unconfig */
193*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_init */
194*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_fini */
195*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_access_enter */
196*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_access_exit */
197*7836SJohn.Forte@Sun.COM 	NULL,				/* bus_power */
198*7836SJohn.Forte@Sun.COM 	NULL
199*7836SJohn.Forte@Sun.COM };
200*7836SJohn.Forte@Sun.COM 
201*7836SJohn.Forte@Sun.COM struct kmem_cache *fctl_job_cache;
202*7836SJohn.Forte@Sun.COM 
203*7836SJohn.Forte@Sun.COM static fc_errmap_t fc_errlist [] = {
204*7836SJohn.Forte@Sun.COM 	{ FC_FAILURE, 		"Operation failed" 			},
205*7836SJohn.Forte@Sun.COM 	{ FC_SUCCESS, 		"Operation success" 			},
206*7836SJohn.Forte@Sun.COM 	{ FC_CAP_ERROR, 	"Capability error" 			},
207*7836SJohn.Forte@Sun.COM 	{ FC_CAP_FOUND, 	"Capability found" 			},
208*7836SJohn.Forte@Sun.COM 	{ FC_CAP_SETTABLE, 	"Capability settable" 			},
209*7836SJohn.Forte@Sun.COM 	{ FC_UNBOUND, 		"Port not bound" 			},
210*7836SJohn.Forte@Sun.COM 	{ FC_NOMEM, 		"No memory" 				},
211*7836SJohn.Forte@Sun.COM 	{ FC_BADPACKET, 	"Bad packet" 				},
212*7836SJohn.Forte@Sun.COM 	{ FC_OFFLINE, 		"Port offline" 				},
213*7836SJohn.Forte@Sun.COM 	{ FC_OLDPORT, 		"Old Port" 				},
214*7836SJohn.Forte@Sun.COM 	{ FC_NO_MAP, 		"No map available" 			},
215*7836SJohn.Forte@Sun.COM 	{ FC_TRANSPORT_ERROR, 	"Transport error" 			},
216*7836SJohn.Forte@Sun.COM 	{ FC_ELS_FREJECT, 	"ELS Frejected" 			},
217*7836SJohn.Forte@Sun.COM 	{ FC_ELS_PREJECT, 	"ELS PRejected" 			},
218*7836SJohn.Forte@Sun.COM 	{ FC_ELS_BAD, 		"Bad ELS request" 			},
219*7836SJohn.Forte@Sun.COM 	{ FC_ELS_MALFORMED, 	"Malformed ELS request" 		},
220*7836SJohn.Forte@Sun.COM 	{ FC_TOOMANY, 		"Too many commands" 			},
221*7836SJohn.Forte@Sun.COM 	{ FC_UB_BADTOKEN, 	"Bad Unsolicited buffer token" 		},
222*7836SJohn.Forte@Sun.COM 	{ FC_UB_ERROR, 		"Unsolicited buffer error" 		},
223*7836SJohn.Forte@Sun.COM 	{ FC_UB_BUSY, 		"Unsolicited buffer busy" 		},
224*7836SJohn.Forte@Sun.COM 	{ FC_BADULP, 		"Bad ULP" 				},
225*7836SJohn.Forte@Sun.COM 	{ FC_BADTYPE, 		"Bad Type" 				},
226*7836SJohn.Forte@Sun.COM 	{ FC_UNCLAIMED, 	"Not Claimed" 				},
227*7836SJohn.Forte@Sun.COM 	{ FC_ULP_SAMEMODULE, 	"Same ULP Module" 			},
228*7836SJohn.Forte@Sun.COM 	{ FC_ULP_SAMETYPE, 	"Same ULP Type" 			},
229*7836SJohn.Forte@Sun.COM 	{ FC_ABORTED, 		"Command Aborted" 			},
230*7836SJohn.Forte@Sun.COM 	{ FC_ABORT_FAILED, 	"Abort Failed" 				},
231*7836SJohn.Forte@Sun.COM 	{ FC_BADEXCHANGE, 	"Bad Exchange" 				},
232*7836SJohn.Forte@Sun.COM 	{ FC_BADWWN, 		"Bad World Wide Name" 			},
233*7836SJohn.Forte@Sun.COM 	{ FC_BADDEV, 		"Bad Device" 				},
234*7836SJohn.Forte@Sun.COM 	{ FC_BADCMD, 		"Bad Command" 				},
235*7836SJohn.Forte@Sun.COM 	{ FC_BADOBJECT, 	"Bad Object" 				},
236*7836SJohn.Forte@Sun.COM 	{ FC_BADPORT, 		"Bad Port" 				},
237*7836SJohn.Forte@Sun.COM 	{ FC_NOTTHISPORT, 	"Not on this Port" 			},
238*7836SJohn.Forte@Sun.COM 	{ FC_PREJECT, 		"Operation Prejected" 			},
239*7836SJohn.Forte@Sun.COM 	{ FC_FREJECT, 		"Operation Frejected" 			},
240*7836SJohn.Forte@Sun.COM 	{ FC_PBUSY, 		"Operation Pbusyed" 			},
241*7836SJohn.Forte@Sun.COM 	{ FC_FBUSY, 		"Operation Fbusyed" 			},
242*7836SJohn.Forte@Sun.COM 	{ FC_ALREADY, 		"Already done" 				},
243*7836SJohn.Forte@Sun.COM 	{ FC_LOGINREQ, 		"PLOGI Required" 			},
244*7836SJohn.Forte@Sun.COM 	{ FC_RESETFAIL, 	"Reset operation failed" 		},
245*7836SJohn.Forte@Sun.COM 	{ FC_INVALID_REQUEST, 	"Invalid Request" 			},
246*7836SJohn.Forte@Sun.COM 	{ FC_OUTOFBOUNDS, 	"Out of Bounds" 			},
247*7836SJohn.Forte@Sun.COM 	{ FC_TRAN_BUSY, 	"Command transport Busy" 		},
248*7836SJohn.Forte@Sun.COM 	{ FC_STATEC_BUSY, 	"State change Busy" 			},
249*7836SJohn.Forte@Sun.COM 	{ FC_DEVICE_BUSY,	"Port driver is working on this device"	}
250*7836SJohn.Forte@Sun.COM };
251*7836SJohn.Forte@Sun.COM 
252*7836SJohn.Forte@Sun.COM fc_pkt_reason_t remote_stop_reasons [] = {
253*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ABTS,	"Abort Sequence"	},
254*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ABTX,	"Abort Exchange"	},
255*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,	NULL			}
256*7836SJohn.Forte@Sun.COM };
257*7836SJohn.Forte@Sun.COM 
258*7836SJohn.Forte@Sun.COM fc_pkt_reason_t general_reasons [] = {
259*7836SJohn.Forte@Sun.COM 	{ FC_REASON_HW_ERROR,		"Hardware Error" 		},
260*7836SJohn.Forte@Sun.COM 	{ FC_REASON_SEQ_TIMEOUT,	"Sequence Timeout"		},
261*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORTED,		"Aborted"			},
262*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORT_FAILED,	"Abort Failed"			},
263*7836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_CONNECTION,	"No Connection"			},
264*7836SJohn.Forte@Sun.COM 	{ FC_REASON_XCHG_DROPPED,	"Exchange Dropped"		},
265*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_FRAME,	"Illegal Frame"			},
266*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_LENGTH,	"Illegal Length"		},
267*7836SJohn.Forte@Sun.COM 	{ FC_REASON_UNSUPPORTED,	"Unsuported"			},
268*7836SJohn.Forte@Sun.COM 	{ FC_REASON_RX_BUF_TIMEOUT,	"Receive Buffer Timeout"	},
269*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FCAL_OPN_FAIL,	"FC AL Open Failed"		},
270*7836SJohn.Forte@Sun.COM 	{ FC_REASON_OVERRUN,		"Over run"			},
271*7836SJohn.Forte@Sun.COM 	{ FC_REASON_QFULL,		"Queue Full"			},
272*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_REQ,	"Illegal Request",		},
273*7836SJohn.Forte@Sun.COM 	{ FC_REASON_PKT_BUSY,		"Busy"				},
274*7836SJohn.Forte@Sun.COM 	{ FC_REASON_OFFLINE,		"Offline"			},
275*7836SJohn.Forte@Sun.COM 	{ FC_REASON_BAD_XID,		"Bad Exchange Id"		},
276*7836SJohn.Forte@Sun.COM 	{ FC_REASON_XCHG_BSY,		"Exchange Busy"			},
277*7836SJohn.Forte@Sun.COM 	{ FC_REASON_NOMEM,		"No Memory"			},
278*7836SJohn.Forte@Sun.COM 	{ FC_REASON_BAD_SID,		"Bad S_ID"			},
279*7836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_SEQ_INIT,	"No Sequence Initiative"	},
280*7836SJohn.Forte@Sun.COM 	{ FC_REASON_DIAG_BUSY,		"Diagnostic Busy"		},
281*7836SJohn.Forte@Sun.COM 	{ FC_REASON_DMA_ERROR,		"DMA Error"			},
282*7836SJohn.Forte@Sun.COM 	{ FC_REASON_CRC_ERROR,		"CRC Error"			},
283*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORT_TIMEOUT,	"Abort Timeout"			},
284*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FCA_UNIQUE,		"FCA Unique"			},
285*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
286*7836SJohn.Forte@Sun.COM };
287*7836SJohn.Forte@Sun.COM 
288*7836SJohn.Forte@Sun.COM fc_pkt_reason_t rjt_reasons [] = {
289*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_D_ID,	"Invalid D_ID"			},
290*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_S_ID,	"Invalid S_ID"			},
291*7836SJohn.Forte@Sun.COM 	{ FC_REASON_TEMP_UNAVAILABLE,	"Temporarily Unavailable"	},
292*7836SJohn.Forte@Sun.COM 	{ FC_REASON_PERM_UNAVAILABLE,	"Permamnently Unavailable"	},
293*7836SJohn.Forte@Sun.COM 	{ FC_REASON_CLASS_NOT_SUPP,	"Class Not Supported",		},
294*7836SJohn.Forte@Sun.COM 	{ FC_REASON_DELIMTER_USAGE_ERROR,
295*7836SJohn.Forte@Sun.COM 					"Delimeter Usage Error"		},
296*7836SJohn.Forte@Sun.COM 	{ FC_REASON_TYPE_NOT_SUPP,	"Type Not Supported"		},
297*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_LINK_CTRL,	"Invalid Link Control"		},
298*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_R_CTL,	"Invalid R_CTL"			},
299*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_F_CTL,	"Invalid F_CTL"			},
300*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_OX_ID,	"Invalid OX_ID"			},
301*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_RX_ID,	"Invalid RX_ID"			},
302*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_SEQ_ID,	"Invalid Sequence ID"		},
303*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_DF_CTL,	"Invalid DF_CTL"		},
304*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_SEQ_CNT,	"Invalid Sequence count"	},
305*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_PARAM,	"Invalid Parameter"		},
306*7836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCH_ERROR,		"Exchange Error"		},
307*7836SJohn.Forte@Sun.COM 	{ FC_REASON_PROTOCOL_ERROR,	"Protocol Error"		},
308*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INCORRECT_LENGTH,	"Incorrect Length"		},
309*7836SJohn.Forte@Sun.COM 	{ FC_REASON_UNEXPECTED_ACK,	"Unexpected Ack"		},
310*7836SJohn.Forte@Sun.COM 	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset" 	},
311*7836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGIN_REQUIRED,	"Login Required"		},
312*7836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCESSIVE_SEQS,	"Excessive Sequences"
313*7836SJohn.Forte@Sun.COM 					" Attempted"			},
314*7836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCH_UNABLE,	"Exchange incapable"		},
315*7836SJohn.Forte@Sun.COM 	{ FC_REASON_ESH_NOT_SUPP,	"Expiration Security Header "
316*7836SJohn.Forte@Sun.COM 					"Not Supported"			},
317*7836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_FABRIC_PATH,	"No Fabric Path"		},
318*7836SJohn.Forte@Sun.COM 	{ FC_REASON_VENDOR_UNIQUE,	"Vendor Unique"			},
319*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
320*7836SJohn.Forte@Sun.COM };
321*7836SJohn.Forte@Sun.COM 
322*7836SJohn.Forte@Sun.COM fc_pkt_reason_t n_port_busy_reasons [] = {
323*7836SJohn.Forte@Sun.COM 	{ FC_REASON_PHYSICAL_BUSY,		"Physical Busy"		},
324*7836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_RESOURCE_BSY,	"Resource Busy"		},
325*7836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_VENDOR_UNIQUE,	"Vendor Unique"		},
326*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,			NULL			}
327*7836SJohn.Forte@Sun.COM };
328*7836SJohn.Forte@Sun.COM 
329*7836SJohn.Forte@Sun.COM fc_pkt_reason_t f_busy_reasons [] = {
330*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FABRIC_BSY,		"Fabric Busy"			},
331*7836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_BSY,		"N_Port Busy"			},
332*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
333*7836SJohn.Forte@Sun.COM };
334*7836SJohn.Forte@Sun.COM 
335*7836SJohn.Forte@Sun.COM fc_pkt_reason_t ls_ba_rjt_reasons [] = {
336*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_LA_CODE,	"Invalid Link Application Code"	},
337*7836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGICAL_ERROR,	"Logical Error"			},
338*7836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGICAL_BSY,	"Logical Busy"			},
339*7836SJohn.Forte@Sun.COM 	{ FC_REASON_PROTOCOL_ERROR_RJT,	"Protocol Error Reject"		},
340*7836SJohn.Forte@Sun.COM 	{ FC_REASON_CMD_UNABLE,		"Unable to Perform Command"	},
341*7836SJohn.Forte@Sun.COM 	{ FC_REASON_CMD_UNSUPPORTED,	"Unsupported Command"		},
342*7836SJohn.Forte@Sun.COM 	{ FC_REASON_VU_RJT,		"Vendor Unique"			},
343*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
344*7836SJohn.Forte@Sun.COM };
345*7836SJohn.Forte@Sun.COM 
346*7836SJohn.Forte@Sun.COM fc_pkt_reason_t fs_rjt_reasons [] = {
347*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_CMD,	"Invalid Command"		},
348*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_VER,	"Invalid Version"		},
349*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_LOGICAL_ERR,	"Logical Error"			},
350*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_IUSIZE,	"Invalid IU Size"		},
351*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_LOGICAL_BUSY,	"Logical Busy"			},
352*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_PROTOCOL_ERR,	"Protocol Error"		},
353*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_CMD_UNABLE,	"Unable to Perform Command"	},
354*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_CMD_UNSUPPORTED,	"Unsupported Command"		},
355*7836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_VENDOR_UNIQUE,	"Vendor Unique"			},
356*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
357*7836SJohn.Forte@Sun.COM };
358*7836SJohn.Forte@Sun.COM 
359*7836SJohn.Forte@Sun.COM fc_pkt_action_t	n_port_busy_actions [] = {
360*7836SJohn.Forte@Sun.COM 	{ FC_ACTION_SEQ_TERM_RETRY,	"Retry terminated Sequence"	},
361*7836SJohn.Forte@Sun.COM 	{ FC_ACTION_SEQ_ACTIVE_RETRY,	"Retry Active Sequence"		},
362*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
363*7836SJohn.Forte@Sun.COM };
364*7836SJohn.Forte@Sun.COM 
365*7836SJohn.Forte@Sun.COM fc_pkt_action_t rjt_timeout_actions [] = {
366*7836SJohn.Forte@Sun.COM 	{ FC_ACTION_RETRYABLE,		"Retryable"			},
367*7836SJohn.Forte@Sun.COM 	{ FC_ACTION_NON_RETRYABLE,	"Non Retryable"			},
368*7836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
369*7836SJohn.Forte@Sun.COM };
370*7836SJohn.Forte@Sun.COM 
371*7836SJohn.Forte@Sun.COM fc_pkt_expln_t ba_rjt_explns [] = {
372*7836SJohn.Forte@Sun.COM 	{ FC_EXPLN_NONE,		"No Explanation"		},
373*7836SJohn.Forte@Sun.COM 	{ FC_EXPLN_INVALID_OX_RX_ID,	"Invalid X_ID"			},
374*7836SJohn.Forte@Sun.COM 	{ FC_EXPLN_SEQ_ABORTED,		"Sequence Aborted"		},
375*7836SJohn.Forte@Sun.COM 	{ FC_EXPLN_INVALID,		NULL				}
376*7836SJohn.Forte@Sun.COM };
377*7836SJohn.Forte@Sun.COM 
378*7836SJohn.Forte@Sun.COM fc_pkt_error_t fc_pkt_errlist[] = {
379*7836SJohn.Forte@Sun.COM 	{
380*7836SJohn.Forte@Sun.COM 		FC_PKT_SUCCESS,
381*7836SJohn.Forte@Sun.COM 		"Operation Success",
382*7836SJohn.Forte@Sun.COM 		NULL,
383*7836SJohn.Forte@Sun.COM 		NULL,
384*7836SJohn.Forte@Sun.COM 		NULL
385*7836SJohn.Forte@Sun.COM 	},
386*7836SJohn.Forte@Sun.COM 	{	FC_PKT_REMOTE_STOP,
387*7836SJohn.Forte@Sun.COM 		"Remote Stop",
388*7836SJohn.Forte@Sun.COM 		remote_stop_reasons,
389*7836SJohn.Forte@Sun.COM 		NULL,
390*7836SJohn.Forte@Sun.COM 		NULL
391*7836SJohn.Forte@Sun.COM 	},
392*7836SJohn.Forte@Sun.COM 	{
393*7836SJohn.Forte@Sun.COM 		FC_PKT_LOCAL_RJT,
394*7836SJohn.Forte@Sun.COM 		"Local Reject",
395*7836SJohn.Forte@Sun.COM 		general_reasons,
396*7836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
397*7836SJohn.Forte@Sun.COM 		NULL
398*7836SJohn.Forte@Sun.COM 	},
399*7836SJohn.Forte@Sun.COM 	{
400*7836SJohn.Forte@Sun.COM 		FC_PKT_NPORT_RJT,
401*7836SJohn.Forte@Sun.COM 		"N_Port Reject",
402*7836SJohn.Forte@Sun.COM 		rjt_reasons,
403*7836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
404*7836SJohn.Forte@Sun.COM 		NULL
405*7836SJohn.Forte@Sun.COM 	},
406*7836SJohn.Forte@Sun.COM 	{
407*7836SJohn.Forte@Sun.COM 		FC_PKT_FABRIC_RJT,
408*7836SJohn.Forte@Sun.COM 		"Fabric Reject",
409*7836SJohn.Forte@Sun.COM 		rjt_reasons,
410*7836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
411*7836SJohn.Forte@Sun.COM 		NULL
412*7836SJohn.Forte@Sun.COM 	},
413*7836SJohn.Forte@Sun.COM 	{
414*7836SJohn.Forte@Sun.COM 		FC_PKT_LOCAL_BSY,
415*7836SJohn.Forte@Sun.COM 		"Local Busy",
416*7836SJohn.Forte@Sun.COM 		general_reasons,
417*7836SJohn.Forte@Sun.COM 		NULL,
418*7836SJohn.Forte@Sun.COM 		NULL,
419*7836SJohn.Forte@Sun.COM 	},
420*7836SJohn.Forte@Sun.COM 	{
421*7836SJohn.Forte@Sun.COM 		FC_PKT_TRAN_BSY,
422*7836SJohn.Forte@Sun.COM 		"Transport Busy",
423*7836SJohn.Forte@Sun.COM 		general_reasons,
424*7836SJohn.Forte@Sun.COM 		NULL,
425*7836SJohn.Forte@Sun.COM 		NULL,
426*7836SJohn.Forte@Sun.COM 	},
427*7836SJohn.Forte@Sun.COM 	{
428*7836SJohn.Forte@Sun.COM 		FC_PKT_NPORT_BSY,
429*7836SJohn.Forte@Sun.COM 		"N_Port Busy",
430*7836SJohn.Forte@Sun.COM 		n_port_busy_reasons,
431*7836SJohn.Forte@Sun.COM 		n_port_busy_actions,
432*7836SJohn.Forte@Sun.COM 		NULL
433*7836SJohn.Forte@Sun.COM 	},
434*7836SJohn.Forte@Sun.COM 	{
435*7836SJohn.Forte@Sun.COM 		FC_PKT_FABRIC_BSY,
436*7836SJohn.Forte@Sun.COM 		"Fabric Busy",
437*7836SJohn.Forte@Sun.COM 		f_busy_reasons,
438*7836SJohn.Forte@Sun.COM 		NULL,
439*7836SJohn.Forte@Sun.COM 		NULL,
440*7836SJohn.Forte@Sun.COM 	},
441*7836SJohn.Forte@Sun.COM 	{
442*7836SJohn.Forte@Sun.COM 		FC_PKT_LS_RJT,
443*7836SJohn.Forte@Sun.COM 		"Link Service Reject",
444*7836SJohn.Forte@Sun.COM 		ls_ba_rjt_reasons,
445*7836SJohn.Forte@Sun.COM 		NULL,
446*7836SJohn.Forte@Sun.COM 		NULL,
447*7836SJohn.Forte@Sun.COM 	},
448*7836SJohn.Forte@Sun.COM 	{
449*7836SJohn.Forte@Sun.COM 		FC_PKT_BA_RJT,
450*7836SJohn.Forte@Sun.COM 		"Basic Reject",
451*7836SJohn.Forte@Sun.COM 		ls_ba_rjt_reasons,
452*7836SJohn.Forte@Sun.COM 		NULL,
453*7836SJohn.Forte@Sun.COM 		ba_rjt_explns,
454*7836SJohn.Forte@Sun.COM 	},
455*7836SJohn.Forte@Sun.COM 	{
456*7836SJohn.Forte@Sun.COM 		FC_PKT_TIMEOUT,
457*7836SJohn.Forte@Sun.COM 		"Timeout",
458*7836SJohn.Forte@Sun.COM 		general_reasons,
459*7836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
460*7836SJohn.Forte@Sun.COM 		NULL
461*7836SJohn.Forte@Sun.COM 	},
462*7836SJohn.Forte@Sun.COM 	{
463*7836SJohn.Forte@Sun.COM 		FC_PKT_FS_RJT,
464*7836SJohn.Forte@Sun.COM 		"Fabric Switch Reject",
465*7836SJohn.Forte@Sun.COM 		fs_rjt_reasons,
466*7836SJohn.Forte@Sun.COM 		NULL,
467*7836SJohn.Forte@Sun.COM 		NULL
468*7836SJohn.Forte@Sun.COM 	},
469*7836SJohn.Forte@Sun.COM 	{
470*7836SJohn.Forte@Sun.COM 		FC_PKT_TRAN_ERROR,
471*7836SJohn.Forte@Sun.COM 		"Packet Transport error",
472*7836SJohn.Forte@Sun.COM 		general_reasons,
473*7836SJohn.Forte@Sun.COM 		NULL,
474*7836SJohn.Forte@Sun.COM 		NULL
475*7836SJohn.Forte@Sun.COM 	},
476*7836SJohn.Forte@Sun.COM 	{
477*7836SJohn.Forte@Sun.COM 		FC_PKT_FAILURE,
478*7836SJohn.Forte@Sun.COM 		"Packet Failure",
479*7836SJohn.Forte@Sun.COM 		general_reasons,
480*7836SJohn.Forte@Sun.COM 		NULL,
481*7836SJohn.Forte@Sun.COM 		NULL
482*7836SJohn.Forte@Sun.COM 	},
483*7836SJohn.Forte@Sun.COM 	{
484*7836SJohn.Forte@Sun.COM 		FC_PKT_PORT_OFFLINE,
485*7836SJohn.Forte@Sun.COM 		"Port Offline",
486*7836SJohn.Forte@Sun.COM 		NULL,
487*7836SJohn.Forte@Sun.COM 		NULL,
488*7836SJohn.Forte@Sun.COM 		NULL
489*7836SJohn.Forte@Sun.COM 	},
490*7836SJohn.Forte@Sun.COM 	{
491*7836SJohn.Forte@Sun.COM 		FC_PKT_ELS_IN_PROGRESS,
492*7836SJohn.Forte@Sun.COM 		"ELS is in Progress",
493*7836SJohn.Forte@Sun.COM 		NULL,
494*7836SJohn.Forte@Sun.COM 		NULL,
495*7836SJohn.Forte@Sun.COM 		NULL
496*7836SJohn.Forte@Sun.COM 	}
497*7836SJohn.Forte@Sun.COM };
498*7836SJohn.Forte@Sun.COM 
499*7836SJohn.Forte@Sun.COM int
500*7836SJohn.Forte@Sun.COM _init()
501*7836SJohn.Forte@Sun.COM {
502*7836SJohn.Forte@Sun.COM 	int rval;
503*7836SJohn.Forte@Sun.COM 
504*7836SJohn.Forte@Sun.COM 	rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
505*7836SJohn.Forte@Sun.COM 	rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
506*7836SJohn.Forte@Sun.COM 	mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
507*7836SJohn.Forte@Sun.COM 	mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
508*7836SJohn.Forte@Sun.COM 
509*7836SJohn.Forte@Sun.COM 	fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
510*7836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size, KM_SLEEP);
511*7836SJohn.Forte@Sun.COM 
512*7836SJohn.Forte@Sun.COM 	fctl_ulp_modules = NULL;
513*7836SJohn.Forte@Sun.COM 	fctl_fca_portlist = NULL;
514*7836SJohn.Forte@Sun.COM 
515*7836SJohn.Forte@Sun.COM 	fctl_job_cache = kmem_cache_create("fctl_cache",
516*7836SJohn.Forte@Sun.COM 	    sizeof (job_request_t), 8, fctl_cache_constructor,
517*7836SJohn.Forte@Sun.COM 	    fctl_cache_destructor, NULL, NULL, NULL, 0);
518*7836SJohn.Forte@Sun.COM 
519*7836SJohn.Forte@Sun.COM 	if (fctl_job_cache == NULL) {
520*7836SJohn.Forte@Sun.COM 		kmem_free(fctl_nwwn_hash_table,
521*7836SJohn.Forte@Sun.COM 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
522*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_nwwn_hash_mutex);
523*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_port_lock);
524*7836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_ulp_lock);
525*7836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_mod_ports_lock);
526*7836SJohn.Forte@Sun.COM 		return (ENOMEM);
527*7836SJohn.Forte@Sun.COM 	}
528*7836SJohn.Forte@Sun.COM 
529*7836SJohn.Forte@Sun.COM 	if ((rval = mod_install(&modlinkage)) != 0) {
530*7836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fctl_job_cache);
531*7836SJohn.Forte@Sun.COM 		kmem_free(fctl_nwwn_hash_table,
532*7836SJohn.Forte@Sun.COM 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
533*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_nwwn_hash_mutex);
534*7836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_port_lock);
535*7836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_ulp_lock);
536*7836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_mod_ports_lock);
537*7836SJohn.Forte@Sun.COM 	}
538*7836SJohn.Forte@Sun.COM 
539*7836SJohn.Forte@Sun.COM 	return (rval);
540*7836SJohn.Forte@Sun.COM }
541*7836SJohn.Forte@Sun.COM 
542*7836SJohn.Forte@Sun.COM 
543*7836SJohn.Forte@Sun.COM /*
544*7836SJohn.Forte@Sun.COM  * The mod_uninstall code doesn't call _fini when
545*7836SJohn.Forte@Sun.COM  * there is living dependent module on fctl. So
546*7836SJohn.Forte@Sun.COM  * there is no need to be extra careful here ?
547*7836SJohn.Forte@Sun.COM  */
548*7836SJohn.Forte@Sun.COM int
549*7836SJohn.Forte@Sun.COM _fini()
550*7836SJohn.Forte@Sun.COM {
551*7836SJohn.Forte@Sun.COM 	int rval;
552*7836SJohn.Forte@Sun.COM 
553*7836SJohn.Forte@Sun.COM 	if ((rval = mod_remove(&modlinkage)) != 0) {
554*7836SJohn.Forte@Sun.COM 		return (rval);
555*7836SJohn.Forte@Sun.COM 	}
556*7836SJohn.Forte@Sun.COM 
557*7836SJohn.Forte@Sun.COM 	kmem_cache_destroy(fctl_job_cache);
558*7836SJohn.Forte@Sun.COM 	kmem_free(fctl_nwwn_hash_table,
559*7836SJohn.Forte@Sun.COM 	    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
560*7836SJohn.Forte@Sun.COM 	mutex_destroy(&fctl_nwwn_hash_mutex);
561*7836SJohn.Forte@Sun.COM 	mutex_destroy(&fctl_port_lock);
562*7836SJohn.Forte@Sun.COM 	rw_destroy(&fctl_ulp_lock);
563*7836SJohn.Forte@Sun.COM 	rw_destroy(&fctl_mod_ports_lock);
564*7836SJohn.Forte@Sun.COM 
565*7836SJohn.Forte@Sun.COM 	return (rval);
566*7836SJohn.Forte@Sun.COM }
567*7836SJohn.Forte@Sun.COM 
568*7836SJohn.Forte@Sun.COM 
569*7836SJohn.Forte@Sun.COM int
570*7836SJohn.Forte@Sun.COM _info(struct modinfo *modinfo_p)
571*7836SJohn.Forte@Sun.COM {
572*7836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfo_p));
573*7836SJohn.Forte@Sun.COM }
574*7836SJohn.Forte@Sun.COM 
575*7836SJohn.Forte@Sun.COM 
576*7836SJohn.Forte@Sun.COM /* ARGSUSED */
577*7836SJohn.Forte@Sun.COM static int
578*7836SJohn.Forte@Sun.COM fctl_cache_constructor(void *buf, void *cdarg, int kmflag)
579*7836SJohn.Forte@Sun.COM {
580*7836SJohn.Forte@Sun.COM 	job_request_t *job = (job_request_t *)buf;
581*7836SJohn.Forte@Sun.COM 
582*7836SJohn.Forte@Sun.COM 	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
583*7836SJohn.Forte@Sun.COM 	sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
584*7836SJohn.Forte@Sun.COM 	sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
585*7836SJohn.Forte@Sun.COM 
586*7836SJohn.Forte@Sun.COM 	return (0);
587*7836SJohn.Forte@Sun.COM }
588*7836SJohn.Forte@Sun.COM 
589*7836SJohn.Forte@Sun.COM 
590*7836SJohn.Forte@Sun.COM /* ARGSUSED */
591*7836SJohn.Forte@Sun.COM static void
592*7836SJohn.Forte@Sun.COM fctl_cache_destructor(void *buf, void *cdarg)
593*7836SJohn.Forte@Sun.COM {
594*7836SJohn.Forte@Sun.COM 	job_request_t *job = (job_request_t *)buf;
595*7836SJohn.Forte@Sun.COM 
596*7836SJohn.Forte@Sun.COM 	sema_destroy(&job->job_fctl_sema);
597*7836SJohn.Forte@Sun.COM 	sema_destroy(&job->job_port_sema);
598*7836SJohn.Forte@Sun.COM 	mutex_destroy(&job->job_mutex);
599*7836SJohn.Forte@Sun.COM }
600*7836SJohn.Forte@Sun.COM 
601*7836SJohn.Forte@Sun.COM 
602*7836SJohn.Forte@Sun.COM /*
603*7836SJohn.Forte@Sun.COM  * fc_ulp_add:
604*7836SJohn.Forte@Sun.COM  *		Add a ULP module
605*7836SJohn.Forte@Sun.COM  *
606*7836SJohn.Forte@Sun.COM  * Return Codes:
607*7836SJohn.Forte@Sun.COM  *		FC_ULP_SAMEMODULE
608*7836SJohn.Forte@Sun.COM  *		FC_SUCCESS
609*7836SJohn.Forte@Sun.COM  *		FC_FAILURE
610*7836SJohn.Forte@Sun.COM  *
611*7836SJohn.Forte@Sun.COM  *   fc_ulp_add  prints  a warning message if there is  already a
612*7836SJohn.Forte@Sun.COM  *   similar ULP type  attached and this is unlikely to change as
613*7836SJohn.Forte@Sun.COM  *   we trudge along.  Further, this  function  returns a failure
614*7836SJohn.Forte@Sun.COM  *   code if the same  module  attempts to add more than once for
615*7836SJohn.Forte@Sun.COM  *   the same FC-4 type.
616*7836SJohn.Forte@Sun.COM  */
617*7836SJohn.Forte@Sun.COM int
618*7836SJohn.Forte@Sun.COM fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
619*7836SJohn.Forte@Sun.COM {
620*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t *mod;
621*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t *prev;
622*7836SJohn.Forte@Sun.COM 	job_request_t 	*job;
623*7836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*new;
624*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 	*fca_port;
625*7836SJohn.Forte@Sun.COM 	int		ntry = 0;
626*7836SJohn.Forte@Sun.COM 
627*7836SJohn.Forte@Sun.COM 	ASSERT(ulp_info != NULL);
628*7836SJohn.Forte@Sun.COM 
629*7836SJohn.Forte@Sun.COM 	/*
630*7836SJohn.Forte@Sun.COM 	 * Make sure ulp_rev matches fctl version.
631*7836SJohn.Forte@Sun.COM 	 * Whenever non-private data structure or non-static interface changes,
632*7836SJohn.Forte@Sun.COM 	 * we should use an increased FCTL_ULP_MODREV_# number here and in all
633*7836SJohn.Forte@Sun.COM 	 * ulps to prevent version mismatch.
634*7836SJohn.Forte@Sun.COM 	 */
635*7836SJohn.Forte@Sun.COM 	if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
636*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
637*7836SJohn.Forte@Sun.COM 		    " ULP %s would not be loaded", ulp_info->ulp_name,
638*7836SJohn.Forte@Sun.COM 		    ulp_info->ulp_name);
639*7836SJohn.Forte@Sun.COM 		return (FC_BADULP);
640*7836SJohn.Forte@Sun.COM 	}
641*7836SJohn.Forte@Sun.COM 
642*7836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
643*7836SJohn.Forte@Sun.COM 	ASSERT(new != NULL);
644*7836SJohn.Forte@Sun.COM 
645*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
646*7836SJohn.Forte@Sun.COM 	new->ulp_info = ulp_info;
647*7836SJohn.Forte@Sun.COM 	if (fctl_ulp_list != NULL) {
648*7836SJohn.Forte@Sun.COM 		new->ulp_next = fctl_ulp_list;
649*7836SJohn.Forte@Sun.COM 	}
650*7836SJohn.Forte@Sun.COM 	fctl_ulp_list = new;
651*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
652*7836SJohn.Forte@Sun.COM 
653*7836SJohn.Forte@Sun.COM 	while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
654*7836SJohn.Forte@Sun.COM 		delay(drv_usectohz(1000000));
655*7836SJohn.Forte@Sun.COM 		if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
656*7836SJohn.Forte@Sun.COM 			fc_ulp_list_t   *list;
657*7836SJohn.Forte@Sun.COM 			fc_ulp_list_t   *last;
658*7836SJohn.Forte@Sun.COM 			mutex_enter(&fctl_ulp_list_mutex);
659*7836SJohn.Forte@Sun.COM 			for (last = NULL, list = fctl_ulp_list; list != NULL;
660*7836SJohn.Forte@Sun.COM 			    list = list->ulp_next) {
661*7836SJohn.Forte@Sun.COM 				if (list->ulp_info == ulp_info) {
662*7836SJohn.Forte@Sun.COM 					break;
663*7836SJohn.Forte@Sun.COM 				}
664*7836SJohn.Forte@Sun.COM 				last = list;
665*7836SJohn.Forte@Sun.COM 			}
666*7836SJohn.Forte@Sun.COM 
667*7836SJohn.Forte@Sun.COM 			if (list) {
668*7836SJohn.Forte@Sun.COM 				if (last) {
669*7836SJohn.Forte@Sun.COM 					last->ulp_next = list->ulp_next;
670*7836SJohn.Forte@Sun.COM 				} else {
671*7836SJohn.Forte@Sun.COM 					fctl_ulp_list = list->ulp_next;
672*7836SJohn.Forte@Sun.COM 				}
673*7836SJohn.Forte@Sun.COM 				kmem_free(list, sizeof (*list));
674*7836SJohn.Forte@Sun.COM 			}
675*7836SJohn.Forte@Sun.COM 			mutex_exit(&fctl_ulp_list_mutex);
676*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "fctl: ULP %s unable to load",
677*7836SJohn.Forte@Sun.COM 			    ulp_info->ulp_name);
678*7836SJohn.Forte@Sun.COM 			return (FC_FAILURE);
679*7836SJohn.Forte@Sun.COM 		}
680*7836SJohn.Forte@Sun.COM 	}
681*7836SJohn.Forte@Sun.COM 
682*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
683*7836SJohn.Forte@Sun.COM 		ASSERT(mod->mod_info != NULL);
684*7836SJohn.Forte@Sun.COM 
685*7836SJohn.Forte@Sun.COM 		if (ulp_info == mod->mod_info &&
686*7836SJohn.Forte@Sun.COM 		    ulp_info->ulp_type == mod->mod_info->ulp_type) {
687*7836SJohn.Forte@Sun.COM 			rw_exit(&fctl_ulp_lock);
688*7836SJohn.Forte@Sun.COM 			return (FC_ULP_SAMEMODULE);
689*7836SJohn.Forte@Sun.COM 		}
690*7836SJohn.Forte@Sun.COM 
691*7836SJohn.Forte@Sun.COM 		if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
692*7836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
693*7836SJohn.Forte@Sun.COM 			    ulp_info->ulp_type);
694*7836SJohn.Forte@Sun.COM 		}
695*7836SJohn.Forte@Sun.COM 		prev = mod;
696*7836SJohn.Forte@Sun.COM 	}
697*7836SJohn.Forte@Sun.COM 
698*7836SJohn.Forte@Sun.COM 	mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
699*7836SJohn.Forte@Sun.COM 	mod->mod_info = ulp_info;
700*7836SJohn.Forte@Sun.COM 	mod->mod_next = NULL;
701*7836SJohn.Forte@Sun.COM 
702*7836SJohn.Forte@Sun.COM 	if (prev) {
703*7836SJohn.Forte@Sun.COM 		prev->mod_next = mod;
704*7836SJohn.Forte@Sun.COM 	} else {
705*7836SJohn.Forte@Sun.COM 		fctl_ulp_modules = mod;
706*7836SJohn.Forte@Sun.COM 	}
707*7836SJohn.Forte@Sun.COM 
708*7836SJohn.Forte@Sun.COM 	/*
709*7836SJohn.Forte@Sun.COM 	 * Schedule a job to each port's job_handler
710*7836SJohn.Forte@Sun.COM 	 * thread to attach their ports with this ULP.
711*7836SJohn.Forte@Sun.COM 	 */
712*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
713*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
714*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
715*7836SJohn.Forte@Sun.COM 
716*7836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
717*7836SJohn.Forte@Sun.COM 		    NULL, NULL, KM_SLEEP);
718*7836SJohn.Forte@Sun.COM 
719*7836SJohn.Forte@Sun.COM 		fctl_enque_job(fca_port->port_handle, job);
720*7836SJohn.Forte@Sun.COM 	}
721*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
722*7836SJohn.Forte@Sun.COM 
723*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
724*7836SJohn.Forte@Sun.COM 
725*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
726*7836SJohn.Forte@Sun.COM }
727*7836SJohn.Forte@Sun.COM 
728*7836SJohn.Forte@Sun.COM 
729*7836SJohn.Forte@Sun.COM /*
730*7836SJohn.Forte@Sun.COM  * fc_ulp_remove
731*7836SJohn.Forte@Sun.COM  *	Remove a ULP module
732*7836SJohn.Forte@Sun.COM  *
733*7836SJohn.Forte@Sun.COM  * A misbehaving ULP may call this routine while I/Os are in progress.
734*7836SJohn.Forte@Sun.COM  * Currently there is no mechanism to detect it to fail such a request.
735*7836SJohn.Forte@Sun.COM  *
736*7836SJohn.Forte@Sun.COM  * Return Codes:
737*7836SJohn.Forte@Sun.COM  *		FC_SUCCESS
738*7836SJohn.Forte@Sun.COM  *		FC_FAILURE
739*7836SJohn.Forte@Sun.COM  */
740*7836SJohn.Forte@Sun.COM int
741*7836SJohn.Forte@Sun.COM fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
742*7836SJohn.Forte@Sun.COM {
743*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t *mod;
744*7836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*list;
745*7836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*last;
746*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t *prev;
747*7836SJohn.Forte@Sun.COM 
748*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
749*7836SJohn.Forte@Sun.COM 
750*7836SJohn.Forte@Sun.COM 	for (last = NULL, list = fctl_ulp_list; list != NULL;
751*7836SJohn.Forte@Sun.COM 	    list = list->ulp_next) {
752*7836SJohn.Forte@Sun.COM 		if (list->ulp_info == ulp_info) {
753*7836SJohn.Forte@Sun.COM 			break;
754*7836SJohn.Forte@Sun.COM 		}
755*7836SJohn.Forte@Sun.COM 		last = list;
756*7836SJohn.Forte@Sun.COM 	}
757*7836SJohn.Forte@Sun.COM 
758*7836SJohn.Forte@Sun.COM 	if (list) {
759*7836SJohn.Forte@Sun.COM 		if (last) {
760*7836SJohn.Forte@Sun.COM 			last->ulp_next = list->ulp_next;
761*7836SJohn.Forte@Sun.COM 		} else {
762*7836SJohn.Forte@Sun.COM 			fctl_ulp_list = list->ulp_next;
763*7836SJohn.Forte@Sun.COM 		}
764*7836SJohn.Forte@Sun.COM 		kmem_free(list, sizeof (*list));
765*7836SJohn.Forte@Sun.COM 	}
766*7836SJohn.Forte@Sun.COM 
767*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
768*7836SJohn.Forte@Sun.COM 
769*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_WRITER);
770*7836SJohn.Forte@Sun.COM 
771*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
772*7836SJohn.Forte@Sun.COM 	    mod = mod->mod_next) {
773*7836SJohn.Forte@Sun.COM 		if (mod->mod_info == ulp_info) {
774*7836SJohn.Forte@Sun.COM 			break;
775*7836SJohn.Forte@Sun.COM 		}
776*7836SJohn.Forte@Sun.COM 		prev = mod;
777*7836SJohn.Forte@Sun.COM 	}
778*7836SJohn.Forte@Sun.COM 
779*7836SJohn.Forte@Sun.COM 	if (mod) {
780*7836SJohn.Forte@Sun.COM 		fc_ulp_ports_t *next;
781*7836SJohn.Forte@Sun.COM 
782*7836SJohn.Forte@Sun.COM 		if (prev) {
783*7836SJohn.Forte@Sun.COM 			prev->mod_next = mod->mod_next;
784*7836SJohn.Forte@Sun.COM 		} else {
785*7836SJohn.Forte@Sun.COM 			fctl_ulp_modules = mod->mod_next;
786*7836SJohn.Forte@Sun.COM 		}
787*7836SJohn.Forte@Sun.COM 
788*7836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_WRITER);
789*7836SJohn.Forte@Sun.COM 
790*7836SJohn.Forte@Sun.COM 		while ((next = mod->mod_ports) != NULL) {
791*7836SJohn.Forte@Sun.COM 			mod->mod_ports = next->port_next;
792*7836SJohn.Forte@Sun.COM 			fctl_dealloc_ulp_port(next);
793*7836SJohn.Forte@Sun.COM 		}
794*7836SJohn.Forte@Sun.COM 
795*7836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
796*7836SJohn.Forte@Sun.COM 		rw_exit(&fctl_ulp_lock);
797*7836SJohn.Forte@Sun.COM 
798*7836SJohn.Forte@Sun.COM 		kmem_free(mod, sizeof (*mod));
799*7836SJohn.Forte@Sun.COM 
800*7836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
801*7836SJohn.Forte@Sun.COM 	}
802*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
803*7836SJohn.Forte@Sun.COM 
804*7836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
805*7836SJohn.Forte@Sun.COM }
806*7836SJohn.Forte@Sun.COM 
807*7836SJohn.Forte@Sun.COM 
808*7836SJohn.Forte@Sun.COM /*
809*7836SJohn.Forte@Sun.COM  * The callers typically cache allocate the packet, complete the
810*7836SJohn.Forte@Sun.COM  * DMA setup for pkt_cmd and pkt_resp fields of the packet and
811*7836SJohn.Forte@Sun.COM  * call this function to see if the FCA is interested in doing
812*7836SJohn.Forte@Sun.COM  * its own intialization. For example, socal may like to initialize
813*7836SJohn.Forte@Sun.COM  * the soc_hdr which is pointed to by the pkt_fca_private field
814*7836SJohn.Forte@Sun.COM  * and sitting right below fc_packet_t in memory.
815*7836SJohn.Forte@Sun.COM  *
816*7836SJohn.Forte@Sun.COM  * The caller is required to ensure that pkt_pd is populated with the
817*7836SJohn.Forte@Sun.COM  * handle that it was given when the transport notified it about the
818*7836SJohn.Forte@Sun.COM  * device this packet is associated with.  If there is no associated
819*7836SJohn.Forte@Sun.COM  * device, pkt_pd must be set to NULL.  A non-NULL pkt_pd will cause an
820*7836SJohn.Forte@Sun.COM  * increment of the reference count for said pd.  When the packet is freed,
821*7836SJohn.Forte@Sun.COM  * the reference count will be decremented.  This reference count, in
822*7836SJohn.Forte@Sun.COM  * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
823*7836SJohn.Forte@Sun.COM  * will not wink out of existence while there is a packet outstanding.
824*7836SJohn.Forte@Sun.COM  *
825*7836SJohn.Forte@Sun.COM  * This function and fca_init_pkt must not perform any operations that
826*7836SJohn.Forte@Sun.COM  * would result in a call back to the ULP, as the ULP may be required
827*7836SJohn.Forte@Sun.COM  * to hold a mutex across this call to ensure that the pd in question
828*7836SJohn.Forte@Sun.COM  * won't go away prior the call to fc_ulp_transport.
829*7836SJohn.Forte@Sun.COM  *
830*7836SJohn.Forte@Sun.COM  * ULPs are responsible for using the handles they are given during state
831*7836SJohn.Forte@Sun.COM  * change callback processing in a manner that ensures consistency.  That
832*7836SJohn.Forte@Sun.COM  * is, they must be aware that they could be processing a state change
833*7836SJohn.Forte@Sun.COM  * notification that tells them the device associated with a particular
834*7836SJohn.Forte@Sun.COM  * handle has gone away at the same time they are being asked to
835*7836SJohn.Forte@Sun.COM  * initialize a packet using that handle. ULPs must therefore ensure
836*7836SJohn.Forte@Sun.COM  * that their state change processing and packet initialization code
837*7836SJohn.Forte@Sun.COM  * paths are sufficiently synchronized to avoid the use of an
838*7836SJohn.Forte@Sun.COM  * invalidated handle in any fc_packet_t struct that is passed to the
839*7836SJohn.Forte@Sun.COM  * fc_ulp_init_packet() function.
840*7836SJohn.Forte@Sun.COM  */
841*7836SJohn.Forte@Sun.COM int
842*7836SJohn.Forte@Sun.COM fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
843*7836SJohn.Forte@Sun.COM {
844*7836SJohn.Forte@Sun.COM 	int rval;
845*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
846*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
847*7836SJohn.Forte@Sun.COM 
848*7836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
849*7836SJohn.Forte@Sun.COM 
850*7836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
851*7836SJohn.Forte@Sun.COM 
852*7836SJohn.Forte@Sun.COM 	/* Call the FCA driver's fca_init_pkt entry point function. */
853*7836SJohn.Forte@Sun.COM 	rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
854*7836SJohn.Forte@Sun.COM 
855*7836SJohn.Forte@Sun.COM 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
856*7836SJohn.Forte@Sun.COM 		/*
857*7836SJohn.Forte@Sun.COM 		 * A !NULL pd here must still be a valid
858*7836SJohn.Forte@Sun.COM 		 * reference to the fc_remote_port_t.
859*7836SJohn.Forte@Sun.COM 		 */
860*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
861*7836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_ref_count >= 0);
862*7836SJohn.Forte@Sun.COM 		pd->pd_ref_count++;
863*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
864*7836SJohn.Forte@Sun.COM 	}
865*7836SJohn.Forte@Sun.COM 
866*7836SJohn.Forte@Sun.COM 	return (rval);
867*7836SJohn.Forte@Sun.COM }
868*7836SJohn.Forte@Sun.COM 
869*7836SJohn.Forte@Sun.COM 
870*7836SJohn.Forte@Sun.COM /*
871*7836SJohn.Forte@Sun.COM  * This function is called before destroying the cache allocated
872*7836SJohn.Forte@Sun.COM  * fc_packet to free up (and uninitialize) any resource specially
873*7836SJohn.Forte@Sun.COM  * allocated by the FCA driver during tran_init_pkt().
874*7836SJohn.Forte@Sun.COM  *
875*7836SJohn.Forte@Sun.COM  * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
876*7836SJohn.Forte@Sun.COM  * the pd_ref_count reference count is decremented for the indicated
877*7836SJohn.Forte@Sun.COM  * fc_remote_port_t struct.
878*7836SJohn.Forte@Sun.COM  */
879*7836SJohn.Forte@Sun.COM int
880*7836SJohn.Forte@Sun.COM fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
881*7836SJohn.Forte@Sun.COM {
882*7836SJohn.Forte@Sun.COM 	int rval;
883*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
884*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
885*7836SJohn.Forte@Sun.COM 
886*7836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
887*7836SJohn.Forte@Sun.COM 
888*7836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
889*7836SJohn.Forte@Sun.COM 
890*7836SJohn.Forte@Sun.COM 	/* Call the FCA driver's fca_un_init_pkt entry point function */
891*7836SJohn.Forte@Sun.COM 	rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
892*7836SJohn.Forte@Sun.COM 
893*7836SJohn.Forte@Sun.COM 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
894*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
895*7836SJohn.Forte@Sun.COM 
896*7836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_ref_count > 0);
897*7836SJohn.Forte@Sun.COM 		pd->pd_ref_count--;
898*7836SJohn.Forte@Sun.COM 
899*7836SJohn.Forte@Sun.COM 		/*
900*7836SJohn.Forte@Sun.COM 		 * If at this point the state of this fc_remote_port_t
901*7836SJohn.Forte@Sun.COM 		 * struct is PORT_DEVICE_INVALID, it probably means somebody
902*7836SJohn.Forte@Sun.COM 		 * is cleaning up old (e.g. retried) packets. If the
903*7836SJohn.Forte@Sun.COM 		 * pd_ref_count has also dropped to zero, it's time to
904*7836SJohn.Forte@Sun.COM 		 * deallocate this fc_remote_port_t struct.
905*7836SJohn.Forte@Sun.COM 		 */
906*7836SJohn.Forte@Sun.COM 		if (pd->pd_state == PORT_DEVICE_INVALID &&
907*7836SJohn.Forte@Sun.COM 		    pd->pd_ref_count == 0) {
908*7836SJohn.Forte@Sun.COM 			fc_remote_node_t *node = pd->pd_remote_nodep;
909*7836SJohn.Forte@Sun.COM 
910*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
911*7836SJohn.Forte@Sun.COM 
912*7836SJohn.Forte@Sun.COM 			/*
913*7836SJohn.Forte@Sun.COM 			 * Also deallocate the associated fc_remote_node_t
914*7836SJohn.Forte@Sun.COM 			 * struct if it has no other associated
915*7836SJohn.Forte@Sun.COM 			 * fc_remote_port_t structs.
916*7836SJohn.Forte@Sun.COM 			 */
917*7836SJohn.Forte@Sun.COM 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
918*7836SJohn.Forte@Sun.COM 			    (node != NULL)) {
919*7836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
920*7836SJohn.Forte@Sun.COM 			}
921*7836SJohn.Forte@Sun.COM 			return (rval);
922*7836SJohn.Forte@Sun.COM 		}
923*7836SJohn.Forte@Sun.COM 
924*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
925*7836SJohn.Forte@Sun.COM 	}
926*7836SJohn.Forte@Sun.COM 
927*7836SJohn.Forte@Sun.COM 	return (rval);
928*7836SJohn.Forte@Sun.COM }
929*7836SJohn.Forte@Sun.COM 
930*7836SJohn.Forte@Sun.COM 
931*7836SJohn.Forte@Sun.COM int
932*7836SJohn.Forte@Sun.COM fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
933*7836SJohn.Forte@Sun.COM     int flag)
934*7836SJohn.Forte@Sun.COM {
935*7836SJohn.Forte@Sun.COM 	int		job_code;
936*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
937*7836SJohn.Forte@Sun.COM 	job_request_t	*job;
938*7836SJohn.Forte@Sun.COM 	fc_portmap_t	*tmp_map;
939*7836SJohn.Forte@Sun.COM 	uint32_t	tmp_len;
940*7836SJohn.Forte@Sun.COM 	fc_portmap_t	*change_list = NULL;
941*7836SJohn.Forte@Sun.COM 	uint32_t	listlen = 0;
942*7836SJohn.Forte@Sun.COM 
943*7836SJohn.Forte@Sun.COM 	port = port_handle;
944*7836SJohn.Forte@Sun.COM 
945*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
946*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
947*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
948*7836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
949*7836SJohn.Forte@Sun.COM 	}
950*7836SJohn.Forte@Sun.COM 
951*7836SJohn.Forte@Sun.COM 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
952*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
953*7836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
954*7836SJohn.Forte@Sun.COM 	}
955*7836SJohn.Forte@Sun.COM 
956*7836SJohn.Forte@Sun.COM 	if (port->fp_dev_count && (port->fp_dev_count ==
957*7836SJohn.Forte@Sun.COM 	    port->fp_total_devices)) {
958*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
959*7836SJohn.Forte@Sun.COM 		fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
960*7836SJohn.Forte@Sun.COM 		if (listlen > *len) {
961*7836SJohn.Forte@Sun.COM 			tmp_map = (fc_portmap_t *)kmem_zalloc(
962*7836SJohn.Forte@Sun.COM 			    listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
963*7836SJohn.Forte@Sun.COM 			if (tmp_map == NULL) {
964*7836SJohn.Forte@Sun.COM 				return (FC_NOMEM);
965*7836SJohn.Forte@Sun.COM 			}
966*7836SJohn.Forte@Sun.COM 			if (*map) {
967*7836SJohn.Forte@Sun.COM 				kmem_free(*map, (*len) * sizeof (fc_portmap_t));
968*7836SJohn.Forte@Sun.COM 			}
969*7836SJohn.Forte@Sun.COM 			*map = tmp_map;
970*7836SJohn.Forte@Sun.COM 		}
971*7836SJohn.Forte@Sun.COM 		if (change_list) {
972*7836SJohn.Forte@Sun.COM 			bcopy(change_list, *map,
973*7836SJohn.Forte@Sun.COM 			    listlen * sizeof (fc_portmap_t));
974*7836SJohn.Forte@Sun.COM 			kmem_free(change_list, listlen * sizeof (fc_portmap_t));
975*7836SJohn.Forte@Sun.COM 		}
976*7836SJohn.Forte@Sun.COM 		*len = listlen;
977*7836SJohn.Forte@Sun.COM 	} else {
978*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
979*7836SJohn.Forte@Sun.COM 
980*7836SJohn.Forte@Sun.COM 		switch (flag) {
981*7836SJohn.Forte@Sun.COM 		case FC_ULP_PLOGI_DONTCARE:
982*7836SJohn.Forte@Sun.COM 			job_code = JOB_PORT_GETMAP;
983*7836SJohn.Forte@Sun.COM 			break;
984*7836SJohn.Forte@Sun.COM 
985*7836SJohn.Forte@Sun.COM 		case FC_ULP_PLOGI_PRESERVE:
986*7836SJohn.Forte@Sun.COM 			job_code = JOB_PORT_GETMAP_PLOGI_ALL;
987*7836SJohn.Forte@Sun.COM 			break;
988*7836SJohn.Forte@Sun.COM 
989*7836SJohn.Forte@Sun.COM 		default:
990*7836SJohn.Forte@Sun.COM 			return (FC_INVALID_REQUEST);
991*7836SJohn.Forte@Sun.COM 		}
992*7836SJohn.Forte@Sun.COM 		/*
993*7836SJohn.Forte@Sun.COM 		 * Submit a job request to the job handler
994*7836SJohn.Forte@Sun.COM 		 * thread to get the map and wait
995*7836SJohn.Forte@Sun.COM 		 */
996*7836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
997*7836SJohn.Forte@Sun.COM 		job->job_private = (opaque_t)map;
998*7836SJohn.Forte@Sun.COM 		job->job_arg = (opaque_t)len;
999*7836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
1000*7836SJohn.Forte@Sun.COM 
1001*7836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
1002*7836SJohn.Forte@Sun.COM 		/*
1003*7836SJohn.Forte@Sun.COM 		 * The result of the last I/O operation is
1004*7836SJohn.Forte@Sun.COM 		 * in job_code. We don't care to look at it
1005*7836SJohn.Forte@Sun.COM 		 * Rather we look at the number of devices
1006*7836SJohn.Forte@Sun.COM 		 * that are found to fill out the map for
1007*7836SJohn.Forte@Sun.COM 		 * ULPs.
1008*7836SJohn.Forte@Sun.COM 		 */
1009*7836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
1010*7836SJohn.Forte@Sun.COM 	}
1011*7836SJohn.Forte@Sun.COM 
1012*7836SJohn.Forte@Sun.COM 	/*
1013*7836SJohn.Forte@Sun.COM 	 * If we're here, we're returning a map to the caller, which means
1014*7836SJohn.Forte@Sun.COM 	 * we'd better make sure every pd in that map has the
1015*7836SJohn.Forte@Sun.COM 	 * PD_GIVEN_TO_ULPS flag set.
1016*7836SJohn.Forte@Sun.COM 	 */
1017*7836SJohn.Forte@Sun.COM 
1018*7836SJohn.Forte@Sun.COM 	tmp_len = *len;
1019*7836SJohn.Forte@Sun.COM 	tmp_map = *map;
1020*7836SJohn.Forte@Sun.COM 
1021*7836SJohn.Forte@Sun.COM 	while (tmp_len-- != 0) {
1022*7836SJohn.Forte@Sun.COM 		if (tmp_map->map_state != PORT_DEVICE_INVALID) {
1023*7836SJohn.Forte@Sun.COM 			fc_remote_port_t *pd =
1024*7836SJohn.Forte@Sun.COM 			    (fc_remote_port_t *)tmp_map->map_pd;
1025*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
1026*7836SJohn.Forte@Sun.COM 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1027*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
1028*7836SJohn.Forte@Sun.COM 		}
1029*7836SJohn.Forte@Sun.COM 		tmp_map++;
1030*7836SJohn.Forte@Sun.COM 	}
1031*7836SJohn.Forte@Sun.COM 
1032*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
1033*7836SJohn.Forte@Sun.COM }
1034*7836SJohn.Forte@Sun.COM 
1035*7836SJohn.Forte@Sun.COM 
1036*7836SJohn.Forte@Sun.COM int
1037*7836SJohn.Forte@Sun.COM fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
1038*7836SJohn.Forte@Sun.COM {
1039*7836SJohn.Forte@Sun.COM 	int			rval = FC_SUCCESS;
1040*7836SJohn.Forte@Sun.COM 	int 			job_flags;
1041*7836SJohn.Forte@Sun.COM 	uint32_t		count;
1042*7836SJohn.Forte@Sun.COM 	fc_packet_t		**tmp_array;
1043*7836SJohn.Forte@Sun.COM 	job_request_t 		*job;
1044*7836SJohn.Forte@Sun.COM 	fc_local_port_t 	*port = port_handle;
1045*7836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
1046*7836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
1047*7836SJohn.Forte@Sun.COM 
1048*7836SJohn.Forte@Sun.COM 	/*
1049*7836SJohn.Forte@Sun.COM 	 * If the port is OFFLINE, or if the port driver is
1050*7836SJohn.Forte@Sun.COM 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1051*7836SJohn.Forte@Sun.COM 	 * PLOGI operations
1052*7836SJohn.Forte@Sun.COM 	 */
1053*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1054*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
1055*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1056*7836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
1057*7836SJohn.Forte@Sun.COM 	}
1058*7836SJohn.Forte@Sun.COM 
1059*7836SJohn.Forte@Sun.COM 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1060*7836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
1061*7836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1062*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1063*7836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
1064*7836SJohn.Forte@Sun.COM 	}
1065*7836SJohn.Forte@Sun.COM 
1066*7836SJohn.Forte@Sun.COM 	/*
1067*7836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
1068*7836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1069*7836SJohn.Forte@Sun.COM 	 */
1070*7836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
1071*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1072*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1073*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1074*7836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
1075*7836SJohn.Forte@Sun.COM 	}
1076*7836SJohn.Forte@Sun.COM 
1077*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
1078*7836SJohn.Forte@Sun.COM 
1079*7836SJohn.Forte@Sun.COM 	tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
1080*7836SJohn.Forte@Sun.COM 	for (count = 0; count < listlen; count++) {
1081*7836SJohn.Forte@Sun.COM 		tmp_array[count] = ulp_pkt[count];
1082*7836SJohn.Forte@Sun.COM 	}
1083*7836SJohn.Forte@Sun.COM 
1084*7836SJohn.Forte@Sun.COM 	job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
1085*7836SJohn.Forte@Sun.COM 	    ? 0 : JOB_TYPE_FCTL_ASYNC;
1086*7836SJohn.Forte@Sun.COM 
1087*7836SJohn.Forte@Sun.COM #ifdef	DEBUG
1088*7836SJohn.Forte@Sun.COM 	{
1089*7836SJohn.Forte@Sun.COM 		int next;
1090*7836SJohn.Forte@Sun.COM 		int count;
1091*7836SJohn.Forte@Sun.COM 		int polled;
1092*7836SJohn.Forte@Sun.COM 
1093*7836SJohn.Forte@Sun.COM 		polled = ((ulp_pkt[0]->pkt_tran_flags) &
1094*7836SJohn.Forte@Sun.COM 		    FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1095*7836SJohn.Forte@Sun.COM 
1096*7836SJohn.Forte@Sun.COM 		for (count = 0; count < listlen; count++) {
1097*7836SJohn.Forte@Sun.COM 			next = ((ulp_pkt[count]->pkt_tran_flags)
1098*7836SJohn.Forte@Sun.COM 			    & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1099*7836SJohn.Forte@Sun.COM 			ASSERT(next == polled);
1100*7836SJohn.Forte@Sun.COM 		}
1101*7836SJohn.Forte@Sun.COM 	}
1102*7836SJohn.Forte@Sun.COM #endif
1103*7836SJohn.Forte@Sun.COM 
1104*7836SJohn.Forte@Sun.COM 	job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
1105*7836SJohn.Forte@Sun.COM 	job->job_ulp_pkts = tmp_array;
1106*7836SJohn.Forte@Sun.COM 	job->job_ulp_listlen = listlen;
1107*7836SJohn.Forte@Sun.COM 
1108*7836SJohn.Forte@Sun.COM 	while (listlen--) {
1109*7836SJohn.Forte@Sun.COM 		fc_packet_t *pkt;
1110*7836SJohn.Forte@Sun.COM 
1111*7836SJohn.Forte@Sun.COM 		pkt = tmp_array[listlen];
1112*7836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd == NULL) {
1113*7836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_SUCCESS;
1114*7836SJohn.Forte@Sun.COM 			continue;
1115*7836SJohn.Forte@Sun.COM 		}
1116*7836SJohn.Forte@Sun.COM 
1117*7836SJohn.Forte@Sun.COM 		mutex_enter(&pkt->pkt_pd->pd_mutex);
1118*7836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
1119*7836SJohn.Forte@Sun.COM 		    pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
1120*7836SJohn.Forte@Sun.COM 			/*
1121*7836SJohn.Forte@Sun.COM 			 * Set the packet state and let the port
1122*7836SJohn.Forte@Sun.COM 			 * driver call the completion routine
1123*7836SJohn.Forte@Sun.COM 			 * from its thread
1124*7836SJohn.Forte@Sun.COM 			 */
1125*7836SJohn.Forte@Sun.COM 			mutex_exit(&pkt->pkt_pd->pd_mutex);
1126*7836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
1127*7836SJohn.Forte@Sun.COM 			continue;
1128*7836SJohn.Forte@Sun.COM 		}
1129*7836SJohn.Forte@Sun.COM 
1130*7836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
1131*7836SJohn.Forte@Sun.COM 		    pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
1132*7836SJohn.Forte@Sun.COM 			mutex_exit(&pkt->pkt_pd->pd_mutex);
1133*7836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_LOCAL_RJT;
1134*7836SJohn.Forte@Sun.COM 			continue;
1135*7836SJohn.Forte@Sun.COM 		}
1136*7836SJohn.Forte@Sun.COM 		mutex_exit(&pkt->pkt_pd->pd_mutex);
1137*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_SUCCESS;
1138*7836SJohn.Forte@Sun.COM 	}
1139*7836SJohn.Forte@Sun.COM 
1140*7836SJohn.Forte@Sun.COM 	fctl_enque_job(port, job);
1141*7836SJohn.Forte@Sun.COM 
1142*7836SJohn.Forte@Sun.COM 	if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
1143*7836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
1144*7836SJohn.Forte@Sun.COM 		rval = job->job_result;
1145*7836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
1146*7836SJohn.Forte@Sun.COM 	}
1147*7836SJohn.Forte@Sun.COM 
1148*7836SJohn.Forte@Sun.COM 	return (rval);
1149*7836SJohn.Forte@Sun.COM }
1150*7836SJohn.Forte@Sun.COM 
1151*7836SJohn.Forte@Sun.COM 
1152*7836SJohn.Forte@Sun.COM opaque_t
1153*7836SJohn.Forte@Sun.COM fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
1154*7836SJohn.Forte@Sun.COM     int create)
1155*7836SJohn.Forte@Sun.COM {
1156*7836SJohn.Forte@Sun.COM 	fc_local_port_t 	*port;
1157*7836SJohn.Forte@Sun.COM 	job_request_t		*job;
1158*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
1159*7836SJohn.Forte@Sun.COM 
1160*7836SJohn.Forte@Sun.COM 	port = port_handle;
1161*7836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1162*7836SJohn.Forte@Sun.COM 
1163*7836SJohn.Forte@Sun.COM 	if (pd != NULL) {
1164*7836SJohn.Forte@Sun.COM 		*error = FC_SUCCESS;
1165*7836SJohn.Forte@Sun.COM 		/*
1166*7836SJohn.Forte@Sun.COM 		 * A ULP now knows about this pd, so mark it
1167*7836SJohn.Forte@Sun.COM 		 */
1168*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
1169*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1170*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
1171*7836SJohn.Forte@Sun.COM 		return (pd);
1172*7836SJohn.Forte@Sun.COM 	}
1173*7836SJohn.Forte@Sun.COM 
1174*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1175*7836SJohn.Forte@Sun.COM 	if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
1176*7836SJohn.Forte@Sun.COM 		uint32_t	d_id;
1177*7836SJohn.Forte@Sun.COM 		fctl_ns_req_t 	*ns_cmd;
1178*7836SJohn.Forte@Sun.COM 
1179*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1180*7836SJohn.Forte@Sun.COM 
1181*7836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1182*7836SJohn.Forte@Sun.COM 
1183*7836SJohn.Forte@Sun.COM 		if (job == NULL) {
1184*7836SJohn.Forte@Sun.COM 			*error = FC_NOMEM;
1185*7836SJohn.Forte@Sun.COM 			return (pd);
1186*7836SJohn.Forte@Sun.COM 		}
1187*7836SJohn.Forte@Sun.COM 
1188*7836SJohn.Forte@Sun.COM 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
1189*7836SJohn.Forte@Sun.COM 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
1190*7836SJohn.Forte@Sun.COM 		    0, KM_SLEEP);
1191*7836SJohn.Forte@Sun.COM 
1192*7836SJohn.Forte@Sun.COM 		if (ns_cmd == NULL) {
1193*7836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
1194*7836SJohn.Forte@Sun.COM 			*error = FC_NOMEM;
1195*7836SJohn.Forte@Sun.COM 			return (pd);
1196*7836SJohn.Forte@Sun.COM 		}
1197*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_code = NS_GID_PN;
1198*7836SJohn.Forte@Sun.COM 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
1199*7836SJohn.Forte@Sun.COM 
1200*7836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
1201*7836SJohn.Forte@Sun.COM 		job->job_private = (void *)ns_cmd;
1202*7836SJohn.Forte@Sun.COM 		job->job_counter = 1;
1203*7836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
1204*7836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
1205*7836SJohn.Forte@Sun.COM 
1206*7836SJohn.Forte@Sun.COM 		if (job->job_result != FC_SUCCESS) {
1207*7836SJohn.Forte@Sun.COM 			*error = job->job_result;
1208*7836SJohn.Forte@Sun.COM 			fctl_free_ns_cmd(ns_cmd);
1209*7836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
1210*7836SJohn.Forte@Sun.COM 			return (pd);
1211*7836SJohn.Forte@Sun.COM 		}
1212*7836SJohn.Forte@Sun.COM 		d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
1213*7836SJohn.Forte@Sun.COM 		fctl_free_ns_cmd(ns_cmd);
1214*7836SJohn.Forte@Sun.COM 
1215*7836SJohn.Forte@Sun.COM 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
1216*7836SJohn.Forte@Sun.COM 		    sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
1217*7836SJohn.Forte@Sun.COM 		    KM_SLEEP);
1218*7836SJohn.Forte@Sun.COM 		ASSERT(ns_cmd != NULL);
1219*7836SJohn.Forte@Sun.COM 
1220*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_gan_max = 1;
1221*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_code = NS_GA_NXT;
1222*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
1223*7836SJohn.Forte@Sun.COM 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
1224*7836SJohn.Forte@Sun.COM 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
1225*7836SJohn.Forte@Sun.COM 
1226*7836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
1227*7836SJohn.Forte@Sun.COM 		job->job_private = (void *)ns_cmd;
1228*7836SJohn.Forte@Sun.COM 		job->job_counter = 1;
1229*7836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
1230*7836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
1231*7836SJohn.Forte@Sun.COM 
1232*7836SJohn.Forte@Sun.COM 		fctl_free_ns_cmd(ns_cmd);
1233*7836SJohn.Forte@Sun.COM 		if (job->job_result != FC_SUCCESS) {
1234*7836SJohn.Forte@Sun.COM 			*error = job->job_result;
1235*7836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
1236*7836SJohn.Forte@Sun.COM 			return (pd);
1237*7836SJohn.Forte@Sun.COM 		}
1238*7836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
1239*7836SJohn.Forte@Sun.COM 
1240*7836SJohn.Forte@Sun.COM 		/*
1241*7836SJohn.Forte@Sun.COM 		 * Check if the port device is created now.
1242*7836SJohn.Forte@Sun.COM 		 */
1243*7836SJohn.Forte@Sun.COM 		pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1244*7836SJohn.Forte@Sun.COM 
1245*7836SJohn.Forte@Sun.COM 		if (pd == NULL) {
1246*7836SJohn.Forte@Sun.COM 			*error = FC_FAILURE;
1247*7836SJohn.Forte@Sun.COM 		} else {
1248*7836SJohn.Forte@Sun.COM 			*error = FC_SUCCESS;
1249*7836SJohn.Forte@Sun.COM 
1250*7836SJohn.Forte@Sun.COM 			/*
1251*7836SJohn.Forte@Sun.COM 			 * A ULP now knows about this pd, so mark it
1252*7836SJohn.Forte@Sun.COM 			 */
1253*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
1254*7836SJohn.Forte@Sun.COM 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1255*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
1256*7836SJohn.Forte@Sun.COM 		}
1257*7836SJohn.Forte@Sun.COM 	} else {
1258*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1259*7836SJohn.Forte@Sun.COM 		*error = FC_FAILURE;
1260*7836SJohn.Forte@Sun.COM 	}
1261*7836SJohn.Forte@Sun.COM 
1262*7836SJohn.Forte@Sun.COM 	return (pd);
1263*7836SJohn.Forte@Sun.COM }
1264*7836SJohn.Forte@Sun.COM 
1265*7836SJohn.Forte@Sun.COM 
1266*7836SJohn.Forte@Sun.COM /*
1267*7836SJohn.Forte@Sun.COM  * If a NS object exists in the host and query is performed
1268*7836SJohn.Forte@Sun.COM  * on that object, we should retrieve it from our basket
1269*7836SJohn.Forte@Sun.COM  * and return it right here, there by saving a request going
1270*7836SJohn.Forte@Sun.COM  * all the up to the Name Server.
1271*7836SJohn.Forte@Sun.COM  */
1272*7836SJohn.Forte@Sun.COM int
1273*7836SJohn.Forte@Sun.COM fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
1274*7836SJohn.Forte@Sun.COM {
1275*7836SJohn.Forte@Sun.COM 	int 		rval;
1276*7836SJohn.Forte@Sun.COM 	int		fabric;
1277*7836SJohn.Forte@Sun.COM 	job_request_t	*job;
1278*7836SJohn.Forte@Sun.COM 	fctl_ns_req_t	*ns_cmd;
1279*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
1280*7836SJohn.Forte@Sun.COM 
1281*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1282*7836SJohn.Forte@Sun.COM 	fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
1283*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
1284*7836SJohn.Forte@Sun.COM 
1285*7836SJohn.Forte@Sun.COM 	/*
1286*7836SJohn.Forte@Sun.COM 	 * Name server query can't be performed for devices not in Fabric
1287*7836SJohn.Forte@Sun.COM 	 */
1288*7836SJohn.Forte@Sun.COM 	if (!fabric && pd) {
1289*7836SJohn.Forte@Sun.COM 		return (FC_BADOBJECT);
1290*7836SJohn.Forte@Sun.COM 	}
1291*7836SJohn.Forte@Sun.COM 
1292*7836SJohn.Forte@Sun.COM 	if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
1293*7836SJohn.Forte@Sun.COM 		if (pd == NULL) {
1294*7836SJohn.Forte@Sun.COM 			rval = fctl_update_host_ns_values(port, ns_req);
1295*7836SJohn.Forte@Sun.COM 			if (rval != FC_SUCCESS) {
1296*7836SJohn.Forte@Sun.COM 				return (rval);
1297*7836SJohn.Forte@Sun.COM 			}
1298*7836SJohn.Forte@Sun.COM 		} else {
1299*7836SJohn.Forte@Sun.COM 			/*
1300*7836SJohn.Forte@Sun.COM 			 * Guess what, FC-GS-2 currently prohibits (not
1301*7836SJohn.Forte@Sun.COM 			 * in the strongest language though) setting of
1302*7836SJohn.Forte@Sun.COM 			 * NS object values by other ports. But we might
1303*7836SJohn.Forte@Sun.COM 			 * get that changed to at least accommodate setting
1304*7836SJohn.Forte@Sun.COM 			 * symbolic node/port names - But if disks/tapes
1305*7836SJohn.Forte@Sun.COM 			 * were going to provide a method to set these
1306*7836SJohn.Forte@Sun.COM 			 * values directly (which in turn might register
1307*7836SJohn.Forte@Sun.COM 			 * with the NS when they come up; yep, for that
1308*7836SJohn.Forte@Sun.COM 			 * to happen the disks will have to be very well
1309*7836SJohn.Forte@Sun.COM 			 * behaved Fabric citizen) we won't need to
1310*7836SJohn.Forte@Sun.COM 			 * register the symbolic port/node names for
1311*7836SJohn.Forte@Sun.COM 			 * other ports too (rather send down SCSI commands
1312*7836SJohn.Forte@Sun.COM 			 * to the devices to set the names)
1313*7836SJohn.Forte@Sun.COM 			 *
1314*7836SJohn.Forte@Sun.COM 			 * Be that as it may, let's continue to fail
1315*7836SJohn.Forte@Sun.COM 			 * registration requests for other ports. period.
1316*7836SJohn.Forte@Sun.COM 			 */
1317*7836SJohn.Forte@Sun.COM 			return (FC_BADOBJECT);
1318*7836SJohn.Forte@Sun.COM 		}
1319*7836SJohn.Forte@Sun.COM 
1320*7836SJohn.Forte@Sun.COM 		if (!fabric) {
1321*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
1322*7836SJohn.Forte@Sun.COM 		}
1323*7836SJohn.Forte@Sun.COM 	} else if (!fabric) {
1324*7836SJohn.Forte@Sun.COM 		return (fctl_retrieve_host_ns_values(port, ns_req));
1325*7836SJohn.Forte@Sun.COM 	}
1326*7836SJohn.Forte@Sun.COM 
1327*7836SJohn.Forte@Sun.COM 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1328*7836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
1329*7836SJohn.Forte@Sun.COM 
1330*7836SJohn.Forte@Sun.COM 	ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
1331*7836SJohn.Forte@Sun.COM 	    ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
1332*7836SJohn.Forte@Sun.COM 	ASSERT(ns_cmd != NULL);
1333*7836SJohn.Forte@Sun.COM 	ns_cmd->ns_cmd_code = ns_req->ns_cmd;
1334*7836SJohn.Forte@Sun.COM 	bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
1335*7836SJohn.Forte@Sun.COM 	    ns_req->ns_req_len);
1336*7836SJohn.Forte@Sun.COM 
1337*7836SJohn.Forte@Sun.COM 	job->job_private = (void *)ns_cmd;
1338*7836SJohn.Forte@Sun.COM 	fctl_enque_job(port, job);
1339*7836SJohn.Forte@Sun.COM 	fctl_jobwait(job);
1340*7836SJohn.Forte@Sun.COM 	rval = job->job_result;
1341*7836SJohn.Forte@Sun.COM 
1342*7836SJohn.Forte@Sun.COM 	if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
1343*7836SJohn.Forte@Sun.COM 		bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
1344*7836SJohn.Forte@Sun.COM 		    ns_cmd->ns_data_len);
1345*7836SJohn.Forte@Sun.COM 	}
1346*7836SJohn.Forte@Sun.COM 	bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
1347*7836SJohn.Forte@Sun.COM 	    sizeof (fc_ct_header_t));
1348*7836SJohn.Forte@Sun.COM 
1349*7836SJohn.Forte@Sun.COM 	fctl_free_ns_cmd(ns_cmd);
1350*7836SJohn.Forte@Sun.COM 	fctl_dealloc_job(job);
1351*7836SJohn.Forte@Sun.COM 
1352*7836SJohn.Forte@Sun.COM 	return (rval);
1353*7836SJohn.Forte@Sun.COM }
1354*7836SJohn.Forte@Sun.COM 
1355*7836SJohn.Forte@Sun.COM 
1356*7836SJohn.Forte@Sun.COM int
1357*7836SJohn.Forte@Sun.COM fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
1358*7836SJohn.Forte@Sun.COM {
1359*7836SJohn.Forte@Sun.COM 	int			rval;
1360*7836SJohn.Forte@Sun.COM 	fc_local_port_t 	*port;
1361*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd, *newpd;
1362*7836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
1363*7836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1364*7836SJohn.Forte@Sun.COM 
1365*7836SJohn.Forte@Sun.COM 	port = port_handle;
1366*7836SJohn.Forte@Sun.COM 
1367*7836SJohn.Forte@Sun.COM 	if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
1368*7836SJohn.Forte@Sun.COM 		return (port->fp_fca_tran->fca_transport(
1369*7836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, pkt));
1370*7836SJohn.Forte@Sun.COM 	}
1371*7836SJohn.Forte@Sun.COM 
1372*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1373*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
1374*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1375*7836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
1376*7836SJohn.Forte@Sun.COM 	}
1377*7836SJohn.Forte@Sun.COM 
1378*7836SJohn.Forte@Sun.COM 	/* A locus of race conditions */
1379*7836SJohn.Forte@Sun.COM 	if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
1380*7836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
1381*7836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1382*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1383*7836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
1384*7836SJohn.Forte@Sun.COM 	}
1385*7836SJohn.Forte@Sun.COM 
1386*7836SJohn.Forte@Sun.COM 	/*
1387*7836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
1388*7836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1389*7836SJohn.Forte@Sun.COM 	 */
1390*7836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
1391*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1392*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1393*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1394*7836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
1395*7836SJohn.Forte@Sun.COM 	}
1396*7836SJohn.Forte@Sun.COM 
1397*7836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
1398*7836SJohn.Forte@Sun.COM 	if (pd) {
1399*7836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
1400*7836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
1401*7836SJohn.Forte@Sun.COM 
1402*7836SJohn.Forte@Sun.COM 			newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
1403*7836SJohn.Forte@Sun.COM 			    &pd->pd_port_name);
1404*7836SJohn.Forte@Sun.COM 
1405*7836SJohn.Forte@Sun.COM 			/*
1406*7836SJohn.Forte@Sun.COM 			 * The remote port (pd) in the packet is no longer
1407*7836SJohn.Forte@Sun.COM 			 * usable, as the old pd still exists we can use the
1408*7836SJohn.Forte@Sun.COM 			 * WWN to check if we have a current pd for the device
1409*7836SJohn.Forte@Sun.COM 			 * we want. Either way we continue with the old logic
1410*7836SJohn.Forte@Sun.COM 			 * whether we have a new pd or not, as the new pd
1411*7836SJohn.Forte@Sun.COM 			 * could be bad, or have become unusable.
1412*7836SJohn.Forte@Sun.COM 			 */
1413*7836SJohn.Forte@Sun.COM 			if ((newpd) && (newpd != pd)) {
1414*7836SJohn.Forte@Sun.COM 
1415*7836SJohn.Forte@Sun.COM 				/*
1416*7836SJohn.Forte@Sun.COM 				 * There is a better remote port (pd) to try,
1417*7836SJohn.Forte@Sun.COM 				 * so we need to fix the reference counts, etc.
1418*7836SJohn.Forte@Sun.COM 				 */
1419*7836SJohn.Forte@Sun.COM 				mutex_enter(&newpd->pd_mutex);
1420*7836SJohn.Forte@Sun.COM 				newpd->pd_ref_count++;
1421*7836SJohn.Forte@Sun.COM 				pkt->pkt_pd = newpd;
1422*7836SJohn.Forte@Sun.COM 				mutex_exit(&newpd->pd_mutex);
1423*7836SJohn.Forte@Sun.COM 
1424*7836SJohn.Forte@Sun.COM 				mutex_enter(&pd->pd_mutex);
1425*7836SJohn.Forte@Sun.COM 				pd->pd_ref_count--;
1426*7836SJohn.Forte@Sun.COM 				if ((pd->pd_state == PORT_DEVICE_INVALID) &&
1427*7836SJohn.Forte@Sun.COM 				    (pd->pd_ref_count == 0)) {
1428*7836SJohn.Forte@Sun.COM 					fc_remote_node_t *node =
1429*7836SJohn.Forte@Sun.COM 					    pd->pd_remote_nodep;
1430*7836SJohn.Forte@Sun.COM 
1431*7836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
1432*7836SJohn.Forte@Sun.COM 					mutex_exit(&port->fp_mutex);
1433*7836SJohn.Forte@Sun.COM 
1434*7836SJohn.Forte@Sun.COM 					/*
1435*7836SJohn.Forte@Sun.COM 					 * This will create another PD hole
1436*7836SJohn.Forte@Sun.COM 					 * where we have a reference to a pd,
1437*7836SJohn.Forte@Sun.COM 					 * but someone else could remove it.
1438*7836SJohn.Forte@Sun.COM 					 */
1439*7836SJohn.Forte@Sun.COM 					if ((fctl_destroy_remote_port(port, pd)
1440*7836SJohn.Forte@Sun.COM 					    == 0) && (node != NULL)) {
1441*7836SJohn.Forte@Sun.COM 						fctl_destroy_remote_node(node);
1442*7836SJohn.Forte@Sun.COM 					}
1443*7836SJohn.Forte@Sun.COM 					mutex_enter(&port->fp_mutex);
1444*7836SJohn.Forte@Sun.COM 				} else {
1445*7836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
1446*7836SJohn.Forte@Sun.COM 				}
1447*7836SJohn.Forte@Sun.COM 				pd = newpd;
1448*7836SJohn.Forte@Sun.COM 			}
1449*7836SJohn.Forte@Sun.COM 		}
1450*7836SJohn.Forte@Sun.COM 
1451*7836SJohn.Forte@Sun.COM 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1452*7836SJohn.Forte@Sun.COM 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1453*7836SJohn.Forte@Sun.COM 			    FC_LOGINREQ : FC_BADDEV;
1454*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
1455*7836SJohn.Forte@Sun.COM 			return (rval);
1456*7836SJohn.Forte@Sun.COM 		}
1457*7836SJohn.Forte@Sun.COM 
1458*7836SJohn.Forte@Sun.COM 		if (pd->pd_flags != PD_IDLE) {
1459*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
1460*7836SJohn.Forte@Sun.COM 			return (FC_DEVICE_BUSY);
1461*7836SJohn.Forte@Sun.COM 		}
1462*7836SJohn.Forte@Sun.COM 
1463*7836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
1464*7836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
1465*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
1466*7836SJohn.Forte@Sun.COM 			return (FC_BADDEV);
1467*7836SJohn.Forte@Sun.COM 		}
1468*7836SJohn.Forte@Sun.COM 
1469*7836SJohn.Forte@Sun.COM 	} else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
1470*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1471*7836SJohn.Forte@Sun.COM 		return (FC_BADPACKET);
1472*7836SJohn.Forte@Sun.COM 	}
1473*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
1474*7836SJohn.Forte@Sun.COM 
1475*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
1476*7836SJohn.Forte@Sun.COM }
1477*7836SJohn.Forte@Sun.COM 
1478*7836SJohn.Forte@Sun.COM 
1479*7836SJohn.Forte@Sun.COM int
1480*7836SJohn.Forte@Sun.COM fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
1481*7836SJohn.Forte@Sun.COM {
1482*7836SJohn.Forte@Sun.COM 	int			rval;
1483*7836SJohn.Forte@Sun.COM 	fc_local_port_t 	*port = port_handle;
1484*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
1485*7836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
1486*7836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1487*7836SJohn.Forte@Sun.COM 
1488*7836SJohn.Forte@Sun.COM 	/*
1489*7836SJohn.Forte@Sun.COM 	 * If the port is OFFLINE, or if the port driver is
1490*7836SJohn.Forte@Sun.COM 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1491*7836SJohn.Forte@Sun.COM 	 * ELS operations
1492*7836SJohn.Forte@Sun.COM 	 */
1493*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1494*7836SJohn.Forte@Sun.COM 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1495*7836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
1496*7836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1497*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1498*7836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
1499*7836SJohn.Forte@Sun.COM 	}
1500*7836SJohn.Forte@Sun.COM 
1501*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
1502*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1503*7836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
1504*7836SJohn.Forte@Sun.COM 	}
1505*7836SJohn.Forte@Sun.COM 
1506*7836SJohn.Forte@Sun.COM 	/*
1507*7836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
1508*7836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1509*7836SJohn.Forte@Sun.COM 	 */
1510*7836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
1511*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1512*7836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1513*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1514*7836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
1515*7836SJohn.Forte@Sun.COM 	}
1516*7836SJohn.Forte@Sun.COM 
1517*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
1518*7836SJohn.Forte@Sun.COM 
1519*7836SJohn.Forte@Sun.COM 	if ((pd = pkt->pkt_pd) != NULL) {
1520*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
1521*7836SJohn.Forte@Sun.COM 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1522*7836SJohn.Forte@Sun.COM 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1523*7836SJohn.Forte@Sun.COM 			    FC_LOGINREQ : FC_BADDEV;
1524*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
1525*7836SJohn.Forte@Sun.COM 			return (rval);
1526*7836SJohn.Forte@Sun.COM 		}
1527*7836SJohn.Forte@Sun.COM 
1528*7836SJohn.Forte@Sun.COM 		if (pd->pd_flags != PD_IDLE) {
1529*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
1530*7836SJohn.Forte@Sun.COM 			return (FC_DEVICE_BUSY);
1531*7836SJohn.Forte@Sun.COM 		}
1532*7836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
1533*7836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
1534*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
1535*7836SJohn.Forte@Sun.COM 			return (FC_BADDEV);
1536*7836SJohn.Forte@Sun.COM 		}
1537*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
1538*7836SJohn.Forte@Sun.COM 	}
1539*7836SJohn.Forte@Sun.COM 
1540*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
1541*7836SJohn.Forte@Sun.COM }
1542*7836SJohn.Forte@Sun.COM 
1543*7836SJohn.Forte@Sun.COM 
1544*7836SJohn.Forte@Sun.COM int
1545*7836SJohn.Forte@Sun.COM fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
1546*7836SJohn.Forte@Sun.COM     uint32_t type, uint64_t *tokens)
1547*7836SJohn.Forte@Sun.COM {
1548*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1549*7836SJohn.Forte@Sun.COM 
1550*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
1551*7836SJohn.Forte@Sun.COM 	    tokens, size, count, type));
1552*7836SJohn.Forte@Sun.COM }
1553*7836SJohn.Forte@Sun.COM 
1554*7836SJohn.Forte@Sun.COM 
1555*7836SJohn.Forte@Sun.COM int
1556*7836SJohn.Forte@Sun.COM fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1557*7836SJohn.Forte@Sun.COM {
1558*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1559*7836SJohn.Forte@Sun.COM 
1560*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
1561*7836SJohn.Forte@Sun.COM 	    count, tokens));
1562*7836SJohn.Forte@Sun.COM }
1563*7836SJohn.Forte@Sun.COM 
1564*7836SJohn.Forte@Sun.COM 
1565*7836SJohn.Forte@Sun.COM int
1566*7836SJohn.Forte@Sun.COM fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1567*7836SJohn.Forte@Sun.COM {
1568*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1569*7836SJohn.Forte@Sun.COM 
1570*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
1571*7836SJohn.Forte@Sun.COM 	    count, tokens));
1572*7836SJohn.Forte@Sun.COM }
1573*7836SJohn.Forte@Sun.COM 
1574*7836SJohn.Forte@Sun.COM 
1575*7836SJohn.Forte@Sun.COM int
1576*7836SJohn.Forte@Sun.COM fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
1577*7836SJohn.Forte@Sun.COM {
1578*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1579*7836SJohn.Forte@Sun.COM 
1580*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
1581*7836SJohn.Forte@Sun.COM }
1582*7836SJohn.Forte@Sun.COM 
1583*7836SJohn.Forte@Sun.COM 
1584*7836SJohn.Forte@Sun.COM /*
1585*7836SJohn.Forte@Sun.COM  * Submit an asynchronous request to the job handler if the sleep
1586*7836SJohn.Forte@Sun.COM  * flag is set to KM_NOSLEEP, as such calls could have been made
1587*7836SJohn.Forte@Sun.COM  * in interrupt contexts, and the goal is to avoid busy waiting,
1588*7836SJohn.Forte@Sun.COM  * blocking on a conditional variable, a semaphore or any of the
1589*7836SJohn.Forte@Sun.COM  * synchronization primitives. A noticeable draw back with this
1590*7836SJohn.Forte@Sun.COM  * asynchronous request is that an FC_SUCCESS is returned long
1591*7836SJohn.Forte@Sun.COM  * before the reset is complete (successful or not).
1592*7836SJohn.Forte@Sun.COM  */
1593*7836SJohn.Forte@Sun.COM int
1594*7836SJohn.Forte@Sun.COM fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
1595*7836SJohn.Forte@Sun.COM {
1596*7836SJohn.Forte@Sun.COM 	int		rval;
1597*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
1598*7836SJohn.Forte@Sun.COM 	job_request_t	*job;
1599*7836SJohn.Forte@Sun.COM 
1600*7836SJohn.Forte@Sun.COM 	port = port_handle;
1601*7836SJohn.Forte@Sun.COM 	/*
1602*7836SJohn.Forte@Sun.COM 	 * Many a times, this function is called from interrupt
1603*7836SJohn.Forte@Sun.COM 	 * contexts and there have been several dead locks and
1604*7836SJohn.Forte@Sun.COM 	 * hangs - One of the simplest work arounds is to fib
1605*7836SJohn.Forte@Sun.COM 	 * if a RESET is in progress.
1606*7836SJohn.Forte@Sun.COM 	 */
1607*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
1608*7836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
1609*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1610*7836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
1611*7836SJohn.Forte@Sun.COM 	}
1612*7836SJohn.Forte@Sun.COM 
1613*7836SJohn.Forte@Sun.COM 	/*
1614*7836SJohn.Forte@Sun.COM 	 * Ward off this reset if a state change is in progress.
1615*7836SJohn.Forte@Sun.COM 	 */
1616*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
1617*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1618*7836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
1619*7836SJohn.Forte@Sun.COM 	}
1620*7836SJohn.Forte@Sun.COM 	port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
1621*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
1622*7836SJohn.Forte@Sun.COM 
1623*7836SJohn.Forte@Sun.COM 	if (fctl_busy_port(port) != 0) {
1624*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
1625*7836SJohn.Forte@Sun.COM 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1626*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1627*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
1628*7836SJohn.Forte@Sun.COM 	}
1629*7836SJohn.Forte@Sun.COM 
1630*7836SJohn.Forte@Sun.COM 	if (sleep == KM_SLEEP) {
1631*7836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
1632*7836SJohn.Forte@Sun.COM 		ASSERT(job != NULL);
1633*7836SJohn.Forte@Sun.COM 
1634*7836SJohn.Forte@Sun.COM 		job->job_private = (void *)pwwn;
1635*7836SJohn.Forte@Sun.COM 		job->job_counter = 1;
1636*7836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
1637*7836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
1638*7836SJohn.Forte@Sun.COM 
1639*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
1640*7836SJohn.Forte@Sun.COM 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1641*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1642*7836SJohn.Forte@Sun.COM 
1643*7836SJohn.Forte@Sun.COM 		fctl_idle_port(port);
1644*7836SJohn.Forte@Sun.COM 
1645*7836SJohn.Forte@Sun.COM 		rval = job->job_result;
1646*7836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
1647*7836SJohn.Forte@Sun.COM 	} else {
1648*7836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
1649*7836SJohn.Forte@Sun.COM 		    fctl_link_reset_done, port, sleep);
1650*7836SJohn.Forte@Sun.COM 		if (job == NULL) {
1651*7836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
1652*7836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1653*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
1654*7836SJohn.Forte@Sun.COM 			fctl_idle_port(port);
1655*7836SJohn.Forte@Sun.COM 			return (FC_NOMEM);
1656*7836SJohn.Forte@Sun.COM 		}
1657*7836SJohn.Forte@Sun.COM 		job->job_private = (void *)pwwn;
1658*7836SJohn.Forte@Sun.COM 		job->job_counter = 1;
1659*7836SJohn.Forte@Sun.COM 		fctl_priority_enque_job(port, job);
1660*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
1661*7836SJohn.Forte@Sun.COM 	}
1662*7836SJohn.Forte@Sun.COM 
1663*7836SJohn.Forte@Sun.COM 	return (rval);
1664*7836SJohn.Forte@Sun.COM }
1665*7836SJohn.Forte@Sun.COM 
1666*7836SJohn.Forte@Sun.COM 
1667*7836SJohn.Forte@Sun.COM int
1668*7836SJohn.Forte@Sun.COM fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
1669*7836SJohn.Forte@Sun.COM {
1670*7836SJohn.Forte@Sun.COM 	int		rval = FC_SUCCESS;
1671*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1672*7836SJohn.Forte@Sun.COM 
1673*7836SJohn.Forte@Sun.COM 	switch (cmd) {
1674*7836SJohn.Forte@Sun.COM 	case FC_RESET_PORT:
1675*7836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
1676*7836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_LINK_RESET);
1677*7836SJohn.Forte@Sun.COM 		break;
1678*7836SJohn.Forte@Sun.COM 
1679*7836SJohn.Forte@Sun.COM 	case FC_RESET_ADAPTER:
1680*7836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
1681*7836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_RESET);
1682*7836SJohn.Forte@Sun.COM 		break;
1683*7836SJohn.Forte@Sun.COM 
1684*7836SJohn.Forte@Sun.COM 	case FC_RESET_DUMP:
1685*7836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
1686*7836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_CORE);
1687*7836SJohn.Forte@Sun.COM 		break;
1688*7836SJohn.Forte@Sun.COM 
1689*7836SJohn.Forte@Sun.COM 	case FC_RESET_CRASH:
1690*7836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
1691*7836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
1692*7836SJohn.Forte@Sun.COM 		break;
1693*7836SJohn.Forte@Sun.COM 
1694*7836SJohn.Forte@Sun.COM 	default:
1695*7836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
1696*7836SJohn.Forte@Sun.COM 	}
1697*7836SJohn.Forte@Sun.COM 
1698*7836SJohn.Forte@Sun.COM 	return (rval);
1699*7836SJohn.Forte@Sun.COM }
1700*7836SJohn.Forte@Sun.COM 
1701*7836SJohn.Forte@Sun.COM 
1702*7836SJohn.Forte@Sun.COM int
1703*7836SJohn.Forte@Sun.COM fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
1704*7836SJohn.Forte@Sun.COM {
1705*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1706*7836SJohn.Forte@Sun.COM 
1707*7836SJohn.Forte@Sun.COM 	/* Copy the login parameters */
1708*7836SJohn.Forte@Sun.COM 	*login_params = port->fp_service_params;
1709*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
1710*7836SJohn.Forte@Sun.COM }
1711*7836SJohn.Forte@Sun.COM 
1712*7836SJohn.Forte@Sun.COM 
1713*7836SJohn.Forte@Sun.COM int
1714*7836SJohn.Forte@Sun.COM fc_ulp_get_port_instance(opaque_t port_handle)
1715*7836SJohn.Forte@Sun.COM {
1716*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
1717*7836SJohn.Forte@Sun.COM 
1718*7836SJohn.Forte@Sun.COM 	return (port->fp_instance);
1719*7836SJohn.Forte@Sun.COM }
1720*7836SJohn.Forte@Sun.COM 
1721*7836SJohn.Forte@Sun.COM 
1722*7836SJohn.Forte@Sun.COM opaque_t
1723*7836SJohn.Forte@Sun.COM fc_ulp_get_port_handle(int port_instance)
1724*7836SJohn.Forte@Sun.COM {
1725*7836SJohn.Forte@Sun.COM 	opaque_t	port_handle = NULL;
1726*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 	*cur;
1727*7836SJohn.Forte@Sun.COM 
1728*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
1729*7836SJohn.Forte@Sun.COM 	for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
1730*7836SJohn.Forte@Sun.COM 		if (cur->port_handle->fp_instance == port_instance) {
1731*7836SJohn.Forte@Sun.COM 			port_handle = (opaque_t)cur->port_handle;
1732*7836SJohn.Forte@Sun.COM 			break;
1733*7836SJohn.Forte@Sun.COM 		}
1734*7836SJohn.Forte@Sun.COM 	}
1735*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
1736*7836SJohn.Forte@Sun.COM 
1737*7836SJohn.Forte@Sun.COM 	return (port_handle);
1738*7836SJohn.Forte@Sun.COM }
1739*7836SJohn.Forte@Sun.COM 
1740*7836SJohn.Forte@Sun.COM 
1741*7836SJohn.Forte@Sun.COM int
1742*7836SJohn.Forte@Sun.COM fc_ulp_error(int fc_errno, char **errmsg)
1743*7836SJohn.Forte@Sun.COM {
1744*7836SJohn.Forte@Sun.COM 	return (fctl_error(fc_errno, errmsg));
1745*7836SJohn.Forte@Sun.COM }
1746*7836SJohn.Forte@Sun.COM 
1747*7836SJohn.Forte@Sun.COM 
1748*7836SJohn.Forte@Sun.COM int
1749*7836SJohn.Forte@Sun.COM fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
1750*7836SJohn.Forte@Sun.COM     char **action, char **expln)
1751*7836SJohn.Forte@Sun.COM {
1752*7836SJohn.Forte@Sun.COM 	return (fctl_pkt_error(pkt, state, reason, action, expln));
1753*7836SJohn.Forte@Sun.COM }
1754*7836SJohn.Forte@Sun.COM 
1755*7836SJohn.Forte@Sun.COM 
1756*7836SJohn.Forte@Sun.COM /*
1757*7836SJohn.Forte@Sun.COM  * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
1758*7836SJohn.Forte@Sun.COM  */
1759*7836SJohn.Forte@Sun.COM int
1760*7836SJohn.Forte@Sun.COM fc_ulp_is_name_present(caddr_t ulp_name)
1761*7836SJohn.Forte@Sun.COM {
1762*7836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
1763*7836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*list;
1764*7836SJohn.Forte@Sun.COM 
1765*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
1766*7836SJohn.Forte@Sun.COM 	for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
1767*7836SJohn.Forte@Sun.COM 		if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
1768*7836SJohn.Forte@Sun.COM 			rval = FC_SUCCESS;
1769*7836SJohn.Forte@Sun.COM 			break;
1770*7836SJohn.Forte@Sun.COM 		}
1771*7836SJohn.Forte@Sun.COM 	}
1772*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
1773*7836SJohn.Forte@Sun.COM 
1774*7836SJohn.Forte@Sun.COM 	return (rval);
1775*7836SJohn.Forte@Sun.COM }
1776*7836SJohn.Forte@Sun.COM 
1777*7836SJohn.Forte@Sun.COM 
1778*7836SJohn.Forte@Sun.COM /*
1779*7836SJohn.Forte@Sun.COM  * Return port WWN for a port Identifier
1780*7836SJohn.Forte@Sun.COM  */
1781*7836SJohn.Forte@Sun.COM int
1782*7836SJohn.Forte@Sun.COM fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
1783*7836SJohn.Forte@Sun.COM {
1784*7836SJohn.Forte@Sun.COM 	int			rval = FC_FAILURE;
1785*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
1786*7836SJohn.Forte@Sun.COM 	fc_local_port_t		*port = port_handle;
1787*7836SJohn.Forte@Sun.COM 
1788*7836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
1789*7836SJohn.Forte@Sun.COM 	if (pd != NULL) {
1790*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
1791*7836SJohn.Forte@Sun.COM 		*pwwn = pd->pd_port_name;
1792*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
1793*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
1794*7836SJohn.Forte@Sun.COM 	}
1795*7836SJohn.Forte@Sun.COM 
1796*7836SJohn.Forte@Sun.COM 	return (rval);
1797*7836SJohn.Forte@Sun.COM }
1798*7836SJohn.Forte@Sun.COM 
1799*7836SJohn.Forte@Sun.COM 
1800*7836SJohn.Forte@Sun.COM /*
1801*7836SJohn.Forte@Sun.COM  * Return a port map for a port WWN
1802*7836SJohn.Forte@Sun.COM  */
1803*7836SJohn.Forte@Sun.COM int
1804*7836SJohn.Forte@Sun.COM fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
1805*7836SJohn.Forte@Sun.COM {
1806*7836SJohn.Forte@Sun.COM 	fc_local_port_t		*port = port_handle;
1807*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*node;
1808*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
1809*7836SJohn.Forte@Sun.COM 
1810*7836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn(port, bytes);
1811*7836SJohn.Forte@Sun.COM 	if (pd == NULL) {
1812*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
1813*7836SJohn.Forte@Sun.COM 	}
1814*7836SJohn.Forte@Sun.COM 
1815*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
1816*7836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
1817*7836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
1818*7836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
1819*7836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
1820*7836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
1821*7836SJohn.Forte@Sun.COM 	map->map_flags = 0;
1822*7836SJohn.Forte@Sun.COM 
1823*7836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
1824*7836SJohn.Forte@Sun.COM 
1825*7836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
1826*7836SJohn.Forte@Sun.COM 
1827*7836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
1828*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
1829*7836SJohn.Forte@Sun.COM 
1830*7836SJohn.Forte@Sun.COM 	if (node) {
1831*7836SJohn.Forte@Sun.COM 		mutex_enter(&node->fd_mutex);
1832*7836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
1833*7836SJohn.Forte@Sun.COM 		mutex_exit(&node->fd_mutex);
1834*7836SJohn.Forte@Sun.COM 	}
1835*7836SJohn.Forte@Sun.COM 	map->map_pd = pd;
1836*7836SJohn.Forte@Sun.COM 
1837*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
1838*7836SJohn.Forte@Sun.COM }
1839*7836SJohn.Forte@Sun.COM 
1840*7836SJohn.Forte@Sun.COM 
1841*7836SJohn.Forte@Sun.COM opaque_t
1842*7836SJohn.Forte@Sun.COM fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
1843*7836SJohn.Forte@Sun.COM {
1844*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
1845*7836SJohn.Forte@Sun.COM 
1846*7836SJohn.Forte@Sun.COM 	if (port->fp_fca_tran->fca_get_device == NULL) {
1847*7836SJohn.Forte@Sun.COM 		return (NULL);
1848*7836SJohn.Forte@Sun.COM 	}
1849*7836SJohn.Forte@Sun.COM 
1850*7836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
1851*7836SJohn.Forte@Sun.COM }
1852*7836SJohn.Forte@Sun.COM 
1853*7836SJohn.Forte@Sun.COM 
1854*7836SJohn.Forte@Sun.COM int
1855*7836SJohn.Forte@Sun.COM fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
1856*7836SJohn.Forte@Sun.COM {
1857*7836SJohn.Forte@Sun.COM 	int		rval = FC_SUCCESS;
1858*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
1859*7836SJohn.Forte@Sun.COM 
1860*7836SJohn.Forte@Sun.COM 	if (port->fp_fca_tran->fca_notify) {
1861*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
1862*7836SJohn.Forte@Sun.COM 		switch (cmd) {
1863*7836SJohn.Forte@Sun.COM 		case FC_NOTIFY_TARGET_MODE:
1864*7836SJohn.Forte@Sun.COM 			port->fp_options |= FP_TARGET_MODE;
1865*7836SJohn.Forte@Sun.COM 			break;
1866*7836SJohn.Forte@Sun.COM 		case FC_NOTIFY_NO_TARGET_MODE:
1867*7836SJohn.Forte@Sun.COM 			port->fp_options &= ~FP_TARGET_MODE;
1868*7836SJohn.Forte@Sun.COM 			break;
1869*7836SJohn.Forte@Sun.COM 		}
1870*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
1871*7836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
1872*7836SJohn.Forte@Sun.COM 	}
1873*7836SJohn.Forte@Sun.COM 
1874*7836SJohn.Forte@Sun.COM 	return (rval);
1875*7836SJohn.Forte@Sun.COM }
1876*7836SJohn.Forte@Sun.COM 
1877*7836SJohn.Forte@Sun.COM 
1878*7836SJohn.Forte@Sun.COM void
1879*7836SJohn.Forte@Sun.COM fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1880*7836SJohn.Forte@Sun.COM {
1881*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd =
1882*7836SJohn.Forte@Sun.COM 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1883*7836SJohn.Forte@Sun.COM 
1884*7836SJohn.Forte@Sun.COM 	if (pd) {
1885*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
1886*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_DISABLE_RELOGIN;
1887*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
1888*7836SJohn.Forte@Sun.COM 	}
1889*7836SJohn.Forte@Sun.COM }
1890*7836SJohn.Forte@Sun.COM 
1891*7836SJohn.Forte@Sun.COM 
1892*7836SJohn.Forte@Sun.COM void
1893*7836SJohn.Forte@Sun.COM fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1894*7836SJohn.Forte@Sun.COM {
1895*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd =
1896*7836SJohn.Forte@Sun.COM 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1897*7836SJohn.Forte@Sun.COM 
1898*7836SJohn.Forte@Sun.COM 	if (pd) {
1899*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
1900*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1901*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
1902*7836SJohn.Forte@Sun.COM 	}
1903*7836SJohn.Forte@Sun.COM }
1904*7836SJohn.Forte@Sun.COM 
1905*7836SJohn.Forte@Sun.COM 
1906*7836SJohn.Forte@Sun.COM /*
1907*7836SJohn.Forte@Sun.COM  * fc_fca_init
1908*7836SJohn.Forte@Sun.COM  * 		Overload the FCA bus_ops vector in its dev_ops with
1909*7836SJohn.Forte@Sun.COM  *		fctl_fca_busops to handle all the INITchilds for "sf"
1910*7836SJohn.Forte@Sun.COM  *		in one common place.
1911*7836SJohn.Forte@Sun.COM  *
1912*7836SJohn.Forte@Sun.COM  *		Should be called from FCA _init routine.
1913*7836SJohn.Forte@Sun.COM  */
1914*7836SJohn.Forte@Sun.COM void
1915*7836SJohn.Forte@Sun.COM fc_fca_init(struct dev_ops *fca_devops_p)
1916*7836SJohn.Forte@Sun.COM {
1917*7836SJohn.Forte@Sun.COM #ifndef	__lock_lint
1918*7836SJohn.Forte@Sun.COM 	fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1919*7836SJohn.Forte@Sun.COM #endif	/* __lock_lint */
1920*7836SJohn.Forte@Sun.COM }
1921*7836SJohn.Forte@Sun.COM 
1922*7836SJohn.Forte@Sun.COM 
1923*7836SJohn.Forte@Sun.COM /*
1924*7836SJohn.Forte@Sun.COM  * fc_fca_attach
1925*7836SJohn.Forte@Sun.COM  */
1926*7836SJohn.Forte@Sun.COM int
1927*7836SJohn.Forte@Sun.COM fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1928*7836SJohn.Forte@Sun.COM {
1929*7836SJohn.Forte@Sun.COM 	/*
1930*7836SJohn.Forte@Sun.COM 	 * When we are in a position to offer downward compatibility
1931*7836SJohn.Forte@Sun.COM 	 * we should change the following check to allow lower revision
1932*7836SJohn.Forte@Sun.COM 	 * of FCAs; But we aren't there right now.
1933*7836SJohn.Forte@Sun.COM 	 */
1934*7836SJohn.Forte@Sun.COM 	if (tran->fca_version != FCTL_FCA_MODREV_5) {
1935*7836SJohn.Forte@Sun.COM 		const char *name = ddi_driver_name(fca_dip);
1936*7836SJohn.Forte@Sun.COM 
1937*7836SJohn.Forte@Sun.COM 		ASSERT(name != NULL);
1938*7836SJohn.Forte@Sun.COM 
1939*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
1940*7836SJohn.Forte@Sun.COM 		    " please upgrade %s", name, name);
1941*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
1942*7836SJohn.Forte@Sun.COM 	}
1943*7836SJohn.Forte@Sun.COM 
1944*7836SJohn.Forte@Sun.COM 	ddi_set_driver_private(fca_dip, (caddr_t)tran);
1945*7836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
1946*7836SJohn.Forte@Sun.COM }
1947*7836SJohn.Forte@Sun.COM 
1948*7836SJohn.Forte@Sun.COM 
1949*7836SJohn.Forte@Sun.COM /*
1950*7836SJohn.Forte@Sun.COM  * fc_fca_detach
1951*7836SJohn.Forte@Sun.COM  */
1952*7836SJohn.Forte@Sun.COM int
1953*7836SJohn.Forte@Sun.COM fc_fca_detach(dev_info_t *fca_dip)
1954*7836SJohn.Forte@Sun.COM {
1955*7836SJohn.Forte@Sun.COM 	ddi_set_driver_private(fca_dip, NULL);
1956*7836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
1957*7836SJohn.Forte@Sun.COM }
1958*7836SJohn.Forte@Sun.COM 
1959*7836SJohn.Forte@Sun.COM 
1960*7836SJohn.Forte@Sun.COM /*
1961*7836SJohn.Forte@Sun.COM  * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
1962*7836SJohn.Forte@Sun.COM  * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
1963*7836SJohn.Forte@Sun.COM  * Link Service responses such as BA_RJT and Extended Link Service response
1964*7836SJohn.Forte@Sun.COM  * such as LS_RJT. If the response is a Link_Data Frame or something that
1965*7836SJohn.Forte@Sun.COM  * this function doesn't understand return FC_FAILURE; Otherwise, fill out
1966*7836SJohn.Forte@Sun.COM  * various fields (state, action, reason, expln) from the response gotten
1967*7836SJohn.Forte@Sun.COM  * in the packet and return FC_SUCCESS.
1968*7836SJohn.Forte@Sun.COM  */
1969*7836SJohn.Forte@Sun.COM int
1970*7836SJohn.Forte@Sun.COM fc_fca_update_errors(fc_packet_t *pkt)
1971*7836SJohn.Forte@Sun.COM {
1972*7836SJohn.Forte@Sun.COM 	int ret = FC_SUCCESS;
1973*7836SJohn.Forte@Sun.COM 
1974*7836SJohn.Forte@Sun.COM 	switch (pkt->pkt_resp_fhdr.r_ctl) {
1975*7836SJohn.Forte@Sun.COM 	case R_CTL_P_RJT: {
1976*7836SJohn.Forte@Sun.COM 		uint32_t prjt;
1977*7836SJohn.Forte@Sun.COM 
1978*7836SJohn.Forte@Sun.COM 		prjt = pkt->pkt_resp_fhdr.ro;
1979*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_NPORT_RJT;
1980*7836SJohn.Forte@Sun.COM 		pkt->pkt_action = (prjt & 0xFF000000) >> 24;
1981*7836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (prjt & 0xFF0000) >> 16;
1982*7836SJohn.Forte@Sun.COM 		break;
1983*7836SJohn.Forte@Sun.COM 	}
1984*7836SJohn.Forte@Sun.COM 
1985*7836SJohn.Forte@Sun.COM 	case R_CTL_F_RJT: {
1986*7836SJohn.Forte@Sun.COM 		uint32_t frjt;
1987*7836SJohn.Forte@Sun.COM 
1988*7836SJohn.Forte@Sun.COM 		frjt = pkt->pkt_resp_fhdr.ro;
1989*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_FABRIC_RJT;
1990*7836SJohn.Forte@Sun.COM 		pkt->pkt_action = (frjt & 0xFF000000) >> 24;
1991*7836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (frjt & 0xFF0000) >> 16;
1992*7836SJohn.Forte@Sun.COM 		break;
1993*7836SJohn.Forte@Sun.COM 	}
1994*7836SJohn.Forte@Sun.COM 
1995*7836SJohn.Forte@Sun.COM 	case R_CTL_P_BSY: {
1996*7836SJohn.Forte@Sun.COM 		uint32_t pbsy;
1997*7836SJohn.Forte@Sun.COM 
1998*7836SJohn.Forte@Sun.COM 		pbsy = pkt->pkt_resp_fhdr.ro;
1999*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_NPORT_BSY;
2000*7836SJohn.Forte@Sun.COM 		pkt->pkt_action = (pbsy & 0xFF000000) >> 24;
2001*7836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (pbsy & 0xFF0000) >> 16;
2002*7836SJohn.Forte@Sun.COM 		break;
2003*7836SJohn.Forte@Sun.COM 	}
2004*7836SJohn.Forte@Sun.COM 
2005*7836SJohn.Forte@Sun.COM 	case R_CTL_F_BSY_LC:
2006*7836SJohn.Forte@Sun.COM 	case R_CTL_F_BSY_DF: {
2007*7836SJohn.Forte@Sun.COM 		uchar_t fbsy;
2008*7836SJohn.Forte@Sun.COM 
2009*7836SJohn.Forte@Sun.COM 		fbsy = pkt->pkt_resp_fhdr.type;
2010*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_FABRIC_BSY;
2011*7836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (fbsy & 0xF0) >> 4;
2012*7836SJohn.Forte@Sun.COM 		break;
2013*7836SJohn.Forte@Sun.COM 	}
2014*7836SJohn.Forte@Sun.COM 
2015*7836SJohn.Forte@Sun.COM 	case R_CTL_LS_BA_RJT: {
2016*7836SJohn.Forte@Sun.COM 		uint32_t brjt;
2017*7836SJohn.Forte@Sun.COM 
2018*7836SJohn.Forte@Sun.COM 		brjt = *(uint32_t *)pkt->pkt_resp;
2019*7836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_BA_RJT;
2020*7836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (brjt & 0xFF0000) >> 16;
2021*7836SJohn.Forte@Sun.COM 		pkt->pkt_expln = (brjt & 0xFF00) >> 8;
2022*7836SJohn.Forte@Sun.COM 		break;
2023*7836SJohn.Forte@Sun.COM 	}
2024*7836SJohn.Forte@Sun.COM 
2025*7836SJohn.Forte@Sun.COM 	case R_CTL_ELS_RSP: {
2026*7836SJohn.Forte@Sun.COM 		la_els_rjt_t *lsrjt;
2027*7836SJohn.Forte@Sun.COM 
2028*7836SJohn.Forte@Sun.COM 		lsrjt = (la_els_rjt_t *)pkt->pkt_resp;
2029*7836SJohn.Forte@Sun.COM 		if (lsrjt->ls_code.ls_code == LA_ELS_RJT) {
2030*7836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_LS_RJT;
2031*7836SJohn.Forte@Sun.COM 			pkt->pkt_reason = lsrjt->reason;
2032*7836SJohn.Forte@Sun.COM 			pkt->pkt_action = lsrjt->action;
2033*7836SJohn.Forte@Sun.COM 			break;
2034*7836SJohn.Forte@Sun.COM 		}
2035*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
2036*7836SJohn.Forte@Sun.COM 	}
2037*7836SJohn.Forte@Sun.COM 
2038*7836SJohn.Forte@Sun.COM 	default:
2039*7836SJohn.Forte@Sun.COM 		ret = FC_FAILURE;
2040*7836SJohn.Forte@Sun.COM 		break;
2041*7836SJohn.Forte@Sun.COM 	}
2042*7836SJohn.Forte@Sun.COM 
2043*7836SJohn.Forte@Sun.COM 	return (ret);
2044*7836SJohn.Forte@Sun.COM }
2045*7836SJohn.Forte@Sun.COM 
2046*7836SJohn.Forte@Sun.COM 
2047*7836SJohn.Forte@Sun.COM int
2048*7836SJohn.Forte@Sun.COM fc_fca_error(int fc_errno, char **errmsg)
2049*7836SJohn.Forte@Sun.COM {
2050*7836SJohn.Forte@Sun.COM 	return (fctl_error(fc_errno, errmsg));
2051*7836SJohn.Forte@Sun.COM }
2052*7836SJohn.Forte@Sun.COM 
2053*7836SJohn.Forte@Sun.COM 
2054*7836SJohn.Forte@Sun.COM int
2055*7836SJohn.Forte@Sun.COM fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
2056*7836SJohn.Forte@Sun.COM     char **action, char **expln)
2057*7836SJohn.Forte@Sun.COM {
2058*7836SJohn.Forte@Sun.COM 	return (fctl_pkt_error(pkt, state, reason, action, expln));
2059*7836SJohn.Forte@Sun.COM }
2060*7836SJohn.Forte@Sun.COM 
2061*7836SJohn.Forte@Sun.COM 
2062*7836SJohn.Forte@Sun.COM /*
2063*7836SJohn.Forte@Sun.COM  * WWN to string goodie. Unpredictable results will happen
2064*7836SJohn.Forte@Sun.COM  * if enough memory isn't supplied in str argument. If you
2065*7836SJohn.Forte@Sun.COM  * are wondering how much does this routine need, it is just
2066*7836SJohn.Forte@Sun.COM  * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
2067*7836SJohn.Forte@Sun.COM  * argument should have atleast 17 bytes allocated.
2068*7836SJohn.Forte@Sun.COM  */
2069*7836SJohn.Forte@Sun.COM void
2070*7836SJohn.Forte@Sun.COM fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
2071*7836SJohn.Forte@Sun.COM {
2072*7836SJohn.Forte@Sun.COM 	int count;
2073*7836SJohn.Forte@Sun.COM 
2074*7836SJohn.Forte@Sun.COM 	for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
2075*7836SJohn.Forte@Sun.COM 		(void) sprintf(str, "%02x", wwn->raw_wwn[count]);
2076*7836SJohn.Forte@Sun.COM 	}
2077*7836SJohn.Forte@Sun.COM 	*str = '\0';
2078*7836SJohn.Forte@Sun.COM }
2079*7836SJohn.Forte@Sun.COM 
2080*7836SJohn.Forte@Sun.COM #define	FC_ATOB(x)	(((x) >= '0' && (x) <= '9') ? ((x) - '0') :\
2081*7836SJohn.Forte@Sun.COM 			((x) >= 'a' && (x) <= 'f') ?\
2082*7836SJohn.Forte@Sun.COM 			((x) - 'a' + 10) : ((x) - 'A' + 10))
2083*7836SJohn.Forte@Sun.COM 
2084*7836SJohn.Forte@Sun.COM void
2085*7836SJohn.Forte@Sun.COM fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
2086*7836SJohn.Forte@Sun.COM {
2087*7836SJohn.Forte@Sun.COM 	int count = 0;
2088*7836SJohn.Forte@Sun.COM 	uchar_t byte;
2089*7836SJohn.Forte@Sun.COM 
2090*7836SJohn.Forte@Sun.COM 	while (*str) {
2091*7836SJohn.Forte@Sun.COM 		byte = FC_ATOB(*str);
2092*7836SJohn.Forte@Sun.COM 		str++;
2093*7836SJohn.Forte@Sun.COM 		byte = byte << 4 | FC_ATOB(*str);
2094*7836SJohn.Forte@Sun.COM 		str++;
2095*7836SJohn.Forte@Sun.COM 		wwn->raw_wwn[count++] = byte;
2096*7836SJohn.Forte@Sun.COM 	}
2097*7836SJohn.Forte@Sun.COM }
2098*7836SJohn.Forte@Sun.COM 
2099*7836SJohn.Forte@Sun.COM /*
2100*7836SJohn.Forte@Sun.COM  * FCA driver's intercepted bus control operations.
2101*7836SJohn.Forte@Sun.COM  */
2102*7836SJohn.Forte@Sun.COM static int
2103*7836SJohn.Forte@Sun.COM fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
2104*7836SJohn.Forte@Sun.COM 	ddi_ctl_enum_t op, void *arg, void *result)
2105*7836SJohn.Forte@Sun.COM {
2106*7836SJohn.Forte@Sun.COM 	switch (op) {
2107*7836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_REPORTDEV:
2108*7836SJohn.Forte@Sun.COM 		break;
2109*7836SJohn.Forte@Sun.COM 
2110*7836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_IOMIN:
2111*7836SJohn.Forte@Sun.COM 		break;
2112*7836SJohn.Forte@Sun.COM 
2113*7836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_INITCHILD:
2114*7836SJohn.Forte@Sun.COM 		return (fctl_initchild(fca_dip, (dev_info_t *)arg));
2115*7836SJohn.Forte@Sun.COM 
2116*7836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_UNINITCHILD:
2117*7836SJohn.Forte@Sun.COM 		return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
2118*7836SJohn.Forte@Sun.COM 
2119*7836SJohn.Forte@Sun.COM 	default:
2120*7836SJohn.Forte@Sun.COM 		return (ddi_ctlops(fca_dip, rip, op, arg, result));
2121*7836SJohn.Forte@Sun.COM 	}
2122*7836SJohn.Forte@Sun.COM 
2123*7836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
2124*7836SJohn.Forte@Sun.COM }
2125*7836SJohn.Forte@Sun.COM 
2126*7836SJohn.Forte@Sun.COM 
2127*7836SJohn.Forte@Sun.COM /*
2128*7836SJohn.Forte@Sun.COM  * FCAs indicate the maximum number of ports supported in their
2129*7836SJohn.Forte@Sun.COM  * tran structure. Fail the INITCHILD if the child port number
2130*7836SJohn.Forte@Sun.COM  * is any greater than the maximum number of ports supported
2131*7836SJohn.Forte@Sun.COM  * by the FCA.
2132*7836SJohn.Forte@Sun.COM  */
2133*7836SJohn.Forte@Sun.COM static int
2134*7836SJohn.Forte@Sun.COM fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2135*7836SJohn.Forte@Sun.COM {
2136*7836SJohn.Forte@Sun.COM 	int 		rval;
2137*7836SJohn.Forte@Sun.COM 	int 		port_no;
2138*7836SJohn.Forte@Sun.COM 	int 		port_len;
2139*7836SJohn.Forte@Sun.COM 	char 		name[20];
2140*7836SJohn.Forte@Sun.COM 	fc_fca_tran_t 	*tran;
2141*7836SJohn.Forte@Sun.COM 	dev_info_t	*dip;
2142*7836SJohn.Forte@Sun.COM 	int		portprop;
2143*7836SJohn.Forte@Sun.COM 
2144*7836SJohn.Forte@Sun.COM 	port_len = sizeof (port_no);
2145*7836SJohn.Forte@Sun.COM 
2146*7836SJohn.Forte@Sun.COM 	/* physical port do not has this property */
2147*7836SJohn.Forte@Sun.COM 	portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
2148*7836SJohn.Forte@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2149*7836SJohn.Forte@Sun.COM 	    "phyport-instance", -1);
2150*7836SJohn.Forte@Sun.COM 
2151*7836SJohn.Forte@Sun.COM 	if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
2152*7836SJohn.Forte@Sun.COM 		/*
2153*7836SJohn.Forte@Sun.COM 		 * Clear any addr bindings created by fcode interpreter
2154*7836SJohn.Forte@Sun.COM 		 * in devi_last_addr so that a ndi_devi_find should never
2155*7836SJohn.Forte@Sun.COM 		 * return this fcode node.
2156*7836SJohn.Forte@Sun.COM 		 */
2157*7836SJohn.Forte@Sun.COM 		ddi_set_name_addr(port_dip, NULL);
2158*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
2159*7836SJohn.Forte@Sun.COM 	}
2160*7836SJohn.Forte@Sun.COM 
2161*7836SJohn.Forte@Sun.COM 	rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
2162*7836SJohn.Forte@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
2163*7836SJohn.Forte@Sun.COM 	    (caddr_t)&port_no, &port_len);
2164*7836SJohn.Forte@Sun.COM 
2165*7836SJohn.Forte@Sun.COM 	if (rval != DDI_SUCCESS) {
2166*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
2167*7836SJohn.Forte@Sun.COM 	}
2168*7836SJohn.Forte@Sun.COM 
2169*7836SJohn.Forte@Sun.COM 	tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
2170*7836SJohn.Forte@Sun.COM 	ASSERT(tran != NULL);
2171*7836SJohn.Forte@Sun.COM 
2172*7836SJohn.Forte@Sun.COM 	(void) sprintf((char *)name, "%x,0", port_no);
2173*7836SJohn.Forte@Sun.COM 	ddi_set_name_addr(port_dip, name);
2174*7836SJohn.Forte@Sun.COM 
2175*7836SJohn.Forte@Sun.COM 	dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2176*7836SJohn.Forte@Sun.COM 
2177*7836SJohn.Forte@Sun.COM 	/*
2178*7836SJohn.Forte@Sun.COM 	 * Even though we never initialize FCode nodes of fp, such a node
2179*7836SJohn.Forte@Sun.COM 	 * could still be there after a DR operation. There will only be
2180*7836SJohn.Forte@Sun.COM 	 * one FCode node, so if this is the one, clear it and issue a
2181*7836SJohn.Forte@Sun.COM 	 * ndi_devi_find again.
2182*7836SJohn.Forte@Sun.COM 	 */
2183*7836SJohn.Forte@Sun.COM 	if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
2184*7836SJohn.Forte@Sun.COM 		ddi_set_name_addr(dip, NULL);
2185*7836SJohn.Forte@Sun.COM 		dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2186*7836SJohn.Forte@Sun.COM 	}
2187*7836SJohn.Forte@Sun.COM 
2188*7836SJohn.Forte@Sun.COM 	if ((portprop == -1) && dip && (dip != port_dip)) {
2189*7836SJohn.Forte@Sun.COM 		/*
2190*7836SJohn.Forte@Sun.COM 		 * Here we have a duplicate .conf entry. Clear the addr
2191*7836SJohn.Forte@Sun.COM 		 * set previously and return failure.
2192*7836SJohn.Forte@Sun.COM 		 */
2193*7836SJohn.Forte@Sun.COM 		ddi_set_name_addr(port_dip, NULL);
2194*7836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
2195*7836SJohn.Forte@Sun.COM 	}
2196*7836SJohn.Forte@Sun.COM 
2197*7836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
2198*7836SJohn.Forte@Sun.COM }
2199*7836SJohn.Forte@Sun.COM 
2200*7836SJohn.Forte@Sun.COM 
2201*7836SJohn.Forte@Sun.COM /* ARGSUSED */
2202*7836SJohn.Forte@Sun.COM static int
2203*7836SJohn.Forte@Sun.COM fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2204*7836SJohn.Forte@Sun.COM {
2205*7836SJohn.Forte@Sun.COM 	ddi_set_name_addr(port_dip, NULL);
2206*7836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
2207*7836SJohn.Forte@Sun.COM }
2208*7836SJohn.Forte@Sun.COM 
2209*7836SJohn.Forte@Sun.COM 
2210*7836SJohn.Forte@Sun.COM static dev_info_t *
2211*7836SJohn.Forte@Sun.COM fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
2212*7836SJohn.Forte@Sun.COM {
2213*7836SJohn.Forte@Sun.COM 	dev_info_t *dip;
2214*7836SJohn.Forte@Sun.COM 	char *addr;
2215*7836SJohn.Forte@Sun.COM 
2216*7836SJohn.Forte@Sun.COM 	ASSERT(cname != NULL && caddr != NULL);
2217*7836SJohn.Forte@Sun.COM 	/* ASSERT(DEVI_BUSY_OWNED(pdip)); */
2218*7836SJohn.Forte@Sun.COM 
2219*7836SJohn.Forte@Sun.COM 	for (dip = ddi_get_child(pdip); dip != NULL;
2220*7836SJohn.Forte@Sun.COM 	    dip = ddi_get_next_sibling(dip)) {
2221*7836SJohn.Forte@Sun.COM 		if (strcmp(cname, ddi_node_name(dip)) != 0)
2222*7836SJohn.Forte@Sun.COM 			continue;
2223*7836SJohn.Forte@Sun.COM 
2224*7836SJohn.Forte@Sun.COM 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
2225*7836SJohn.Forte@Sun.COM 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
2226*7836SJohn.Forte@Sun.COM 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2227*7836SJohn.Forte@Sun.COM 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2228*7836SJohn.Forte@Sun.COM 				if (strcmp(caddr, addr) == 0) {
2229*7836SJohn.Forte@Sun.COM 					ddi_prop_free(addr);
2230*7836SJohn.Forte@Sun.COM 					return (dip);
2231*7836SJohn.Forte@Sun.COM 				}
2232*7836SJohn.Forte@Sun.COM 				ddi_prop_free(addr);
2233*7836SJohn.Forte@Sun.COM 			}
2234*7836SJohn.Forte@Sun.COM 		} else {
2235*7836SJohn.Forte@Sun.COM 			if (strcmp(caddr, addr) == 0)
2236*7836SJohn.Forte@Sun.COM 				return (dip);
2237*7836SJohn.Forte@Sun.COM 		}
2238*7836SJohn.Forte@Sun.COM 	}
2239*7836SJohn.Forte@Sun.COM 
2240*7836SJohn.Forte@Sun.COM 	return (NULL);
2241*7836SJohn.Forte@Sun.COM }
2242*7836SJohn.Forte@Sun.COM 
2243*7836SJohn.Forte@Sun.COM int
2244*7836SJohn.Forte@Sun.COM fctl_check_npiv_portindex(dev_info_t *dip, int vindex)
2245*7836SJohn.Forte@Sun.COM {
2246*7836SJohn.Forte@Sun.COM 	int i, instance;
2247*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
2248*7836SJohn.Forte@Sun.COM 
2249*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
2250*7836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2251*7836SJohn.Forte@Sun.COM 	if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
2252*7836SJohn.Forte@Sun.COM 		return (0);
2253*7836SJohn.Forte@Sun.COM 	}
2254*7836SJohn.Forte@Sun.COM 
2255*7836SJohn.Forte@Sun.COM 	i = vindex-1;
2256*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
2257*7836SJohn.Forte@Sun.COM 	if (port->fp_npiv_portindex[i] == 0) {
2258*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
2259*7836SJohn.Forte@Sun.COM 		return (vindex);
2260*7836SJohn.Forte@Sun.COM 	}
2261*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
2262*7836SJohn.Forte@Sun.COM 	return (0);
2263*7836SJohn.Forte@Sun.COM }
2264*7836SJohn.Forte@Sun.COM 
2265*7836SJohn.Forte@Sun.COM int
2266*7836SJohn.Forte@Sun.COM fctl_get_npiv_portindex(dev_info_t *dip)
2267*7836SJohn.Forte@Sun.COM {
2268*7836SJohn.Forte@Sun.COM 	int i, instance;
2269*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
2270*7836SJohn.Forte@Sun.COM 
2271*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
2272*7836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2273*7836SJohn.Forte@Sun.COM 	if (!port) {
2274*7836SJohn.Forte@Sun.COM 		return (0);
2275*7836SJohn.Forte@Sun.COM 	}
2276*7836SJohn.Forte@Sun.COM 
2277*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
2278*7836SJohn.Forte@Sun.COM 	for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
2279*7836SJohn.Forte@Sun.COM 		if (port->fp_npiv_portindex[i] == 0) {
2280*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
2281*7836SJohn.Forte@Sun.COM 			return (i+1);
2282*7836SJohn.Forte@Sun.COM 		}
2283*7836SJohn.Forte@Sun.COM 	}
2284*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
2285*7836SJohn.Forte@Sun.COM 	return (0);
2286*7836SJohn.Forte@Sun.COM }
2287*7836SJohn.Forte@Sun.COM 
2288*7836SJohn.Forte@Sun.COM 
2289*7836SJohn.Forte@Sun.COM void
2290*7836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(dev_info_t *dip, int index)
2291*7836SJohn.Forte@Sun.COM {
2292*7836SJohn.Forte@Sun.COM 	int instance;
2293*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
2294*7836SJohn.Forte@Sun.COM 
2295*7836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
2296*7836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2297*7836SJohn.Forte@Sun.COM 	if (!port) {
2298*7836SJohn.Forte@Sun.COM 		return;
2299*7836SJohn.Forte@Sun.COM 	}
2300*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
2301*7836SJohn.Forte@Sun.COM 	port->fp_npiv_portindex[index - 1] = 1;
2302*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
2303*7836SJohn.Forte@Sun.COM }
2304*7836SJohn.Forte@Sun.COM 
2305*7836SJohn.Forte@Sun.COM 
2306*7836SJohn.Forte@Sun.COM int
2307*7836SJohn.Forte@Sun.COM fctl_fca_create_npivport(dev_info_t *parent,
2308*7836SJohn.Forte@Sun.COM     dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
2309*7836SJohn.Forte@Sun.COM {
2310*7836SJohn.Forte@Sun.COM 	int rval = 0, devstrlen;
2311*7836SJohn.Forte@Sun.COM 	char    *devname, *cname, *caddr, *devstr;
2312*7836SJohn.Forte@Sun.COM 	dev_info_t	*child = NULL;
2313*7836SJohn.Forte@Sun.COM 	int		portnum;
2314*7836SJohn.Forte@Sun.COM 
2315*7836SJohn.Forte@Sun.COM 	if (*vindex == 0) {
2316*7836SJohn.Forte@Sun.COM 		portnum = fctl_get_npiv_portindex(phydip);
2317*7836SJohn.Forte@Sun.COM 		*vindex = portnum;
2318*7836SJohn.Forte@Sun.COM 	} else {
2319*7836SJohn.Forte@Sun.COM 		portnum = fctl_check_npiv_portindex(phydip, *vindex);
2320*7836SJohn.Forte@Sun.COM 	}
2321*7836SJohn.Forte@Sun.COM 
2322*7836SJohn.Forte@Sun.COM 	if (portnum == 0) {
2323*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
2324*7836SJohn.Forte@Sun.COM 		    "Cann't find valid port index, fail to create devnode");
2325*7836SJohn.Forte@Sun.COM 		return (NDI_FAILURE);
2326*7836SJohn.Forte@Sun.COM 	}
2327*7836SJohn.Forte@Sun.COM 
2328*7836SJohn.Forte@Sun.COM 	devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2329*7836SJohn.Forte@Sun.COM 	(void) sprintf(devname, "fp@%x,0", portnum);
2330*7836SJohn.Forte@Sun.COM 	devstrlen = strlen(devname) + 1;
2331*7836SJohn.Forte@Sun.COM 	devstr = i_ddi_strdup(devname, KM_SLEEP);
2332*7836SJohn.Forte@Sun.COM 	i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2333*7836SJohn.Forte@Sun.COM 
2334*7836SJohn.Forte@Sun.COM 	if (fctl_findchild(parent, cname, caddr) != NULL) {
2335*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2336*7836SJohn.Forte@Sun.COM 		goto freememory;
2337*7836SJohn.Forte@Sun.COM 	}
2338*7836SJohn.Forte@Sun.COM 
2339*7836SJohn.Forte@Sun.COM 	ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
2340*7836SJohn.Forte@Sun.COM 	if (child == NULL) {
2341*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
2342*7836SJohn.Forte@Sun.COM 		    "fctl_create_npiv_port fail to create new devinfo");
2343*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2344*7836SJohn.Forte@Sun.COM 		goto freememory;
2345*7836SJohn.Forte@Sun.COM 	}
2346*7836SJohn.Forte@Sun.COM 
2347*7836SJohn.Forte@Sun.COM 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2348*7836SJohn.Forte@Sun.COM 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2349*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
2350*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
2351*7836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
2352*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2353*7836SJohn.Forte@Sun.COM 		goto freememory;
2354*7836SJohn.Forte@Sun.COM 	}
2355*7836SJohn.Forte@Sun.COM 
2356*7836SJohn.Forte@Sun.COM 	if (strlen(nname) != 0) {
2357*7836SJohn.Forte@Sun.COM 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2358*7836SJohn.Forte@Sun.COM 		    "node-name", nname) != DDI_PROP_SUCCESS) {
2359*7836SJohn.Forte@Sun.COM 			(void) ndi_devi_free(child);
2360*7836SJohn.Forte@Sun.COM 			rval = NDI_FAILURE;
2361*7836SJohn.Forte@Sun.COM 			goto freememory;
2362*7836SJohn.Forte@Sun.COM 		}
2363*7836SJohn.Forte@Sun.COM 	}
2364*7836SJohn.Forte@Sun.COM 
2365*7836SJohn.Forte@Sun.COM 	if (strlen(pname) != 0) {
2366*7836SJohn.Forte@Sun.COM 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2367*7836SJohn.Forte@Sun.COM 		    "port-name", pname) != DDI_PROP_SUCCESS) {
2368*7836SJohn.Forte@Sun.COM 			(void) ndi_devi_free(child);
2369*7836SJohn.Forte@Sun.COM 			rval = NDI_FAILURE;
2370*7836SJohn.Forte@Sun.COM 			goto freememory;
2371*7836SJohn.Forte@Sun.COM 		}
2372*7836SJohn.Forte@Sun.COM 	}
2373*7836SJohn.Forte@Sun.COM 
2374*7836SJohn.Forte@Sun.COM 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2375*7836SJohn.Forte@Sun.COM 	    "port", portnum) != DDI_PROP_SUCCESS) {
2376*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
2377*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
2378*7836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
2379*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2380*7836SJohn.Forte@Sun.COM 		goto freememory;
2381*7836SJohn.Forte@Sun.COM 	}
2382*7836SJohn.Forte@Sun.COM 
2383*7836SJohn.Forte@Sun.COM 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2384*7836SJohn.Forte@Sun.COM 	    "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
2385*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
2386*7836SJohn.Forte@Sun.COM 		    "fp%d: prop_update phyport-instance %s@%s failed",
2387*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
2388*7836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
2389*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2390*7836SJohn.Forte@Sun.COM 		goto freememory;
2391*7836SJohn.Forte@Sun.COM 	}
2392*7836SJohn.Forte@Sun.COM 
2393*7836SJohn.Forte@Sun.COM 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
2394*7836SJohn.Forte@Sun.COM 	if (rval != NDI_SUCCESS) {
2395*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fp%d: online_driver %s failed",
2396*7836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname);
2397*7836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
2398*7836SJohn.Forte@Sun.COM 		goto freememory;
2399*7836SJohn.Forte@Sun.COM 	}
2400*7836SJohn.Forte@Sun.COM 
2401*7836SJohn.Forte@Sun.COM 	fctl_set_npiv_portindex(phydip, portnum);
2402*7836SJohn.Forte@Sun.COM freememory:
2403*7836SJohn.Forte@Sun.COM 	kmem_free(devstr, devstrlen);
2404*7836SJohn.Forte@Sun.COM 	kmem_free(devname, MAXNAMELEN);
2405*7836SJohn.Forte@Sun.COM 
2406*7836SJohn.Forte@Sun.COM 	return (rval);
2407*7836SJohn.Forte@Sun.COM }
2408*7836SJohn.Forte@Sun.COM 
2409*7836SJohn.Forte@Sun.COM 
2410*7836SJohn.Forte@Sun.COM void
2411*7836SJohn.Forte@Sun.COM fctl_add_port(fc_local_port_t *port)
2412*7836SJohn.Forte@Sun.COM {
2413*7836SJohn.Forte@Sun.COM 	fc_fca_port_t *new;
2414*7836SJohn.Forte@Sun.COM 
2415*7836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2416*7836SJohn.Forte@Sun.COM 
2417*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
2418*7836SJohn.Forte@Sun.COM 	new->port_handle = port;
2419*7836SJohn.Forte@Sun.COM 	new->port_next = fctl_fca_portlist;
2420*7836SJohn.Forte@Sun.COM 	fctl_fca_portlist = new;
2421*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
2422*7836SJohn.Forte@Sun.COM }
2423*7836SJohn.Forte@Sun.COM 
2424*7836SJohn.Forte@Sun.COM 
2425*7836SJohn.Forte@Sun.COM void
2426*7836SJohn.Forte@Sun.COM fctl_remove_port(fc_local_port_t *port)
2427*7836SJohn.Forte@Sun.COM {
2428*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
2429*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 		*prev;
2430*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 		*list;
2431*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
2432*7836SJohn.Forte@Sun.COM 
2433*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_WRITER);
2434*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2435*7836SJohn.Forte@Sun.COM 
2436*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2437*7836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
2438*7836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
2439*7836SJohn.Forte@Sun.COM 			continue;
2440*7836SJohn.Forte@Sun.COM 		}
2441*7836SJohn.Forte@Sun.COM 
2442*7836SJohn.Forte@Sun.COM #ifndef	__lock_lint
2443*7836SJohn.Forte@Sun.COM 		ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2444*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */
2445*7836SJohn.Forte@Sun.COM 
2446*7836SJohn.Forte@Sun.COM 		(void) fctl_remove_ulp_port(mod, port);
2447*7836SJohn.Forte@Sun.COM 	}
2448*7836SJohn.Forte@Sun.COM 
2449*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
2450*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
2451*7836SJohn.Forte@Sun.COM 
2452*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
2453*7836SJohn.Forte@Sun.COM 
2454*7836SJohn.Forte@Sun.COM 	list = fctl_fca_portlist;
2455*7836SJohn.Forte@Sun.COM 	prev = NULL;
2456*7836SJohn.Forte@Sun.COM 	while (list != NULL) {
2457*7836SJohn.Forte@Sun.COM 		if (list->port_handle == port) {
2458*7836SJohn.Forte@Sun.COM 			if (prev == NULL) {
2459*7836SJohn.Forte@Sun.COM 				fctl_fca_portlist = list->port_next;
2460*7836SJohn.Forte@Sun.COM 			} else {
2461*7836SJohn.Forte@Sun.COM 				prev->port_next = list->port_next;
2462*7836SJohn.Forte@Sun.COM 			}
2463*7836SJohn.Forte@Sun.COM 			kmem_free(list, sizeof (*list));
2464*7836SJohn.Forte@Sun.COM 			break;
2465*7836SJohn.Forte@Sun.COM 		}
2466*7836SJohn.Forte@Sun.COM 		prev = list;
2467*7836SJohn.Forte@Sun.COM 		list = list->port_next;
2468*7836SJohn.Forte@Sun.COM 	}
2469*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
2470*7836SJohn.Forte@Sun.COM }
2471*7836SJohn.Forte@Sun.COM 
2472*7836SJohn.Forte@Sun.COM 
2473*7836SJohn.Forte@Sun.COM void
2474*7836SJohn.Forte@Sun.COM fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
2475*7836SJohn.Forte@Sun.COM     struct modlinkage *linkage)
2476*7836SJohn.Forte@Sun.COM {
2477*7836SJohn.Forte@Sun.COM 	int			rval;
2478*7836SJohn.Forte@Sun.COM 	uint32_t		s_id;
2479*7836SJohn.Forte@Sun.COM 	uint32_t		state;
2480*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
2481*7836SJohn.Forte@Sun.COM 	fc_ulp_port_info_t 	info;
2482*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
2483*7836SJohn.Forte@Sun.COM 
2484*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
2485*7836SJohn.Forte@Sun.COM 
2486*7836SJohn.Forte@Sun.COM 	info.port_linkage = linkage;
2487*7836SJohn.Forte@Sun.COM 	info.port_dip = port->fp_port_dip;
2488*7836SJohn.Forte@Sun.COM 	info.port_handle = (opaque_t)port;
2489*7836SJohn.Forte@Sun.COM 	info.port_dma_behavior = port->fp_dma_behavior;
2490*7836SJohn.Forte@Sun.COM 	info.port_fcp_dma = port->fp_fcp_dma;
2491*7836SJohn.Forte@Sun.COM 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2492*7836SJohn.Forte@Sun.COM 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2493*7836SJohn.Forte@Sun.COM 	info.port_reset_action = port->fp_reset_action;
2494*7836SJohn.Forte@Sun.COM 
2495*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
2496*7836SJohn.Forte@Sun.COM 
2497*7836SJohn.Forte@Sun.COM 	/*
2498*7836SJohn.Forte@Sun.COM 	 * It is still possible that another thread could have gotten
2499*7836SJohn.Forte@Sun.COM 	 * into the detach process before we got here.
2500*7836SJohn.Forte@Sun.COM 	 */
2501*7836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
2502*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
2503*7836SJohn.Forte@Sun.COM 		return;
2504*7836SJohn.Forte@Sun.COM 	}
2505*7836SJohn.Forte@Sun.COM 
2506*7836SJohn.Forte@Sun.COM 	s_id = port->fp_port_id.port_id;
2507*7836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
2508*7836SJohn.Forte@Sun.COM 		info.port_state = port->fp_bind_state;
2509*7836SJohn.Forte@Sun.COM 	} else {
2510*7836SJohn.Forte@Sun.COM 		info.port_state = port->fp_state;
2511*7836SJohn.Forte@Sun.COM 	}
2512*7836SJohn.Forte@Sun.COM 
2513*7836SJohn.Forte@Sun.COM 	switch (state = FC_PORT_STATE_MASK(info.port_state)) {
2514*7836SJohn.Forte@Sun.COM 	case FC_STATE_LOOP:
2515*7836SJohn.Forte@Sun.COM 	case FC_STATE_NAMESERVICE:
2516*7836SJohn.Forte@Sun.COM 		info.port_state &= ~state;
2517*7836SJohn.Forte@Sun.COM 		info.port_state |= FC_STATE_ONLINE;
2518*7836SJohn.Forte@Sun.COM 		break;
2519*7836SJohn.Forte@Sun.COM 
2520*7836SJohn.Forte@Sun.COM 	default:
2521*7836SJohn.Forte@Sun.COM 		break;
2522*7836SJohn.Forte@Sun.COM 	}
2523*7836SJohn.Forte@Sun.COM 	ASSERT((info.port_state & FC_STATE_LOOP) == 0);
2524*7836SJohn.Forte@Sun.COM 
2525*7836SJohn.Forte@Sun.COM 	info.port_flags = port->fp_topology;
2526*7836SJohn.Forte@Sun.COM 	info.port_pwwn = port->fp_service_params.nport_ww_name;
2527*7836SJohn.Forte@Sun.COM 	info.port_nwwn = port->fp_service_params.node_ww_name;
2528*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
2529*7836SJohn.Forte@Sun.COM 
2530*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
2531*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2532*7836SJohn.Forte@Sun.COM 
2533*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2534*7836SJohn.Forte@Sun.COM 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2535*7836SJohn.Forte@Sun.COM 			ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
2536*7836SJohn.Forte@Sun.COM 			ASSERT(ulp_port != NULL);
2537*7836SJohn.Forte@Sun.COM 
2538*7836SJohn.Forte@Sun.COM 			mutex_enter(&ulp_port->port_mutex);
2539*7836SJohn.Forte@Sun.COM 			ulp_port->port_statec = (info.port_state &
2540*7836SJohn.Forte@Sun.COM 			    FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
2541*7836SJohn.Forte@Sun.COM 			    FC_ULP_STATEC_OFFLINE;
2542*7836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
2543*7836SJohn.Forte@Sun.COM 		}
2544*7836SJohn.Forte@Sun.COM 	}
2545*7836SJohn.Forte@Sun.COM 
2546*7836SJohn.Forte@Sun.COM 	rw_downgrade(&fctl_mod_ports_lock);
2547*7836SJohn.Forte@Sun.COM 
2548*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2549*7836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
2550*7836SJohn.Forte@Sun.COM 		ASSERT(ulp_port != NULL);
2551*7836SJohn.Forte@Sun.COM 
2552*7836SJohn.Forte@Sun.COM 		if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
2553*7836SJohn.Forte@Sun.COM 			continue;
2554*7836SJohn.Forte@Sun.COM 		}
2555*7836SJohn.Forte@Sun.COM 
2556*7836SJohn.Forte@Sun.COM 		fctl_init_dma_attr(port, mod, &info);
2557*7836SJohn.Forte@Sun.COM 
2558*7836SJohn.Forte@Sun.COM 		rval = mod->mod_info->ulp_port_attach(
2559*7836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, &info, cmd, s_id);
2560*7836SJohn.Forte@Sun.COM 
2561*7836SJohn.Forte@Sun.COM 		fctl_post_attach(mod, ulp_port, cmd, rval);
2562*7836SJohn.Forte@Sun.COM 
2563*7836SJohn.Forte@Sun.COM 		if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
2564*7836SJohn.Forte@Sun.COM 		    strcmp(mod->mod_info->ulp_name, "fcp") == 0) {
2565*7836SJohn.Forte@Sun.COM 			ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
2566*7836SJohn.Forte@Sun.COM 		}
2567*7836SJohn.Forte@Sun.COM 	}
2568*7836SJohn.Forte@Sun.COM 
2569*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
2570*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
2571*7836SJohn.Forte@Sun.COM }
2572*7836SJohn.Forte@Sun.COM 
2573*7836SJohn.Forte@Sun.COM 
2574*7836SJohn.Forte@Sun.COM static int
2575*7836SJohn.Forte@Sun.COM fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
2576*7836SJohn.Forte@Sun.COM {
2577*7836SJohn.Forte@Sun.COM 	int rval = FC_SUCCESS;
2578*7836SJohn.Forte@Sun.COM 
2579*7836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
2580*7836SJohn.Forte@Sun.COM 
2581*7836SJohn.Forte@Sun.COM 	switch (cmd) {
2582*7836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH:
2583*7836SJohn.Forte@Sun.COM 		if (ulp_port->port_dstate & ULP_PORT_ATTACH) {
2584*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2585*7836SJohn.Forte@Sun.COM 		}
2586*7836SJohn.Forte@Sun.COM 		break;
2587*7836SJohn.Forte@Sun.COM 
2588*7836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
2589*7836SJohn.Forte@Sun.COM 		ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
2590*7836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2591*7836SJohn.Forte@Sun.COM 		    !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) {
2592*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2593*7836SJohn.Forte@Sun.COM 		}
2594*7836SJohn.Forte@Sun.COM 		break;
2595*7836SJohn.Forte@Sun.COM 
2596*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
2597*7836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2598*7836SJohn.Forte@Sun.COM 		    !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
2599*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2600*7836SJohn.Forte@Sun.COM 		}
2601*7836SJohn.Forte@Sun.COM 		break;
2602*7836SJohn.Forte@Sun.COM 	}
2603*7836SJohn.Forte@Sun.COM 
2604*7836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
2605*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_BUSY;
2606*7836SJohn.Forte@Sun.COM 	}
2607*7836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
2608*7836SJohn.Forte@Sun.COM 
2609*7836SJohn.Forte@Sun.COM 	return (rval);
2610*7836SJohn.Forte@Sun.COM }
2611*7836SJohn.Forte@Sun.COM 
2612*7836SJohn.Forte@Sun.COM 
2613*7836SJohn.Forte@Sun.COM static void
2614*7836SJohn.Forte@Sun.COM fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2615*7836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, int rval)
2616*7836SJohn.Forte@Sun.COM {
2617*7836SJohn.Forte@Sun.COM 	int	be_chatty;
2618*7836SJohn.Forte@Sun.COM 
2619*7836SJohn.Forte@Sun.COM 	ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
2620*7836SJohn.Forte@Sun.COM 	    cmd == FC_CMD_POWER_UP);
2621*7836SJohn.Forte@Sun.COM 
2622*7836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
2623*7836SJohn.Forte@Sun.COM 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2624*7836SJohn.Forte@Sun.COM 
2625*7836SJohn.Forte@Sun.COM 	be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1;
2626*7836SJohn.Forte@Sun.COM 
2627*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
2628*7836SJohn.Forte@Sun.COM 		caddr_t		op;
2629*7836SJohn.Forte@Sun.COM 		fc_local_port_t *port = ulp_port->port_handle;
2630*7836SJohn.Forte@Sun.COM 
2631*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
2632*7836SJohn.Forte@Sun.COM 
2633*7836SJohn.Forte@Sun.COM 		switch (cmd) {
2634*7836SJohn.Forte@Sun.COM 		case FC_CMD_ATTACH:
2635*7836SJohn.Forte@Sun.COM 			op = "attach";
2636*7836SJohn.Forte@Sun.COM 			break;
2637*7836SJohn.Forte@Sun.COM 
2638*7836SJohn.Forte@Sun.COM 		case FC_CMD_RESUME:
2639*7836SJohn.Forte@Sun.COM 			op = "resume";
2640*7836SJohn.Forte@Sun.COM 			break;
2641*7836SJohn.Forte@Sun.COM 
2642*7836SJohn.Forte@Sun.COM 		case FC_CMD_POWER_UP:
2643*7836SJohn.Forte@Sun.COM 			op = "power up";
2644*7836SJohn.Forte@Sun.COM 			break;
2645*7836SJohn.Forte@Sun.COM 		}
2646*7836SJohn.Forte@Sun.COM 
2647*7836SJohn.Forte@Sun.COM 		if (be_chatty) {
2648*7836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2649*7836SJohn.Forte@Sun.COM 			    port->fp_instance, op, mod->mod_info->ulp_name);
2650*7836SJohn.Forte@Sun.COM 		}
2651*7836SJohn.Forte@Sun.COM 
2652*7836SJohn.Forte@Sun.COM 		return;
2653*7836SJohn.Forte@Sun.COM 	}
2654*7836SJohn.Forte@Sun.COM 
2655*7836SJohn.Forte@Sun.COM 	switch (cmd) {
2656*7836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH:
2657*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_ATTACH;
2658*7836SJohn.Forte@Sun.COM 		break;
2659*7836SJohn.Forte@Sun.COM 
2660*7836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
2661*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_SUSPEND;
2662*7836SJohn.Forte@Sun.COM 		break;
2663*7836SJohn.Forte@Sun.COM 
2664*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
2665*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN;
2666*7836SJohn.Forte@Sun.COM 		break;
2667*7836SJohn.Forte@Sun.COM 	}
2668*7836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
2669*7836SJohn.Forte@Sun.COM }
2670*7836SJohn.Forte@Sun.COM 
2671*7836SJohn.Forte@Sun.COM 
2672*7836SJohn.Forte@Sun.COM int
2673*7836SJohn.Forte@Sun.COM fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
2674*7836SJohn.Forte@Sun.COM     struct modlinkage *linkage)
2675*7836SJohn.Forte@Sun.COM {
2676*7836SJohn.Forte@Sun.COM 	int			rval = FC_SUCCESS;
2677*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
2678*7836SJohn.Forte@Sun.COM 	fc_ulp_port_info_t 	info;
2679*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
2680*7836SJohn.Forte@Sun.COM 
2681*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
2682*7836SJohn.Forte@Sun.COM 
2683*7836SJohn.Forte@Sun.COM 	info.port_linkage = linkage;
2684*7836SJohn.Forte@Sun.COM 	info.port_dip = port->fp_port_dip;
2685*7836SJohn.Forte@Sun.COM 	info.port_handle = (opaque_t)port;
2686*7836SJohn.Forte@Sun.COM 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2687*7836SJohn.Forte@Sun.COM 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2688*7836SJohn.Forte@Sun.COM 
2689*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
2690*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_READER);
2691*7836SJohn.Forte@Sun.COM 
2692*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2693*7836SJohn.Forte@Sun.COM 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2694*7836SJohn.Forte@Sun.COM 			continue;
2695*7836SJohn.Forte@Sun.COM 		}
2696*7836SJohn.Forte@Sun.COM 
2697*7836SJohn.Forte@Sun.COM 		if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
2698*7836SJohn.Forte@Sun.COM 			continue;
2699*7836SJohn.Forte@Sun.COM 		}
2700*7836SJohn.Forte@Sun.COM 
2701*7836SJohn.Forte@Sun.COM 		fctl_init_dma_attr(port, mod, &info);
2702*7836SJohn.Forte@Sun.COM 
2703*7836SJohn.Forte@Sun.COM 		rval = mod->mod_info->ulp_port_detach(
2704*7836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, &info, cmd);
2705*7836SJohn.Forte@Sun.COM 
2706*7836SJohn.Forte@Sun.COM 		fctl_post_detach(mod, ulp_port, cmd, rval);
2707*7836SJohn.Forte@Sun.COM 
2708*7836SJohn.Forte@Sun.COM 		if (rval != FC_SUCCESS) {
2709*7836SJohn.Forte@Sun.COM 			break;
2710*7836SJohn.Forte@Sun.COM 		}
2711*7836SJohn.Forte@Sun.COM 
2712*7836SJohn.Forte@Sun.COM 		if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
2713*7836SJohn.Forte@Sun.COM 		    "fcp") == 0) {
2714*7836SJohn.Forte@Sun.COM 			ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
2715*7836SJohn.Forte@Sun.COM 		}
2716*7836SJohn.Forte@Sun.COM 
2717*7836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
2718*7836SJohn.Forte@Sun.COM 		ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE;
2719*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
2720*7836SJohn.Forte@Sun.COM 	}
2721*7836SJohn.Forte@Sun.COM 
2722*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
2723*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
2724*7836SJohn.Forte@Sun.COM 
2725*7836SJohn.Forte@Sun.COM 	return (rval);
2726*7836SJohn.Forte@Sun.COM }
2727*7836SJohn.Forte@Sun.COM 
2728*7836SJohn.Forte@Sun.COM static	void
2729*7836SJohn.Forte@Sun.COM fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
2730*7836SJohn.Forte@Sun.COM     fc_ulp_port_info_t 	*info)
2731*7836SJohn.Forte@Sun.COM {
2732*7836SJohn.Forte@Sun.COM 
2733*7836SJohn.Forte@Sun.COM 		if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
2734*7836SJohn.Forte@Sun.COM 		    (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
2735*7836SJohn.Forte@Sun.COM 			info->port_cmd_dma_attr =
2736*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcp_cmd_attr;
2737*7836SJohn.Forte@Sun.COM 			info->port_data_dma_attr =
2738*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcp_data_attr;
2739*7836SJohn.Forte@Sun.COM 			info->port_resp_dma_attr =
2740*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcp_rsp_attr;
2741*7836SJohn.Forte@Sun.COM 		} else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
2742*7836SJohn.Forte@Sun.COM 			info->port_cmd_dma_attr =
2743*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
2744*7836SJohn.Forte@Sun.COM 			info->port_data_dma_attr =
2745*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_attr;
2746*7836SJohn.Forte@Sun.COM 			info->port_resp_dma_attr =
2747*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
2748*7836SJohn.Forte@Sun.COM 		} else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
2749*7836SJohn.Forte@Sun.COM 			info->port_cmd_dma_attr =
2750*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcip_cmd_attr;
2751*7836SJohn.Forte@Sun.COM 			info->port_data_dma_attr =
2752*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_attr;
2753*7836SJohn.Forte@Sun.COM 			info->port_resp_dma_attr =
2754*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_fcip_rsp_attr;
2755*7836SJohn.Forte@Sun.COM 		} else {
2756*7836SJohn.Forte@Sun.COM 			info->port_cmd_dma_attr = info->port_data_dma_attr =
2757*7836SJohn.Forte@Sun.COM 			    info->port_resp_dma_attr =
2758*7836SJohn.Forte@Sun.COM 			    port->fp_fca_tran->fca_dma_attr; /* default */
2759*7836SJohn.Forte@Sun.COM 		}
2760*7836SJohn.Forte@Sun.COM }
2761*7836SJohn.Forte@Sun.COM 
2762*7836SJohn.Forte@Sun.COM static int
2763*7836SJohn.Forte@Sun.COM fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
2764*7836SJohn.Forte@Sun.COM {
2765*7836SJohn.Forte@Sun.COM 	int rval = FC_SUCCESS;
2766*7836SJohn.Forte@Sun.COM 
2767*7836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
2768*7836SJohn.Forte@Sun.COM 
2769*7836SJohn.Forte@Sun.COM 	switch (cmd) {
2770*7836SJohn.Forte@Sun.COM 	case FC_CMD_DETACH:
2771*7836SJohn.Forte@Sun.COM 		if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
2772*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2773*7836SJohn.Forte@Sun.COM 		}
2774*7836SJohn.Forte@Sun.COM 		break;
2775*7836SJohn.Forte@Sun.COM 
2776*7836SJohn.Forte@Sun.COM 	case FC_CMD_SUSPEND:
2777*7836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2778*7836SJohn.Forte@Sun.COM 		    ulp_port->port_dstate & ULP_PORT_SUSPEND) {
2779*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2780*7836SJohn.Forte@Sun.COM 		}
2781*7836SJohn.Forte@Sun.COM 		break;
2782*7836SJohn.Forte@Sun.COM 
2783*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_DOWN:
2784*7836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2785*7836SJohn.Forte@Sun.COM 		    ulp_port->port_dstate & ULP_PORT_POWER_DOWN) {
2786*7836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
2787*7836SJohn.Forte@Sun.COM 		}
2788*7836SJohn.Forte@Sun.COM 		break;
2789*7836SJohn.Forte@Sun.COM 	}
2790*7836SJohn.Forte@Sun.COM 
2791*7836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
2792*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_BUSY;
2793*7836SJohn.Forte@Sun.COM 	}
2794*7836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
2795*7836SJohn.Forte@Sun.COM 
2796*7836SJohn.Forte@Sun.COM 	return (rval);
2797*7836SJohn.Forte@Sun.COM }
2798*7836SJohn.Forte@Sun.COM 
2799*7836SJohn.Forte@Sun.COM 
2800*7836SJohn.Forte@Sun.COM static void
2801*7836SJohn.Forte@Sun.COM fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2802*7836SJohn.Forte@Sun.COM     fc_detach_cmd_t cmd, int rval)
2803*7836SJohn.Forte@Sun.COM {
2804*7836SJohn.Forte@Sun.COM 	ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
2805*7836SJohn.Forte@Sun.COM 	    cmd == FC_CMD_POWER_DOWN);
2806*7836SJohn.Forte@Sun.COM 
2807*7836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
2808*7836SJohn.Forte@Sun.COM 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2809*7836SJohn.Forte@Sun.COM 
2810*7836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
2811*7836SJohn.Forte@Sun.COM 		caddr_t		op;
2812*7836SJohn.Forte@Sun.COM 		fc_local_port_t *port = ulp_port->port_handle;
2813*7836SJohn.Forte@Sun.COM 
2814*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
2815*7836SJohn.Forte@Sun.COM 
2816*7836SJohn.Forte@Sun.COM 		switch (cmd) {
2817*7836SJohn.Forte@Sun.COM 		case FC_CMD_DETACH:
2818*7836SJohn.Forte@Sun.COM 			op = "detach";
2819*7836SJohn.Forte@Sun.COM 			break;
2820*7836SJohn.Forte@Sun.COM 
2821*7836SJohn.Forte@Sun.COM 		case FC_CMD_SUSPEND:
2822*7836SJohn.Forte@Sun.COM 			op = "suspend";
2823*7836SJohn.Forte@Sun.COM 			break;
2824*7836SJohn.Forte@Sun.COM 
2825*7836SJohn.Forte@Sun.COM 		case FC_CMD_POWER_DOWN:
2826*7836SJohn.Forte@Sun.COM 			op = "power down";
2827*7836SJohn.Forte@Sun.COM 			break;
2828*7836SJohn.Forte@Sun.COM 		}
2829*7836SJohn.Forte@Sun.COM 
2830*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2831*7836SJohn.Forte@Sun.COM 		    port->fp_instance, op, mod->mod_info->ulp_name);
2832*7836SJohn.Forte@Sun.COM 
2833*7836SJohn.Forte@Sun.COM 		return;
2834*7836SJohn.Forte@Sun.COM 	}
2835*7836SJohn.Forte@Sun.COM 
2836*7836SJohn.Forte@Sun.COM 	switch (cmd) {
2837*7836SJohn.Forte@Sun.COM 	case FC_CMD_DETACH:
2838*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_ATTACH;
2839*7836SJohn.Forte@Sun.COM 		break;
2840*7836SJohn.Forte@Sun.COM 
2841*7836SJohn.Forte@Sun.COM 	case FC_CMD_SUSPEND:
2842*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_SUSPEND;
2843*7836SJohn.Forte@Sun.COM 		break;
2844*7836SJohn.Forte@Sun.COM 
2845*7836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_DOWN:
2846*7836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_POWER_DOWN;
2847*7836SJohn.Forte@Sun.COM 		break;
2848*7836SJohn.Forte@Sun.COM 	}
2849*7836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
2850*7836SJohn.Forte@Sun.COM }
2851*7836SJohn.Forte@Sun.COM 
2852*7836SJohn.Forte@Sun.COM 
2853*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
2854*7836SJohn.Forte@Sun.COM fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
2855*7836SJohn.Forte@Sun.COM     int sleep)
2856*7836SJohn.Forte@Sun.COM {
2857*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *last;
2858*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
2859*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *new;
2860*7836SJohn.Forte@Sun.COM 
2861*7836SJohn.Forte@Sun.COM 	ASSERT(RW_READ_HELD(&fctl_ulp_lock));
2862*7836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2863*7836SJohn.Forte@Sun.COM 
2864*7836SJohn.Forte@Sun.COM 	last = NULL;
2865*7836SJohn.Forte@Sun.COM 	next = ulp_module->mod_ports;
2866*7836SJohn.Forte@Sun.COM 
2867*7836SJohn.Forte@Sun.COM 	while (next != NULL) {
2868*7836SJohn.Forte@Sun.COM 		last = next;
2869*7836SJohn.Forte@Sun.COM 		next = next->port_next;
2870*7836SJohn.Forte@Sun.COM 	}
2871*7836SJohn.Forte@Sun.COM 
2872*7836SJohn.Forte@Sun.COM 	new = fctl_alloc_ulp_port(sleep);
2873*7836SJohn.Forte@Sun.COM 	if (new == NULL) {
2874*7836SJohn.Forte@Sun.COM 		return (new);
2875*7836SJohn.Forte@Sun.COM 	}
2876*7836SJohn.Forte@Sun.COM 
2877*7836SJohn.Forte@Sun.COM 	new->port_handle = port_handle;
2878*7836SJohn.Forte@Sun.COM 	if (last == NULL) {
2879*7836SJohn.Forte@Sun.COM 		ulp_module->mod_ports = new;
2880*7836SJohn.Forte@Sun.COM 	} else {
2881*7836SJohn.Forte@Sun.COM 		last->port_next = new;
2882*7836SJohn.Forte@Sun.COM 	}
2883*7836SJohn.Forte@Sun.COM 
2884*7836SJohn.Forte@Sun.COM 	return (new);
2885*7836SJohn.Forte@Sun.COM }
2886*7836SJohn.Forte@Sun.COM 
2887*7836SJohn.Forte@Sun.COM 
2888*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
2889*7836SJohn.Forte@Sun.COM fctl_alloc_ulp_port(int sleep)
2890*7836SJohn.Forte@Sun.COM {
2891*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *new;
2892*7836SJohn.Forte@Sun.COM 
2893*7836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), sleep);
2894*7836SJohn.Forte@Sun.COM 	if (new == NULL) {
2895*7836SJohn.Forte@Sun.COM 		return (new);
2896*7836SJohn.Forte@Sun.COM 	}
2897*7836SJohn.Forte@Sun.COM 	mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
2898*7836SJohn.Forte@Sun.COM 
2899*7836SJohn.Forte@Sun.COM 	return (new);
2900*7836SJohn.Forte@Sun.COM }
2901*7836SJohn.Forte@Sun.COM 
2902*7836SJohn.Forte@Sun.COM 
2903*7836SJohn.Forte@Sun.COM static int
2904*7836SJohn.Forte@Sun.COM fctl_remove_ulp_port(struct ulp_module *ulp_module,
2905*7836SJohn.Forte@Sun.COM     fc_local_port_t *port_handle)
2906*7836SJohn.Forte@Sun.COM {
2907*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *last;
2908*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
2909*7836SJohn.Forte@Sun.COM 
2910*7836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_ulp_lock));
2911*7836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2912*7836SJohn.Forte@Sun.COM 
2913*7836SJohn.Forte@Sun.COM 	last = NULL;
2914*7836SJohn.Forte@Sun.COM 	next = ulp_module->mod_ports;
2915*7836SJohn.Forte@Sun.COM 
2916*7836SJohn.Forte@Sun.COM 	while (next != NULL) {
2917*7836SJohn.Forte@Sun.COM 		if (next->port_handle == port_handle) {
2918*7836SJohn.Forte@Sun.COM 			if (next->port_dstate & ULP_PORT_ATTACH) {
2919*7836SJohn.Forte@Sun.COM 				return (FC_FAILURE);
2920*7836SJohn.Forte@Sun.COM 			}
2921*7836SJohn.Forte@Sun.COM 			break;
2922*7836SJohn.Forte@Sun.COM 		}
2923*7836SJohn.Forte@Sun.COM 		last = next;
2924*7836SJohn.Forte@Sun.COM 		next = next->port_next;
2925*7836SJohn.Forte@Sun.COM 	}
2926*7836SJohn.Forte@Sun.COM 
2927*7836SJohn.Forte@Sun.COM 	if (next != NULL) {
2928*7836SJohn.Forte@Sun.COM 		ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
2929*7836SJohn.Forte@Sun.COM 
2930*7836SJohn.Forte@Sun.COM 		if (last == NULL) {
2931*7836SJohn.Forte@Sun.COM 			ulp_module->mod_ports = next->port_next;
2932*7836SJohn.Forte@Sun.COM 		} else {
2933*7836SJohn.Forte@Sun.COM 			last->port_next = next->port_next;
2934*7836SJohn.Forte@Sun.COM 		}
2935*7836SJohn.Forte@Sun.COM 		fctl_dealloc_ulp_port(next);
2936*7836SJohn.Forte@Sun.COM 
2937*7836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
2938*7836SJohn.Forte@Sun.COM 	} else {
2939*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
2940*7836SJohn.Forte@Sun.COM 	}
2941*7836SJohn.Forte@Sun.COM }
2942*7836SJohn.Forte@Sun.COM 
2943*7836SJohn.Forte@Sun.COM 
2944*7836SJohn.Forte@Sun.COM static void
2945*7836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(fc_ulp_ports_t *next)
2946*7836SJohn.Forte@Sun.COM {
2947*7836SJohn.Forte@Sun.COM 	mutex_destroy(&next->port_mutex);
2948*7836SJohn.Forte@Sun.COM 	kmem_free(next, sizeof (*next));
2949*7836SJohn.Forte@Sun.COM }
2950*7836SJohn.Forte@Sun.COM 
2951*7836SJohn.Forte@Sun.COM 
2952*7836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
2953*7836SJohn.Forte@Sun.COM fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
2954*7836SJohn.Forte@Sun.COM {
2955*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
2956*7836SJohn.Forte@Sun.COM 
2957*7836SJohn.Forte@Sun.COM 	ASSERT(RW_LOCK_HELD(&fctl_ulp_lock));
2958*7836SJohn.Forte@Sun.COM 	ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock));
2959*7836SJohn.Forte@Sun.COM 
2960*7836SJohn.Forte@Sun.COM 	for (next = ulp_module->mod_ports; next != NULL;
2961*7836SJohn.Forte@Sun.COM 	    next = next->port_next) {
2962*7836SJohn.Forte@Sun.COM 		if (next->port_handle == port_handle) {
2963*7836SJohn.Forte@Sun.COM 			return (next);
2964*7836SJohn.Forte@Sun.COM 		}
2965*7836SJohn.Forte@Sun.COM 	}
2966*7836SJohn.Forte@Sun.COM 
2967*7836SJohn.Forte@Sun.COM 	return (NULL);
2968*7836SJohn.Forte@Sun.COM }
2969*7836SJohn.Forte@Sun.COM 
2970*7836SJohn.Forte@Sun.COM 
2971*7836SJohn.Forte@Sun.COM /*
2972*7836SJohn.Forte@Sun.COM  * Pass state change notfications on to registered ULPs.
2973*7836SJohn.Forte@Sun.COM  *
2974*7836SJohn.Forte@Sun.COM  * Can issue wakeups to client callers who might be waiting for completions
2975*7836SJohn.Forte@Sun.COM  * on other threads.
2976*7836SJohn.Forte@Sun.COM  *
2977*7836SJohn.Forte@Sun.COM  * Caution: will silently deallocate any fc_remote_port_t and/or
2978*7836SJohn.Forte@Sun.COM  * fc_remote_node_t structs it finds that are not in use.
2979*7836SJohn.Forte@Sun.COM  */
2980*7836SJohn.Forte@Sun.COM void
2981*7836SJohn.Forte@Sun.COM fctl_ulp_statec_cb(void *arg)
2982*7836SJohn.Forte@Sun.COM {
2983*7836SJohn.Forte@Sun.COM 	uint32_t		s_id;
2984*7836SJohn.Forte@Sun.COM 	uint32_t		new_state;
2985*7836SJohn.Forte@Sun.COM 	fc_local_port_t		*port;
2986*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
2987*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
2988*7836SJohn.Forte@Sun.COM 	fc_port_clist_t 	*clist = (fc_port_clist_t *)arg;
2989*7836SJohn.Forte@Sun.COM 
2990*7836SJohn.Forte@Sun.COM 	ASSERT(clist != NULL);
2991*7836SJohn.Forte@Sun.COM 
2992*7836SJohn.Forte@Sun.COM 	port = clist->clist_port;
2993*7836SJohn.Forte@Sun.COM 
2994*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
2995*7836SJohn.Forte@Sun.COM 	s_id = port->fp_port_id.port_id;
2996*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
2997*7836SJohn.Forte@Sun.COM 
2998*7836SJohn.Forte@Sun.COM 	switch (clist->clist_state) {
2999*7836SJohn.Forte@Sun.COM 	case FC_STATE_ONLINE:
3000*7836SJohn.Forte@Sun.COM 		new_state = FC_ULP_STATEC_ONLINE;
3001*7836SJohn.Forte@Sun.COM 		break;
3002*7836SJohn.Forte@Sun.COM 
3003*7836SJohn.Forte@Sun.COM 	case FC_STATE_OFFLINE:
3004*7836SJohn.Forte@Sun.COM 		if (clist->clist_len) {
3005*7836SJohn.Forte@Sun.COM 			new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT;
3006*7836SJohn.Forte@Sun.COM 		} else {
3007*7836SJohn.Forte@Sun.COM 			new_state = FC_ULP_STATEC_OFFLINE;
3008*7836SJohn.Forte@Sun.COM 		}
3009*7836SJohn.Forte@Sun.COM 		break;
3010*7836SJohn.Forte@Sun.COM 
3011*7836SJohn.Forte@Sun.COM 	default:
3012*7836SJohn.Forte@Sun.COM 		new_state = FC_ULP_STATEC_DONT_CARE;
3013*7836SJohn.Forte@Sun.COM 		break;
3014*7836SJohn.Forte@Sun.COM 	}
3015*7836SJohn.Forte@Sun.COM 
3016*7836SJohn.Forte@Sun.COM #ifdef	DEBUG
3017*7836SJohn.Forte@Sun.COM 	/*
3018*7836SJohn.Forte@Sun.COM 	 * sanity check for presence of OLD devices in the hash lists
3019*7836SJohn.Forte@Sun.COM 	 */
3020*7836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
3021*7836SJohn.Forte@Sun.COM 		int 			count;
3022*7836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd;
3023*7836SJohn.Forte@Sun.COM 
3024*7836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
3025*7836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len; count++) {
3026*7836SJohn.Forte@Sun.COM 			if (clist->clist_map[count].map_state ==
3027*7836SJohn.Forte@Sun.COM 			    PORT_DEVICE_INVALID) {
3028*7836SJohn.Forte@Sun.COM 				la_wwn_t 	pwwn;
3029*7836SJohn.Forte@Sun.COM 				fc_portid_t 	d_id;
3030*7836SJohn.Forte@Sun.COM 
3031*7836SJohn.Forte@Sun.COM 				pd = clist->clist_map[count].map_pd;
3032*7836SJohn.Forte@Sun.COM 				if (pd != NULL) {
3033*7836SJohn.Forte@Sun.COM 					mutex_enter(&pd->pd_mutex);
3034*7836SJohn.Forte@Sun.COM 					pwwn = pd->pd_port_name;
3035*7836SJohn.Forte@Sun.COM 					d_id = pd->pd_port_id;
3036*7836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
3037*7836SJohn.Forte@Sun.COM 
3038*7836SJohn.Forte@Sun.COM 					pd = fctl_get_remote_port_by_pwwn(port,
3039*7836SJohn.Forte@Sun.COM 					    &pwwn);
3040*7836SJohn.Forte@Sun.COM 
3041*7836SJohn.Forte@Sun.COM 					ASSERT(pd != clist->clist_map[count].
3042*7836SJohn.Forte@Sun.COM 					    map_pd);
3043*7836SJohn.Forte@Sun.COM 
3044*7836SJohn.Forte@Sun.COM 					pd = fctl_get_remote_port_by_did(port,
3045*7836SJohn.Forte@Sun.COM 					    d_id.port_id);
3046*7836SJohn.Forte@Sun.COM 					ASSERT(pd != clist->clist_map[count].
3047*7836SJohn.Forte@Sun.COM 					    map_pd);
3048*7836SJohn.Forte@Sun.COM 				}
3049*7836SJohn.Forte@Sun.COM 			}
3050*7836SJohn.Forte@Sun.COM 		}
3051*7836SJohn.Forte@Sun.COM 	}
3052*7836SJohn.Forte@Sun.COM #endif
3053*7836SJohn.Forte@Sun.COM 
3054*7836SJohn.Forte@Sun.COM 	/*
3055*7836SJohn.Forte@Sun.COM 	 * Check for duplicate map entries
3056*7836SJohn.Forte@Sun.COM 	 */
3057*7836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
3058*7836SJohn.Forte@Sun.COM 		int 			count;
3059*7836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd1, *pd2;
3060*7836SJohn.Forte@Sun.COM 
3061*7836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
3062*7836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len-1; count++) {
3063*7836SJohn.Forte@Sun.COM 			int count2;
3064*7836SJohn.Forte@Sun.COM 
3065*7836SJohn.Forte@Sun.COM 			pd1 = clist->clist_map[count].map_pd;
3066*7836SJohn.Forte@Sun.COM 			if (pd1 == NULL) {
3067*7836SJohn.Forte@Sun.COM 				continue;
3068*7836SJohn.Forte@Sun.COM 			}
3069*7836SJohn.Forte@Sun.COM 
3070*7836SJohn.Forte@Sun.COM 			for (count2 = count+1;
3071*7836SJohn.Forte@Sun.COM 			    count2 < clist->clist_len;
3072*7836SJohn.Forte@Sun.COM 			    count2++) {
3073*7836SJohn.Forte@Sun.COM 
3074*7836SJohn.Forte@Sun.COM 				pd2 = clist->clist_map[count2].map_pd;
3075*7836SJohn.Forte@Sun.COM 				if (pd2 == NULL) {
3076*7836SJohn.Forte@Sun.COM 					continue;
3077*7836SJohn.Forte@Sun.COM 				}
3078*7836SJohn.Forte@Sun.COM 
3079*7836SJohn.Forte@Sun.COM 				if (pd1 == pd2) {
3080*7836SJohn.Forte@Sun.COM 					clist->clist_map[count].map_flags |=
3081*7836SJohn.Forte@Sun.COM 					    PORT_DEVICE_DUPLICATE_MAP_ENTRY;
3082*7836SJohn.Forte@Sun.COM 					break;
3083*7836SJohn.Forte@Sun.COM 				}
3084*7836SJohn.Forte@Sun.COM 			}
3085*7836SJohn.Forte@Sun.COM 		}
3086*7836SJohn.Forte@Sun.COM 	}
3087*7836SJohn.Forte@Sun.COM 
3088*7836SJohn.Forte@Sun.COM 
3089*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
3090*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
3091*7836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
3092*7836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
3093*7836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
3094*7836SJohn.Forte@Sun.COM 
3095*7836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
3096*7836SJohn.Forte@Sun.COM 			continue;
3097*7836SJohn.Forte@Sun.COM 		}
3098*7836SJohn.Forte@Sun.COM 
3099*7836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
3100*7836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
3101*7836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
3102*7836SJohn.Forte@Sun.COM 			continue;
3103*7836SJohn.Forte@Sun.COM 		}
3104*7836SJohn.Forte@Sun.COM 
3105*7836SJohn.Forte@Sun.COM 		switch (ulp_port->port_statec) {
3106*7836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_DONT_CARE:
3107*7836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec != new_state) {
3108*7836SJohn.Forte@Sun.COM 				ulp_port->port_statec = new_state;
3109*7836SJohn.Forte@Sun.COM 			}
3110*7836SJohn.Forte@Sun.COM 			break;
3111*7836SJohn.Forte@Sun.COM 
3112*7836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_ONLINE:
3113*7836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_OFFLINE:
3114*7836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec == new_state) {
3115*7836SJohn.Forte@Sun.COM 				mutex_exit(&ulp_port->port_mutex);
3116*7836SJohn.Forte@Sun.COM 				continue;
3117*7836SJohn.Forte@Sun.COM 			}
3118*7836SJohn.Forte@Sun.COM 			ulp_port->port_statec = new_state;
3119*7836SJohn.Forte@Sun.COM 			break;
3120*7836SJohn.Forte@Sun.COM 
3121*7836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_OFFLINE_TIMEOUT:
3122*7836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec == new_state ||
3123*7836SJohn.Forte@Sun.COM 			    new_state == FC_ULP_STATEC_OFFLINE) {
3124*7836SJohn.Forte@Sun.COM 				mutex_exit(&ulp_port->port_mutex);
3125*7836SJohn.Forte@Sun.COM 				continue;
3126*7836SJohn.Forte@Sun.COM 			}
3127*7836SJohn.Forte@Sun.COM 			ulp_port->port_statec = new_state;
3128*7836SJohn.Forte@Sun.COM 			break;
3129*7836SJohn.Forte@Sun.COM 
3130*7836SJohn.Forte@Sun.COM 		default:
3131*7836SJohn.Forte@Sun.COM 			ASSERT(0);
3132*7836SJohn.Forte@Sun.COM 			break;
3133*7836SJohn.Forte@Sun.COM 		}
3134*7836SJohn.Forte@Sun.COM 
3135*7836SJohn.Forte@Sun.COM 		mod->mod_info->ulp_statec_callback(
3136*7836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, (opaque_t)port,
3137*7836SJohn.Forte@Sun.COM 		    clist->clist_state, clist->clist_flags,
3138*7836SJohn.Forte@Sun.COM 		    clist->clist_map, clist->clist_len, s_id);
3139*7836SJohn.Forte@Sun.COM 
3140*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
3141*7836SJohn.Forte@Sun.COM 	}
3142*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
3143*7836SJohn.Forte@Sun.COM 
3144*7836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
3145*7836SJohn.Forte@Sun.COM 		int 			count;
3146*7836SJohn.Forte@Sun.COM 		fc_remote_node_t	*node;
3147*7836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd;
3148*7836SJohn.Forte@Sun.COM 
3149*7836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
3150*7836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len; count++) {
3151*7836SJohn.Forte@Sun.COM 
3152*7836SJohn.Forte@Sun.COM 			if ((pd = clist->clist_map[count].map_pd) == NULL) {
3153*7836SJohn.Forte@Sun.COM 				continue;
3154*7836SJohn.Forte@Sun.COM 			}
3155*7836SJohn.Forte@Sun.COM 
3156*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
3157*7836SJohn.Forte@Sun.COM 
3158*7836SJohn.Forte@Sun.COM 			pd->pd_ref_count--;
3159*7836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
3160*7836SJohn.Forte@Sun.COM 
3161*7836SJohn.Forte@Sun.COM 			if (clist->clist_map[count].map_state !=
3162*7836SJohn.Forte@Sun.COM 			    PORT_DEVICE_INVALID) {
3163*7836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
3164*7836SJohn.Forte@Sun.COM 				continue;
3165*7836SJohn.Forte@Sun.COM 			}
3166*7836SJohn.Forte@Sun.COM 
3167*7836SJohn.Forte@Sun.COM 			node = pd->pd_remote_nodep;
3168*7836SJohn.Forte@Sun.COM 			pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS;
3169*7836SJohn.Forte@Sun.COM 
3170*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
3171*7836SJohn.Forte@Sun.COM 
3172*7836SJohn.Forte@Sun.COM 			/*
3173*7836SJohn.Forte@Sun.COM 			 * This fc_remote_port_t is no longer referenced
3174*7836SJohn.Forte@Sun.COM 			 * by any ULPs. Deallocate it if its pd_ref_count
3175*7836SJohn.Forte@Sun.COM 			 * has reached zero.
3176*7836SJohn.Forte@Sun.COM 			 */
3177*7836SJohn.Forte@Sun.COM 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
3178*7836SJohn.Forte@Sun.COM 			    (node != NULL)) {
3179*7836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
3180*7836SJohn.Forte@Sun.COM 			}
3181*7836SJohn.Forte@Sun.COM 		}
3182*7836SJohn.Forte@Sun.COM 
3183*7836SJohn.Forte@Sun.COM 		kmem_free(clist->clist_map,
3184*7836SJohn.Forte@Sun.COM 		    sizeof (*(clist->clist_map)) * clist->clist_size);
3185*7836SJohn.Forte@Sun.COM 	}
3186*7836SJohn.Forte@Sun.COM 
3187*7836SJohn.Forte@Sun.COM 	if (clist->clist_wait) {
3188*7836SJohn.Forte@Sun.COM 		mutex_enter(&clist->clist_mutex);
3189*7836SJohn.Forte@Sun.COM 		clist->clist_wait = 0;
3190*7836SJohn.Forte@Sun.COM 		cv_signal(&clist->clist_cv);
3191*7836SJohn.Forte@Sun.COM 		mutex_exit(&clist->clist_mutex);
3192*7836SJohn.Forte@Sun.COM 	} else {
3193*7836SJohn.Forte@Sun.COM 		kmem_free(clist, sizeof (*clist));
3194*7836SJohn.Forte@Sun.COM 	}
3195*7836SJohn.Forte@Sun.COM }
3196*7836SJohn.Forte@Sun.COM 
3197*7836SJohn.Forte@Sun.COM 
3198*7836SJohn.Forte@Sun.COM /*
3199*7836SJohn.Forte@Sun.COM  * Allocate an fc_remote_node_t struct to represent a remote node for the
3200*7836SJohn.Forte@Sun.COM  * given nwwn.  This will also add the nwwn to the global nwwn table.
3201*7836SJohn.Forte@Sun.COM  *
3202*7836SJohn.Forte@Sun.COM  * Returns a pointer to the newly-allocated struct.  Returns NULL if
3203*7836SJohn.Forte@Sun.COM  * the kmem_zalloc fails or if the enlist_wwn attempt fails.
3204*7836SJohn.Forte@Sun.COM  */
3205*7836SJohn.Forte@Sun.COM fc_remote_node_t *
3206*7836SJohn.Forte@Sun.COM fctl_create_remote_node(la_wwn_t *nwwn, int sleep)
3207*7836SJohn.Forte@Sun.COM {
3208*7836SJohn.Forte@Sun.COM 	fc_remote_node_t *rnodep;
3209*7836SJohn.Forte@Sun.COM 
3210*7836SJohn.Forte@Sun.COM 	if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
3211*7836SJohn.Forte@Sun.COM 		return (NULL);
3212*7836SJohn.Forte@Sun.COM 	}
3213*7836SJohn.Forte@Sun.COM 
3214*7836SJohn.Forte@Sun.COM 	mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
3215*7836SJohn.Forte@Sun.COM 
3216*7836SJohn.Forte@Sun.COM 	rnodep->fd_node_name = *nwwn;
3217*7836SJohn.Forte@Sun.COM 	rnodep->fd_flags = FC_REMOTE_NODE_VALID;
3218*7836SJohn.Forte@Sun.COM 	rnodep->fd_numports = 1;
3219*7836SJohn.Forte@Sun.COM 
3220*7836SJohn.Forte@Sun.COM 	if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
3221*7836SJohn.Forte@Sun.COM 		mutex_destroy(&rnodep->fd_mutex);
3222*7836SJohn.Forte@Sun.COM 		kmem_free(rnodep, sizeof (*rnodep));
3223*7836SJohn.Forte@Sun.COM 		return (NULL);
3224*7836SJohn.Forte@Sun.COM 	}
3225*7836SJohn.Forte@Sun.COM 
3226*7836SJohn.Forte@Sun.COM 	return (rnodep);
3227*7836SJohn.Forte@Sun.COM }
3228*7836SJohn.Forte@Sun.COM 
3229*7836SJohn.Forte@Sun.COM /*
3230*7836SJohn.Forte@Sun.COM  * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
3231*7836SJohn.Forte@Sun.COM  * Silently skips the deconstruct/free if there are any fc_remote_port_t
3232*7836SJohn.Forte@Sun.COM  * (remote port device) structs still referenced by the given
3233*7836SJohn.Forte@Sun.COM  * fc_remote_node_t struct.
3234*7836SJohn.Forte@Sun.COM  */
3235*7836SJohn.Forte@Sun.COM void
3236*7836SJohn.Forte@Sun.COM fctl_destroy_remote_node(fc_remote_node_t *rnodep)
3237*7836SJohn.Forte@Sun.COM {
3238*7836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
3239*7836SJohn.Forte@Sun.COM 
3240*7836SJohn.Forte@Sun.COM 	/*
3241*7836SJohn.Forte@Sun.COM 	 * Look at the count and linked list of of remote ports
3242*7836SJohn.Forte@Sun.COM 	 * (fc_remote_port_t structs); bail if these indicate that
3243*7836SJohn.Forte@Sun.COM 	 * given fc_remote_node_t may be in use.
3244*7836SJohn.Forte@Sun.COM 	 */
3245*7836SJohn.Forte@Sun.COM 	if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
3246*7836SJohn.Forte@Sun.COM 		mutex_exit(&rnodep->fd_mutex);
3247*7836SJohn.Forte@Sun.COM 		return;
3248*7836SJohn.Forte@Sun.COM 	}
3249*7836SJohn.Forte@Sun.COM 
3250*7836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
3251*7836SJohn.Forte@Sun.COM 
3252*7836SJohn.Forte@Sun.COM 	mutex_destroy(&rnodep->fd_mutex);
3253*7836SJohn.Forte@Sun.COM 	kmem_free(rnodep, sizeof (*rnodep));
3254*7836SJohn.Forte@Sun.COM }
3255*7836SJohn.Forte@Sun.COM 
3256*7836SJohn.Forte@Sun.COM 
3257*7836SJohn.Forte@Sun.COM /*
3258*7836SJohn.Forte@Sun.COM  * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
3259*7836SJohn.Forte@Sun.COM  * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3260*7836SJohn.Forte@Sun.COM  * This only fails if the kmem_zalloc fails.  This does not check for a
3261*7836SJohn.Forte@Sun.COM  * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
3262*7836SJohn.Forte@Sun.COM  * This is only called from fctl_create_remote_node().
3263*7836SJohn.Forte@Sun.COM  */
3264*7836SJohn.Forte@Sun.COM int
3265*7836SJohn.Forte@Sun.COM fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
3266*7836SJohn.Forte@Sun.COM {
3267*7836SJohn.Forte@Sun.COM 	int 			index;
3268*7836SJohn.Forte@Sun.COM 	fctl_nwwn_elem_t 	*new;
3269*7836SJohn.Forte@Sun.COM 	fctl_nwwn_list_t 	*head;
3270*7836SJohn.Forte@Sun.COM 
3271*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3272*7836SJohn.Forte@Sun.COM 
3273*7836SJohn.Forte@Sun.COM 	if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
3274*7836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
3275*7836SJohn.Forte@Sun.COM 	}
3276*7836SJohn.Forte@Sun.COM 
3277*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
3278*7836SJohn.Forte@Sun.COM 	new->fne_nodep = rnodep;
3279*7836SJohn.Forte@Sun.COM 
3280*7836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
3281*7836SJohn.Forte@Sun.COM 	ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
3282*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3283*7836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
3284*7836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
3285*7836SJohn.Forte@Sun.COM 
3286*7836SJohn.Forte@Sun.COM 	head = &fctl_nwwn_hash_table[index];
3287*7836SJohn.Forte@Sun.COM 
3288*7836SJohn.Forte@Sun.COM 	/* Link it in at the head of the hash list */
3289*7836SJohn.Forte@Sun.COM 	new->fne_nextp = head->fnl_headp;
3290*7836SJohn.Forte@Sun.COM 	head->fnl_headp = new;
3291*7836SJohn.Forte@Sun.COM 
3292*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
3293*7836SJohn.Forte@Sun.COM 
3294*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
3295*7836SJohn.Forte@Sun.COM }
3296*7836SJohn.Forte@Sun.COM 
3297*7836SJohn.Forte@Sun.COM 
3298*7836SJohn.Forte@Sun.COM /*
3299*7836SJohn.Forte@Sun.COM  * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
3300*7836SJohn.Forte@Sun.COM  * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3301*7836SJohn.Forte@Sun.COM  */
3302*7836SJohn.Forte@Sun.COM void
3303*7836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
3304*7836SJohn.Forte@Sun.COM {
3305*7836SJohn.Forte@Sun.COM 	int 			index;
3306*7836SJohn.Forte@Sun.COM 	fctl_nwwn_list_t 	*head;
3307*7836SJohn.Forte@Sun.COM 	fctl_nwwn_elem_t 	*elem;
3308*7836SJohn.Forte@Sun.COM 	fctl_nwwn_elem_t 	*prev;
3309*7836SJohn.Forte@Sun.COM 
3310*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
3311*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
3312*7836SJohn.Forte@Sun.COM 
3313*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3314*7836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
3315*7836SJohn.Forte@Sun.COM 
3316*7836SJohn.Forte@Sun.COM 	head = &fctl_nwwn_hash_table[index];
3317*7836SJohn.Forte@Sun.COM 	elem = head->fnl_headp;
3318*7836SJohn.Forte@Sun.COM 	prev = NULL;
3319*7836SJohn.Forte@Sun.COM 
3320*7836SJohn.Forte@Sun.COM 	while (elem != NULL) {
3321*7836SJohn.Forte@Sun.COM 		if (elem->fne_nodep == rnodep) {
3322*7836SJohn.Forte@Sun.COM 			/*
3323*7836SJohn.Forte@Sun.COM 			 * Found it -- unlink it from the list & decrement
3324*7836SJohn.Forte@Sun.COM 			 * the count for the hash chain.
3325*7836SJohn.Forte@Sun.COM 			 */
3326*7836SJohn.Forte@Sun.COM 			if (prev == NULL) {
3327*7836SJohn.Forte@Sun.COM 				head->fnl_headp = elem->fne_nextp;
3328*7836SJohn.Forte@Sun.COM 			} else {
3329*7836SJohn.Forte@Sun.COM 				prev->fne_nextp = elem->fne_nextp;
3330*7836SJohn.Forte@Sun.COM 			}
3331*7836SJohn.Forte@Sun.COM 			break;
3332*7836SJohn.Forte@Sun.COM 		}
3333*7836SJohn.Forte@Sun.COM 		prev = elem;
3334*7836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
3335*7836SJohn.Forte@Sun.COM 	}
3336*7836SJohn.Forte@Sun.COM 
3337*7836SJohn.Forte@Sun.COM 	if (elem != NULL) {
3338*7836SJohn.Forte@Sun.COM 		kmem_free(elem, sizeof (*elem));
3339*7836SJohn.Forte@Sun.COM 	}
3340*7836SJohn.Forte@Sun.COM }
3341*7836SJohn.Forte@Sun.COM 
3342*7836SJohn.Forte@Sun.COM 
3343*7836SJohn.Forte@Sun.COM /*
3344*7836SJohn.Forte@Sun.COM  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3345*7836SJohn.Forte@Sun.COM  * Looks in the global fctl_nwwn_hash_table[]. Identical to the
3346*7836SJohn.Forte@Sun.COM  * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
3347*7836SJohn.Forte@Sun.COM  * the fc_count reference count in the f_device_t before returning.
3348*7836SJohn.Forte@Sun.COM  *
3349*7836SJohn.Forte@Sun.COM  * This function is called by: fctl_create_remote_port_t().
3350*7836SJohn.Forte@Sun.COM  *
3351*7836SJohn.Forte@Sun.COM  * OLD COMMENT:
3352*7836SJohn.Forte@Sun.COM  * Note: The calling thread needs to make sure it isn't holding any device
3353*7836SJohn.Forte@Sun.COM  * mutex (more so the fc_remote_node_t that could potentially have this wwn).
3354*7836SJohn.Forte@Sun.COM  */
3355*7836SJohn.Forte@Sun.COM fc_remote_node_t *
3356*7836SJohn.Forte@Sun.COM fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
3357*7836SJohn.Forte@Sun.COM {
3358*7836SJohn.Forte@Sun.COM 	int 			index;
3359*7836SJohn.Forte@Sun.COM 	fctl_nwwn_elem_t 	*elem;
3360*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*next;
3361*7836SJohn.Forte@Sun.COM 	fc_remote_node_t 	*rnodep = NULL;
3362*7836SJohn.Forte@Sun.COM 
3363*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3364*7836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
3365*7836SJohn.Forte@Sun.COM 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3366*7836SJohn.Forte@Sun.COM 
3367*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
3368*7836SJohn.Forte@Sun.COM 	elem = fctl_nwwn_hash_table[index].fnl_headp;
3369*7836SJohn.Forte@Sun.COM 	while (elem != NULL) {
3370*7836SJohn.Forte@Sun.COM 		next = elem->fne_nodep;
3371*7836SJohn.Forte@Sun.COM 		if (next != NULL) {
3372*7836SJohn.Forte@Sun.COM 			mutex_enter(&next->fd_mutex);
3373*7836SJohn.Forte@Sun.COM 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3374*7836SJohn.Forte@Sun.COM 				rnodep = next;
3375*7836SJohn.Forte@Sun.COM 				mutex_exit(&next->fd_mutex);
3376*7836SJohn.Forte@Sun.COM 				break;
3377*7836SJohn.Forte@Sun.COM 			}
3378*7836SJohn.Forte@Sun.COM 			mutex_exit(&next->fd_mutex);
3379*7836SJohn.Forte@Sun.COM 		}
3380*7836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
3381*7836SJohn.Forte@Sun.COM 	}
3382*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
3383*7836SJohn.Forte@Sun.COM 
3384*7836SJohn.Forte@Sun.COM 	return (rnodep);
3385*7836SJohn.Forte@Sun.COM }
3386*7836SJohn.Forte@Sun.COM 
3387*7836SJohn.Forte@Sun.COM 
3388*7836SJohn.Forte@Sun.COM /*
3389*7836SJohn.Forte@Sun.COM  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3390*7836SJohn.Forte@Sun.COM  * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
3391*7836SJohn.Forte@Sun.COM  * reference count in the f_device_t before returning.
3392*7836SJohn.Forte@Sun.COM  *
3393*7836SJohn.Forte@Sun.COM  * This function is only called by fctl_create_remote_port_t().
3394*7836SJohn.Forte@Sun.COM  */
3395*7836SJohn.Forte@Sun.COM fc_remote_node_t *
3396*7836SJohn.Forte@Sun.COM fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
3397*7836SJohn.Forte@Sun.COM {
3398*7836SJohn.Forte@Sun.COM 	int 			index;
3399*7836SJohn.Forte@Sun.COM 	fctl_nwwn_elem_t 	*elem;
3400*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*next;
3401*7836SJohn.Forte@Sun.COM 	fc_remote_node_t 	*rnodep = NULL;
3402*7836SJohn.Forte@Sun.COM 
3403*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3404*7836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
3405*7836SJohn.Forte@Sun.COM 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3406*7836SJohn.Forte@Sun.COM 
3407*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
3408*7836SJohn.Forte@Sun.COM 	elem = fctl_nwwn_hash_table[index].fnl_headp;
3409*7836SJohn.Forte@Sun.COM 	while (elem != NULL) {
3410*7836SJohn.Forte@Sun.COM 		next = elem->fne_nodep;
3411*7836SJohn.Forte@Sun.COM 		if (next != NULL) {
3412*7836SJohn.Forte@Sun.COM 			mutex_enter(&next->fd_mutex);
3413*7836SJohn.Forte@Sun.COM 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3414*7836SJohn.Forte@Sun.COM 				rnodep = next;
3415*7836SJohn.Forte@Sun.COM 				rnodep->fd_numports++;
3416*7836SJohn.Forte@Sun.COM 				mutex_exit(&next->fd_mutex);
3417*7836SJohn.Forte@Sun.COM 				break;
3418*7836SJohn.Forte@Sun.COM 			}
3419*7836SJohn.Forte@Sun.COM 			mutex_exit(&next->fd_mutex);
3420*7836SJohn.Forte@Sun.COM 		}
3421*7836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
3422*7836SJohn.Forte@Sun.COM 	}
3423*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
3424*7836SJohn.Forte@Sun.COM 
3425*7836SJohn.Forte@Sun.COM 	return (rnodep);
3426*7836SJohn.Forte@Sun.COM }
3427*7836SJohn.Forte@Sun.COM 
3428*7836SJohn.Forte@Sun.COM 
3429*7836SJohn.Forte@Sun.COM /*
3430*7836SJohn.Forte@Sun.COM  * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
3431*7836SJohn.Forte@Sun.COM  * the newly allocated struct.  Only fails if the kmem_zalloc() fails.
3432*7836SJohn.Forte@Sun.COM  */
3433*7836SJohn.Forte@Sun.COM fc_remote_port_t *
3434*7836SJohn.Forte@Sun.COM fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
3435*7836SJohn.Forte@Sun.COM     uint32_t d_id, uchar_t recepient, int sleep)
3436*7836SJohn.Forte@Sun.COM {
3437*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
3438*7836SJohn.Forte@Sun.COM 
3439*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3440*7836SJohn.Forte@Sun.COM 	ASSERT(FC_IS_REAL_DEVICE(d_id));
3441*7836SJohn.Forte@Sun.COM 
3442*7836SJohn.Forte@Sun.COM 	if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
3443*7836SJohn.Forte@Sun.COM 		return (NULL);
3444*7836SJohn.Forte@Sun.COM 	}
3445*7836SJohn.Forte@Sun.COM 	fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
3446*7836SJohn.Forte@Sun.COM 	    FC_LOGO_TOLERANCE_TIME_LIMIT);
3447*7836SJohn.Forte@Sun.COM 
3448*7836SJohn.Forte@Sun.COM 	mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
3449*7836SJohn.Forte@Sun.COM 
3450*7836SJohn.Forte@Sun.COM 	pd->pd_port_id.port_id = d_id;
3451*7836SJohn.Forte@Sun.COM 	pd->pd_port_name = *port_wwn;
3452*7836SJohn.Forte@Sun.COM 	pd->pd_port = port;
3453*7836SJohn.Forte@Sun.COM 	pd->pd_state = PORT_DEVICE_VALID;
3454*7836SJohn.Forte@Sun.COM 	pd->pd_type = PORT_DEVICE_NEW;
3455*7836SJohn.Forte@Sun.COM 	pd->pd_recepient = recepient;
3456*7836SJohn.Forte@Sun.COM 
3457*7836SJohn.Forte@Sun.COM 	return (pd);
3458*7836SJohn.Forte@Sun.COM }
3459*7836SJohn.Forte@Sun.COM 
3460*7836SJohn.Forte@Sun.COM 
3461*7836SJohn.Forte@Sun.COM /*
3462*7836SJohn.Forte@Sun.COM  * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
3463*7836SJohn.Forte@Sun.COM  */
3464*7836SJohn.Forte@Sun.COM void
3465*7836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(fc_remote_port_t *pd)
3466*7836SJohn.Forte@Sun.COM {
3467*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3468*7836SJohn.Forte@Sun.COM 
3469*7836SJohn.Forte@Sun.COM 	fctl_tc_destructor(&pd->pd_logo_tc);
3470*7836SJohn.Forte@Sun.COM 	mutex_destroy(&pd->pd_mutex);
3471*7836SJohn.Forte@Sun.COM 	kmem_free(pd, sizeof (*pd));
3472*7836SJohn.Forte@Sun.COM }
3473*7836SJohn.Forte@Sun.COM 
3474*7836SJohn.Forte@Sun.COM /*
3475*7836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t onto the linked list of remote port
3476*7836SJohn.Forte@Sun.COM  * devices associated with the given fc_remote_node_t. Does NOT add the
3477*7836SJohn.Forte@Sun.COM  * fc_remote_port_t to the list if already exists on the list.
3478*7836SJohn.Forte@Sun.COM  */
3479*7836SJohn.Forte@Sun.COM void
3480*7836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
3481*7836SJohn.Forte@Sun.COM     fc_remote_port_t *pd)
3482*7836SJohn.Forte@Sun.COM {
3483*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *last;
3484*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *ports;
3485*7836SJohn.Forte@Sun.COM 
3486*7836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
3487*7836SJohn.Forte@Sun.COM 
3488*7836SJohn.Forte@Sun.COM 	last = NULL;
3489*7836SJohn.Forte@Sun.COM 	for (ports = rnodep->fd_portlistp; ports != NULL;
3490*7836SJohn.Forte@Sun.COM 	    ports = ports->pd_port_next) {
3491*7836SJohn.Forte@Sun.COM 		if (ports == pd) {
3492*7836SJohn.Forte@Sun.COM 			/*
3493*7836SJohn.Forte@Sun.COM 			 * The given fc_remote_port_t is already on the linked
3494*7836SJohn.Forte@Sun.COM 			 * list chain for the given remote node, so bail now.
3495*7836SJohn.Forte@Sun.COM 			 */
3496*7836SJohn.Forte@Sun.COM 			mutex_exit(&rnodep->fd_mutex);
3497*7836SJohn.Forte@Sun.COM 			return;
3498*7836SJohn.Forte@Sun.COM 		}
3499*7836SJohn.Forte@Sun.COM 		last = ports;
3500*7836SJohn.Forte@Sun.COM 	}
3501*7836SJohn.Forte@Sun.COM 
3502*7836SJohn.Forte@Sun.COM 	/* Add the fc_remote_port_t to the tail of the linked list */
3503*7836SJohn.Forte@Sun.COM 	if (last != NULL) {
3504*7836SJohn.Forte@Sun.COM 		last->pd_port_next = pd;
3505*7836SJohn.Forte@Sun.COM 	} else {
3506*7836SJohn.Forte@Sun.COM 		rnodep->fd_portlistp = pd;
3507*7836SJohn.Forte@Sun.COM 	}
3508*7836SJohn.Forte@Sun.COM 	pd->pd_port_next = NULL;
3509*7836SJohn.Forte@Sun.COM 
3510*7836SJohn.Forte@Sun.COM 	/*
3511*7836SJohn.Forte@Sun.COM 	 * Link the fc_remote_port_t back to the associated fc_remote_node_t.
3512*7836SJohn.Forte@Sun.COM 	 */
3513*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
3514*7836SJohn.Forte@Sun.COM 	pd->pd_remote_nodep = rnodep;
3515*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
3516*7836SJohn.Forte@Sun.COM 
3517*7836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
3518*7836SJohn.Forte@Sun.COM }
3519*7836SJohn.Forte@Sun.COM 
3520*7836SJohn.Forte@Sun.COM 
3521*7836SJohn.Forte@Sun.COM /*
3522*7836SJohn.Forte@Sun.COM  * Remove the specified fc_remote_port_t from the linked list of remote ports
3523*7836SJohn.Forte@Sun.COM  * for the given fc_remote_node_t.
3524*7836SJohn.Forte@Sun.COM  *
3525*7836SJohn.Forte@Sun.COM  * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
3526*7836SJohn.Forte@Sun.COM  * list of the fc_remote_node_t.
3527*7836SJohn.Forte@Sun.COM  *
3528*7836SJohn.Forte@Sun.COM  * The fd_numports on the given fc_remote_node_t is decremented, and if
3529*7836SJohn.Forte@Sun.COM  * it hits zero then this function also removes the fc_remote_node_t from the
3530*7836SJohn.Forte@Sun.COM  * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
3531*7836SJohn.Forte@Sun.COM  * are removed from the fctl_nwwn_hash_table[].
3532*7836SJohn.Forte@Sun.COM  */
3533*7836SJohn.Forte@Sun.COM int
3534*7836SJohn.Forte@Sun.COM fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
3535*7836SJohn.Forte@Sun.COM     fc_remote_port_t *pd)
3536*7836SJohn.Forte@Sun.COM {
3537*7836SJohn.Forte@Sun.COM 	int			rcount = 0;
3538*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*last;
3539*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*ports;
3540*7836SJohn.Forte@Sun.COM 
3541*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3542*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3543*7836SJohn.Forte@Sun.COM 
3544*7836SJohn.Forte@Sun.COM 	last = NULL;
3545*7836SJohn.Forte@Sun.COM 
3546*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
3547*7836SJohn.Forte@Sun.COM 
3548*7836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
3549*7836SJohn.Forte@Sun.COM 
3550*7836SJohn.Forte@Sun.COM 	/*
3551*7836SJohn.Forte@Sun.COM 	 * Go thru the linked list of fc_remote_port_t structs for the given
3552*7836SJohn.Forte@Sun.COM 	 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
3553*7836SJohn.Forte@Sun.COM 	 */
3554*7836SJohn.Forte@Sun.COM 	ports = rnodep->fd_portlistp;
3555*7836SJohn.Forte@Sun.COM 	while (ports != NULL) {
3556*7836SJohn.Forte@Sun.COM 		if (ports == pd) {
3557*7836SJohn.Forte@Sun.COM 			break;	/* Found the requested fc_remote_port_t */
3558*7836SJohn.Forte@Sun.COM 		}
3559*7836SJohn.Forte@Sun.COM 		last = ports;
3560*7836SJohn.Forte@Sun.COM 		ports = ports->pd_port_next;
3561*7836SJohn.Forte@Sun.COM 	}
3562*7836SJohn.Forte@Sun.COM 
3563*7836SJohn.Forte@Sun.COM 	if (ports) {
3564*7836SJohn.Forte@Sun.COM 		rcount = --rnodep->fd_numports;
3565*7836SJohn.Forte@Sun.COM 		if (rcount == 0) {
3566*7836SJohn.Forte@Sun.COM 			/* Note: this is only ever called from here */
3567*7836SJohn.Forte@Sun.COM 			fctl_delist_nwwn_table(rnodep);
3568*7836SJohn.Forte@Sun.COM 		}
3569*7836SJohn.Forte@Sun.COM 		if (last) {
3570*7836SJohn.Forte@Sun.COM 			last->pd_port_next = pd->pd_port_next;
3571*7836SJohn.Forte@Sun.COM 		} else {
3572*7836SJohn.Forte@Sun.COM 			rnodep->fd_portlistp = pd->pd_port_next;
3573*7836SJohn.Forte@Sun.COM 		}
3574*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
3575*7836SJohn.Forte@Sun.COM 		pd->pd_remote_nodep = NULL;
3576*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
3577*7836SJohn.Forte@Sun.COM 	}
3578*7836SJohn.Forte@Sun.COM 
3579*7836SJohn.Forte@Sun.COM 	pd->pd_port_next = NULL;
3580*7836SJohn.Forte@Sun.COM 
3581*7836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
3582*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
3583*7836SJohn.Forte@Sun.COM 
3584*7836SJohn.Forte@Sun.COM 	return (rcount);
3585*7836SJohn.Forte@Sun.COM }
3586*7836SJohn.Forte@Sun.COM 
3587*7836SJohn.Forte@Sun.COM 
3588*7836SJohn.Forte@Sun.COM /*
3589*7836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t struct to the d_id table in the given
3590*7836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
3591*7836SJohn.Forte@Sun.COM  * fc_remote_port_t.
3592*7836SJohn.Forte@Sun.COM  *
3593*7836SJohn.Forte@Sun.COM  * No memory allocs are required, so this never fails, but it does use the
3594*7836SJohn.Forte@Sun.COM  * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
3595*7836SJohn.Forte@Sun.COM  * (There does not seem to be a way to tell the caller that a duplicate
3596*7836SJohn.Forte@Sun.COM  * exists.)
3597*7836SJohn.Forte@Sun.COM  */
3598*7836SJohn.Forte@Sun.COM void
3599*7836SJohn.Forte@Sun.COM fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3600*7836SJohn.Forte@Sun.COM {
3601*7836SJohn.Forte@Sun.COM 	struct d_id_hash *head;
3602*7836SJohn.Forte@Sun.COM 
3603*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3604*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
3605*7836SJohn.Forte@Sun.COM 
3606*7836SJohn.Forte@Sun.COM 	if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
3607*7836SJohn.Forte@Sun.COM 		return;
3608*7836SJohn.Forte@Sun.COM 	}
3609*7836SJohn.Forte@Sun.COM 
3610*7836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id,
3611*7836SJohn.Forte@Sun.COM 	    did_table_size)];
3612*7836SJohn.Forte@Sun.COM 
3613*7836SJohn.Forte@Sun.COM #ifdef	DEBUG
3614*7836SJohn.Forte@Sun.COM 	{
3615*7836SJohn.Forte@Sun.COM 		int			index;
3616*7836SJohn.Forte@Sun.COM 		fc_remote_port_t 	*tmp_pd;
3617*7836SJohn.Forte@Sun.COM 		struct d_id_hash	*tmp_head;
3618*7836SJohn.Forte@Sun.COM 
3619*7836SJohn.Forte@Sun.COM 		/*
3620*7836SJohn.Forte@Sun.COM 		 * Search down in each bucket for a duplicate pd
3621*7836SJohn.Forte@Sun.COM 		 * Also search for duplicate D_IDs
3622*7836SJohn.Forte@Sun.COM 		 * This DEBUG code will force an ASSERT if a duplicate
3623*7836SJohn.Forte@Sun.COM 		 * is ever found.
3624*7836SJohn.Forte@Sun.COM 		 */
3625*7836SJohn.Forte@Sun.COM 		for (index = 0; index < did_table_size; index++) {
3626*7836SJohn.Forte@Sun.COM 			tmp_head = &port->fp_did_table[index];
3627*7836SJohn.Forte@Sun.COM 
3628*7836SJohn.Forte@Sun.COM 			tmp_pd = tmp_head->d_id_head;
3629*7836SJohn.Forte@Sun.COM 			while (tmp_pd != NULL) {
3630*7836SJohn.Forte@Sun.COM 				ASSERT(tmp_pd != pd);
3631*7836SJohn.Forte@Sun.COM 
3632*7836SJohn.Forte@Sun.COM 				if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3633*7836SJohn.Forte@Sun.COM 				    tmp_pd->pd_type != PORT_DEVICE_OLD) {
3634*7836SJohn.Forte@Sun.COM 					ASSERT(tmp_pd->pd_port_id.port_id !=
3635*7836SJohn.Forte@Sun.COM 					    pd->pd_port_id.port_id);
3636*7836SJohn.Forte@Sun.COM 				}
3637*7836SJohn.Forte@Sun.COM 
3638*7836SJohn.Forte@Sun.COM 				tmp_pd = tmp_pd->pd_did_hnext;
3639*7836SJohn.Forte@Sun.COM 			}
3640*7836SJohn.Forte@Sun.COM 		}
3641*7836SJohn.Forte@Sun.COM 	}
3642*7836SJohn.Forte@Sun.COM 
3643*7836SJohn.Forte@Sun.COM 	bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack));
3644*7836SJohn.Forte@Sun.COM 	pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH);
3645*7836SJohn.Forte@Sun.COM #endif
3646*7836SJohn.Forte@Sun.COM 
3647*7836SJohn.Forte@Sun.COM 	pd->pd_did_hnext = head->d_id_head;
3648*7836SJohn.Forte@Sun.COM 	head->d_id_head = pd;
3649*7836SJohn.Forte@Sun.COM 
3650*7836SJohn.Forte@Sun.COM 	pd->pd_aux_flags |= PD_IN_DID_QUEUE;
3651*7836SJohn.Forte@Sun.COM 	head->d_id_count++;
3652*7836SJohn.Forte@Sun.COM }
3653*7836SJohn.Forte@Sun.COM 
3654*7836SJohn.Forte@Sun.COM 
3655*7836SJohn.Forte@Sun.COM /*
3656*7836SJohn.Forte@Sun.COM  * Remove the given fc_remote_port_t struct from the d_id table in the given
3657*7836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
3658*7836SJohn.Forte@Sun.COM  * fc_remote_port_t.
3659*7836SJohn.Forte@Sun.COM  *
3660*7836SJohn.Forte@Sun.COM  * Does nothing if the requested fc_remote_port_t was not found.
3661*7836SJohn.Forte@Sun.COM  */
3662*7836SJohn.Forte@Sun.COM void
3663*7836SJohn.Forte@Sun.COM fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3664*7836SJohn.Forte@Sun.COM {
3665*7836SJohn.Forte@Sun.COM 	uint32_t		d_id;
3666*7836SJohn.Forte@Sun.COM 	struct d_id_hash 	*head;
3667*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd_next;
3668*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*last;
3669*7836SJohn.Forte@Sun.COM 
3670*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3671*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
3672*7836SJohn.Forte@Sun.COM 
3673*7836SJohn.Forte@Sun.COM 	d_id = pd->pd_port_id.port_id;
3674*7836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3675*7836SJohn.Forte@Sun.COM 
3676*7836SJohn.Forte@Sun.COM 	pd_next = head->d_id_head;
3677*7836SJohn.Forte@Sun.COM 	last = NULL;
3678*7836SJohn.Forte@Sun.COM 	while (pd_next != NULL) {
3679*7836SJohn.Forte@Sun.COM 		if (pd == pd_next) {
3680*7836SJohn.Forte@Sun.COM 			break;	/* Found the given fc_remote_port_t */
3681*7836SJohn.Forte@Sun.COM 		}
3682*7836SJohn.Forte@Sun.COM 		last = pd_next;
3683*7836SJohn.Forte@Sun.COM 		pd_next = pd_next->pd_did_hnext;
3684*7836SJohn.Forte@Sun.COM 	}
3685*7836SJohn.Forte@Sun.COM 
3686*7836SJohn.Forte@Sun.COM 	if (pd_next) {
3687*7836SJohn.Forte@Sun.COM 		/*
3688*7836SJohn.Forte@Sun.COM 		 * Found the given fc_remote_port_t; now remove it from the
3689*7836SJohn.Forte@Sun.COM 		 * d_id list.
3690*7836SJohn.Forte@Sun.COM 		 */
3691*7836SJohn.Forte@Sun.COM 		head->d_id_count--;
3692*7836SJohn.Forte@Sun.COM 		if (last == NULL) {
3693*7836SJohn.Forte@Sun.COM 			head->d_id_head = pd->pd_did_hnext;
3694*7836SJohn.Forte@Sun.COM 		} else {
3695*7836SJohn.Forte@Sun.COM 			last->pd_did_hnext = pd->pd_did_hnext;
3696*7836SJohn.Forte@Sun.COM 		}
3697*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
3698*7836SJohn.Forte@Sun.COM 		pd->pd_did_hnext = NULL;
3699*7836SJohn.Forte@Sun.COM 	}
3700*7836SJohn.Forte@Sun.COM }
3701*7836SJohn.Forte@Sun.COM 
3702*7836SJohn.Forte@Sun.COM 
3703*7836SJohn.Forte@Sun.COM /*
3704*7836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t struct to the pwwn table in the given
3705*7836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
3706*7836SJohn.Forte@Sun.COM  * in the fc_remote_port_t.
3707*7836SJohn.Forte@Sun.COM  *
3708*7836SJohn.Forte@Sun.COM  * No memory allocs are required, so this never fails.
3709*7836SJohn.Forte@Sun.COM  */
3710*7836SJohn.Forte@Sun.COM void
3711*7836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3712*7836SJohn.Forte@Sun.COM {
3713*7836SJohn.Forte@Sun.COM 	int index;
3714*7836SJohn.Forte@Sun.COM 	struct pwwn_hash *head;
3715*7836SJohn.Forte@Sun.COM 
3716*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3717*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
3718*7836SJohn.Forte@Sun.COM 
3719*7836SJohn.Forte@Sun.COM 	ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE);
3720*7836SJohn.Forte@Sun.COM 
3721*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn),
3722*7836SJohn.Forte@Sun.COM 	    pwwn_table_size);
3723*7836SJohn.Forte@Sun.COM 
3724*7836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
3725*7836SJohn.Forte@Sun.COM 
3726*7836SJohn.Forte@Sun.COM #ifdef	DEBUG
3727*7836SJohn.Forte@Sun.COM 	{
3728*7836SJohn.Forte@Sun.COM 		int			index;
3729*7836SJohn.Forte@Sun.COM 		fc_remote_port_t 	*tmp_pd;
3730*7836SJohn.Forte@Sun.COM 		struct pwwn_hash	*tmp_head;
3731*7836SJohn.Forte@Sun.COM 
3732*7836SJohn.Forte@Sun.COM 		/*
3733*7836SJohn.Forte@Sun.COM 		 * Search down in each bucket for a duplicate pd
3734*7836SJohn.Forte@Sun.COM 		 * Search also for a duplicate WWN
3735*7836SJohn.Forte@Sun.COM 		 * Throw an ASSERT if any duplicate is found.
3736*7836SJohn.Forte@Sun.COM 		 */
3737*7836SJohn.Forte@Sun.COM 		for (index = 0; index < pwwn_table_size; index++) {
3738*7836SJohn.Forte@Sun.COM 			tmp_head = &port->fp_pwwn_table[index];
3739*7836SJohn.Forte@Sun.COM 
3740*7836SJohn.Forte@Sun.COM 			tmp_pd = tmp_head->pwwn_head;
3741*7836SJohn.Forte@Sun.COM 			while (tmp_pd != NULL) {
3742*7836SJohn.Forte@Sun.COM 				ASSERT(tmp_pd != pd);
3743*7836SJohn.Forte@Sun.COM 
3744*7836SJohn.Forte@Sun.COM 				if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3745*7836SJohn.Forte@Sun.COM 				    tmp_pd->pd_type != PORT_DEVICE_OLD) {
3746*7836SJohn.Forte@Sun.COM 					ASSERT(fctl_wwn_cmp(
3747*7836SJohn.Forte@Sun.COM 					    &tmp_pd->pd_port_name,
3748*7836SJohn.Forte@Sun.COM 					    &pd->pd_port_name) != 0);
3749*7836SJohn.Forte@Sun.COM 				}
3750*7836SJohn.Forte@Sun.COM 
3751*7836SJohn.Forte@Sun.COM 				tmp_pd = tmp_pd->pd_wwn_hnext;
3752*7836SJohn.Forte@Sun.COM 			}
3753*7836SJohn.Forte@Sun.COM 		}
3754*7836SJohn.Forte@Sun.COM 	}
3755*7836SJohn.Forte@Sun.COM 
3756*7836SJohn.Forte@Sun.COM 	bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack));
3757*7836SJohn.Forte@Sun.COM 	pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH);
3758*7836SJohn.Forte@Sun.COM #endif /* DEBUG */
3759*7836SJohn.Forte@Sun.COM 
3760*7836SJohn.Forte@Sun.COM 	pd->pd_wwn_hnext = head->pwwn_head;
3761*7836SJohn.Forte@Sun.COM 	head->pwwn_head = pd;
3762*7836SJohn.Forte@Sun.COM 
3763*7836SJohn.Forte@Sun.COM 	head->pwwn_count++;
3764*7836SJohn.Forte@Sun.COM 	/*
3765*7836SJohn.Forte@Sun.COM 	 * Make sure we tie fp_dev_count to the size of the
3766*7836SJohn.Forte@Sun.COM 	 * pwwn_table
3767*7836SJohn.Forte@Sun.COM 	 */
3768*7836SJohn.Forte@Sun.COM 	port->fp_dev_count++;
3769*7836SJohn.Forte@Sun.COM }
3770*7836SJohn.Forte@Sun.COM 
3771*7836SJohn.Forte@Sun.COM 
3772*7836SJohn.Forte@Sun.COM /*
3773*7836SJohn.Forte@Sun.COM  * Remove the given fc_remote_port_t struct from the pwwn table in the given
3774*7836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
3775*7836SJohn.Forte@Sun.COM  * in the fc_remote_port_t.
3776*7836SJohn.Forte@Sun.COM  *
3777*7836SJohn.Forte@Sun.COM  * Does nothing if the requested fc_remote_port_t was not found.
3778*7836SJohn.Forte@Sun.COM  */
3779*7836SJohn.Forte@Sun.COM void
3780*7836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3781*7836SJohn.Forte@Sun.COM {
3782*7836SJohn.Forte@Sun.COM 	int			index;
3783*7836SJohn.Forte@Sun.COM 	la_wwn_t		pwwn;
3784*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
3785*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd_next;
3786*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*last;
3787*7836SJohn.Forte@Sun.COM 
3788*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3789*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
3790*7836SJohn.Forte@Sun.COM 
3791*7836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
3792*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size);
3793*7836SJohn.Forte@Sun.COM 
3794*7836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
3795*7836SJohn.Forte@Sun.COM 
3796*7836SJohn.Forte@Sun.COM 	last = NULL;
3797*7836SJohn.Forte@Sun.COM 	pd_next = head->pwwn_head;
3798*7836SJohn.Forte@Sun.COM 	while (pd_next != NULL) {
3799*7836SJohn.Forte@Sun.COM 		if (pd_next == pd) {
3800*7836SJohn.Forte@Sun.COM 			break;	/* Found the given fc_remote_port_t */
3801*7836SJohn.Forte@Sun.COM 		}
3802*7836SJohn.Forte@Sun.COM 		last = pd_next;
3803*7836SJohn.Forte@Sun.COM 		pd_next = pd_next->pd_wwn_hnext;
3804*7836SJohn.Forte@Sun.COM 	}
3805*7836SJohn.Forte@Sun.COM 
3806*7836SJohn.Forte@Sun.COM 	if (pd_next) {
3807*7836SJohn.Forte@Sun.COM 		/*
3808*7836SJohn.Forte@Sun.COM 		 * Found the given fc_remote_port_t; now remove it from the
3809*7836SJohn.Forte@Sun.COM 		 * pwwn list.
3810*7836SJohn.Forte@Sun.COM 		 */
3811*7836SJohn.Forte@Sun.COM 		head->pwwn_count--;
3812*7836SJohn.Forte@Sun.COM 		/*
3813*7836SJohn.Forte@Sun.COM 		 * Make sure we tie fp_dev_count to the size of the
3814*7836SJohn.Forte@Sun.COM 		 * pwwn_table
3815*7836SJohn.Forte@Sun.COM 		 */
3816*7836SJohn.Forte@Sun.COM 		port->fp_dev_count--;
3817*7836SJohn.Forte@Sun.COM 		if (last == NULL) {
3818*7836SJohn.Forte@Sun.COM 			head->pwwn_head = pd->pd_wwn_hnext;
3819*7836SJohn.Forte@Sun.COM 		} else {
3820*7836SJohn.Forte@Sun.COM 			last->pd_wwn_hnext = pd->pd_wwn_hnext;
3821*7836SJohn.Forte@Sun.COM 		}
3822*7836SJohn.Forte@Sun.COM 		pd->pd_wwn_hnext = NULL;
3823*7836SJohn.Forte@Sun.COM 	}
3824*7836SJohn.Forte@Sun.COM }
3825*7836SJohn.Forte@Sun.COM 
3826*7836SJohn.Forte@Sun.COM 
3827*7836SJohn.Forte@Sun.COM /*
3828*7836SJohn.Forte@Sun.COM  * Looks in the d_id table of the specified fc_local_port_t for the
3829*7836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon
3830*7836SJohn.Forte@Sun.COM  * the given d_id.
3831*7836SJohn.Forte@Sun.COM  * Returns a pointer to the fc_remote_port_t struct, but does not update any
3832*7836SJohn.Forte@Sun.COM  * reference counts or otherwise indicate that the fc_remote_port_t is in
3833*7836SJohn.Forte@Sun.COM  * use.
3834*7836SJohn.Forte@Sun.COM  */
3835*7836SJohn.Forte@Sun.COM fc_remote_port_t *
3836*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3837*7836SJohn.Forte@Sun.COM {
3838*7836SJohn.Forte@Sun.COM 	struct d_id_hash 	*head;
3839*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
3840*7836SJohn.Forte@Sun.COM 
3841*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3842*7836SJohn.Forte@Sun.COM 
3843*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
3844*7836SJohn.Forte@Sun.COM 
3845*7836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3846*7836SJohn.Forte@Sun.COM 
3847*7836SJohn.Forte@Sun.COM 	pd = head->d_id_head;
3848*7836SJohn.Forte@Sun.COM 	while (pd != NULL) {
3849*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
3850*7836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id == d_id) {
3851*7836SJohn.Forte@Sun.COM 			/* Match found -- break out of the loop */
3852*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
3853*7836SJohn.Forte@Sun.COM 			break;
3854*7836SJohn.Forte@Sun.COM 		}
3855*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
3856*7836SJohn.Forte@Sun.COM 		pd = pd->pd_did_hnext;
3857*7836SJohn.Forte@Sun.COM 	}
3858*7836SJohn.Forte@Sun.COM 
3859*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
3860*7836SJohn.Forte@Sun.COM 
3861*7836SJohn.Forte@Sun.COM 	return (pd);
3862*7836SJohn.Forte@Sun.COM }
3863*7836SJohn.Forte@Sun.COM 
3864*7836SJohn.Forte@Sun.COM 
3865*7836SJohn.Forte@Sun.COM #ifndef	__lock_lint		/* uncomment when there is a consumer */
3866*7836SJohn.Forte@Sun.COM 
3867*7836SJohn.Forte@Sun.COM void
3868*7836SJohn.Forte@Sun.COM fc_ulp_hold_remote_port(opaque_t port_handle)
3869*7836SJohn.Forte@Sun.COM {
3870*7836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd = port_handle;
3871*7836SJohn.Forte@Sun.COM 
3872*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
3873*7836SJohn.Forte@Sun.COM 	pd->pd_ref_count++;
3874*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
3875*7836SJohn.Forte@Sun.COM }
3876*7836SJohn.Forte@Sun.COM 
3877*7836SJohn.Forte@Sun.COM /*
3878*7836SJohn.Forte@Sun.COM  * Looks in the d_id table of the specified fc_local_port_t for the
3879*7836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon
3880*7836SJohn.Forte@Sun.COM  * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3881*7836SJohn.Forte@Sun.COM  *
3882*7836SJohn.Forte@Sun.COM  * Increments pd_ref_count in the fc_remote_port_t if the
3883*7836SJohn.Forte@Sun.COM  * fc_remote_port_t is found at the given d_id.
3884*7836SJohn.Forte@Sun.COM  *
3885*7836SJohn.Forte@Sun.COM  * The fc_remote_port_t is ignored (treated as non-existent) if either
3886*7836SJohn.Forte@Sun.COM  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3887*7836SJohn.Forte@Sun.COM  */
3888*7836SJohn.Forte@Sun.COM fc_remote_port_t *
3889*7836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3890*7836SJohn.Forte@Sun.COM {
3891*7836SJohn.Forte@Sun.COM 	struct d_id_hash 	*head;
3892*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
3893*7836SJohn.Forte@Sun.COM 
3894*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3895*7836SJohn.Forte@Sun.COM 
3896*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
3897*7836SJohn.Forte@Sun.COM 
3898*7836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3899*7836SJohn.Forte@Sun.COM 
3900*7836SJohn.Forte@Sun.COM 	pd = head->d_id_head;
3901*7836SJohn.Forte@Sun.COM 	while (pd != NULL) {
3902*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
3903*7836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
3904*7836SJohn.Forte@Sun.COM 		    PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
3905*7836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
3906*7836SJohn.Forte@Sun.COM 			pd->pd_ref_count++;
3907*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
3908*7836SJohn.Forte@Sun.COM 			break;
3909*7836SJohn.Forte@Sun.COM 		}
3910*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
3911*7836SJohn.Forte@Sun.COM 		pd = pd->pd_did_hnext;
3912*7836SJohn.Forte@Sun.COM 	}
3913*7836SJohn.Forte@Sun.COM 
3914*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
3915*7836SJohn.Forte@Sun.COM 
3916*7836SJohn.Forte@Sun.COM 	return (pd);
3917*7836SJohn.Forte@Sun.COM }
3918*7836SJohn.Forte@Sun.COM 
3919*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */
3920*7836SJohn.Forte@Sun.COM 
3921*7836SJohn.Forte@Sun.COM /*
3922*7836SJohn.Forte@Sun.COM  * Looks in the pwwn table of the specified fc_local_port_t for the
3923*7836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given pwwn.  Hashes based upon the
3924*7836SJohn.Forte@Sun.COM  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3925*7836SJohn.Forte@Sun.COM  * but does not update any reference counts or otherwise indicate that
3926*7836SJohn.Forte@Sun.COM  * the fc_remote_port_t is in use.
3927*7836SJohn.Forte@Sun.COM  */
3928*7836SJohn.Forte@Sun.COM fc_remote_port_t *
3929*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
3930*7836SJohn.Forte@Sun.COM {
3931*7836SJohn.Forte@Sun.COM 	int			index;
3932*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
3933*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
3934*7836SJohn.Forte@Sun.COM 
3935*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
3936*7836SJohn.Forte@Sun.COM 
3937*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
3938*7836SJohn.Forte@Sun.COM 
3939*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3940*7836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
3941*7836SJohn.Forte@Sun.COM 
3942*7836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
3943*7836SJohn.Forte@Sun.COM 	while (pd != NULL) {
3944*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
3945*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3946*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
3947*7836SJohn.Forte@Sun.COM 			break;
3948*7836SJohn.Forte@Sun.COM 		}
3949*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
3950*7836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
3951*7836SJohn.Forte@Sun.COM 	}
3952*7836SJohn.Forte@Sun.COM 
3953*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
3954*7836SJohn.Forte@Sun.COM 
3955*7836SJohn.Forte@Sun.COM 	return (pd);
3956*7836SJohn.Forte@Sun.COM }
3957*7836SJohn.Forte@Sun.COM 
3958*7836SJohn.Forte@Sun.COM 
3959*7836SJohn.Forte@Sun.COM /*
3960*7836SJohn.Forte@Sun.COM  * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
3961*7836SJohn.Forte@Sun.COM  * the caller already hold the fp_mutex in the fc_local_port_t struct.
3962*7836SJohn.Forte@Sun.COM  */
3963*7836SJohn.Forte@Sun.COM fc_remote_port_t *
3964*7836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
3965*7836SJohn.Forte@Sun.COM {
3966*7836SJohn.Forte@Sun.COM 	int			index;
3967*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
3968*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
3969*7836SJohn.Forte@Sun.COM 
3970*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3971*7836SJohn.Forte@Sun.COM 
3972*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3973*7836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
3974*7836SJohn.Forte@Sun.COM 
3975*7836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
3976*7836SJohn.Forte@Sun.COM 	while (pd != NULL) {
3977*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
3978*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3979*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
3980*7836SJohn.Forte@Sun.COM 			break;
3981*7836SJohn.Forte@Sun.COM 		}
3982*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
3983*7836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
3984*7836SJohn.Forte@Sun.COM 	}
3985*7836SJohn.Forte@Sun.COM 
3986*7836SJohn.Forte@Sun.COM 	return (pd);
3987*7836SJohn.Forte@Sun.COM }
3988*7836SJohn.Forte@Sun.COM 
3989*7836SJohn.Forte@Sun.COM 
3990*7836SJohn.Forte@Sun.COM /*
3991*7836SJohn.Forte@Sun.COM  * Looks in the pwwn table of the specified fc_local_port_t for the
3992*7836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon the
3993*7836SJohn.Forte@Sun.COM  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
3994*7836SJohn.Forte@Sun.COM  *
3995*7836SJohn.Forte@Sun.COM  * Increments pd_ref_count in the fc_remote_port_t if the
3996*7836SJohn.Forte@Sun.COM  * fc_remote_port_t is found at the given pwwn.
3997*7836SJohn.Forte@Sun.COM  *
3998*7836SJohn.Forte@Sun.COM  * The fc_remote_port_t is ignored (treated as non-existent) if either
3999*7836SJohn.Forte@Sun.COM  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
4000*7836SJohn.Forte@Sun.COM  */
4001*7836SJohn.Forte@Sun.COM fc_remote_port_t *
4002*7836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
4003*7836SJohn.Forte@Sun.COM {
4004*7836SJohn.Forte@Sun.COM 	int			index;
4005*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
4006*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
4007*7836SJohn.Forte@Sun.COM 
4008*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4009*7836SJohn.Forte@Sun.COM 
4010*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4011*7836SJohn.Forte@Sun.COM 
4012*7836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
4013*7836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
4014*7836SJohn.Forte@Sun.COM 
4015*7836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
4016*7836SJohn.Forte@Sun.COM 	while (pd != NULL) {
4017*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
4018*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 &&
4019*7836SJohn.Forte@Sun.COM 		    pd->pd_state != PORT_DEVICE_INVALID &&
4020*7836SJohn.Forte@Sun.COM 		    pd->pd_type != PORT_DEVICE_OLD) {
4021*7836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
4022*7836SJohn.Forte@Sun.COM 			pd->pd_ref_count++;
4023*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
4024*7836SJohn.Forte@Sun.COM 			break;
4025*7836SJohn.Forte@Sun.COM 		}
4026*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
4027*7836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
4028*7836SJohn.Forte@Sun.COM 	}
4029*7836SJohn.Forte@Sun.COM 
4030*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4031*7836SJohn.Forte@Sun.COM 
4032*7836SJohn.Forte@Sun.COM 	return (pd);
4033*7836SJohn.Forte@Sun.COM }
4034*7836SJohn.Forte@Sun.COM 
4035*7836SJohn.Forte@Sun.COM 
4036*7836SJohn.Forte@Sun.COM /*
4037*7836SJohn.Forte@Sun.COM  * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
4038*7836SJohn.Forte@Sun.COM  * struct.
4039*7836SJohn.Forte@Sun.COM  *
4040*7836SJohn.Forte@Sun.COM  * If pd_ref_count reaches zero, then this function will see if the
4041*7836SJohn.Forte@Sun.COM  * fc_remote_port_t has been marked for deallocation. If so (and also if there
4042*7836SJohn.Forte@Sun.COM  * are no other potential operations in progress, as indicated by the
4043*7836SJohn.Forte@Sun.COM  * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
4044*7836SJohn.Forte@Sun.COM  * fctl_destroy_remote_port_t() is called to deconstruct/free the given
4045*7836SJohn.Forte@Sun.COM  * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
4046*7836SJohn.Forte@Sun.COM  * on the associated fc_local_port_t).  If the associated fc_remote_node_t is no
4047*7836SJohn.Forte@Sun.COM  * longer in use, then it too is deconstructed/freed.
4048*7836SJohn.Forte@Sun.COM  */
4049*7836SJohn.Forte@Sun.COM void
4050*7836SJohn.Forte@Sun.COM fctl_release_remote_port(fc_remote_port_t *pd)
4051*7836SJohn.Forte@Sun.COM {
4052*7836SJohn.Forte@Sun.COM 	int			remove = 0;
4053*7836SJohn.Forte@Sun.COM 	fc_remote_node_t 	*node;
4054*7836SJohn.Forte@Sun.COM 	fc_local_port_t 	*port;
4055*7836SJohn.Forte@Sun.COM 
4056*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
4057*7836SJohn.Forte@Sun.COM 	port = pd->pd_port;
4058*7836SJohn.Forte@Sun.COM 
4059*7836SJohn.Forte@Sun.COM 	ASSERT(pd->pd_ref_count > 0);
4060*7836SJohn.Forte@Sun.COM 	pd->pd_ref_count--;
4061*7836SJohn.Forte@Sun.COM 	if (pd->pd_ref_count == 0 &&
4062*7836SJohn.Forte@Sun.COM 	    (pd->pd_aux_flags & PD_NEEDS_REMOVAL) &&
4063*7836SJohn.Forte@Sun.COM 	    (pd->pd_flags != PD_ELS_IN_PROGRESS) &&
4064*7836SJohn.Forte@Sun.COM 	    (pd->pd_flags != PD_ELS_MARK)) {
4065*7836SJohn.Forte@Sun.COM 		remove = 1;
4066*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL;
4067*7836SJohn.Forte@Sun.COM 	}
4068*7836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
4069*7836SJohn.Forte@Sun.COM 	ASSERT(node != NULL);
4070*7836SJohn.Forte@Sun.COM 
4071*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
4072*7836SJohn.Forte@Sun.COM 
4073*7836SJohn.Forte@Sun.COM 	if (remove) {
4074*7836SJohn.Forte@Sun.COM 		/*
4075*7836SJohn.Forte@Sun.COM 		 * The fc_remote_port_t struct has to go away now, so call the
4076*7836SJohn.Forte@Sun.COM 		 * cleanup function to get it off the various lists and remove
4077*7836SJohn.Forte@Sun.COM 		 * references to it in any other associated structs.
4078*7836SJohn.Forte@Sun.COM 		 */
4079*7836SJohn.Forte@Sun.COM 		if (fctl_destroy_remote_port(port, pd) == 0) {
4080*7836SJohn.Forte@Sun.COM 			/*
4081*7836SJohn.Forte@Sun.COM 			 * No more fc_remote_port_t references found in the
4082*7836SJohn.Forte@Sun.COM 			 * associated fc_remote_node_t, so deallocate the
4083*7836SJohn.Forte@Sun.COM 			 * fc_remote_node_t (if it even exists).
4084*7836SJohn.Forte@Sun.COM 			 */
4085*7836SJohn.Forte@Sun.COM 			if (node) {
4086*7836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
4087*7836SJohn.Forte@Sun.COM 			}
4088*7836SJohn.Forte@Sun.COM 		}
4089*7836SJohn.Forte@Sun.COM 	}
4090*7836SJohn.Forte@Sun.COM }
4091*7836SJohn.Forte@Sun.COM 
4092*7836SJohn.Forte@Sun.COM 
4093*7836SJohn.Forte@Sun.COM void
4094*7836SJohn.Forte@Sun.COM fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
4095*7836SJohn.Forte@Sun.COM     int whole_map, int justcopy, int orphan)
4096*7836SJohn.Forte@Sun.COM {
4097*7836SJohn.Forte@Sun.COM 	int			index;
4098*7836SJohn.Forte@Sun.COM 	int			listlen;
4099*7836SJohn.Forte@Sun.COM 	int			full_list;
4100*7836SJohn.Forte@Sun.COM 	int			initiator;
4101*7836SJohn.Forte@Sun.COM 	uint32_t		topology;
4102*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
4103*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
4104*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*old_pd;
4105*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*last_pd;
4106*7836SJohn.Forte@Sun.COM 	fc_portmap_t		*listptr;
4107*7836SJohn.Forte@Sun.COM 
4108*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4109*7836SJohn.Forte@Sun.COM 
4110*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4111*7836SJohn.Forte@Sun.COM 
4112*7836SJohn.Forte@Sun.COM 	topology = port->fp_topology;
4113*7836SJohn.Forte@Sun.COM 
4114*7836SJohn.Forte@Sun.COM 	if (orphan) {
4115*7836SJohn.Forte@Sun.COM 		ASSERT(!FC_IS_TOP_SWITCH(topology));
4116*7836SJohn.Forte@Sun.COM 	}
4117*7836SJohn.Forte@Sun.COM 
4118*7836SJohn.Forte@Sun.COM 	for (full_list = listlen = index = 0;
4119*7836SJohn.Forte@Sun.COM 	    index < pwwn_table_size; index++) {
4120*7836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
4121*7836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
4122*7836SJohn.Forte@Sun.COM 		while (pd != NULL) {
4123*7836SJohn.Forte@Sun.COM 			full_list++;
4124*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
4125*7836SJohn.Forte@Sun.COM 			if (pd->pd_type != PORT_DEVICE_NOCHANGE) {
4126*7836SJohn.Forte@Sun.COM 				listlen++;
4127*7836SJohn.Forte@Sun.COM 			}
4128*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
4129*7836SJohn.Forte@Sun.COM 			pd = pd->pd_wwn_hnext;
4130*7836SJohn.Forte@Sun.COM 		}
4131*7836SJohn.Forte@Sun.COM 	}
4132*7836SJohn.Forte@Sun.COM 
4133*7836SJohn.Forte@Sun.COM 	if (whole_map == 0) {
4134*7836SJohn.Forte@Sun.COM 		if (listlen == 0 && *len == 0) {
4135*7836SJohn.Forte@Sun.COM 			*map = NULL;
4136*7836SJohn.Forte@Sun.COM 			*len = listlen;
4137*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
4138*7836SJohn.Forte@Sun.COM 			return;
4139*7836SJohn.Forte@Sun.COM 		}
4140*7836SJohn.Forte@Sun.COM 	} else {
4141*7836SJohn.Forte@Sun.COM 		if (full_list == 0 && *len == 0) {
4142*7836SJohn.Forte@Sun.COM 			*map = NULL;
4143*7836SJohn.Forte@Sun.COM 			*len = full_list;
4144*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
4145*7836SJohn.Forte@Sun.COM 			return;
4146*7836SJohn.Forte@Sun.COM 		}
4147*7836SJohn.Forte@Sun.COM 	}
4148*7836SJohn.Forte@Sun.COM 
4149*7836SJohn.Forte@Sun.COM 	if (*len == 0) {
4150*7836SJohn.Forte@Sun.COM 		ASSERT(*map == NULL);
4151*7836SJohn.Forte@Sun.COM 		if (whole_map == 0) {
4152*7836SJohn.Forte@Sun.COM 			listptr = *map = kmem_zalloc(
4153*7836SJohn.Forte@Sun.COM 			    sizeof (*listptr) * listlen, KM_SLEEP);
4154*7836SJohn.Forte@Sun.COM 			*len = listlen;
4155*7836SJohn.Forte@Sun.COM 		} else {
4156*7836SJohn.Forte@Sun.COM 			listptr = *map = kmem_zalloc(
4157*7836SJohn.Forte@Sun.COM 			    sizeof (*listptr) * full_list, KM_SLEEP);
4158*7836SJohn.Forte@Sun.COM 			*len = full_list;
4159*7836SJohn.Forte@Sun.COM 		}
4160*7836SJohn.Forte@Sun.COM 	} else {
4161*7836SJohn.Forte@Sun.COM 		/*
4162*7836SJohn.Forte@Sun.COM 		 * By design this routine mandates the callers to
4163*7836SJohn.Forte@Sun.COM 		 * ask for a whole map when they specify the length
4164*7836SJohn.Forte@Sun.COM 		 * and the listptr.
4165*7836SJohn.Forte@Sun.COM 		 */
4166*7836SJohn.Forte@Sun.COM 		ASSERT(whole_map == 1);
4167*7836SJohn.Forte@Sun.COM 		if (*len < full_list) {
4168*7836SJohn.Forte@Sun.COM 			*len = full_list;
4169*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
4170*7836SJohn.Forte@Sun.COM 			return;
4171*7836SJohn.Forte@Sun.COM 		}
4172*7836SJohn.Forte@Sun.COM 		listptr = *map;
4173*7836SJohn.Forte@Sun.COM 		*len = full_list;
4174*7836SJohn.Forte@Sun.COM 	}
4175*7836SJohn.Forte@Sun.COM 
4176*7836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
4177*7836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
4178*7836SJohn.Forte@Sun.COM 		last_pd = NULL;
4179*7836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
4180*7836SJohn.Forte@Sun.COM 		while (pd != NULL) {
4181*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
4182*7836SJohn.Forte@Sun.COM 			if ((whole_map == 0 &&
4183*7836SJohn.Forte@Sun.COM 			    pd->pd_type == PORT_DEVICE_NOCHANGE) ||
4184*7836SJohn.Forte@Sun.COM 			    pd->pd_state == PORT_DEVICE_INVALID) {
4185*7836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
4186*7836SJohn.Forte@Sun.COM 				last_pd = pd;
4187*7836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
4188*7836SJohn.Forte@Sun.COM 				continue;
4189*7836SJohn.Forte@Sun.COM 			}
4190*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
4191*7836SJohn.Forte@Sun.COM 
4192*7836SJohn.Forte@Sun.COM 			fctl_copy_portmap(listptr, pd);
4193*7836SJohn.Forte@Sun.COM 
4194*7836SJohn.Forte@Sun.COM 			if (justcopy) {
4195*7836SJohn.Forte@Sun.COM 				last_pd = pd;
4196*7836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
4197*7836SJohn.Forte@Sun.COM 				listptr++;
4198*7836SJohn.Forte@Sun.COM 				continue;
4199*7836SJohn.Forte@Sun.COM 			}
4200*7836SJohn.Forte@Sun.COM 
4201*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
4202*7836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_state != PORT_DEVICE_INVALID);
4203*7836SJohn.Forte@Sun.COM 			if (pd->pd_type == PORT_DEVICE_OLD) {
4204*7836SJohn.Forte@Sun.COM 				listptr->map_pd = pd;
4205*7836SJohn.Forte@Sun.COM 				listptr->map_state = pd->pd_state =
4206*7836SJohn.Forte@Sun.COM 				    PORT_DEVICE_INVALID;
4207*7836SJohn.Forte@Sun.COM 				/*
4208*7836SJohn.Forte@Sun.COM 				 * Remove this from the PWWN hash table.
4209*7836SJohn.Forte@Sun.COM 				 */
4210*7836SJohn.Forte@Sun.COM 				old_pd = pd;
4211*7836SJohn.Forte@Sun.COM 				pd = old_pd->pd_wwn_hnext;
4212*7836SJohn.Forte@Sun.COM 
4213*7836SJohn.Forte@Sun.COM 				if (last_pd == NULL) {
4214*7836SJohn.Forte@Sun.COM 					ASSERT(old_pd == head->pwwn_head);
4215*7836SJohn.Forte@Sun.COM 
4216*7836SJohn.Forte@Sun.COM 					head->pwwn_head = pd;
4217*7836SJohn.Forte@Sun.COM 				} else {
4218*7836SJohn.Forte@Sun.COM 					last_pd->pd_wwn_hnext = pd;
4219*7836SJohn.Forte@Sun.COM 				}
4220*7836SJohn.Forte@Sun.COM 				head->pwwn_count--;
4221*7836SJohn.Forte@Sun.COM 				/*
4222*7836SJohn.Forte@Sun.COM 				 * Make sure we tie fp_dev_count to the size
4223*7836SJohn.Forte@Sun.COM 				 * of the pwwn_table
4224*7836SJohn.Forte@Sun.COM 				 */
4225*7836SJohn.Forte@Sun.COM 				port->fp_dev_count--;
4226*7836SJohn.Forte@Sun.COM 				old_pd->pd_wwn_hnext = NULL;
4227*7836SJohn.Forte@Sun.COM 
4228*7836SJohn.Forte@Sun.COM 				if (port->fp_topology == FC_TOP_PRIVATE_LOOP &&
4229*7836SJohn.Forte@Sun.COM 				    port->fp_statec_busy && !orphan) {
4230*7836SJohn.Forte@Sun.COM 					fctl_check_alpa_list(port, old_pd);
4231*7836SJohn.Forte@Sun.COM 				}
4232*7836SJohn.Forte@Sun.COM 
4233*7836SJohn.Forte@Sun.COM 				/*
4234*7836SJohn.Forte@Sun.COM 				 * Remove if the port device has stealthily
4235*7836SJohn.Forte@Sun.COM 				 * present in the D_ID hash table
4236*7836SJohn.Forte@Sun.COM 				 */
4237*7836SJohn.Forte@Sun.COM 				fctl_delist_did_table(port, old_pd);
4238*7836SJohn.Forte@Sun.COM 
4239*7836SJohn.Forte@Sun.COM 				ASSERT(old_pd->pd_remote_nodep != NULL);
4240*7836SJohn.Forte@Sun.COM 
4241*7836SJohn.Forte@Sun.COM 				initiator = (old_pd->pd_recepient ==
4242*7836SJohn.Forte@Sun.COM 				    PD_PLOGI_INITIATOR) ? 1 : 0;
4243*7836SJohn.Forte@Sun.COM 
4244*7836SJohn.Forte@Sun.COM 				mutex_exit(&old_pd->pd_mutex);
4245*7836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
4246*7836SJohn.Forte@Sun.COM 
4247*7836SJohn.Forte@Sun.COM 				if (orphan) {
4248*7836SJohn.Forte@Sun.COM 					fctl_print_if_not_orphan(port, old_pd);
4249*7836SJohn.Forte@Sun.COM 
4250*7836SJohn.Forte@Sun.COM 					(void) fctl_add_orphan(port, old_pd,
4251*7836SJohn.Forte@Sun.COM 					    KM_NOSLEEP);
4252*7836SJohn.Forte@Sun.COM 				}
4253*7836SJohn.Forte@Sun.COM 
4254*7836SJohn.Forte@Sun.COM 				if (FC_IS_TOP_SWITCH(topology) && initiator) {
4255*7836SJohn.Forte@Sun.COM 					(void) fctl_add_orphan(port, old_pd,
4256*7836SJohn.Forte@Sun.COM 					    KM_NOSLEEP);
4257*7836SJohn.Forte@Sun.COM 				}
4258*7836SJohn.Forte@Sun.COM 				mutex_enter(&port->fp_mutex);
4259*7836SJohn.Forte@Sun.COM 			} else {
4260*7836SJohn.Forte@Sun.COM 				listptr->map_pd = pd;
4261*7836SJohn.Forte@Sun.COM 				pd->pd_type = PORT_DEVICE_NOCHANGE;
4262*7836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
4263*7836SJohn.Forte@Sun.COM 				last_pd = pd;
4264*7836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
4265*7836SJohn.Forte@Sun.COM 			}
4266*7836SJohn.Forte@Sun.COM 			listptr++;
4267*7836SJohn.Forte@Sun.COM 		}
4268*7836SJohn.Forte@Sun.COM 	}
4269*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4270*7836SJohn.Forte@Sun.COM }
4271*7836SJohn.Forte@Sun.COM 
4272*7836SJohn.Forte@Sun.COM 
4273*7836SJohn.Forte@Sun.COM job_request_t *
4274*7836SJohn.Forte@Sun.COM fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
4275*7836SJohn.Forte@Sun.COM     opaque_t arg, int sleep)
4276*7836SJohn.Forte@Sun.COM {
4277*7836SJohn.Forte@Sun.COM 	job_request_t *job;
4278*7836SJohn.Forte@Sun.COM 
4279*7836SJohn.Forte@Sun.COM 	job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
4280*7836SJohn.Forte@Sun.COM 	if (job != NULL) {
4281*7836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
4282*7836SJohn.Forte@Sun.COM 		job->job_code = job_code;
4283*7836SJohn.Forte@Sun.COM 		job->job_flags = job_flags;
4284*7836SJohn.Forte@Sun.COM 		job->job_cb_arg = arg;
4285*7836SJohn.Forte@Sun.COM 		job->job_comp = comp;
4286*7836SJohn.Forte@Sun.COM 		job->job_private = NULL;
4287*7836SJohn.Forte@Sun.COM 		job->job_ulp_pkts = NULL;
4288*7836SJohn.Forte@Sun.COM 		job->job_ulp_listlen = 0;
4289*7836SJohn.Forte@Sun.COM #ifndef __lock_lint
4290*7836SJohn.Forte@Sun.COM 		job->job_counter = 0;
4291*7836SJohn.Forte@Sun.COM 		job->job_next = NULL;
4292*7836SJohn.Forte@Sun.COM #endif /* __lock_lint */
4293*7836SJohn.Forte@Sun.COM 	}
4294*7836SJohn.Forte@Sun.COM 
4295*7836SJohn.Forte@Sun.COM 	return (job);
4296*7836SJohn.Forte@Sun.COM }
4297*7836SJohn.Forte@Sun.COM 
4298*7836SJohn.Forte@Sun.COM 
4299*7836SJohn.Forte@Sun.COM void
4300*7836SJohn.Forte@Sun.COM fctl_dealloc_job(job_request_t *job)
4301*7836SJohn.Forte@Sun.COM {
4302*7836SJohn.Forte@Sun.COM 	kmem_cache_free(fctl_job_cache, (void *)job);
4303*7836SJohn.Forte@Sun.COM }
4304*7836SJohn.Forte@Sun.COM 
4305*7836SJohn.Forte@Sun.COM 
4306*7836SJohn.Forte@Sun.COM void
4307*7836SJohn.Forte@Sun.COM fctl_enque_job(fc_local_port_t *port, job_request_t *job)
4308*7836SJohn.Forte@Sun.COM {
4309*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4310*7836SJohn.Forte@Sun.COM 
4311*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4312*7836SJohn.Forte@Sun.COM 
4313*7836SJohn.Forte@Sun.COM 	if (port->fp_job_tail == NULL) {
4314*7836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_head == NULL);
4315*7836SJohn.Forte@Sun.COM 		port->fp_job_head = port->fp_job_tail = job;
4316*7836SJohn.Forte@Sun.COM 	} else {
4317*7836SJohn.Forte@Sun.COM 		port->fp_job_tail->job_next = job;
4318*7836SJohn.Forte@Sun.COM 		port->fp_job_tail = job;
4319*7836SJohn.Forte@Sun.COM 	}
4320*7836SJohn.Forte@Sun.COM 	job->job_next = NULL;
4321*7836SJohn.Forte@Sun.COM 
4322*7836SJohn.Forte@Sun.COM 	cv_signal(&port->fp_cv);
4323*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4324*7836SJohn.Forte@Sun.COM }
4325*7836SJohn.Forte@Sun.COM 
4326*7836SJohn.Forte@Sun.COM 
4327*7836SJohn.Forte@Sun.COM job_request_t *
4328*7836SJohn.Forte@Sun.COM fctl_deque_job(fc_local_port_t *port)
4329*7836SJohn.Forte@Sun.COM {
4330*7836SJohn.Forte@Sun.COM 	job_request_t *job;
4331*7836SJohn.Forte@Sun.COM 
4332*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
4333*7836SJohn.Forte@Sun.COM 
4334*7836SJohn.Forte@Sun.COM 	if (port->fp_job_head == NULL) {
4335*7836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_tail == NULL);
4336*7836SJohn.Forte@Sun.COM 		job = NULL;
4337*7836SJohn.Forte@Sun.COM 	} else {
4338*7836SJohn.Forte@Sun.COM 		job = port->fp_job_head;
4339*7836SJohn.Forte@Sun.COM 		if (job->job_next == NULL) {
4340*7836SJohn.Forte@Sun.COM 			ASSERT(job == port->fp_job_tail);
4341*7836SJohn.Forte@Sun.COM 			port->fp_job_tail = NULL;
4342*7836SJohn.Forte@Sun.COM 		}
4343*7836SJohn.Forte@Sun.COM 		port->fp_job_head = job->job_next;
4344*7836SJohn.Forte@Sun.COM 	}
4345*7836SJohn.Forte@Sun.COM 
4346*7836SJohn.Forte@Sun.COM 	return (job);
4347*7836SJohn.Forte@Sun.COM }
4348*7836SJohn.Forte@Sun.COM 
4349*7836SJohn.Forte@Sun.COM 
4350*7836SJohn.Forte@Sun.COM void
4351*7836SJohn.Forte@Sun.COM fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job)
4352*7836SJohn.Forte@Sun.COM {
4353*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
4354*7836SJohn.Forte@Sun.COM 
4355*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4356*7836SJohn.Forte@Sun.COM 	if (port->fp_job_tail == NULL) {
4357*7836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_head == NULL);
4358*7836SJohn.Forte@Sun.COM 		port->fp_job_head = port->fp_job_tail = job;
4359*7836SJohn.Forte@Sun.COM 		job->job_next = NULL;
4360*7836SJohn.Forte@Sun.COM 	} else {
4361*7836SJohn.Forte@Sun.COM 		job->job_next = port->fp_job_head;
4362*7836SJohn.Forte@Sun.COM 		port->fp_job_head = job;
4363*7836SJohn.Forte@Sun.COM 	}
4364*7836SJohn.Forte@Sun.COM 	cv_signal(&port->fp_cv);
4365*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4366*7836SJohn.Forte@Sun.COM }
4367*7836SJohn.Forte@Sun.COM 
4368*7836SJohn.Forte@Sun.COM 
4369*7836SJohn.Forte@Sun.COM void
4370*7836SJohn.Forte@Sun.COM fctl_jobwait(job_request_t *job)
4371*7836SJohn.Forte@Sun.COM {
4372*7836SJohn.Forte@Sun.COM 	ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC));
4373*7836SJohn.Forte@Sun.COM 	sema_p(&job->job_fctl_sema);
4374*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&job->job_mutex));
4375*7836SJohn.Forte@Sun.COM }
4376*7836SJohn.Forte@Sun.COM 
4377*7836SJohn.Forte@Sun.COM 
4378*7836SJohn.Forte@Sun.COM void
4379*7836SJohn.Forte@Sun.COM fctl_jobdone(job_request_t *job)
4380*7836SJohn.Forte@Sun.COM {
4381*7836SJohn.Forte@Sun.COM 	if (job->job_flags & JOB_TYPE_FCTL_ASYNC) {
4382*7836SJohn.Forte@Sun.COM 		if (job->job_comp) {
4383*7836SJohn.Forte@Sun.COM 			job->job_comp(job->job_cb_arg, job->job_result);
4384*7836SJohn.Forte@Sun.COM 		}
4385*7836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
4386*7836SJohn.Forte@Sun.COM 	} else {
4387*7836SJohn.Forte@Sun.COM 		sema_v(&job->job_fctl_sema);
4388*7836SJohn.Forte@Sun.COM 	}
4389*7836SJohn.Forte@Sun.COM }
4390*7836SJohn.Forte@Sun.COM 
4391*7836SJohn.Forte@Sun.COM 
4392*7836SJohn.Forte@Sun.COM /*
4393*7836SJohn.Forte@Sun.COM  * Compare two WWNs. The NAA is omitted for comparison.
4394*7836SJohn.Forte@Sun.COM  *
4395*7836SJohn.Forte@Sun.COM  * Note particularly that the indentation used in this
4396*7836SJohn.Forte@Sun.COM  * function  isn't according to Sun recommendations. It
4397*7836SJohn.Forte@Sun.COM  * is indented to make reading a bit easy.
4398*7836SJohn.Forte@Sun.COM  *
4399*7836SJohn.Forte@Sun.COM  * Return Values:
4400*7836SJohn.Forte@Sun.COM  *   if src == dst return  0
4401*7836SJohn.Forte@Sun.COM  *   if src > dst  return  1
4402*7836SJohn.Forte@Sun.COM  *   if src < dst  return -1
4403*7836SJohn.Forte@Sun.COM  */
4404*7836SJohn.Forte@Sun.COM int
4405*7836SJohn.Forte@Sun.COM fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
4406*7836SJohn.Forte@Sun.COM {
4407*7836SJohn.Forte@Sun.COM 	la_wwn_t tmpsrc, tmpdst;
4408*7836SJohn.Forte@Sun.COM 
4409*7836SJohn.Forte@Sun.COM 	/*
4410*7836SJohn.Forte@Sun.COM 	 * Fibre Channel protocol is big endian, so compare
4411*7836SJohn.Forte@Sun.COM 	 * as big endian values
4412*7836SJohn.Forte@Sun.COM 	 */
4413*7836SJohn.Forte@Sun.COM 	tmpsrc.i_wwn[0] = BE_32(src->i_wwn[0]);
4414*7836SJohn.Forte@Sun.COM 	tmpsrc.i_wwn[1] = BE_32(src->i_wwn[1]);
4415*7836SJohn.Forte@Sun.COM 
4416*7836SJohn.Forte@Sun.COM 	tmpdst.i_wwn[0] = BE_32(dst->i_wwn[0]);
4417*7836SJohn.Forte@Sun.COM 	tmpdst.i_wwn[1] = BE_32(dst->i_wwn[1]);
4418*7836SJohn.Forte@Sun.COM 
4419*7836SJohn.Forte@Sun.COM 	return (
4420*7836SJohn.Forte@Sun.COM 	    (tmpsrc.w.nport_id == tmpdst.w.nport_id) ?
4421*7836SJohn.Forte@Sun.COM 		((tmpsrc.w.wwn_hi == tmpdst.w.wwn_hi) ?
4422*7836SJohn.Forte@Sun.COM 		    ((tmpsrc.w.wwn_lo == tmpdst.w.wwn_lo) ? 0 :
4423*7836SJohn.Forte@Sun.COM 		    (tmpsrc.w.wwn_lo > tmpdst.w.wwn_lo) ? 1 : -1) :
4424*7836SJohn.Forte@Sun.COM 		(tmpsrc.w.wwn_hi > tmpdst.w.wwn_hi) ? 1 : -1) :
4425*7836SJohn.Forte@Sun.COM 	    (tmpsrc.w.nport_id > tmpdst.w.nport_id) ? 1 : -1);
4426*7836SJohn.Forte@Sun.COM }
4427*7836SJohn.Forte@Sun.COM 
4428*7836SJohn.Forte@Sun.COM 
4429*7836SJohn.Forte@Sun.COM /*
4430*7836SJohn.Forte@Sun.COM  * ASCII to Integer goodie with support for base 16, 10, 2 and 8
4431*7836SJohn.Forte@Sun.COM  */
4432*7836SJohn.Forte@Sun.COM int
4433*7836SJohn.Forte@Sun.COM fctl_atoi(char *s, int base)
4434*7836SJohn.Forte@Sun.COM {
4435*7836SJohn.Forte@Sun.COM 	int val;
4436*7836SJohn.Forte@Sun.COM 	int ch;
4437*7836SJohn.Forte@Sun.COM 
4438*7836SJohn.Forte@Sun.COM 	for (val = 0; *s != '\0'; s++) {
4439*7836SJohn.Forte@Sun.COM 		switch (base) {
4440*7836SJohn.Forte@Sun.COM 		case 16:
4441*7836SJohn.Forte@Sun.COM 			if (*s >= '0' && *s <= '9') {
4442*7836SJohn.Forte@Sun.COM 				ch = *s - '0';
4443*7836SJohn.Forte@Sun.COM 			} else if (*s >= 'a' && *s <= 'f') {
4444*7836SJohn.Forte@Sun.COM 				ch = *s - 'a' + 10;
4445*7836SJohn.Forte@Sun.COM 			} else if (*s >= 'A' && *s <= 'F') {
4446*7836SJohn.Forte@Sun.COM 				ch = *s - 'A' + 10;
4447*7836SJohn.Forte@Sun.COM 			} else {
4448*7836SJohn.Forte@Sun.COM 				return (-1);
4449*7836SJohn.Forte@Sun.COM 			}
4450*7836SJohn.Forte@Sun.COM 			break;
4451*7836SJohn.Forte@Sun.COM 
4452*7836SJohn.Forte@Sun.COM 		case 10:
4453*7836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '9') {
4454*7836SJohn.Forte@Sun.COM 				return (-1);
4455*7836SJohn.Forte@Sun.COM 			}
4456*7836SJohn.Forte@Sun.COM 			ch = *s - '0';
4457*7836SJohn.Forte@Sun.COM 			break;
4458*7836SJohn.Forte@Sun.COM 
4459*7836SJohn.Forte@Sun.COM 		case 2:
4460*7836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '1') {
4461*7836SJohn.Forte@Sun.COM 				return (-1);
4462*7836SJohn.Forte@Sun.COM 			}
4463*7836SJohn.Forte@Sun.COM 			ch = *s - '0';
4464*7836SJohn.Forte@Sun.COM 			break;
4465*7836SJohn.Forte@Sun.COM 
4466*7836SJohn.Forte@Sun.COM 		case 8:
4467*7836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '7') {
4468*7836SJohn.Forte@Sun.COM 				return (-1);
4469*7836SJohn.Forte@Sun.COM 			}
4470*7836SJohn.Forte@Sun.COM 			ch = *s - '0';
4471*7836SJohn.Forte@Sun.COM 			break;
4472*7836SJohn.Forte@Sun.COM 
4473*7836SJohn.Forte@Sun.COM 		default:
4474*7836SJohn.Forte@Sun.COM 			return (-1);
4475*7836SJohn.Forte@Sun.COM 		}
4476*7836SJohn.Forte@Sun.COM 		val = (val * base) + ch;
4477*7836SJohn.Forte@Sun.COM 	}
4478*7836SJohn.Forte@Sun.COM 	return (val);
4479*7836SJohn.Forte@Sun.COM }
4480*7836SJohn.Forte@Sun.COM 
4481*7836SJohn.Forte@Sun.COM 
4482*7836SJohn.Forte@Sun.COM /*
4483*7836SJohn.Forte@Sun.COM  * Create the fc_remote_port_t struct for the given port_wwn and d_id.
4484*7836SJohn.Forte@Sun.COM  *
4485*7836SJohn.Forte@Sun.COM  * If the struct already exists (and is "valid"), then use it. Before using
4486*7836SJohn.Forte@Sun.COM  * it, the code below also checks: (a) if the d_id has changed, and (b) if
4487*7836SJohn.Forte@Sun.COM  * the device is maked as PORT_DEVICE_OLD.
4488*7836SJohn.Forte@Sun.COM  *
4489*7836SJohn.Forte@Sun.COM  * If no fc_remote_node_t struct exists for the given node_wwn, then that
4490*7836SJohn.Forte@Sun.COM  * struct is also created (and linked with the fc_remote_port_t).
4491*7836SJohn.Forte@Sun.COM  *
4492*7836SJohn.Forte@Sun.COM  * The given fc_local_port_t struct is updated with the info on the new
4493*7836SJohn.Forte@Sun.COM  * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
4494*7836SJohn.Forte@Sun.COM  * The global node_hash_table[] is updated (if necessary).
4495*7836SJohn.Forte@Sun.COM  */
4496*7836SJohn.Forte@Sun.COM fc_remote_port_t *
4497*7836SJohn.Forte@Sun.COM fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
4498*7836SJohn.Forte@Sun.COM     la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep)
4499*7836SJohn.Forte@Sun.COM {
4500*7836SJohn.Forte@Sun.COM 	int			invalid = 0;
4501*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*rnodep;
4502*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
4503*7836SJohn.Forte@Sun.COM 
4504*7836SJohn.Forte@Sun.COM 	rnodep = fctl_get_remote_node_by_nwwn(node_wwn);
4505*7836SJohn.Forte@Sun.COM 	if (rnodep) {
4506*7836SJohn.Forte@Sun.COM 		/*
4507*7836SJohn.Forte@Sun.COM 		 * We found an fc_remote_node_t for the remote node -- see if
4508*7836SJohn.Forte@Sun.COM 		 * anyone has marked it as going away or gone.
4509*7836SJohn.Forte@Sun.COM 		 */
4510*7836SJohn.Forte@Sun.COM 		mutex_enter(&rnodep->fd_mutex);
4511*7836SJohn.Forte@Sun.COM 		invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0;
4512*7836SJohn.Forte@Sun.COM 		mutex_exit(&rnodep->fd_mutex);
4513*7836SJohn.Forte@Sun.COM 	}
4514*7836SJohn.Forte@Sun.COM 	if (rnodep == NULL || invalid) {
4515*7836SJohn.Forte@Sun.COM 		/*
4516*7836SJohn.Forte@Sun.COM 		 * No valid remote node struct found -- create it.
4517*7836SJohn.Forte@Sun.COM 		 * Note: this is the only place that this func is called.
4518*7836SJohn.Forte@Sun.COM 		 */
4519*7836SJohn.Forte@Sun.COM 		rnodep = fctl_create_remote_node(node_wwn, sleep);
4520*7836SJohn.Forte@Sun.COM 		if (rnodep == NULL) {
4521*7836SJohn.Forte@Sun.COM 			return (NULL);
4522*7836SJohn.Forte@Sun.COM 		}
4523*7836SJohn.Forte@Sun.COM 	}
4524*7836SJohn.Forte@Sun.COM 
4525*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4526*7836SJohn.Forte@Sun.COM 
4527*7836SJohn.Forte@Sun.COM 	/*
4528*7836SJohn.Forte@Sun.COM 	 * See if there already is an fc_remote_port_t struct in existence
4529*7836SJohn.Forte@Sun.COM 	 * on the specified fc_local_port_t for the given pwwn.  If so, then
4530*7836SJohn.Forte@Sun.COM 	 * grab a reference to it. The 'held' here just means that fp_mutex
4531*7836SJohn.Forte@Sun.COM 	 * is held by the caller -- no reference counts are updated.
4532*7836SJohn.Forte@Sun.COM 	 */
4533*7836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn);
4534*7836SJohn.Forte@Sun.COM 	if (pd) {
4535*7836SJohn.Forte@Sun.COM 		/*
4536*7836SJohn.Forte@Sun.COM 		 * An fc_remote_port_t struct was found -- see if anyone has
4537*7836SJohn.Forte@Sun.COM 		 * marked it as "invalid", which means that it is in the
4538*7836SJohn.Forte@Sun.COM 		 * process of going away & we don't want to use it.
4539*7836SJohn.Forte@Sun.COM 		 */
4540*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
4541*7836SJohn.Forte@Sun.COM 		invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0;
4542*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
4543*7836SJohn.Forte@Sun.COM 	}
4544*7836SJohn.Forte@Sun.COM 
4545*7836SJohn.Forte@Sun.COM 	if (pd == NULL || invalid) {
4546*7836SJohn.Forte@Sun.COM 		/*
4547*7836SJohn.Forte@Sun.COM 		 * No fc_remote_port_t was found (or the existing one is
4548*7836SJohn.Forte@Sun.COM 		 * marked as "invalid".) Allocate a new one and use that.
4549*7836SJohn.Forte@Sun.COM 		 * This call will also update the d_id and pwwn hash tables
4550*7836SJohn.Forte@Sun.COM 		 * in the given fc_local_port_t struct with the newly allocated
4551*7836SJohn.Forte@Sun.COM 		 * fc_remote_port_t.
4552*7836SJohn.Forte@Sun.COM 		 */
4553*7836SJohn.Forte@Sun.COM 		if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id,
4554*7836SJohn.Forte@Sun.COM 		    recepient, sleep)) == NULL) {
4555*7836SJohn.Forte@Sun.COM 			/* Just give up if the allocation fails. */
4556*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
4557*7836SJohn.Forte@Sun.COM 			fctl_destroy_remote_node(rnodep);
4558*7836SJohn.Forte@Sun.COM 			return (pd);
4559*7836SJohn.Forte@Sun.COM 		}
4560*7836SJohn.Forte@Sun.COM 
4561*7836SJohn.Forte@Sun.COM 		/*
4562*7836SJohn.Forte@Sun.COM 		 * Add the new fc_remote_port_t struct to the d_id and pwwn
4563*7836SJohn.Forte@Sun.COM 		 * hash tables on the associated fc_local_port_t struct.
4564*7836SJohn.Forte@Sun.COM 		 */
4565*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
4566*7836SJohn.Forte@Sun.COM 		pd->pd_remote_nodep = rnodep;
4567*7836SJohn.Forte@Sun.COM 		fctl_enlist_did_table(port, pd);
4568*7836SJohn.Forte@Sun.COM 		fctl_enlist_pwwn_table(port, pd);
4569*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
4570*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
4571*7836SJohn.Forte@Sun.COM 
4572*7836SJohn.Forte@Sun.COM 		/*
4573*7836SJohn.Forte@Sun.COM 		 * Retrieve a pointer to the fc_remote_node_t (i.e., remote
4574*7836SJohn.Forte@Sun.COM 		 * node) specified by the given node_wwn.  This looks in the
4575*7836SJohn.Forte@Sun.COM 		 * global fctl_nwwn_hash_table[]. The fd_numports reference
4576*7836SJohn.Forte@Sun.COM 		 * count in the fc_remote_node_t struct is incremented.
4577*7836SJohn.Forte@Sun.COM 		 */
4578*7836SJohn.Forte@Sun.COM 		rnodep = fctl_lock_remote_node_by_nwwn(node_wwn);
4579*7836SJohn.Forte@Sun.COM 
4580*7836SJohn.Forte@Sun.COM 	} else {
4581*7836SJohn.Forte@Sun.COM 		/*
4582*7836SJohn.Forte@Sun.COM 		 * An existing and valid fc_remote_port_t struct already
4583*7836SJohn.Forte@Sun.COM 		 * exists on the fc_local_port_t for the given pwwn.
4584*7836SJohn.Forte@Sun.COM 		 */
4585*7836SJohn.Forte@Sun.COM 
4586*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
4587*7836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_remote_nodep != NULL);
4588*7836SJohn.Forte@Sun.COM 
4589*7836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id != d_id) {
4590*7836SJohn.Forte@Sun.COM 			/*
4591*7836SJohn.Forte@Sun.COM 			 * A very unlikely occurance in a well
4592*7836SJohn.Forte@Sun.COM 			 * behaved environment.
4593*7836SJohn.Forte@Sun.COM 			 */
4594*7836SJohn.Forte@Sun.COM 
4595*7836SJohn.Forte@Sun.COM 			/*
4596*7836SJohn.Forte@Sun.COM 			 * The existing fc_remote_port_t has a different
4597*7836SJohn.Forte@Sun.COM 			 * d_id than what we were given. This code will
4598*7836SJohn.Forte@Sun.COM 			 * update the existing one with the one that was
4599*7836SJohn.Forte@Sun.COM 			 * just given.
4600*7836SJohn.Forte@Sun.COM 			 */
4601*7836SJohn.Forte@Sun.COM 			char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1];
4602*7836SJohn.Forte@Sun.COM 			uint32_t old_id;
4603*7836SJohn.Forte@Sun.COM 
4604*7836SJohn.Forte@Sun.COM 			fc_wwn_to_str(port_wwn, string);
4605*7836SJohn.Forte@Sun.COM 
4606*7836SJohn.Forte@Sun.COM 			old_id = pd->pd_port_id.port_id;
4607*7836SJohn.Forte@Sun.COM 
4608*7836SJohn.Forte@Sun.COM 			fctl_delist_did_table(port, pd);
4609*7836SJohn.Forte@Sun.COM 
4610*7836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device"
4611*7836SJohn.Forte@Sun.COM 			    " with PWWN %s changed. New D_ID = %x,"
4612*7836SJohn.Forte@Sun.COM 			    " OLD D_ID = %x", port->fp_instance, string,
4613*7836SJohn.Forte@Sun.COM 			    d_id, old_id);
4614*7836SJohn.Forte@Sun.COM 
4615*7836SJohn.Forte@Sun.COM 			pd->pd_port_id.port_id = d_id;
4616*7836SJohn.Forte@Sun.COM 
4617*7836SJohn.Forte@Sun.COM 			/*
4618*7836SJohn.Forte@Sun.COM 			 * Looks like we have to presume here that the
4619*7836SJohn.Forte@Sun.COM 			 * remote port could be something entirely different
4620*7836SJohn.Forte@Sun.COM 			 * from what was previously existing & valid at this
4621*7836SJohn.Forte@Sun.COM 			 * pwwn.
4622*7836SJohn.Forte@Sun.COM 			 */
4623*7836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_CHANGED;
4624*7836SJohn.Forte@Sun.COM 
4625*7836SJohn.Forte@Sun.COM 			/* Record (update) the new d_id for the remote port */
4626*7836SJohn.Forte@Sun.COM 			fctl_enlist_did_table(port, pd);
4627*7836SJohn.Forte@Sun.COM 
4628*7836SJohn.Forte@Sun.COM 		} else if (pd->pd_type == PORT_DEVICE_OLD) {
4629*7836SJohn.Forte@Sun.COM 			/*
4630*7836SJohn.Forte@Sun.COM 			 * OK at least the old & new d_id's match. So for
4631*7836SJohn.Forte@Sun.COM 			 * PORT_DEVICE_OLD, this assumes that the remote
4632*7836SJohn.Forte@Sun.COM 			 * port had disappeared but now has come back.
4633*7836SJohn.Forte@Sun.COM 			 * Update the pd_type and pd_state to put the
4634*7836SJohn.Forte@Sun.COM 			 * remote port back into service.
4635*7836SJohn.Forte@Sun.COM 			 */
4636*7836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_NOCHANGE;
4637*7836SJohn.Forte@Sun.COM 			pd->pd_state = PORT_DEVICE_VALID;
4638*7836SJohn.Forte@Sun.COM 
4639*7836SJohn.Forte@Sun.COM 			fctl_enlist_did_table(port, pd);
4640*7836SJohn.Forte@Sun.COM 
4641*7836SJohn.Forte@Sun.COM 		} else {
4642*7836SJohn.Forte@Sun.COM 			/*
4643*7836SJohn.Forte@Sun.COM 			 * OK the old & new d_id's match, and the remote
4644*7836SJohn.Forte@Sun.COM 			 * port struct is not marked as PORT_DEVICE_OLD, so
4645*7836SJohn.Forte@Sun.COM 			 * presume that it's still the same device and is
4646*7836SJohn.Forte@Sun.COM 			 * still in good shape.  Also this presumes that we
4647*7836SJohn.Forte@Sun.COM 			 * do not need to update d_id or pwwn hash tables.
4648*7836SJohn.Forte@Sun.COM 			 */
4649*7836SJohn.Forte@Sun.COM 			/* sanitize device values */
4650*7836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_NOCHANGE;
4651*7836SJohn.Forte@Sun.COM 			pd->pd_state = PORT_DEVICE_VALID;
4652*7836SJohn.Forte@Sun.COM 		}
4653*7836SJohn.Forte@Sun.COM 
4654*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
4655*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
4656*7836SJohn.Forte@Sun.COM 
4657*7836SJohn.Forte@Sun.COM 		if (rnodep != pd->pd_remote_nodep) {
4658*7836SJohn.Forte@Sun.COM 			if ((rnodep != NULL) &&
4659*7836SJohn.Forte@Sun.COM 			    (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name,
4660*7836SJohn.Forte@Sun.COM 			    node_wwn) != 0)) {
4661*7836SJohn.Forte@Sun.COM 				/*
4662*7836SJohn.Forte@Sun.COM 				 * Rut-roh, there is an fc_remote_node_t remote
4663*7836SJohn.Forte@Sun.COM 				 * node struct for the given node_wwn, but the
4664*7836SJohn.Forte@Sun.COM 				 * fc_remote_port_t remote port struct doesn't
4665*7836SJohn.Forte@Sun.COM 				 * know about it.  This just prints a warning
4666*7836SJohn.Forte@Sun.COM 				 * message & fails the fc_remote_port_t
4667*7836SJohn.Forte@Sun.COM 				 * allocation (possible leak here?).
4668*7836SJohn.Forte@Sun.COM 				 */
4669*7836SJohn.Forte@Sun.COM 				char	ww1_name[17];
4670*7836SJohn.Forte@Sun.COM 				char	ww2_name[17];
4671*7836SJohn.Forte@Sun.COM 
4672*7836SJohn.Forte@Sun.COM 				fc_wwn_to_str(
4673*7836SJohn.Forte@Sun.COM 				    &pd->pd_remote_nodep->fd_node_name,
4674*7836SJohn.Forte@Sun.COM 				    ww1_name);
4675*7836SJohn.Forte@Sun.COM 				fc_wwn_to_str(node_wwn, ww2_name);
4676*7836SJohn.Forte@Sun.COM 
4677*7836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: "
4678*7836SJohn.Forte@Sun.COM 				    "Expected %s Got %s", port->fp_instance,
4679*7836SJohn.Forte@Sun.COM 				    ww1_name, ww2_name);
4680*7836SJohn.Forte@Sun.COM 			}
4681*7836SJohn.Forte@Sun.COM 
4682*7836SJohn.Forte@Sun.COM 			return (NULL);
4683*7836SJohn.Forte@Sun.COM 		}
4684*7836SJohn.Forte@Sun.COM 	}
4685*7836SJohn.Forte@Sun.COM 
4686*7836SJohn.Forte@Sun.COM 	/*
4687*7836SJohn.Forte@Sun.COM 	 * Add  the fc_remote_port_t onto the linked list of remote port
4688*7836SJohn.Forte@Sun.COM 	 * devices associated with the given fc_remote_node_t (remote node).
4689*7836SJohn.Forte@Sun.COM 	 */
4690*7836SJohn.Forte@Sun.COM 	fctl_link_remote_port_to_remote_node(rnodep, pd);
4691*7836SJohn.Forte@Sun.COM 
4692*7836SJohn.Forte@Sun.COM 	return (pd);
4693*7836SJohn.Forte@Sun.COM }
4694*7836SJohn.Forte@Sun.COM 
4695*7836SJohn.Forte@Sun.COM 
4696*7836SJohn.Forte@Sun.COM /*
4697*7836SJohn.Forte@Sun.COM  * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
4698*7836SJohn.Forte@Sun.COM  * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
4699*7836SJohn.Forte@Sun.COM  * references to the fc_remote_port_t from the d_id and pwwn tables in the
4700*7836SJohn.Forte@Sun.COM  * given fc_local_port_t.  Deallocates the given fc_remote_port_t.
4701*7836SJohn.Forte@Sun.COM  *
4702*7836SJohn.Forte@Sun.COM  * Returns a count of the number of remaining fc_remote_port_t structs
4703*7836SJohn.Forte@Sun.COM  * associated with the fc_remote_node_t struct.
4704*7836SJohn.Forte@Sun.COM  *
4705*7836SJohn.Forte@Sun.COM  * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
4706*7836SJohn.Forte@Sun.COM  * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
4707*7836SJohn.Forte@Sun.COM  * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
4708*7836SJohn.Forte@Sun.COM  * the cleanup.  The function then also returns '1'
4709*7836SJohn.Forte@Sun.COM  * instead of the actual number of remaining fc_remote_port_t structs
4710*7836SJohn.Forte@Sun.COM  *
4711*7836SJohn.Forte@Sun.COM  * If there are no more remote ports on the remote node, return 0.
4712*7836SJohn.Forte@Sun.COM  * Otherwise, return non-zero.
4713*7836SJohn.Forte@Sun.COM  */
4714*7836SJohn.Forte@Sun.COM int
4715*7836SJohn.Forte@Sun.COM fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
4716*7836SJohn.Forte@Sun.COM {
4717*7836SJohn.Forte@Sun.COM 	fc_remote_node_t 	*rnodep;
4718*7836SJohn.Forte@Sun.COM 	int			rcount = 0;
4719*7836SJohn.Forte@Sun.COM 
4720*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
4721*7836SJohn.Forte@Sun.COM 
4722*7836SJohn.Forte@Sun.COM 	/*
4723*7836SJohn.Forte@Sun.COM 	 * If pd_ref_count > 0, we can't pull the rug out from any
4724*7836SJohn.Forte@Sun.COM 	 * current users of this fc_remote_port_t.  We'll mark it as old
4725*7836SJohn.Forte@Sun.COM 	 * and in need of removal.  The same goes for any fc_remote_port_t
4726*7836SJohn.Forte@Sun.COM 	 * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
4727*7836SJohn.Forte@Sun.COM 	 * have not yet been notified that the handle is no longer valid
4728*7836SJohn.Forte@Sun.COM 	 * (i.e., PD_GIVEN_TO_ULPS is set).
4729*7836SJohn.Forte@Sun.COM 	 */
4730*7836SJohn.Forte@Sun.COM 	if ((pd->pd_ref_count > 0) ||
4731*7836SJohn.Forte@Sun.COM 	    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) {
4732*7836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_NEEDS_REMOVAL;
4733*7836SJohn.Forte@Sun.COM 		pd->pd_type = PORT_DEVICE_OLD;
4734*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
4735*7836SJohn.Forte@Sun.COM 		return (1);
4736*7836SJohn.Forte@Sun.COM 	}
4737*7836SJohn.Forte@Sun.COM 
4738*7836SJohn.Forte@Sun.COM 	pd->pd_type = PORT_DEVICE_OLD;
4739*7836SJohn.Forte@Sun.COM 
4740*7836SJohn.Forte@Sun.COM 	rnodep = pd->pd_remote_nodep;
4741*7836SJohn.Forte@Sun.COM 
4742*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
4743*7836SJohn.Forte@Sun.COM 
4744*7836SJohn.Forte@Sun.COM 	if (rnodep != NULL) {
4745*7836SJohn.Forte@Sun.COM 		/*
4746*7836SJohn.Forte@Sun.COM 		 * Remove the fc_remote_port_t from the linked list of remote
4747*7836SJohn.Forte@Sun.COM 		 * ports for the given fc_remote_node_t. This is only called
4748*7836SJohn.Forte@Sun.COM 		 * here and in fctl_destroy_all_remote_ports().
4749*7836SJohn.Forte@Sun.COM 		 */
4750*7836SJohn.Forte@Sun.COM 		rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd);
4751*7836SJohn.Forte@Sun.COM 	}
4752*7836SJohn.Forte@Sun.COM 
4753*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4754*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
4755*7836SJohn.Forte@Sun.COM 
4756*7836SJohn.Forte@Sun.COM 	fctl_delist_did_table(port, pd);
4757*7836SJohn.Forte@Sun.COM 	fctl_delist_pwwn_table(port, pd);
4758*7836SJohn.Forte@Sun.COM 
4759*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
4760*7836SJohn.Forte@Sun.COM 
4761*7836SJohn.Forte@Sun.COM 	/*
4762*7836SJohn.Forte@Sun.COM 	 * Deconstruct & free the fc_remote_port_t. This is only called
4763*7836SJohn.Forte@Sun.COM 	 * here and in fctl_destroy_all_remote_ports().
4764*7836SJohn.Forte@Sun.COM 	 */
4765*7836SJohn.Forte@Sun.COM 	fctl_dealloc_remote_port(pd);
4766*7836SJohn.Forte@Sun.COM 
4767*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4768*7836SJohn.Forte@Sun.COM 
4769*7836SJohn.Forte@Sun.COM 	return (rcount);
4770*7836SJohn.Forte@Sun.COM }
4771*7836SJohn.Forte@Sun.COM 
4772*7836SJohn.Forte@Sun.COM 
4773*7836SJohn.Forte@Sun.COM /*
4774*7836SJohn.Forte@Sun.COM  * This goes thru the d_id table on the given fc_local_port_t.
4775*7836SJohn.Forte@Sun.COM  * For each fc_remote_port_t found, this will:
4776*7836SJohn.Forte@Sun.COM  *
4777*7836SJohn.Forte@Sun.COM  *  - Remove the fc_remote_port_t from the linked list of remote ports for
4778*7836SJohn.Forte@Sun.COM  *    the associated fc_remote_node_t.  If the linked list goes empty, then this
4779*7836SJohn.Forte@Sun.COM  *    tries to deconstruct & free the fc_remote_node_t (that also removes the
4780*7836SJohn.Forte@Sun.COM  *    fc_remote_node_t from the global fctl_nwwn_hash_table[]).
4781*7836SJohn.Forte@Sun.COM  *
4782*7836SJohn.Forte@Sun.COM  *  - Remove the fc_remote_port_t from the pwwn list on the given
4783*7836SJohn.Forte@Sun.COM  *    fc_local_port_t.
4784*7836SJohn.Forte@Sun.COM  *
4785*7836SJohn.Forte@Sun.COM  *  - Deconstruct and free the fc_remote_port_t.
4786*7836SJohn.Forte@Sun.COM  *
4787*7836SJohn.Forte@Sun.COM  *  - Removes the link to the fc_remote_port_t in the d_id table. Note, this
4788*7836SJohn.Forte@Sun.COM  *    does not appear to correctle decrement the d_id_count tho.
4789*7836SJohn.Forte@Sun.COM  */
4790*7836SJohn.Forte@Sun.COM void
4791*7836SJohn.Forte@Sun.COM fctl_destroy_all_remote_ports(fc_local_port_t *port)
4792*7836SJohn.Forte@Sun.COM {
4793*7836SJohn.Forte@Sun.COM 	int			index;
4794*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
4795*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*rnodep;
4796*7836SJohn.Forte@Sun.COM 	struct d_id_hash 	*head;
4797*7836SJohn.Forte@Sun.COM 
4798*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
4799*7836SJohn.Forte@Sun.COM 
4800*7836SJohn.Forte@Sun.COM 	for (index = 0; index < did_table_size; index++) {
4801*7836SJohn.Forte@Sun.COM 
4802*7836SJohn.Forte@Sun.COM 		head = &port->fp_did_table[index];
4803*7836SJohn.Forte@Sun.COM 
4804*7836SJohn.Forte@Sun.COM 		while (head->d_id_head != NULL) {
4805*7836SJohn.Forte@Sun.COM 			pd = head->d_id_head;
4806*7836SJohn.Forte@Sun.COM 
4807*7836SJohn.Forte@Sun.COM 			/*
4808*7836SJohn.Forte@Sun.COM 			 * See if this remote port (fc_remote_port_t) has a
4809*7836SJohn.Forte@Sun.COM 			 * reference to a remote node (fc_remote_node_t) in its
4810*7836SJohn.Forte@Sun.COM 			 * pd->pd_remote_nodep pointer.
4811*7836SJohn.Forte@Sun.COM 			 */
4812*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
4813*7836SJohn.Forte@Sun.COM 			rnodep = pd->pd_remote_nodep;
4814*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
4815*7836SJohn.Forte@Sun.COM 
4816*7836SJohn.Forte@Sun.COM 			if (rnodep != NULL) {
4817*7836SJohn.Forte@Sun.COM 				/*
4818*7836SJohn.Forte@Sun.COM 				 * An fc_remote_node_t reference exists. Remove
4819*7836SJohn.Forte@Sun.COM 				 * the fc_remote_port_t from the linked list of
4820*7836SJohn.Forte@Sun.COM 				 * remote ports for fc_remote_node_t.
4821*7836SJohn.Forte@Sun.COM 				 */
4822*7836SJohn.Forte@Sun.COM 				if (fctl_unlink_remote_port_from_remote_node(
4823*7836SJohn.Forte@Sun.COM 				    rnodep, pd) == 0) {
4824*7836SJohn.Forte@Sun.COM 					/*
4825*7836SJohn.Forte@Sun.COM 					 * The fd_numports reference count
4826*7836SJohn.Forte@Sun.COM 					 * in the fc_remote_node_t has come
4827*7836SJohn.Forte@Sun.COM 					 * back as zero, so we can free the
4828*7836SJohn.Forte@Sun.COM 					 * fc_remote_node_t. This also means
4829*7836SJohn.Forte@Sun.COM 					 * that the fc_remote_node_t was
4830*7836SJohn.Forte@Sun.COM 					 * removed from the
4831*7836SJohn.Forte@Sun.COM 					 * fctl_nwwn_hash_table[].
4832*7836SJohn.Forte@Sun.COM 					 *
4833*7836SJohn.Forte@Sun.COM 					 * This will silently skip the
4834*7836SJohn.Forte@Sun.COM 					 * kmem_free() if either the
4835*7836SJohn.Forte@Sun.COM 					 * fd_numports is nonzero or
4836*7836SJohn.Forte@Sun.COM 					 * the fd_port is not NULL in
4837*7836SJohn.Forte@Sun.COM 					 * the fc_remote_node_t.
4838*7836SJohn.Forte@Sun.COM 					 */
4839*7836SJohn.Forte@Sun.COM 					fctl_destroy_remote_node(rnodep);
4840*7836SJohn.Forte@Sun.COM 				}
4841*7836SJohn.Forte@Sun.COM 			}
4842*7836SJohn.Forte@Sun.COM 
4843*7836SJohn.Forte@Sun.COM 			/*
4844*7836SJohn.Forte@Sun.COM 			 * Clean up the entry in the fc_local_port_t's pwwn
4845*7836SJohn.Forte@Sun.COM 			 * table for the given fc_remote_port_t (i.e., the pd).
4846*7836SJohn.Forte@Sun.COM 			 */
4847*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
4848*7836SJohn.Forte@Sun.COM 			fctl_delist_pwwn_table(port, pd);
4849*7836SJohn.Forte@Sun.COM 			pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
4850*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
4851*7836SJohn.Forte@Sun.COM 
4852*7836SJohn.Forte@Sun.COM 			/*
4853*7836SJohn.Forte@Sun.COM 			 * Remove the current entry from the d_id list.
4854*7836SJohn.Forte@Sun.COM 			 */
4855*7836SJohn.Forte@Sun.COM 			head->d_id_head = pd->pd_did_hnext;
4856*7836SJohn.Forte@Sun.COM 
4857*7836SJohn.Forte@Sun.COM 			/*
4858*7836SJohn.Forte@Sun.COM 			 * Deconstruct & free the fc_remote_port_t (pd)
4859*7836SJohn.Forte@Sun.COM 			 * Note: this is only called here and in
4860*7836SJohn.Forte@Sun.COM 			 * fctl_destroy_remote_port_t().
4861*7836SJohn.Forte@Sun.COM 			 */
4862*7836SJohn.Forte@Sun.COM 			fctl_dealloc_remote_port(pd);
4863*7836SJohn.Forte@Sun.COM 		}
4864*7836SJohn.Forte@Sun.COM 	}
4865*7836SJohn.Forte@Sun.COM 
4866*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
4867*7836SJohn.Forte@Sun.COM }
4868*7836SJohn.Forte@Sun.COM 
4869*7836SJohn.Forte@Sun.COM 
4870*7836SJohn.Forte@Sun.COM int
4871*7836SJohn.Forte@Sun.COM fctl_is_wwn_zero(la_wwn_t *wwn)
4872*7836SJohn.Forte@Sun.COM {
4873*7836SJohn.Forte@Sun.COM 	int count;
4874*7836SJohn.Forte@Sun.COM 
4875*7836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (la_wwn_t); count++) {
4876*7836SJohn.Forte@Sun.COM 		if (wwn->raw_wwn[count] != 0) {
4877*7836SJohn.Forte@Sun.COM 			return (FC_FAILURE);
4878*7836SJohn.Forte@Sun.COM 		}
4879*7836SJohn.Forte@Sun.COM 	}
4880*7836SJohn.Forte@Sun.COM 
4881*7836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
4882*7836SJohn.Forte@Sun.COM }
4883*7836SJohn.Forte@Sun.COM 
4884*7836SJohn.Forte@Sun.COM 
4885*7836SJohn.Forte@Sun.COM void
4886*7836SJohn.Forte@Sun.COM fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
4887*7836SJohn.Forte@Sun.COM {
4888*7836SJohn.Forte@Sun.COM 	int			data_cb;
4889*7836SJohn.Forte@Sun.COM 	int			check_type;
4890*7836SJohn.Forte@Sun.COM 	int			rval;
4891*7836SJohn.Forte@Sun.COM 	uint32_t		claimed;
4892*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
4893*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
4894*7836SJohn.Forte@Sun.COM 
4895*7836SJohn.Forte@Sun.COM 	claimed = 0;
4896*7836SJohn.Forte@Sun.COM 	check_type = 1;
4897*7836SJohn.Forte@Sun.COM 
4898*7836SJohn.Forte@Sun.COM 	switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) {
4899*7836SJohn.Forte@Sun.COM 	case R_CTL_DEVICE_DATA:
4900*7836SJohn.Forte@Sun.COM 		data_cb = 1;
4901*7836SJohn.Forte@Sun.COM 		break;
4902*7836SJohn.Forte@Sun.COM 
4903*7836SJohn.Forte@Sun.COM 	case R_CTL_EXTENDED_SVC:
4904*7836SJohn.Forte@Sun.COM 		check_type = 0;
4905*7836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
4906*7836SJohn.Forte@Sun.COM 
4907*7836SJohn.Forte@Sun.COM 	case R_CTL_FC4_SVC:
4908*7836SJohn.Forte@Sun.COM 		data_cb = 0;
4909*7836SJohn.Forte@Sun.COM 		break;
4910*7836SJohn.Forte@Sun.COM 
4911*7836SJohn.Forte@Sun.COM 	default:
4912*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
4913*7836SJohn.Forte@Sun.COM 		ASSERT(port->fp_active_ubs > 0);
4914*7836SJohn.Forte@Sun.COM 		if (--(port->fp_active_ubs) == 0) {
4915*7836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4916*7836SJohn.Forte@Sun.COM 		}
4917*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
4918*7836SJohn.Forte@Sun.COM 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4919*7836SJohn.Forte@Sun.COM 		    1, &buf->ub_token);
4920*7836SJohn.Forte@Sun.COM 		return;
4921*7836SJohn.Forte@Sun.COM 	}
4922*7836SJohn.Forte@Sun.COM 
4923*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
4924*7836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
4925*7836SJohn.Forte@Sun.COM 		if (check_type && mod->mod_info->ulp_type != type) {
4926*7836SJohn.Forte@Sun.COM 			continue;
4927*7836SJohn.Forte@Sun.COM 		}
4928*7836SJohn.Forte@Sun.COM 
4929*7836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
4930*7836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
4931*7836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
4932*7836SJohn.Forte@Sun.COM 
4933*7836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
4934*7836SJohn.Forte@Sun.COM 			continue;
4935*7836SJohn.Forte@Sun.COM 		}
4936*7836SJohn.Forte@Sun.COM 
4937*7836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
4938*7836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
4939*7836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
4940*7836SJohn.Forte@Sun.COM 			continue;
4941*7836SJohn.Forte@Sun.COM 		}
4942*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
4943*7836SJohn.Forte@Sun.COM 
4944*7836SJohn.Forte@Sun.COM 		if (data_cb == 1) {
4945*7836SJohn.Forte@Sun.COM 			rval = mod->mod_info->ulp_data_callback(
4946*7836SJohn.Forte@Sun.COM 			    mod->mod_info->ulp_handle,
4947*7836SJohn.Forte@Sun.COM 			    (opaque_t)port, buf, claimed);
4948*7836SJohn.Forte@Sun.COM 		} else {
4949*7836SJohn.Forte@Sun.COM 			rval = mod->mod_info->ulp_els_callback(
4950*7836SJohn.Forte@Sun.COM 			    mod->mod_info->ulp_handle,
4951*7836SJohn.Forte@Sun.COM 			    (opaque_t)port, buf, claimed);
4952*7836SJohn.Forte@Sun.COM 		}
4953*7836SJohn.Forte@Sun.COM 
4954*7836SJohn.Forte@Sun.COM 		if (rval == FC_SUCCESS && claimed == 0) {
4955*7836SJohn.Forte@Sun.COM 			claimed = 1;
4956*7836SJohn.Forte@Sun.COM 		}
4957*7836SJohn.Forte@Sun.COM 	}
4958*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
4959*7836SJohn.Forte@Sun.COM 
4960*7836SJohn.Forte@Sun.COM 	if (claimed == 0) {
4961*7836SJohn.Forte@Sun.COM 		/*
4962*7836SJohn.Forte@Sun.COM 		 * We should actually RJT since nobody claimed it.
4963*7836SJohn.Forte@Sun.COM 		 */
4964*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
4965*7836SJohn.Forte@Sun.COM 		ASSERT(port->fp_active_ubs > 0);
4966*7836SJohn.Forte@Sun.COM 		if (--(port->fp_active_ubs) == 0) {
4967*7836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4968*7836SJohn.Forte@Sun.COM 		}
4969*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
4970*7836SJohn.Forte@Sun.COM 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4971*7836SJohn.Forte@Sun.COM 		    1, &buf->ub_token);
4972*7836SJohn.Forte@Sun.COM 
4973*7836SJohn.Forte@Sun.COM 	} else {
4974*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
4975*7836SJohn.Forte@Sun.COM 		if (--port->fp_active_ubs == 0) {
4976*7836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4977*7836SJohn.Forte@Sun.COM 		}
4978*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
4979*7836SJohn.Forte@Sun.COM 	}
4980*7836SJohn.Forte@Sun.COM }
4981*7836SJohn.Forte@Sun.COM 
4982*7836SJohn.Forte@Sun.COM 
4983*7836SJohn.Forte@Sun.COM /*
4984*7836SJohn.Forte@Sun.COM  * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
4985*7836SJohn.Forte@Sun.COM  *
4986*7836SJohn.Forte@Sun.COM  * With all these mutexes held, we should make sure this function does not eat
4987*7836SJohn.Forte@Sun.COM  * up much time.
4988*7836SJohn.Forte@Sun.COM  */
4989*7836SJohn.Forte@Sun.COM void
4990*7836SJohn.Forte@Sun.COM fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd)
4991*7836SJohn.Forte@Sun.COM {
4992*7836SJohn.Forte@Sun.COM 	fc_remote_node_t *node;
4993*7836SJohn.Forte@Sun.COM 
4994*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
4995*7836SJohn.Forte@Sun.COM 
4996*7836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
4997*7836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
4998*7836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
4999*7836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
5000*7836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
5001*7836SJohn.Forte@Sun.COM 	map->map_flags = 0;
5002*7836SJohn.Forte@Sun.COM 
5003*7836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5004*7836SJohn.Forte@Sun.COM 
5005*7836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5006*7836SJohn.Forte@Sun.COM 
5007*7836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
5008*7836SJohn.Forte@Sun.COM 
5009*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&node->fd_mutex));
5010*7836SJohn.Forte@Sun.COM 
5011*7836SJohn.Forte@Sun.COM 	if (node) {
5012*7836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
5013*7836SJohn.Forte@Sun.COM 	}
5014*7836SJohn.Forte@Sun.COM 	map->map_pd = pd;
5015*7836SJohn.Forte@Sun.COM }
5016*7836SJohn.Forte@Sun.COM 
5017*7836SJohn.Forte@Sun.COM void
5018*7836SJohn.Forte@Sun.COM fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
5019*7836SJohn.Forte@Sun.COM {
5020*7836SJohn.Forte@Sun.COM 	fc_remote_node_t *node;
5021*7836SJohn.Forte@Sun.COM 
5022*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
5023*7836SJohn.Forte@Sun.COM 
5024*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
5025*7836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
5026*7836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
5027*7836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
5028*7836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
5029*7836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
5030*7836SJohn.Forte@Sun.COM 	map->map_flags = 0;
5031*7836SJohn.Forte@Sun.COM 
5032*7836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5033*7836SJohn.Forte@Sun.COM 
5034*7836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5035*7836SJohn.Forte@Sun.COM 
5036*7836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
5037*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
5038*7836SJohn.Forte@Sun.COM 
5039*7836SJohn.Forte@Sun.COM 	if (node) {
5040*7836SJohn.Forte@Sun.COM 		mutex_enter(&node->fd_mutex);
5041*7836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
5042*7836SJohn.Forte@Sun.COM 		mutex_exit(&node->fd_mutex);
5043*7836SJohn.Forte@Sun.COM 	}
5044*7836SJohn.Forte@Sun.COM 	map->map_pd = pd;
5045*7836SJohn.Forte@Sun.COM }
5046*7836SJohn.Forte@Sun.COM 
5047*7836SJohn.Forte@Sun.COM 
5048*7836SJohn.Forte@Sun.COM static int
5049*7836SJohn.Forte@Sun.COM fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5050*7836SJohn.Forte@Sun.COM {
5051*7836SJohn.Forte@Sun.COM 	int 	rval = FC_SUCCESS;
5052*7836SJohn.Forte@Sun.COM 
5053*7836SJohn.Forte@Sun.COM 	switch (ns_req->ns_cmd) {
5054*7836SJohn.Forte@Sun.COM 	case NS_RFT_ID: {
5055*7836SJohn.Forte@Sun.COM 		int		count;
5056*7836SJohn.Forte@Sun.COM 		uint32_t	*src;
5057*7836SJohn.Forte@Sun.COM 		uint32_t	*dst;
5058*7836SJohn.Forte@Sun.COM 		ns_rfc_type_t 	*rfc;
5059*7836SJohn.Forte@Sun.COM 
5060*7836SJohn.Forte@Sun.COM 		rfc = (ns_rfc_type_t *)ns_req->ns_req_payload;
5061*7836SJohn.Forte@Sun.COM 
5062*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5063*7836SJohn.Forte@Sun.COM 		src = (uint32_t *)port->fp_fc4_types;
5064*7836SJohn.Forte@Sun.COM 		dst = (uint32_t *)rfc->rfc_types;
5065*7836SJohn.Forte@Sun.COM 
5066*7836SJohn.Forte@Sun.COM 		for (count = 0; count < 8; count++) {
5067*7836SJohn.Forte@Sun.COM 			*src++ |= *dst++;
5068*7836SJohn.Forte@Sun.COM 		}
5069*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5070*7836SJohn.Forte@Sun.COM 
5071*7836SJohn.Forte@Sun.COM 		break;
5072*7836SJohn.Forte@Sun.COM 	}
5073*7836SJohn.Forte@Sun.COM 
5074*7836SJohn.Forte@Sun.COM 	case NS_RSPN_ID: {
5075*7836SJohn.Forte@Sun.COM 		ns_spn_t *spn;
5076*7836SJohn.Forte@Sun.COM 
5077*7836SJohn.Forte@Sun.COM 		spn = (ns_spn_t *)ns_req->ns_req_payload;
5078*7836SJohn.Forte@Sun.COM 
5079*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5080*7836SJohn.Forte@Sun.COM 		port->fp_sym_port_namelen = spn->spn_len;
5081*7836SJohn.Forte@Sun.COM 		if (spn->spn_len) {
5082*7836SJohn.Forte@Sun.COM 			bcopy((caddr_t)spn + sizeof (ns_spn_t),
5083*7836SJohn.Forte@Sun.COM 			    port->fp_sym_port_name, spn->spn_len);
5084*7836SJohn.Forte@Sun.COM 		}
5085*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5086*7836SJohn.Forte@Sun.COM 
5087*7836SJohn.Forte@Sun.COM 		break;
5088*7836SJohn.Forte@Sun.COM 	}
5089*7836SJohn.Forte@Sun.COM 
5090*7836SJohn.Forte@Sun.COM 	case NS_RSNN_NN: {
5091*7836SJohn.Forte@Sun.COM 		ns_snn_t *snn;
5092*7836SJohn.Forte@Sun.COM 
5093*7836SJohn.Forte@Sun.COM 		snn = (ns_snn_t *)ns_req->ns_req_payload;
5094*7836SJohn.Forte@Sun.COM 
5095*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5096*7836SJohn.Forte@Sun.COM 		port->fp_sym_node_namelen = snn->snn_len;
5097*7836SJohn.Forte@Sun.COM 		if (snn->snn_len) {
5098*7836SJohn.Forte@Sun.COM 			bcopy((caddr_t)snn + sizeof (ns_snn_t),
5099*7836SJohn.Forte@Sun.COM 			    port->fp_sym_node_name, snn->snn_len);
5100*7836SJohn.Forte@Sun.COM 		}
5101*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5102*7836SJohn.Forte@Sun.COM 
5103*7836SJohn.Forte@Sun.COM 		break;
5104*7836SJohn.Forte@Sun.COM 	}
5105*7836SJohn.Forte@Sun.COM 
5106*7836SJohn.Forte@Sun.COM 	case NS_RIP_NN: {
5107*7836SJohn.Forte@Sun.COM 		ns_rip_t *rip;
5108*7836SJohn.Forte@Sun.COM 
5109*7836SJohn.Forte@Sun.COM 		rip = (ns_rip_t *)ns_req->ns_req_payload;
5110*7836SJohn.Forte@Sun.COM 
5111*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5112*7836SJohn.Forte@Sun.COM 		bcopy(rip->rip_ip_addr, port->fp_ip_addr,
5113*7836SJohn.Forte@Sun.COM 		    sizeof (rip->rip_ip_addr));
5114*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5115*7836SJohn.Forte@Sun.COM 
5116*7836SJohn.Forte@Sun.COM 		break;
5117*7836SJohn.Forte@Sun.COM 	}
5118*7836SJohn.Forte@Sun.COM 
5119*7836SJohn.Forte@Sun.COM 	case NS_RIPA_NN: {
5120*7836SJohn.Forte@Sun.COM 		ns_ipa_t *ipa;
5121*7836SJohn.Forte@Sun.COM 
5122*7836SJohn.Forte@Sun.COM 		ipa = (ns_ipa_t *)ns_req->ns_req_payload;
5123*7836SJohn.Forte@Sun.COM 
5124*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5125*7836SJohn.Forte@Sun.COM 		bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value));
5126*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5127*7836SJohn.Forte@Sun.COM 
5128*7836SJohn.Forte@Sun.COM 		break;
5129*7836SJohn.Forte@Sun.COM 	}
5130*7836SJohn.Forte@Sun.COM 
5131*7836SJohn.Forte@Sun.COM 	default:
5132*7836SJohn.Forte@Sun.COM 		rval = FC_BADOBJECT;
5133*7836SJohn.Forte@Sun.COM 		break;
5134*7836SJohn.Forte@Sun.COM 	}
5135*7836SJohn.Forte@Sun.COM 
5136*7836SJohn.Forte@Sun.COM 	return (rval);
5137*7836SJohn.Forte@Sun.COM }
5138*7836SJohn.Forte@Sun.COM 
5139*7836SJohn.Forte@Sun.COM 
5140*7836SJohn.Forte@Sun.COM static int
5141*7836SJohn.Forte@Sun.COM fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5142*7836SJohn.Forte@Sun.COM {
5143*7836SJohn.Forte@Sun.COM 	int 	rval = FC_SUCCESS;
5144*7836SJohn.Forte@Sun.COM 
5145*7836SJohn.Forte@Sun.COM 	switch (ns_req->ns_cmd) {
5146*7836SJohn.Forte@Sun.COM 	case NS_GFT_ID: {
5147*7836SJohn.Forte@Sun.COM 		ns_rfc_type_t *rfc;
5148*7836SJohn.Forte@Sun.COM 
5149*7836SJohn.Forte@Sun.COM 		rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload;
5150*7836SJohn.Forte@Sun.COM 
5151*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5152*7836SJohn.Forte@Sun.COM 		bcopy(port->fp_fc4_types, rfc->rfc_types,
5153*7836SJohn.Forte@Sun.COM 		    sizeof (rfc->rfc_types));
5154*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5155*7836SJohn.Forte@Sun.COM 		break;
5156*7836SJohn.Forte@Sun.COM 	}
5157*7836SJohn.Forte@Sun.COM 
5158*7836SJohn.Forte@Sun.COM 	case NS_GSPN_ID: {
5159*7836SJohn.Forte@Sun.COM 		ns_spn_t *spn;
5160*7836SJohn.Forte@Sun.COM 
5161*7836SJohn.Forte@Sun.COM 		spn = (ns_spn_t *)ns_req->ns_resp_payload;
5162*7836SJohn.Forte@Sun.COM 
5163*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5164*7836SJohn.Forte@Sun.COM 		spn->spn_len = port->fp_sym_port_namelen;
5165*7836SJohn.Forte@Sun.COM 		if (spn->spn_len) {
5166*7836SJohn.Forte@Sun.COM 			bcopy(port->fp_sym_port_name, (caddr_t)spn +
5167*7836SJohn.Forte@Sun.COM 			    sizeof (ns_spn_t), spn->spn_len);
5168*7836SJohn.Forte@Sun.COM 		}
5169*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5170*7836SJohn.Forte@Sun.COM 
5171*7836SJohn.Forte@Sun.COM 		break;
5172*7836SJohn.Forte@Sun.COM 	}
5173*7836SJohn.Forte@Sun.COM 
5174*7836SJohn.Forte@Sun.COM 	case NS_GSNN_NN: {
5175*7836SJohn.Forte@Sun.COM 		ns_snn_t *snn;
5176*7836SJohn.Forte@Sun.COM 
5177*7836SJohn.Forte@Sun.COM 		snn = (ns_snn_t *)ns_req->ns_resp_payload;
5178*7836SJohn.Forte@Sun.COM 
5179*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5180*7836SJohn.Forte@Sun.COM 		snn->snn_len = port->fp_sym_node_namelen;
5181*7836SJohn.Forte@Sun.COM 		if (snn->snn_len) {
5182*7836SJohn.Forte@Sun.COM 			bcopy(port->fp_sym_node_name, (caddr_t)snn +
5183*7836SJohn.Forte@Sun.COM 			    sizeof (ns_snn_t), snn->snn_len);
5184*7836SJohn.Forte@Sun.COM 		}
5185*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5186*7836SJohn.Forte@Sun.COM 
5187*7836SJohn.Forte@Sun.COM 		break;
5188*7836SJohn.Forte@Sun.COM 	}
5189*7836SJohn.Forte@Sun.COM 
5190*7836SJohn.Forte@Sun.COM 	case NS_GIP_NN: {
5191*7836SJohn.Forte@Sun.COM 		ns_rip_t *rip;
5192*7836SJohn.Forte@Sun.COM 
5193*7836SJohn.Forte@Sun.COM 		rip = (ns_rip_t *)ns_req->ns_resp_payload;
5194*7836SJohn.Forte@Sun.COM 
5195*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5196*7836SJohn.Forte@Sun.COM 		bcopy(port->fp_ip_addr, rip->rip_ip_addr,
5197*7836SJohn.Forte@Sun.COM 		    sizeof (rip->rip_ip_addr));
5198*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5199*7836SJohn.Forte@Sun.COM 
5200*7836SJohn.Forte@Sun.COM 		break;
5201*7836SJohn.Forte@Sun.COM 	}
5202*7836SJohn.Forte@Sun.COM 
5203*7836SJohn.Forte@Sun.COM 	case NS_GIPA_NN: {
5204*7836SJohn.Forte@Sun.COM 		ns_ipa_t *ipa;
5205*7836SJohn.Forte@Sun.COM 
5206*7836SJohn.Forte@Sun.COM 		ipa = (ns_ipa_t *)ns_req->ns_resp_payload;
5207*7836SJohn.Forte@Sun.COM 
5208*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5209*7836SJohn.Forte@Sun.COM 		bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value));
5210*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5211*7836SJohn.Forte@Sun.COM 
5212*7836SJohn.Forte@Sun.COM 		break;
5213*7836SJohn.Forte@Sun.COM 	}
5214*7836SJohn.Forte@Sun.COM 
5215*7836SJohn.Forte@Sun.COM 	default:
5216*7836SJohn.Forte@Sun.COM 		rval = FC_BADOBJECT;
5217*7836SJohn.Forte@Sun.COM 		break;
5218*7836SJohn.Forte@Sun.COM 	}
5219*7836SJohn.Forte@Sun.COM 
5220*7836SJohn.Forte@Sun.COM 	return (rval);
5221*7836SJohn.Forte@Sun.COM }
5222*7836SJohn.Forte@Sun.COM 
5223*7836SJohn.Forte@Sun.COM 
5224*7836SJohn.Forte@Sun.COM fctl_ns_req_t *
5225*7836SJohn.Forte@Sun.COM fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len,
5226*7836SJohn.Forte@Sun.COM     uint32_t ns_flags, int sleep)
5227*7836SJohn.Forte@Sun.COM {
5228*7836SJohn.Forte@Sun.COM 	fctl_ns_req_t *ns_cmd;
5229*7836SJohn.Forte@Sun.COM 
5230*7836SJohn.Forte@Sun.COM 	ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep);
5231*7836SJohn.Forte@Sun.COM 	if (ns_cmd == NULL) {
5232*7836SJohn.Forte@Sun.COM 		return (NULL);
5233*7836SJohn.Forte@Sun.COM 	}
5234*7836SJohn.Forte@Sun.COM 
5235*7836SJohn.Forte@Sun.COM 	if (cmd_len) {
5236*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep);
5237*7836SJohn.Forte@Sun.COM 		if (ns_cmd->ns_cmd_buf == NULL) {
5238*7836SJohn.Forte@Sun.COM 			kmem_free(ns_cmd, sizeof (*ns_cmd));
5239*7836SJohn.Forte@Sun.COM 			return (NULL);
5240*7836SJohn.Forte@Sun.COM 		}
5241*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_size = cmd_len;
5242*7836SJohn.Forte@Sun.COM 	}
5243*7836SJohn.Forte@Sun.COM 
5244*7836SJohn.Forte@Sun.COM 	ns_cmd->ns_resp_size = resp_len;
5245*7836SJohn.Forte@Sun.COM 
5246*7836SJohn.Forte@Sun.COM 	if (data_len) {
5247*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep);
5248*7836SJohn.Forte@Sun.COM 		if (ns_cmd->ns_data_buf == NULL) {
5249*7836SJohn.Forte@Sun.COM 			if (ns_cmd->ns_cmd_buf && cmd_len) {
5250*7836SJohn.Forte@Sun.COM 				kmem_free(ns_cmd->ns_cmd_buf, cmd_len);
5251*7836SJohn.Forte@Sun.COM 			}
5252*7836SJohn.Forte@Sun.COM 			kmem_free(ns_cmd, sizeof (*ns_cmd));
5253*7836SJohn.Forte@Sun.COM 			return (NULL);
5254*7836SJohn.Forte@Sun.COM 		}
5255*7836SJohn.Forte@Sun.COM 		ns_cmd->ns_data_len = data_len;
5256*7836SJohn.Forte@Sun.COM 	}
5257*7836SJohn.Forte@Sun.COM 	ns_cmd->ns_flags = ns_flags;
5258*7836SJohn.Forte@Sun.COM 
5259*7836SJohn.Forte@Sun.COM 	return (ns_cmd);
5260*7836SJohn.Forte@Sun.COM }
5261*7836SJohn.Forte@Sun.COM 
5262*7836SJohn.Forte@Sun.COM 
5263*7836SJohn.Forte@Sun.COM void
5264*7836SJohn.Forte@Sun.COM fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd)
5265*7836SJohn.Forte@Sun.COM {
5266*7836SJohn.Forte@Sun.COM 	if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) {
5267*7836SJohn.Forte@Sun.COM 		kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size);
5268*7836SJohn.Forte@Sun.COM 	}
5269*7836SJohn.Forte@Sun.COM 	if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) {
5270*7836SJohn.Forte@Sun.COM 		kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len);
5271*7836SJohn.Forte@Sun.COM 	}
5272*7836SJohn.Forte@Sun.COM 	kmem_free(ns_cmd, sizeof (*ns_cmd));
5273*7836SJohn.Forte@Sun.COM }
5274*7836SJohn.Forte@Sun.COM 
5275*7836SJohn.Forte@Sun.COM 
5276*7836SJohn.Forte@Sun.COM int
5277*7836SJohn.Forte@Sun.COM fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
5278*7836SJohn.Forte@Sun.COM     intptr_t data, int mode, cred_t *credp, int *rval)
5279*7836SJohn.Forte@Sun.COM {
5280*7836SJohn.Forte@Sun.COM 	int			ret;
5281*7836SJohn.Forte@Sun.COM 	int			save;
5282*7836SJohn.Forte@Sun.COM 	uint32_t 		claimed;
5283*7836SJohn.Forte@Sun.COM 	fc_ulp_module_t 	*mod;
5284*7836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
5285*7836SJohn.Forte@Sun.COM 
5286*7836SJohn.Forte@Sun.COM 	save = *rval;
5287*7836SJohn.Forte@Sun.COM 	*rval = ENOTTY;
5288*7836SJohn.Forte@Sun.COM 
5289*7836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
5290*7836SJohn.Forte@Sun.COM 	for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
5291*7836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
5292*7836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
5293*7836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
5294*7836SJohn.Forte@Sun.COM 
5295*7836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
5296*7836SJohn.Forte@Sun.COM 			continue;
5297*7836SJohn.Forte@Sun.COM 		}
5298*7836SJohn.Forte@Sun.COM 
5299*7836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
5300*7836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) ||
5301*7836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_port_ioctl == NULL) {
5302*7836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
5303*7836SJohn.Forte@Sun.COM 			continue;
5304*7836SJohn.Forte@Sun.COM 		}
5305*7836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
5306*7836SJohn.Forte@Sun.COM 
5307*7836SJohn.Forte@Sun.COM 		ret = mod->mod_info->ulp_port_ioctl(
5308*7836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, (opaque_t)port,
5309*7836SJohn.Forte@Sun.COM 		    dev, cmd, data, mode, credp, rval, claimed);
5310*7836SJohn.Forte@Sun.COM 
5311*7836SJohn.Forte@Sun.COM 		if (ret == FC_SUCCESS && claimed == 0) {
5312*7836SJohn.Forte@Sun.COM 			claimed = 1;
5313*7836SJohn.Forte@Sun.COM 		}
5314*7836SJohn.Forte@Sun.COM 	}
5315*7836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
5316*7836SJohn.Forte@Sun.COM 
5317*7836SJohn.Forte@Sun.COM 	ret = *rval;
5318*7836SJohn.Forte@Sun.COM 	*rval = save;
5319*7836SJohn.Forte@Sun.COM 
5320*7836SJohn.Forte@Sun.COM 	return (ret);
5321*7836SJohn.Forte@Sun.COM }
5322*7836SJohn.Forte@Sun.COM 
5323*7836SJohn.Forte@Sun.COM /*
5324*7836SJohn.Forte@Sun.COM  * raise power if necessary, and set the port busy
5325*7836SJohn.Forte@Sun.COM  *
5326*7836SJohn.Forte@Sun.COM  * this may cause power to be raised, so no power related locks should
5327*7836SJohn.Forte@Sun.COM  * be held
5328*7836SJohn.Forte@Sun.COM  */
5329*7836SJohn.Forte@Sun.COM int
5330*7836SJohn.Forte@Sun.COM fc_ulp_busy_port(opaque_t port_handle)
5331*7836SJohn.Forte@Sun.COM {
5332*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
5333*7836SJohn.Forte@Sun.COM 
5334*7836SJohn.Forte@Sun.COM 	return (fctl_busy_port(port));
5335*7836SJohn.Forte@Sun.COM }
5336*7836SJohn.Forte@Sun.COM 
5337*7836SJohn.Forte@Sun.COM void
5338*7836SJohn.Forte@Sun.COM fc_ulp_idle_port(opaque_t port_handle)
5339*7836SJohn.Forte@Sun.COM {
5340*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
5341*7836SJohn.Forte@Sun.COM 	fctl_idle_port(port);
5342*7836SJohn.Forte@Sun.COM }
5343*7836SJohn.Forte@Sun.COM 
5344*7836SJohn.Forte@Sun.COM void
5345*7836SJohn.Forte@Sun.COM fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd)
5346*7836SJohn.Forte@Sun.COM {
5347*7836SJohn.Forte@Sun.COM 	fctl_copy_portmap(map, (fc_remote_port_t *)pd);
5348*7836SJohn.Forte@Sun.COM }
5349*7836SJohn.Forte@Sun.COM 
5350*7836SJohn.Forte@Sun.COM 
5351*7836SJohn.Forte@Sun.COM int
5352*7836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_num(opaque_t port_handle)
5353*7836SJohn.Forte@Sun.COM {
5354*7836SJohn.Forte@Sun.COM 	int portsnum = 0;
5355*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
5356*7836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
5357*7836SJohn.Forte@Sun.COM 
5358*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5359*7836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
5360*7836SJohn.Forte@Sun.COM 	if (!tmpport) {
5361*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5362*7836SJohn.Forte@Sun.COM 		return (portsnum);
5363*7836SJohn.Forte@Sun.COM 	}
5364*7836SJohn.Forte@Sun.COM 	while (tmpport != port) {
5365*7836SJohn.Forte@Sun.COM 		portsnum ++;
5366*7836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
5367*7836SJohn.Forte@Sun.COM 	}
5368*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5369*7836SJohn.Forte@Sun.COM 	return (portsnum);
5370*7836SJohn.Forte@Sun.COM }
5371*7836SJohn.Forte@Sun.COM 
5372*7836SJohn.Forte@Sun.COM fc_local_port_t *
5373*7836SJohn.Forte@Sun.COM fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn)
5374*7836SJohn.Forte@Sun.COM {
5375*7836SJohn.Forte@Sun.COM 	fc_fca_port_t	*fca_port;
5376*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = phyport;
5377*7836SJohn.Forte@Sun.COM 
5378*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
5379*7836SJohn.Forte@Sun.COM 
5380*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
5381*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
5382*7836SJohn.Forte@Sun.COM 		tmpPort = fca_port->port_handle;
5383*7836SJohn.Forte@Sun.COM 		if (tmpPort == NULL) {
5384*7836SJohn.Forte@Sun.COM 			continue;
5385*7836SJohn.Forte@Sun.COM 		}
5386*7836SJohn.Forte@Sun.COM 		mutex_enter(&tmpPort->fp_mutex);
5387*7836SJohn.Forte@Sun.COM 		if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn,
5388*7836SJohn.Forte@Sun.COM 		    pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) {
5389*7836SJohn.Forte@Sun.COM 			mutex_exit(&tmpPort->fp_mutex);
5390*7836SJohn.Forte@Sun.COM 			mutex_exit(&fctl_port_lock);
5391*7836SJohn.Forte@Sun.COM 			return (tmpPort);
5392*7836SJohn.Forte@Sun.COM 		}
5393*7836SJohn.Forte@Sun.COM 		mutex_exit(&tmpPort->fp_mutex);
5394*7836SJohn.Forte@Sun.COM 	}
5395*7836SJohn.Forte@Sun.COM 
5396*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
5397*7836SJohn.Forte@Sun.COM 
5398*7836SJohn.Forte@Sun.COM 	return (NULL);
5399*7836SJohn.Forte@Sun.COM }
5400*7836SJohn.Forte@Sun.COM 
5401*7836SJohn.Forte@Sun.COM int
5402*7836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList)
5403*7836SJohn.Forte@Sun.COM {
5404*7836SJohn.Forte@Sun.COM 	int portsnum = 0;
5405*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
5406*7836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
5407*7836SJohn.Forte@Sun.COM 
5408*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5409*7836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
5410*7836SJohn.Forte@Sun.COM 	if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5411*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5412*7836SJohn.Forte@Sun.COM 		return (portsnum);
5413*7836SJohn.Forte@Sun.COM 	}
5414*7836SJohn.Forte@Sun.COM 
5415*7836SJohn.Forte@Sun.COM 	while (tmpport != port) {
5416*7836SJohn.Forte@Sun.COM 		(void) ddi_pathname(tmpport->fp_port_dip,
5417*7836SJohn.Forte@Sun.COM 		    &pathList[MAXPATHLEN * portsnum]);
5418*7836SJohn.Forte@Sun.COM 		portsnum ++;
5419*7836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
5420*7836SJohn.Forte@Sun.COM 	}
5421*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5422*7836SJohn.Forte@Sun.COM 
5423*7836SJohn.Forte@Sun.COM 	return (portsnum);
5424*7836SJohn.Forte@Sun.COM }
5425*7836SJohn.Forte@Sun.COM 
5426*7836SJohn.Forte@Sun.COM 
5427*7836SJohn.Forte@Sun.COM fc_local_port_t *
5428*7836SJohn.Forte@Sun.COM fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
5429*7836SJohn.Forte@Sun.COM {
5430*7836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
5431*7836SJohn.Forte@Sun.COM 
5432*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5433*7836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
5434*7836SJohn.Forte@Sun.COM 	if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5435*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5436*7836SJohn.Forte@Sun.COM 		return (NULL);
5437*7836SJohn.Forte@Sun.COM 	}
5438*7836SJohn.Forte@Sun.COM 
5439*7836SJohn.Forte@Sun.COM 	while (tmpport != port) {
5440*7836SJohn.Forte@Sun.COM 		if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn,
5441*7836SJohn.Forte@Sun.COM 		    pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) &&
5442*7836SJohn.Forte@Sun.COM 		    (tmpport->fp_npiv_state == 0)) {
5443*7836SJohn.Forte@Sun.COM 			tmpport->fp_npiv_state = FC_NPIV_DELETING;
5444*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
5445*7836SJohn.Forte@Sun.COM 			return (tmpport);
5446*7836SJohn.Forte@Sun.COM 		}
5447*7836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
5448*7836SJohn.Forte@Sun.COM 	}
5449*7836SJohn.Forte@Sun.COM 
5450*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5451*7836SJohn.Forte@Sun.COM 	return (NULL);
5452*7836SJohn.Forte@Sun.COM }
5453*7836SJohn.Forte@Sun.COM 
5454*7836SJohn.Forte@Sun.COM /*
5455*7836SJohn.Forte@Sun.COM  * Get the list of Adapters.  On multi-ported adapters,
5456*7836SJohn.Forte@Sun.COM  * only ONE port on the adapter will be returned.
5457*7836SJohn.Forte@Sun.COM  * pathList should be (count * MAXPATHLEN) long.
5458*7836SJohn.Forte@Sun.COM  * The return value will be set to the number of
5459*7836SJohn.Forte@Sun.COM  * HBAs that were found on the system.  If the value
5460*7836SJohn.Forte@Sun.COM  * is greater than count, the routine should be retried
5461*7836SJohn.Forte@Sun.COM  * with a larger buffer.
5462*7836SJohn.Forte@Sun.COM  */
5463*7836SJohn.Forte@Sun.COM int
5464*7836SJohn.Forte@Sun.COM fc_ulp_get_adapter_paths(char *pathList, int count)
5465*7836SJohn.Forte@Sun.COM {
5466*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 	*fca_port;
5467*7836SJohn.Forte@Sun.COM 	int		in = 0, out = 0, check, skip, maxPorts = 0;
5468*7836SJohn.Forte@Sun.COM 	fc_local_port_t		**portList;
5469*7836SJohn.Forte@Sun.COM 	fc_local_port_t		*new_port, *stored_port;
5470*7836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*new_fru, *stored_fru;
5471*7836SJohn.Forte@Sun.COM 
5472*7836SJohn.Forte@Sun.COM 	ASSERT(pathList != NULL);
5473*7836SJohn.Forte@Sun.COM 
5474*7836SJohn.Forte@Sun.COM 	/* First figure out how many ports we have */
5475*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
5476*7836SJohn.Forte@Sun.COM 
5477*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
5478*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
5479*7836SJohn.Forte@Sun.COM 		maxPorts ++;
5480*7836SJohn.Forte@Sun.COM 	}
5481*7836SJohn.Forte@Sun.COM 
5482*7836SJohn.Forte@Sun.COM 	/* Now allocate a buffer to store all the pointers for comparisons */
5483*7836SJohn.Forte@Sun.COM 	portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP);
5484*7836SJohn.Forte@Sun.COM 
5485*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
5486*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
5487*7836SJohn.Forte@Sun.COM 		skip = 0;
5488*7836SJohn.Forte@Sun.COM 
5489*7836SJohn.Forte@Sun.COM 		/* Lock the new port for subsequent comparisons */
5490*7836SJohn.Forte@Sun.COM 		new_port = fca_port->port_handle;
5491*7836SJohn.Forte@Sun.COM 		mutex_enter(&new_port->fp_mutex);
5492*7836SJohn.Forte@Sun.COM 		new_fru = &new_port->fp_hba_port_attrs.hba_fru_details;
5493*7836SJohn.Forte@Sun.COM 
5494*7836SJohn.Forte@Sun.COM 		/* Filter out secondary ports from the list */
5495*7836SJohn.Forte@Sun.COM 		for (check = 0; check < out; check++) {
5496*7836SJohn.Forte@Sun.COM 		if (portList[check] == NULL) {
5497*7836SJohn.Forte@Sun.COM 			continue;
5498*7836SJohn.Forte@Sun.COM 		}
5499*7836SJohn.Forte@Sun.COM 		/* Guard against duplicates (should never happen) */
5500*7836SJohn.Forte@Sun.COM 		if (portList[check] == fca_port->port_handle) {
5501*7836SJohn.Forte@Sun.COM 			/* Same port */
5502*7836SJohn.Forte@Sun.COM 			skip = 1;
5503*7836SJohn.Forte@Sun.COM 			break;
5504*7836SJohn.Forte@Sun.COM 		}
5505*7836SJohn.Forte@Sun.COM 
5506*7836SJohn.Forte@Sun.COM 		/* Lock the already stored port for comparison */
5507*7836SJohn.Forte@Sun.COM 		stored_port = portList[check];
5508*7836SJohn.Forte@Sun.COM 		mutex_enter(&stored_port->fp_mutex);
5509*7836SJohn.Forte@Sun.COM 		stored_fru = &stored_port->fp_hba_port_attrs.hba_fru_details;
5510*7836SJohn.Forte@Sun.COM 
5511*7836SJohn.Forte@Sun.COM 		/* Are these ports on the same HBA? */
5512*7836SJohn.Forte@Sun.COM 		if (new_fru->high == stored_fru->high &&
5513*7836SJohn.Forte@Sun.COM 			new_fru->low == stored_fru->low) {
5514*7836SJohn.Forte@Sun.COM 		    /* Now double check driver */
5515*7836SJohn.Forte@Sun.COM 		    if (strncmp(new_port->fp_hba_port_attrs.driver_name,
5516*7836SJohn.Forte@Sun.COM 			    stored_port->fp_hba_port_attrs.driver_name,
5517*7836SJohn.Forte@Sun.COM 			    FCHBA_DRIVER_NAME_LEN) == 0) {
5518*7836SJohn.Forte@Sun.COM 			/* we no we don't need to grow the list */
5519*7836SJohn.Forte@Sun.COM 			skip = 1;
5520*7836SJohn.Forte@Sun.COM 			/* Are we looking at a lower port index? */
5521*7836SJohn.Forte@Sun.COM 			if (new_fru->port_index < stored_fru->port_index) {
5522*7836SJohn.Forte@Sun.COM 				/* Replace the port in the list */
5523*7836SJohn.Forte@Sun.COM 				mutex_exit(&stored_port->fp_mutex);
5524*7836SJohn.Forte@Sun.COM 				if (new_port->fp_npiv_type == FC_NPIV_PORT) {
5525*7836SJohn.Forte@Sun.COM 					break;
5526*7836SJohn.Forte@Sun.COM 				}
5527*7836SJohn.Forte@Sun.COM 				portList[check] = new_port;
5528*7836SJohn.Forte@Sun.COM 				break;
5529*7836SJohn.Forte@Sun.COM 			} /* Else, just skip this port */
5530*7836SJohn.Forte@Sun.COM 		    }
5531*7836SJohn.Forte@Sun.COM 		}
5532*7836SJohn.Forte@Sun.COM 
5533*7836SJohn.Forte@Sun.COM 		mutex_exit(&stored_port->fp_mutex);
5534*7836SJohn.Forte@Sun.COM 	    }
5535*7836SJohn.Forte@Sun.COM 	    mutex_exit(&new_port->fp_mutex);
5536*7836SJohn.Forte@Sun.COM 
5537*7836SJohn.Forte@Sun.COM 	    if (!skip) {
5538*7836SJohn.Forte@Sun.COM 		/*
5539*7836SJohn.Forte@Sun.COM 		 * Either this is the first port for this HBA, or
5540*7836SJohn.Forte@Sun.COM 		 * it's a secondary port and we haven't stored the
5541*7836SJohn.Forte@Sun.COM 		 * primary/first port for that HBA.  In the latter case,
5542*7836SJohn.Forte@Sun.COM 		 * will just filter it out as we proceed to loop.
5543*7836SJohn.Forte@Sun.COM 		 */
5544*7836SJohn.Forte@Sun.COM 		if (fca_port->port_handle->fp_npiv_type == FC_NPIV_PORT) {
5545*7836SJohn.Forte@Sun.COM 			continue;
5546*7836SJohn.Forte@Sun.COM 		} else {
5547*7836SJohn.Forte@Sun.COM 			portList[out++] = fca_port->port_handle;
5548*7836SJohn.Forte@Sun.COM 		}
5549*7836SJohn.Forte@Sun.COM 	    }
5550*7836SJohn.Forte@Sun.COM 	}
5551*7836SJohn.Forte@Sun.COM 
5552*7836SJohn.Forte@Sun.COM 	if (out <= count) {
5553*7836SJohn.Forte@Sun.COM 	    for (in = 0; in < out; in++) {
5554*7836SJohn.Forte@Sun.COM 		(void) ddi_pathname(portList[in]->fp_port_dip,
5555*7836SJohn.Forte@Sun.COM 		    &pathList[MAXPATHLEN * in]);
5556*7836SJohn.Forte@Sun.COM 	    }
5557*7836SJohn.Forte@Sun.COM 	}
5558*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
5559*7836SJohn.Forte@Sun.COM 	kmem_free(portList, sizeof (*portList) * maxPorts);
5560*7836SJohn.Forte@Sun.COM 	return (out);
5561*7836SJohn.Forte@Sun.COM }
5562*7836SJohn.Forte@Sun.COM 
5563*7836SJohn.Forte@Sun.COM uint32_t
5564*7836SJohn.Forte@Sun.COM fc_ulp_get_rscn_count(opaque_t port_handle)
5565*7836SJohn.Forte@Sun.COM {
5566*7836SJohn.Forte@Sun.COM 	uint32_t	count;
5567*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*port;
5568*7836SJohn.Forte@Sun.COM 
5569*7836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)port_handle;
5570*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5571*7836SJohn.Forte@Sun.COM 	count = port->fp_rscn_count;
5572*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5573*7836SJohn.Forte@Sun.COM 
5574*7836SJohn.Forte@Sun.COM 	return (count);
5575*7836SJohn.Forte@Sun.COM }
5576*7836SJohn.Forte@Sun.COM 
5577*7836SJohn.Forte@Sun.COM 
5578*7836SJohn.Forte@Sun.COM /*
5579*7836SJohn.Forte@Sun.COM  * This function is a very similar to fctl_add_orphan except that it expects
5580*7836SJohn.Forte@Sun.COM  * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
5581*7836SJohn.Forte@Sun.COM  *
5582*7836SJohn.Forte@Sun.COM  * Note that there is a lock hierarchy here (fp_mutex should be held first) but
5583*7836SJohn.Forte@Sun.COM  * since this function could be called with a different pd's pd_mutex held, we
5584*7836SJohn.Forte@Sun.COM  * should take care not to release fp_mutex in this function.
5585*7836SJohn.Forte@Sun.COM  */
5586*7836SJohn.Forte@Sun.COM int
5587*7836SJohn.Forte@Sun.COM fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
5588*7836SJohn.Forte@Sun.COM {
5589*7836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
5590*7836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
5591*7836SJohn.Forte@Sun.COM 	fc_orphan_t 	*orp;
5592*7836SJohn.Forte@Sun.COM 	fc_orphan_t	*orphan;
5593*7836SJohn.Forte@Sun.COM 
5594*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
5595*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
5596*7836SJohn.Forte@Sun.COM 
5597*7836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
5598*7836SJohn.Forte@Sun.COM 
5599*7836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5600*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5601*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
5602*7836SJohn.Forte@Sun.COM 		}
5603*7836SJohn.Forte@Sun.COM 	}
5604*7836SJohn.Forte@Sun.COM 
5605*7836SJohn.Forte@Sun.COM 	orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP);
5606*7836SJohn.Forte@Sun.COM 	if (orphan) {
5607*7836SJohn.Forte@Sun.COM 		orphan->orp_pwwn = pwwn;
5608*7836SJohn.Forte@Sun.COM 		orphan->orp_tstamp = ddi_get_lbolt();
5609*7836SJohn.Forte@Sun.COM 
5610*7836SJohn.Forte@Sun.COM 		if (port->fp_orphan_list) {
5611*7836SJohn.Forte@Sun.COM 			ASSERT(port->fp_orphan_count > 0);
5612*7836SJohn.Forte@Sun.COM 			orphan->orp_next = port->fp_orphan_list;
5613*7836SJohn.Forte@Sun.COM 		}
5614*7836SJohn.Forte@Sun.COM 		port->fp_orphan_list = orphan;
5615*7836SJohn.Forte@Sun.COM 		port->fp_orphan_count++;
5616*7836SJohn.Forte@Sun.COM 
5617*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
5618*7836SJohn.Forte@Sun.COM 	}
5619*7836SJohn.Forte@Sun.COM 
5620*7836SJohn.Forte@Sun.COM 	return (rval);
5621*7836SJohn.Forte@Sun.COM }
5622*7836SJohn.Forte@Sun.COM 
5623*7836SJohn.Forte@Sun.COM int
5624*7836SJohn.Forte@Sun.COM fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
5625*7836SJohn.Forte@Sun.COM {
5626*7836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
5627*7836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
5628*7836SJohn.Forte@Sun.COM 	fc_orphan_t 	*orp;
5629*7836SJohn.Forte@Sun.COM 	fc_orphan_t	*orphan;
5630*7836SJohn.Forte@Sun.COM 
5631*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5632*7836SJohn.Forte@Sun.COM 
5633*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
5634*7836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
5635*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
5636*7836SJohn.Forte@Sun.COM 
5637*7836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5638*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5639*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
5640*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
5641*7836SJohn.Forte@Sun.COM 		}
5642*7836SJohn.Forte@Sun.COM 	}
5643*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5644*7836SJohn.Forte@Sun.COM 
5645*7836SJohn.Forte@Sun.COM 	orphan = kmem_zalloc(sizeof (*orphan), sleep);
5646*7836SJohn.Forte@Sun.COM 	if (orphan != NULL) {
5647*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
5648*7836SJohn.Forte@Sun.COM 
5649*7836SJohn.Forte@Sun.COM 		orphan->orp_pwwn = pwwn;
5650*7836SJohn.Forte@Sun.COM 		orphan->orp_tstamp = ddi_get_lbolt();
5651*7836SJohn.Forte@Sun.COM 
5652*7836SJohn.Forte@Sun.COM 		if (port->fp_orphan_list) {
5653*7836SJohn.Forte@Sun.COM 			ASSERT(port->fp_orphan_count > 0);
5654*7836SJohn.Forte@Sun.COM 			orphan->orp_next = port->fp_orphan_list;
5655*7836SJohn.Forte@Sun.COM 		}
5656*7836SJohn.Forte@Sun.COM 		port->fp_orphan_list = orphan;
5657*7836SJohn.Forte@Sun.COM 		port->fp_orphan_count++;
5658*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
5659*7836SJohn.Forte@Sun.COM 
5660*7836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
5661*7836SJohn.Forte@Sun.COM 	}
5662*7836SJohn.Forte@Sun.COM 
5663*7836SJohn.Forte@Sun.COM 	return (rval);
5664*7836SJohn.Forte@Sun.COM }
5665*7836SJohn.Forte@Sun.COM 
5666*7836SJohn.Forte@Sun.COM 
5667*7836SJohn.Forte@Sun.COM int
5668*7836SJohn.Forte@Sun.COM fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
5669*7836SJohn.Forte@Sun.COM {
5670*7836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
5671*7836SJohn.Forte@Sun.COM 	fc_orphan_t	*prev = NULL;
5672*7836SJohn.Forte@Sun.COM 	fc_orphan_t 	*orp;
5673*7836SJohn.Forte@Sun.COM 
5674*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5675*7836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5676*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) {
5677*7836SJohn.Forte@Sun.COM 			if (prev) {
5678*7836SJohn.Forte@Sun.COM 				prev->orp_next = orp->orp_next;
5679*7836SJohn.Forte@Sun.COM 			} else {
5680*7836SJohn.Forte@Sun.COM 				ASSERT(port->fp_orphan_list == orp);
5681*7836SJohn.Forte@Sun.COM 				port->fp_orphan_list = orp->orp_next;
5682*7836SJohn.Forte@Sun.COM 			}
5683*7836SJohn.Forte@Sun.COM 			port->fp_orphan_count--;
5684*7836SJohn.Forte@Sun.COM 			rval = FC_SUCCESS;
5685*7836SJohn.Forte@Sun.COM 			break;
5686*7836SJohn.Forte@Sun.COM 		}
5687*7836SJohn.Forte@Sun.COM 		prev = orp;
5688*7836SJohn.Forte@Sun.COM 	}
5689*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5690*7836SJohn.Forte@Sun.COM 
5691*7836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
5692*7836SJohn.Forte@Sun.COM 		kmem_free(orp, sizeof (*orp));
5693*7836SJohn.Forte@Sun.COM 	}
5694*7836SJohn.Forte@Sun.COM 
5695*7836SJohn.Forte@Sun.COM 	return (rval);
5696*7836SJohn.Forte@Sun.COM }
5697*7836SJohn.Forte@Sun.COM 
5698*7836SJohn.Forte@Sun.COM 
5699*7836SJohn.Forte@Sun.COM static void
5700*7836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
5701*7836SJohn.Forte@Sun.COM {
5702*7836SJohn.Forte@Sun.COM 	char 		ww_name[17];
5703*7836SJohn.Forte@Sun.COM 	la_wwn_t 	pwwn;
5704*7836SJohn.Forte@Sun.COM 	fc_orphan_t 	*orp;
5705*7836SJohn.Forte@Sun.COM 
5706*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5707*7836SJohn.Forte@Sun.COM 
5708*7836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
5709*7836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
5710*7836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
5711*7836SJohn.Forte@Sun.COM 
5712*7836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5713*7836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5714*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
5715*7836SJohn.Forte@Sun.COM 			return;
5716*7836SJohn.Forte@Sun.COM 		}
5717*7836SJohn.Forte@Sun.COM 	}
5718*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5719*7836SJohn.Forte@Sun.COM 
5720*7836SJohn.Forte@Sun.COM 	fc_wwn_to_str(&pwwn, ww_name);
5721*7836SJohn.Forte@Sun.COM 
5722*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
5723*7836SJohn.Forte@Sun.COM 	    " disappeared from fabric", port->fp_instance,
5724*7836SJohn.Forte@Sun.COM 	    pd->pd_port_id.port_id, ww_name);
5725*7836SJohn.Forte@Sun.COM }
5726*7836SJohn.Forte@Sun.COM 
5727*7836SJohn.Forte@Sun.COM 
5728*7836SJohn.Forte@Sun.COM /* ARGSUSED */
5729*7836SJohn.Forte@Sun.COM static void
5730*7836SJohn.Forte@Sun.COM fctl_link_reset_done(opaque_t port_handle, uchar_t result)
5731*7836SJohn.Forte@Sun.COM {
5732*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
5733*7836SJohn.Forte@Sun.COM 
5734*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5735*7836SJohn.Forte@Sun.COM 	port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
5736*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5737*7836SJohn.Forte@Sun.COM 
5738*7836SJohn.Forte@Sun.COM 	fctl_idle_port(port);
5739*7836SJohn.Forte@Sun.COM }
5740*7836SJohn.Forte@Sun.COM 
5741*7836SJohn.Forte@Sun.COM 
5742*7836SJohn.Forte@Sun.COM static int
5743*7836SJohn.Forte@Sun.COM fctl_error(int fc_errno, char **errmsg)
5744*7836SJohn.Forte@Sun.COM {
5745*7836SJohn.Forte@Sun.COM 	int count;
5746*7836SJohn.Forte@Sun.COM 
5747*7836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fc_errlist) /
5748*7836SJohn.Forte@Sun.COM 	    sizeof (fc_errlist[0]); count++) {
5749*7836SJohn.Forte@Sun.COM 		if (fc_errlist[count].fc_errno == fc_errno) {
5750*7836SJohn.Forte@Sun.COM 			*errmsg = fc_errlist[count].fc_errname;
5751*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
5752*7836SJohn.Forte@Sun.COM 		}
5753*7836SJohn.Forte@Sun.COM 	}
5754*7836SJohn.Forte@Sun.COM 	*errmsg = fctl_undefined;
5755*7836SJohn.Forte@Sun.COM 
5756*7836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
5757*7836SJohn.Forte@Sun.COM }
5758*7836SJohn.Forte@Sun.COM 
5759*7836SJohn.Forte@Sun.COM 
5760*7836SJohn.Forte@Sun.COM /*
5761*7836SJohn.Forte@Sun.COM  * Return number of successful translations.
5762*7836SJohn.Forte@Sun.COM  *	Anybody with some userland programming experience would have
5763*7836SJohn.Forte@Sun.COM  *	figured it by now that the return value exactly resembles that
5764*7836SJohn.Forte@Sun.COM  *	of scanf(3c). This function returns a count of successful
5765*7836SJohn.Forte@Sun.COM  *	translations. It could range from 0 (no match for state, reason,
5766*7836SJohn.Forte@Sun.COM  *	action, expln) to 4 (successful matches for all state, reason,
5767*7836SJohn.Forte@Sun.COM  *	action, expln) and where translation isn't successful into a
5768*7836SJohn.Forte@Sun.COM  *	friendlier message the relevent field is set to "Undefined"
5769*7836SJohn.Forte@Sun.COM  */
5770*7836SJohn.Forte@Sun.COM static int
5771*7836SJohn.Forte@Sun.COM fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
5772*7836SJohn.Forte@Sun.COM     char **action, char **expln)
5773*7836SJohn.Forte@Sun.COM {
5774*7836SJohn.Forte@Sun.COM 	int		ret;
5775*7836SJohn.Forte@Sun.COM 	int 		len;
5776*7836SJohn.Forte@Sun.COM 	int		index;
5777*7836SJohn.Forte@Sun.COM 	fc_pkt_error_t	*error;
5778*7836SJohn.Forte@Sun.COM 	fc_pkt_reason_t	*reason_b;	/* Base pointer */
5779*7836SJohn.Forte@Sun.COM 	fc_pkt_action_t	*action_b;	/* Base pointer */
5780*7836SJohn.Forte@Sun.COM 	fc_pkt_expln_t	*expln_b;	/* Base pointer */
5781*7836SJohn.Forte@Sun.COM 
5782*7836SJohn.Forte@Sun.COM 	ret = 0;
5783*7836SJohn.Forte@Sun.COM 	*state = *reason = *action = *expln = fctl_undefined;
5784*7836SJohn.Forte@Sun.COM 
5785*7836SJohn.Forte@Sun.COM 	len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0];
5786*7836SJohn.Forte@Sun.COM 	for (index = 0; index < len; index++) {
5787*7836SJohn.Forte@Sun.COM 		error = fc_pkt_errlist + index;
5788*7836SJohn.Forte@Sun.COM 		if (pkt->pkt_state == error->pkt_state) {
5789*7836SJohn.Forte@Sun.COM 			*state = error->pkt_msg;
5790*7836SJohn.Forte@Sun.COM 			ret++;
5791*7836SJohn.Forte@Sun.COM 
5792*7836SJohn.Forte@Sun.COM 			reason_b = error->pkt_reason;
5793*7836SJohn.Forte@Sun.COM 			action_b = error->pkt_action;
5794*7836SJohn.Forte@Sun.COM 			expln_b = error->pkt_expln;
5795*7836SJohn.Forte@Sun.COM 
5796*7836SJohn.Forte@Sun.COM 			while (reason_b != NULL &&
5797*7836SJohn.Forte@Sun.COM 			    reason_b->reason_val != FC_REASON_INVALID) {
5798*7836SJohn.Forte@Sun.COM 				if (reason_b->reason_val == pkt->pkt_reason) {
5799*7836SJohn.Forte@Sun.COM 					*reason = reason_b->reason_msg;
5800*7836SJohn.Forte@Sun.COM 					ret++;
5801*7836SJohn.Forte@Sun.COM 					break;
5802*7836SJohn.Forte@Sun.COM 				}
5803*7836SJohn.Forte@Sun.COM 				reason_b++;
5804*7836SJohn.Forte@Sun.COM 			}
5805*7836SJohn.Forte@Sun.COM 
5806*7836SJohn.Forte@Sun.COM 			while (action_b != NULL &&
5807*7836SJohn.Forte@Sun.COM 			    action_b->action_val != FC_ACTION_INVALID) {
5808*7836SJohn.Forte@Sun.COM 				if (action_b->action_val == pkt->pkt_action) {
5809*7836SJohn.Forte@Sun.COM 					*action = action_b->action_msg;
5810*7836SJohn.Forte@Sun.COM 					ret++;
5811*7836SJohn.Forte@Sun.COM 					break;
5812*7836SJohn.Forte@Sun.COM 				}
5813*7836SJohn.Forte@Sun.COM 				action_b++;
5814*7836SJohn.Forte@Sun.COM 			}
5815*7836SJohn.Forte@Sun.COM 
5816*7836SJohn.Forte@Sun.COM 			while (expln_b != NULL &&
5817*7836SJohn.Forte@Sun.COM 			    expln_b->expln_val != FC_EXPLN_INVALID) {
5818*7836SJohn.Forte@Sun.COM 				if (expln_b->expln_val == pkt->pkt_expln) {
5819*7836SJohn.Forte@Sun.COM 					*expln = expln_b->expln_msg;
5820*7836SJohn.Forte@Sun.COM 					ret++;
5821*7836SJohn.Forte@Sun.COM 					break;
5822*7836SJohn.Forte@Sun.COM 				}
5823*7836SJohn.Forte@Sun.COM 				expln_b++;
5824*7836SJohn.Forte@Sun.COM 			}
5825*7836SJohn.Forte@Sun.COM 			break;
5826*7836SJohn.Forte@Sun.COM 		}
5827*7836SJohn.Forte@Sun.COM 	}
5828*7836SJohn.Forte@Sun.COM 
5829*7836SJohn.Forte@Sun.COM 	return (ret);
5830*7836SJohn.Forte@Sun.COM }
5831*7836SJohn.Forte@Sun.COM 
5832*7836SJohn.Forte@Sun.COM 
5833*7836SJohn.Forte@Sun.COM /*
5834*7836SJohn.Forte@Sun.COM  * Remove all port devices that are marked OLD, remove
5835*7836SJohn.Forte@Sun.COM  * corresponding node devices (fc_remote_node_t)
5836*7836SJohn.Forte@Sun.COM  */
5837*7836SJohn.Forte@Sun.COM void
5838*7836SJohn.Forte@Sun.COM fctl_remove_oldies(fc_local_port_t *port)
5839*7836SJohn.Forte@Sun.COM {
5840*7836SJohn.Forte@Sun.COM 	int			index;
5841*7836SJohn.Forte@Sun.COM 	int			initiator;
5842*7836SJohn.Forte@Sun.COM 	fc_remote_node_t	*node;
5843*7836SJohn.Forte@Sun.COM 	struct pwwn_hash 	*head;
5844*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
5845*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*old_pd;
5846*7836SJohn.Forte@Sun.COM 	fc_remote_port_t	*last_pd;
5847*7836SJohn.Forte@Sun.COM 
5848*7836SJohn.Forte@Sun.COM 	/*
5849*7836SJohn.Forte@Sun.COM 	 * Nuke all OLD devices
5850*7836SJohn.Forte@Sun.COM 	 */
5851*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
5852*7836SJohn.Forte@Sun.COM 
5853*7836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
5854*7836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
5855*7836SJohn.Forte@Sun.COM 		last_pd = NULL;
5856*7836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
5857*7836SJohn.Forte@Sun.COM 
5858*7836SJohn.Forte@Sun.COM 		while (pd != NULL) {
5859*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
5860*7836SJohn.Forte@Sun.COM 			if (pd->pd_type != PORT_DEVICE_OLD) {
5861*7836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
5862*7836SJohn.Forte@Sun.COM 				last_pd = pd;
5863*7836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
5864*7836SJohn.Forte@Sun.COM 				continue;
5865*7836SJohn.Forte@Sun.COM 			}
5866*7836SJohn.Forte@Sun.COM 
5867*7836SJohn.Forte@Sun.COM 			/*
5868*7836SJohn.Forte@Sun.COM 			 * Remove this from the PWWN hash table
5869*7836SJohn.Forte@Sun.COM 			 */
5870*7836SJohn.Forte@Sun.COM 			old_pd = pd;
5871*7836SJohn.Forte@Sun.COM 			pd = old_pd->pd_wwn_hnext;
5872*7836SJohn.Forte@Sun.COM 
5873*7836SJohn.Forte@Sun.COM 			if (last_pd == NULL) {
5874*7836SJohn.Forte@Sun.COM 				ASSERT(old_pd == head->pwwn_head);
5875*7836SJohn.Forte@Sun.COM 				head->pwwn_head = pd;
5876*7836SJohn.Forte@Sun.COM 			} else {
5877*7836SJohn.Forte@Sun.COM 				last_pd->pd_wwn_hnext = pd;
5878*7836SJohn.Forte@Sun.COM 			}
5879*7836SJohn.Forte@Sun.COM 			head->pwwn_count--;
5880*7836SJohn.Forte@Sun.COM 			/*
5881*7836SJohn.Forte@Sun.COM 			 * Make sure we tie fp_dev_count to the size of the
5882*7836SJohn.Forte@Sun.COM 			 * pwwn_table
5883*7836SJohn.Forte@Sun.COM 			 */
5884*7836SJohn.Forte@Sun.COM 			port->fp_dev_count--;
5885*7836SJohn.Forte@Sun.COM 			old_pd->pd_wwn_hnext = NULL;
5886*7836SJohn.Forte@Sun.COM 
5887*7836SJohn.Forte@Sun.COM 			fctl_delist_did_table(port, old_pd);
5888*7836SJohn.Forte@Sun.COM 			node = old_pd->pd_remote_nodep;
5889*7836SJohn.Forte@Sun.COM 			ASSERT(node != NULL);
5890*7836SJohn.Forte@Sun.COM 
5891*7836SJohn.Forte@Sun.COM 			initiator = (old_pd->pd_recepient ==
5892*7836SJohn.Forte@Sun.COM 			    PD_PLOGI_INITIATOR) ? 1 : 0;
5893*7836SJohn.Forte@Sun.COM 
5894*7836SJohn.Forte@Sun.COM 			mutex_exit(&old_pd->pd_mutex);
5895*7836SJohn.Forte@Sun.COM 
5896*7836SJohn.Forte@Sun.COM 			if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) {
5897*7836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
5898*7836SJohn.Forte@Sun.COM 
5899*7836SJohn.Forte@Sun.COM 				(void) fctl_add_orphan(port, old_pd,
5900*7836SJohn.Forte@Sun.COM 				    KM_NOSLEEP);
5901*7836SJohn.Forte@Sun.COM 			} else {
5902*7836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
5903*7836SJohn.Forte@Sun.COM 			}
5904*7836SJohn.Forte@Sun.COM 
5905*7836SJohn.Forte@Sun.COM 			if (fctl_destroy_remote_port(port, old_pd) == 0) {
5906*7836SJohn.Forte@Sun.COM 				if (node) {
5907*7836SJohn.Forte@Sun.COM 					fctl_destroy_remote_node(node);
5908*7836SJohn.Forte@Sun.COM 				}
5909*7836SJohn.Forte@Sun.COM 			}
5910*7836SJohn.Forte@Sun.COM 
5911*7836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
5912*7836SJohn.Forte@Sun.COM 		}
5913*7836SJohn.Forte@Sun.COM 	}
5914*7836SJohn.Forte@Sun.COM 
5915*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
5916*7836SJohn.Forte@Sun.COM }
5917*7836SJohn.Forte@Sun.COM 
5918*7836SJohn.Forte@Sun.COM 
5919*7836SJohn.Forte@Sun.COM static void
5920*7836SJohn.Forte@Sun.COM fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd)
5921*7836SJohn.Forte@Sun.COM {
5922*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
5923*7836SJohn.Forte@Sun.COM 	ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5924*7836SJohn.Forte@Sun.COM 
5925*7836SJohn.Forte@Sun.COM 	if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) {
5926*7836SJohn.Forte@Sun.COM 		return;
5927*7836SJohn.Forte@Sun.COM 	}
5928*7836SJohn.Forte@Sun.COM 
5929*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
5930*7836SJohn.Forte@Sun.COM 	    port->fp_instance, pd->pd_port_id.port_id);
5931*7836SJohn.Forte@Sun.COM }
5932*7836SJohn.Forte@Sun.COM 
5933*7836SJohn.Forte@Sun.COM 
5934*7836SJohn.Forte@Sun.COM static int
5935*7836SJohn.Forte@Sun.COM fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa)
5936*7836SJohn.Forte@Sun.COM {
5937*7836SJohn.Forte@Sun.COM 	int index;
5938*7836SJohn.Forte@Sun.COM 
5939*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
5940*7836SJohn.Forte@Sun.COM 	ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5941*7836SJohn.Forte@Sun.COM 
5942*7836SJohn.Forte@Sun.COM 	for (index = 0; index < port->fp_lilp_map.lilp_length; index++) {
5943*7836SJohn.Forte@Sun.COM 		if (port->fp_lilp_map.lilp_alpalist[index] == alpa) {
5944*7836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
5945*7836SJohn.Forte@Sun.COM 		}
5946*7836SJohn.Forte@Sun.COM 	}
5947*7836SJohn.Forte@Sun.COM 
5948*7836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
5949*7836SJohn.Forte@Sun.COM }
5950*7836SJohn.Forte@Sun.COM 
5951*7836SJohn.Forte@Sun.COM 
5952*7836SJohn.Forte@Sun.COM fc_remote_port_t *
5953*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
5954*7836SJohn.Forte@Sun.COM {
5955*7836SJohn.Forte@Sun.COM 	int			index;
5956*7836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
5957*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
5958*7836SJohn.Forte@Sun.COM 
5959*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
5960*7836SJohn.Forte@Sun.COM 
5961*7836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
5962*7836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
5963*7836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
5964*7836SJohn.Forte@Sun.COM 
5965*7836SJohn.Forte@Sun.COM 		while (pd != NULL) {
5966*7836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
5967*7836SJohn.Forte@Sun.COM 			if (pd->pd_port_id.port_id == d_id) {
5968*7836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
5969*7836SJohn.Forte@Sun.COM 				return (pd);
5970*7836SJohn.Forte@Sun.COM 			}
5971*7836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
5972*7836SJohn.Forte@Sun.COM 			pd = pd->pd_wwn_hnext;
5973*7836SJohn.Forte@Sun.COM 		}
5974*7836SJohn.Forte@Sun.COM 	}
5975*7836SJohn.Forte@Sun.COM 
5976*7836SJohn.Forte@Sun.COM 	return (pd);
5977*7836SJohn.Forte@Sun.COM }
5978*7836SJohn.Forte@Sun.COM 
5979*7836SJohn.Forte@Sun.COM 
5980*7836SJohn.Forte@Sun.COM /*
5981*7836SJohn.Forte@Sun.COM  * trace debugging
5982*7836SJohn.Forte@Sun.COM  */
5983*7836SJohn.Forte@Sun.COM void
5984*7836SJohn.Forte@Sun.COM fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
5985*7836SJohn.Forte@Sun.COM     int errno, const char *fmt, ...)
5986*7836SJohn.Forte@Sun.COM {
5987*7836SJohn.Forte@Sun.COM 	char 	buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
5988*7836SJohn.Forte@Sun.COM 	char	*bufptr = buf;
5989*7836SJohn.Forte@Sun.COM 	va_list	ap;
5990*7836SJohn.Forte@Sun.COM 	int	cnt = 0;
5991*7836SJohn.Forte@Sun.COM 
5992*7836SJohn.Forte@Sun.COM 	if ((dlevel & dflag) == 0) {
5993*7836SJohn.Forte@Sun.COM 		return;
5994*7836SJohn.Forte@Sun.COM 	}
5995*7836SJohn.Forte@Sun.COM 
5996*7836SJohn.Forte@Sun.COM 	if (name) {
5997*7836SJohn.Forte@Sun.COM 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
5998*7836SJohn.Forte@Sun.COM 			logq->il_id++, name);
5999*7836SJohn.Forte@Sun.COM 	} else {
6000*7836SJohn.Forte@Sun.COM 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
6001*7836SJohn.Forte@Sun.COM 			logq->il_id++);
6002*7836SJohn.Forte@Sun.COM 	}
6003*7836SJohn.Forte@Sun.COM 
6004*7836SJohn.Forte@Sun.COM 	if (cnt < FC_MAX_TRACE_BUF_LEN) {
6005*7836SJohn.Forte@Sun.COM 		va_start(ap, fmt);
6006*7836SJohn.Forte@Sun.COM 		cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6007*7836SJohn.Forte@Sun.COM 			fmt, ap);
6008*7836SJohn.Forte@Sun.COM 		va_end(ap);
6009*7836SJohn.Forte@Sun.COM 	}
6010*7836SJohn.Forte@Sun.COM 
6011*7836SJohn.Forte@Sun.COM 	if (cnt > FC_MAX_TRACE_BUF_LEN) {
6012*7836SJohn.Forte@Sun.COM 		cnt = FC_MAX_TRACE_BUF_LEN;
6013*7836SJohn.Forte@Sun.COM 	}
6014*7836SJohn.Forte@Sun.COM 	if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) {
6015*7836SJohn.Forte@Sun.COM 		cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6016*7836SJohn.Forte@Sun.COM 			"error=0x%x\n", errno);
6017*7836SJohn.Forte@Sun.COM 	}
6018*7836SJohn.Forte@Sun.COM 	(void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
6019*7836SJohn.Forte@Sun.COM 
6020*7836SJohn.Forte@Sun.COM 	if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) {
6021*7836SJohn.Forte@Sun.COM 		fc_trace_logmsg(logq, buf, dlevel);
6022*7836SJohn.Forte@Sun.COM 	}
6023*7836SJohn.Forte@Sun.COM 
6024*7836SJohn.Forte@Sun.COM 	/*
6025*7836SJohn.Forte@Sun.COM 	 * We do not want to print the log numbers that appear as
6026*7836SJohn.Forte@Sun.COM 	 * random numbers at the console and messages files, to
6027*7836SJohn.Forte@Sun.COM 	 * the user.
6028*7836SJohn.Forte@Sun.COM 	 */
6029*7836SJohn.Forte@Sun.COM 	if ((bufptr = strchr(buf, '>')) == NULL) {
6030*7836SJohn.Forte@Sun.COM 		/*
6031*7836SJohn.Forte@Sun.COM 		 * We would have added the a string with "=>" above and so,
6032*7836SJohn.Forte@Sun.COM 		 * ideally, we should not get here at all. But, if we do,
6033*7836SJohn.Forte@Sun.COM 		 * we'll just use the full buf.
6034*7836SJohn.Forte@Sun.COM 		 */
6035*7836SJohn.Forte@Sun.COM 		bufptr = buf;
6036*7836SJohn.Forte@Sun.COM 	} else {
6037*7836SJohn.Forte@Sun.COM 		bufptr++;
6038*7836SJohn.Forte@Sun.COM 	}
6039*7836SJohn.Forte@Sun.COM 
6040*7836SJohn.Forte@Sun.COM 	switch (dlevel & FC_TRACE_LOG_MASK) {
6041*7836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_CONSOLE:
6042*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "%s", bufptr);
6043*7836SJohn.Forte@Sun.COM 		break;
6044*7836SJohn.Forte@Sun.COM 
6045*7836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_CONSOLE_MSG:
6046*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "%s", bufptr);
6047*7836SJohn.Forte@Sun.COM 		break;
6048*7836SJohn.Forte@Sun.COM 
6049*7836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_MSG:
6050*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "!%s", bufptr);
6051*7836SJohn.Forte@Sun.COM 		break;
6052*7836SJohn.Forte@Sun.COM 
6053*7836SJohn.Forte@Sun.COM 	default:
6054*7836SJohn.Forte@Sun.COM 		break;
6055*7836SJohn.Forte@Sun.COM 	}
6056*7836SJohn.Forte@Sun.COM }
6057*7836SJohn.Forte@Sun.COM 
6058*7836SJohn.Forte@Sun.COM 
6059*7836SJohn.Forte@Sun.COM /*
6060*7836SJohn.Forte@Sun.COM  * This function can block
6061*7836SJohn.Forte@Sun.COM  */
6062*7836SJohn.Forte@Sun.COM fc_trace_logq_t *
6063*7836SJohn.Forte@Sun.COM fc_trace_alloc_logq(int maxsize)
6064*7836SJohn.Forte@Sun.COM {
6065*7836SJohn.Forte@Sun.COM 	fc_trace_logq_t *logq;
6066*7836SJohn.Forte@Sun.COM 
6067*7836SJohn.Forte@Sun.COM 	logq = kmem_zalloc(sizeof (*logq), KM_SLEEP);
6068*7836SJohn.Forte@Sun.COM 
6069*7836SJohn.Forte@Sun.COM 	mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL);
6070*7836SJohn.Forte@Sun.COM 	logq->il_hiwat = maxsize;
6071*7836SJohn.Forte@Sun.COM 	logq->il_flags |= FC_TRACE_LOGQ_V2;
6072*7836SJohn.Forte@Sun.COM 
6073*7836SJohn.Forte@Sun.COM 	return (logq);
6074*7836SJohn.Forte@Sun.COM }
6075*7836SJohn.Forte@Sun.COM 
6076*7836SJohn.Forte@Sun.COM 
6077*7836SJohn.Forte@Sun.COM void
6078*7836SJohn.Forte@Sun.COM fc_trace_free_logq(fc_trace_logq_t *logq)
6079*7836SJohn.Forte@Sun.COM {
6080*7836SJohn.Forte@Sun.COM 	mutex_enter(&logq->il_lock);
6081*7836SJohn.Forte@Sun.COM 	while (logq->il_msgh) {
6082*7836SJohn.Forte@Sun.COM 		fc_trace_freemsg(logq);
6083*7836SJohn.Forte@Sun.COM 	}
6084*7836SJohn.Forte@Sun.COM 	mutex_exit(&logq->il_lock);
6085*7836SJohn.Forte@Sun.COM 
6086*7836SJohn.Forte@Sun.COM 	mutex_destroy(&logq->il_lock);
6087*7836SJohn.Forte@Sun.COM 	kmem_free(logq, sizeof (*logq));
6088*7836SJohn.Forte@Sun.COM }
6089*7836SJohn.Forte@Sun.COM 
6090*7836SJohn.Forte@Sun.COM 
6091*7836SJohn.Forte@Sun.COM /* ARGSUSED */
6092*7836SJohn.Forte@Sun.COM void
6093*7836SJohn.Forte@Sun.COM fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level)
6094*7836SJohn.Forte@Sun.COM {
6095*7836SJohn.Forte@Sun.COM 	int		qfull = 0;
6096*7836SJohn.Forte@Sun.COM 	fc_trace_dmsg_t	*dmsg;
6097*7836SJohn.Forte@Sun.COM 
6098*7836SJohn.Forte@Sun.COM 	dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP);
6099*7836SJohn.Forte@Sun.COM 	if (dmsg == NULL) {
6100*7836SJohn.Forte@Sun.COM 		mutex_enter(&logq->il_lock);
6101*7836SJohn.Forte@Sun.COM 		logq->il_afail++;
6102*7836SJohn.Forte@Sun.COM 		mutex_exit(&logq->il_lock);
6103*7836SJohn.Forte@Sun.COM 
6104*7836SJohn.Forte@Sun.COM 		return;
6105*7836SJohn.Forte@Sun.COM 	}
6106*7836SJohn.Forte@Sun.COM 
6107*7836SJohn.Forte@Sun.COM 	gethrestime(&dmsg->id_time);
6108*7836SJohn.Forte@Sun.COM 
6109*7836SJohn.Forte@Sun.COM 	dmsg->id_size = strlen(buf) + 1;
6110*7836SJohn.Forte@Sun.COM 	dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP);
6111*7836SJohn.Forte@Sun.COM 	if (dmsg->id_buf == NULL) {
6112*7836SJohn.Forte@Sun.COM 		kmem_free(dmsg, sizeof (*dmsg));
6113*7836SJohn.Forte@Sun.COM 
6114*7836SJohn.Forte@Sun.COM 		mutex_enter(&logq->il_lock);
6115*7836SJohn.Forte@Sun.COM 		logq->il_afail++;
6116*7836SJohn.Forte@Sun.COM 		mutex_exit(&logq->il_lock);
6117*7836SJohn.Forte@Sun.COM 
6118*7836SJohn.Forte@Sun.COM 		return;
6119*7836SJohn.Forte@Sun.COM 	}
6120*7836SJohn.Forte@Sun.COM 	bcopy(buf, dmsg->id_buf, strlen(buf));
6121*7836SJohn.Forte@Sun.COM 	dmsg->id_buf[strlen(buf)] = '\0';
6122*7836SJohn.Forte@Sun.COM 
6123*7836SJohn.Forte@Sun.COM 	mutex_enter(&logq->il_lock);
6124*7836SJohn.Forte@Sun.COM 
6125*7836SJohn.Forte@Sun.COM 	logq->il_size += dmsg->id_size;
6126*7836SJohn.Forte@Sun.COM 	if (logq->il_size >= logq->il_hiwat) {
6127*7836SJohn.Forte@Sun.COM 		qfull = 1;
6128*7836SJohn.Forte@Sun.COM 	}
6129*7836SJohn.Forte@Sun.COM 
6130*7836SJohn.Forte@Sun.COM 	if (qfull) {
6131*7836SJohn.Forte@Sun.COM 		fc_trace_freemsg(logq);
6132*7836SJohn.Forte@Sun.COM 	}
6133*7836SJohn.Forte@Sun.COM 
6134*7836SJohn.Forte@Sun.COM 	dmsg->id_next = NULL;
6135*7836SJohn.Forte@Sun.COM 	if (logq->il_msgt) {
6136*7836SJohn.Forte@Sun.COM 		logq->il_msgt->id_next = dmsg;
6137*7836SJohn.Forte@Sun.COM 	} else {
6138*7836SJohn.Forte@Sun.COM 		ASSERT(logq->il_msgh == NULL);
6139*7836SJohn.Forte@Sun.COM 		logq->il_msgh = dmsg;
6140*7836SJohn.Forte@Sun.COM 	}
6141*7836SJohn.Forte@Sun.COM 	logq->il_msgt = dmsg;
6142*7836SJohn.Forte@Sun.COM 
6143*7836SJohn.Forte@Sun.COM 	mutex_exit(&logq->il_lock);
6144*7836SJohn.Forte@Sun.COM }
6145*7836SJohn.Forte@Sun.COM 
6146*7836SJohn.Forte@Sun.COM 
6147*7836SJohn.Forte@Sun.COM static void
6148*7836SJohn.Forte@Sun.COM fc_trace_freemsg(fc_trace_logq_t *logq)
6149*7836SJohn.Forte@Sun.COM {
6150*7836SJohn.Forte@Sun.COM 	fc_trace_dmsg_t	*dmsg;
6151*7836SJohn.Forte@Sun.COM 
6152*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&logq->il_lock));
6153*7836SJohn.Forte@Sun.COM 
6154*7836SJohn.Forte@Sun.COM 	if ((dmsg = logq->il_msgh) != NULL) {
6155*7836SJohn.Forte@Sun.COM 		logq->il_msgh = dmsg->id_next;
6156*7836SJohn.Forte@Sun.COM 		if (logq->il_msgh == NULL) {
6157*7836SJohn.Forte@Sun.COM 			logq->il_msgt = NULL;
6158*7836SJohn.Forte@Sun.COM 		}
6159*7836SJohn.Forte@Sun.COM 
6160*7836SJohn.Forte@Sun.COM 		logq->il_size -= dmsg->id_size;
6161*7836SJohn.Forte@Sun.COM 		kmem_free(dmsg->id_buf, dmsg->id_size);
6162*7836SJohn.Forte@Sun.COM 		kmem_free(dmsg, sizeof (*dmsg));
6163*7836SJohn.Forte@Sun.COM 	} else {
6164*7836SJohn.Forte@Sun.COM 		ASSERT(logq->il_msgt == NULL);
6165*7836SJohn.Forte@Sun.COM 	}
6166*7836SJohn.Forte@Sun.COM }
6167*7836SJohn.Forte@Sun.COM 
6168*7836SJohn.Forte@Sun.COM /*
6169*7836SJohn.Forte@Sun.COM  * Used by T11 FC-HBA to fetch discovered ports by index.
6170*7836SJohn.Forte@Sun.COM  * Returns NULL if the index isn't valid.
6171*7836SJohn.Forte@Sun.COM  */
6172*7836SJohn.Forte@Sun.COM fc_remote_port_t *
6173*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
6174*7836SJohn.Forte@Sun.COM {
6175*7836SJohn.Forte@Sun.COM 	int			outer;
6176*7836SJohn.Forte@Sun.COM 	int			match = 0;
6177*7836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
6178*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
6179*7836SJohn.Forte@Sun.COM 
6180*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
6181*7836SJohn.Forte@Sun.COM 
6182*7836SJohn.Forte@Sun.COM 	for (outer = 0;
6183*7836SJohn.Forte@Sun.COM 		outer < pwwn_table_size && match <= index;
6184*7836SJohn.Forte@Sun.COM 		outer++) {
6185*7836SJohn.Forte@Sun.COM 	    head = &port->fp_pwwn_table[outer];
6186*7836SJohn.Forte@Sun.COM 	    pd = head->pwwn_head;
6187*7836SJohn.Forte@Sun.COM 	    if (pd != NULL) match ++;
6188*7836SJohn.Forte@Sun.COM 
6189*7836SJohn.Forte@Sun.COM 	    while (pd != NULL && match <= index) {
6190*7836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
6191*7836SJohn.Forte@Sun.COM 		if (pd != NULL) match ++;
6192*7836SJohn.Forte@Sun.COM 	    }
6193*7836SJohn.Forte@Sun.COM 	}
6194*7836SJohn.Forte@Sun.COM 
6195*7836SJohn.Forte@Sun.COM 	return (pd);
6196*7836SJohn.Forte@Sun.COM }
6197*7836SJohn.Forte@Sun.COM 
6198*7836SJohn.Forte@Sun.COM /*
6199*7836SJohn.Forte@Sun.COM  * Search for a matching Node or Port WWN in the discovered port list
6200*7836SJohn.Forte@Sun.COM  */
6201*7836SJohn.Forte@Sun.COM fc_remote_port_t *
6202*7836SJohn.Forte@Sun.COM fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
6203*7836SJohn.Forte@Sun.COM {
6204*7836SJohn.Forte@Sun.COM 	int			index;
6205*7836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
6206*7836SJohn.Forte@Sun.COM 	fc_remote_port_t 	*pd;
6207*7836SJohn.Forte@Sun.COM 
6208*7836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
6209*7836SJohn.Forte@Sun.COM 
6210*7836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
6211*7836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
6212*7836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
6213*7836SJohn.Forte@Sun.COM 
6214*7836SJohn.Forte@Sun.COM 	    while (pd != NULL) {
6215*7836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
6216*7836SJohn.Forte@Sun.COM 		if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
6217*7836SJohn.Forte@Sun.COM 			sizeof (la_wwn_t)) == 0) {
6218*7836SJohn.Forte@Sun.COM 		    mutex_exit(&pd->pd_mutex);
6219*7836SJohn.Forte@Sun.COM 		    return (pd);
6220*7836SJohn.Forte@Sun.COM 		}
6221*7836SJohn.Forte@Sun.COM 		if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn, wwn.raw_wwn,
6222*7836SJohn.Forte@Sun.COM 			sizeof (la_wwn_t)) == 0) {
6223*7836SJohn.Forte@Sun.COM 		    mutex_exit(&pd->pd_mutex);
6224*7836SJohn.Forte@Sun.COM 		    return (pd);
6225*7836SJohn.Forte@Sun.COM 		}
6226*7836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
6227*7836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
6228*7836SJohn.Forte@Sun.COM 	    }
6229*7836SJohn.Forte@Sun.COM 	}
6230*7836SJohn.Forte@Sun.COM 	/* No match */
6231*7836SJohn.Forte@Sun.COM 	return (NULL);
6232*7836SJohn.Forte@Sun.COM }
6233*7836SJohn.Forte@Sun.COM 
6234*7836SJohn.Forte@Sun.COM 
6235*7836SJohn.Forte@Sun.COM /*
6236*7836SJohn.Forte@Sun.COM  * Count the number of ports on this adapter.
6237*7836SJohn.Forte@Sun.COM  * This routine will walk the port list and count up the number of adapters
6238*7836SJohn.Forte@Sun.COM  * with matching fp_hba_port_attrs.hba_fru_details.high and
6239*7836SJohn.Forte@Sun.COM  * fp_hba_port_attrs.hba_fru_details.low.
6240*7836SJohn.Forte@Sun.COM  *
6241*7836SJohn.Forte@Sun.COM  * port->fp_mutex must not be held.
6242*7836SJohn.Forte@Sun.COM  */
6243*7836SJohn.Forte@Sun.COM int
6244*7836SJohn.Forte@Sun.COM fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
6245*7836SJohn.Forte@Sun.COM {
6246*7836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*fru;
6247*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 	*fca_port;
6248*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = NULL;
6249*7836SJohn.Forte@Sun.COM 	uint32_t	count = 1;
6250*7836SJohn.Forte@Sun.COM 
6251*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
6252*7836SJohn.Forte@Sun.COM 
6253*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
6254*7836SJohn.Forte@Sun.COM 	fru = &port->fp_hba_port_attrs.hba_fru_details;
6255*7836SJohn.Forte@Sun.COM 
6256*7836SJohn.Forte@Sun.COM 	/* Detect FCA drivers that don't support linking HBA ports */
6257*7836SJohn.Forte@Sun.COM 	if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6258*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6259*7836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
6260*7836SJohn.Forte@Sun.COM 		return (1);
6261*7836SJohn.Forte@Sun.COM 	}
6262*7836SJohn.Forte@Sun.COM 
6263*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
6264*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
6265*7836SJohn.Forte@Sun.COM 	    tmpPort = fca_port->port_handle;
6266*7836SJohn.Forte@Sun.COM 	    if (tmpPort == port) {
6267*7836SJohn.Forte@Sun.COM 		continue;
6268*7836SJohn.Forte@Sun.COM 	    }
6269*7836SJohn.Forte@Sun.COM 	    mutex_enter(&tmpPort->fp_mutex);
6270*7836SJohn.Forte@Sun.COM 
6271*7836SJohn.Forte@Sun.COM 		/*
6272*7836SJohn.Forte@Sun.COM 		 * If an FCA driver returns unique fru->high and fru->low for
6273*7836SJohn.Forte@Sun.COM 		 * ports on the same card, there is no way for the transport
6274*7836SJohn.Forte@Sun.COM 		 * layer to determine that the two ports on the same FRU. So,
6275*7836SJohn.Forte@Sun.COM 		 * the discovery of the ports on a same FRU  is limited to what
6276*7836SJohn.Forte@Sun.COM 		 * the FCA driver can report back.
6277*7836SJohn.Forte@Sun.COM 		 */
6278*7836SJohn.Forte@Sun.COM 		if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6279*7836SJohn.Forte@Sun.COM 		    fru->high &&
6280*7836SJohn.Forte@Sun.COM 		    tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6281*7836SJohn.Forte@Sun.COM 		    fru->low) {
6282*7836SJohn.Forte@Sun.COM 			/* Now double check driver */
6283*7836SJohn.Forte@Sun.COM 			if (strncmp(port->fp_hba_port_attrs.driver_name,
6284*7836SJohn.Forte@Sun.COM 			    tmpPort->fp_hba_port_attrs.driver_name,
6285*7836SJohn.Forte@Sun.COM 			    FCHBA_DRIVER_NAME_LEN) == 0) {
6286*7836SJohn.Forte@Sun.COM 				if (!npivflag ||
6287*7836SJohn.Forte@Sun.COM 				    (tmpPort->fp_npiv_type != FC_NPIV_PORT)) {
6288*7836SJohn.Forte@Sun.COM 					count++;
6289*7836SJohn.Forte@Sun.COM 				}
6290*7836SJohn.Forte@Sun.COM 			} /* Else, different FCA driver */
6291*7836SJohn.Forte@Sun.COM 		} /* Else not the same HBA FRU */
6292*7836SJohn.Forte@Sun.COM 		mutex_exit(&tmpPort->fp_mutex);
6293*7836SJohn.Forte@Sun.COM 	}
6294*7836SJohn.Forte@Sun.COM 
6295*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
6296*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
6297*7836SJohn.Forte@Sun.COM 
6298*7836SJohn.Forte@Sun.COM 	return (count);
6299*7836SJohn.Forte@Sun.COM }
6300*7836SJohn.Forte@Sun.COM 
6301*7836SJohn.Forte@Sun.COM fc_fca_port_t *
6302*7836SJohn.Forte@Sun.COM fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port)
6303*7836SJohn.Forte@Sun.COM {
6304*7836SJohn.Forte@Sun.COM 	fc_fca_port_t *tmp = list, *newentry = NULL;
6305*7836SJohn.Forte@Sun.COM 
6306*7836SJohn.Forte@Sun.COM 	newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP);
6307*7836SJohn.Forte@Sun.COM 	if (newentry == NULL) {
6308*7836SJohn.Forte@Sun.COM 		return (list);
6309*7836SJohn.Forte@Sun.COM 	}
6310*7836SJohn.Forte@Sun.COM 	newentry->port_handle = port;
6311*7836SJohn.Forte@Sun.COM 
6312*7836SJohn.Forte@Sun.COM 	if (tmp == NULL) {
6313*7836SJohn.Forte@Sun.COM 		return (newentry);
6314*7836SJohn.Forte@Sun.COM 	}
6315*7836SJohn.Forte@Sun.COM 	while (tmp->port_next != NULL)	tmp = tmp->port_next;
6316*7836SJohn.Forte@Sun.COM 	tmp->port_next = newentry;
6317*7836SJohn.Forte@Sun.COM 
6318*7836SJohn.Forte@Sun.COM 	return (list);
6319*7836SJohn.Forte@Sun.COM }
6320*7836SJohn.Forte@Sun.COM 
6321*7836SJohn.Forte@Sun.COM void
6322*7836SJohn.Forte@Sun.COM fctl_local_port_list_free(fc_fca_port_t *list)
6323*7836SJohn.Forte@Sun.COM {
6324*7836SJohn.Forte@Sun.COM 	fc_fca_port_t *tmp = list, *nextentry;
6325*7836SJohn.Forte@Sun.COM 
6326*7836SJohn.Forte@Sun.COM 	if (tmp == NULL) {
6327*7836SJohn.Forte@Sun.COM 		return;
6328*7836SJohn.Forte@Sun.COM 	}
6329*7836SJohn.Forte@Sun.COM 
6330*7836SJohn.Forte@Sun.COM 	while (tmp != NULL) {
6331*7836SJohn.Forte@Sun.COM 		nextentry = tmp->port_next;
6332*7836SJohn.Forte@Sun.COM 		kmem_free(tmp, sizeof (*tmp));
6333*7836SJohn.Forte@Sun.COM 		tmp = nextentry;
6334*7836SJohn.Forte@Sun.COM 	}
6335*7836SJohn.Forte@Sun.COM }
6336*7836SJohn.Forte@Sun.COM 
6337*7836SJohn.Forte@Sun.COM /*
6338*7836SJohn.Forte@Sun.COM  * Fetch another port on the HBA FRU based on index.
6339*7836SJohn.Forte@Sun.COM  * Returns NULL if index not found.
6340*7836SJohn.Forte@Sun.COM  *
6341*7836SJohn.Forte@Sun.COM  * port->fp_mutex must not be held.
6342*7836SJohn.Forte@Sun.COM  */
6343*7836SJohn.Forte@Sun.COM fc_local_port_t *
6344*7836SJohn.Forte@Sun.COM fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
6345*7836SJohn.Forte@Sun.COM {
6346*7836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*fru;
6347*7836SJohn.Forte@Sun.COM 	fc_fca_port_t 	*fca_port;
6348*7836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = NULL;
6349*7836SJohn.Forte@Sun.COM 	fc_fca_port_t	*list = NULL, *tmpEntry;
6350*7836SJohn.Forte@Sun.COM 	fc_local_port_t		*phyPort, *virPort = NULL;
6351*7836SJohn.Forte@Sun.COM 	int	index, phyPortNum = 0;
6352*7836SJohn.Forte@Sun.COM 
6353*7836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
6354*7836SJohn.Forte@Sun.COM 
6355*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
6356*7836SJohn.Forte@Sun.COM 	fru = &port->fp_hba_port_attrs.hba_fru_details;
6357*7836SJohn.Forte@Sun.COM 
6358*7836SJohn.Forte@Sun.COM 	/* Are we looking for this port? */
6359*7836SJohn.Forte@Sun.COM 	if (fru->port_index == port_index) {
6360*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6361*7836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
6362*7836SJohn.Forte@Sun.COM 		return (port);
6363*7836SJohn.Forte@Sun.COM 	}
6364*7836SJohn.Forte@Sun.COM 
6365*7836SJohn.Forte@Sun.COM 	/* Detect FCA drivers that don't support linking HBA ports */
6366*7836SJohn.Forte@Sun.COM 	if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6367*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6368*7836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
6369*7836SJohn.Forte@Sun.COM 		return (NULL);
6370*7836SJohn.Forte@Sun.COM 	}
6371*7836SJohn.Forte@Sun.COM 
6372*7836SJohn.Forte@Sun.COM 	list = fctl_local_port_list_add(list, port);
6373*7836SJohn.Forte@Sun.COM 	phyPortNum++;
6374*7836SJohn.Forte@Sun.COM 	/* Loop through all known ports */
6375*7836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
6376*7836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
6377*7836SJohn.Forte@Sun.COM 	    tmpPort = fca_port->port_handle;
6378*7836SJohn.Forte@Sun.COM 	    if (tmpPort == port) {
6379*7836SJohn.Forte@Sun.COM 		/* Skip over the port that was passed in as the argument */
6380*7836SJohn.Forte@Sun.COM 		continue;
6381*7836SJohn.Forte@Sun.COM 	    }
6382*7836SJohn.Forte@Sun.COM 	    mutex_enter(&tmpPort->fp_mutex);
6383*7836SJohn.Forte@Sun.COM 
6384*7836SJohn.Forte@Sun.COM 	    /* See if this port is on the same HBA FRU (fast check) */
6385*7836SJohn.Forte@Sun.COM 	    if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6386*7836SJohn.Forte@Sun.COM 		    fru->high &&
6387*7836SJohn.Forte@Sun.COM 		    tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6388*7836SJohn.Forte@Sun.COM 		    fru->low) {
6389*7836SJohn.Forte@Sun.COM 		/* Now double check driver (slower check) */
6390*7836SJohn.Forte@Sun.COM 		if (strncmp(port->fp_hba_port_attrs.driver_name,
6391*7836SJohn.Forte@Sun.COM 			tmpPort->fp_hba_port_attrs.driver_name,
6392*7836SJohn.Forte@Sun.COM 			FCHBA_DRIVER_NAME_LEN) == 0) {
6393*7836SJohn.Forte@Sun.COM 
6394*7836SJohn.Forte@Sun.COM 		    fru = &tmpPort->fp_hba_port_attrs.hba_fru_details;
6395*7836SJohn.Forte@Sun.COM 		    /* Check for the matching port_index */
6396*7836SJohn.Forte@Sun.COM 			if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
6397*7836SJohn.Forte@Sun.COM 			    (fru->port_index == port_index)) {
6398*7836SJohn.Forte@Sun.COM 				/* Found it! */
6399*7836SJohn.Forte@Sun.COM 				mutex_exit(&tmpPort->fp_mutex);
6400*7836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
6401*7836SJohn.Forte@Sun.COM 				mutex_exit(&fctl_port_lock);
6402*7836SJohn.Forte@Sun.COM 				fctl_local_port_list_free(list);
6403*7836SJohn.Forte@Sun.COM 				return (tmpPort);
6404*7836SJohn.Forte@Sun.COM 			}
6405*7836SJohn.Forte@Sun.COM 			if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
6406*7836SJohn.Forte@Sun.COM 				(void) fctl_local_port_list_add(list, tmpPort);
6407*7836SJohn.Forte@Sun.COM 				phyPortNum++;
6408*7836SJohn.Forte@Sun.COM 			}
6409*7836SJohn.Forte@Sun.COM 		} /* Else, different FCA driver */
6410*7836SJohn.Forte@Sun.COM 	    } /* Else not the same HBA FRU */
6411*7836SJohn.Forte@Sun.COM 	    mutex_exit(&tmpPort->fp_mutex);
6412*7836SJohn.Forte@Sun.COM 
6413*7836SJohn.Forte@Sun.COM 	}
6414*7836SJohn.Forte@Sun.COM 
6415*7836SJohn.Forte@Sun.COM 	/* scan all physical port on same chip to find virtual port */
6416*7836SJohn.Forte@Sun.COM 	tmpEntry = list;
6417*7836SJohn.Forte@Sun.COM 	index = phyPortNum - 1;
6418*7836SJohn.Forte@Sun.COM 	virPort = NULL;
6419*7836SJohn.Forte@Sun.COM 	while (index < port_index) {
6420*7836SJohn.Forte@Sun.COM 		if (tmpEntry == NULL) {
6421*7836SJohn.Forte@Sun.COM 			break;
6422*7836SJohn.Forte@Sun.COM 		}
6423*7836SJohn.Forte@Sun.COM 		if (virPort == NULL) {
6424*7836SJohn.Forte@Sun.COM 			phyPort = tmpEntry->port_handle;
6425*7836SJohn.Forte@Sun.COM 			virPort = phyPort->fp_port_next;
6426*7836SJohn.Forte@Sun.COM 			if (virPort == NULL) {
6427*7836SJohn.Forte@Sun.COM 				tmpEntry = tmpEntry->port_next;
6428*7836SJohn.Forte@Sun.COM 				continue;
6429*7836SJohn.Forte@Sun.COM 			}
6430*7836SJohn.Forte@Sun.COM 		} else {
6431*7836SJohn.Forte@Sun.COM 			virPort = virPort->fp_port_next;
6432*7836SJohn.Forte@Sun.COM 		}
6433*7836SJohn.Forte@Sun.COM 		if (virPort == phyPort) {
6434*7836SJohn.Forte@Sun.COM 			tmpEntry = tmpEntry->port_next;
6435*7836SJohn.Forte@Sun.COM 			virPort = NULL;
6436*7836SJohn.Forte@Sun.COM 		} else {
6437*7836SJohn.Forte@Sun.COM 			index++;
6438*7836SJohn.Forte@Sun.COM 		}
6439*7836SJohn.Forte@Sun.COM 	}
6440*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
6441*7836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
6442*7836SJohn.Forte@Sun.COM 
6443*7836SJohn.Forte@Sun.COM 	fctl_local_port_list_free(list);
6444*7836SJohn.Forte@Sun.COM 	if (virPort) {
6445*7836SJohn.Forte@Sun.COM 		return (virPort);
6446*7836SJohn.Forte@Sun.COM 	}
6447*7836SJohn.Forte@Sun.COM 	return (NULL);
6448*7836SJohn.Forte@Sun.COM }
6449*7836SJohn.Forte@Sun.COM 
6450*7836SJohn.Forte@Sun.COM int
6451*7836SJohn.Forte@Sun.COM fctl_busy_port(fc_local_port_t *port)
6452*7836SJohn.Forte@Sun.COM {
6453*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
6454*7836SJohn.Forte@Sun.COM 
6455*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
6456*7836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
6457*7836SJohn.Forte@Sun.COM 		/*
6458*7836SJohn.Forte@Sun.COM 		 * If fctl_busy_port() is called before we've registered our
6459*7836SJohn.Forte@Sun.COM 		 * PM components, we return success. We need to be aware of
6460*7836SJohn.Forte@Sun.COM 		 * this because the caller will eventually call fctl_idle_port.
6461*7836SJohn.Forte@Sun.COM 		 * This wouldn't be a problem except that if we have
6462*7836SJohn.Forte@Sun.COM 		 * registered our PM components in the meantime, we will
6463*7836SJohn.Forte@Sun.COM 		 * then be idling a component that was never busied.  PM
6464*7836SJohn.Forte@Sun.COM 		 * will be very unhappy if we do this.  Thus, we keep
6465*7836SJohn.Forte@Sun.COM 		 * track of this with port->fp_pm_busy_nocomp.
6466*7836SJohn.Forte@Sun.COM 		 */
6467*7836SJohn.Forte@Sun.COM 		port->fp_pm_busy_nocomp++;
6468*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6469*7836SJohn.Forte@Sun.COM 		return (0);
6470*7836SJohn.Forte@Sun.COM 	}
6471*7836SJohn.Forte@Sun.COM 	port->fp_pm_busy++;
6472*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
6473*7836SJohn.Forte@Sun.COM 
6474*7836SJohn.Forte@Sun.COM 	if (pm_busy_component(port->fp_port_dip,
6475*7836SJohn.Forte@Sun.COM 	    FP_PM_COMPONENT) != DDI_SUCCESS) {
6476*7836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
6477*7836SJohn.Forte@Sun.COM 		port->fp_pm_busy--;
6478*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6479*7836SJohn.Forte@Sun.COM 		return (ENXIO);
6480*7836SJohn.Forte@Sun.COM 	}
6481*7836SJohn.Forte@Sun.COM 
6482*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
6483*7836SJohn.Forte@Sun.COM 	if (port->fp_pm_level == FP_PM_PORT_DOWN) {
6484*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6485*7836SJohn.Forte@Sun.COM 		if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT,
6486*7836SJohn.Forte@Sun.COM 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
6487*7836SJohn.Forte@Sun.COM 
6488*7836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
6489*7836SJohn.Forte@Sun.COM 			port->fp_pm_busy--;
6490*7836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
6491*7836SJohn.Forte@Sun.COM 
6492*7836SJohn.Forte@Sun.COM 			(void) pm_idle_component(port->fp_port_dip,
6493*7836SJohn.Forte@Sun.COM 			    FP_PM_COMPONENT);
6494*7836SJohn.Forte@Sun.COM 			return (EIO);
6495*7836SJohn.Forte@Sun.COM 		}
6496*7836SJohn.Forte@Sun.COM 		return (0);
6497*7836SJohn.Forte@Sun.COM 	}
6498*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
6499*7836SJohn.Forte@Sun.COM 	return (0);
6500*7836SJohn.Forte@Sun.COM }
6501*7836SJohn.Forte@Sun.COM 
6502*7836SJohn.Forte@Sun.COM void
6503*7836SJohn.Forte@Sun.COM fctl_idle_port(fc_local_port_t *port)
6504*7836SJohn.Forte@Sun.COM {
6505*7836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
6506*7836SJohn.Forte@Sun.COM 
6507*7836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
6508*7836SJohn.Forte@Sun.COM 
6509*7836SJohn.Forte@Sun.COM 	/*
6510*7836SJohn.Forte@Sun.COM 	 * If port->fp_pm_busy_nocomp is > 0, that means somebody had
6511*7836SJohn.Forte@Sun.COM 	 * called fctl_busy_port prior to us registering our PM components.
6512*7836SJohn.Forte@Sun.COM 	 * In that case, we just decrement fp_pm_busy_nocomp and return.
6513*7836SJohn.Forte@Sun.COM 	 */
6514*7836SJohn.Forte@Sun.COM 
6515*7836SJohn.Forte@Sun.COM 	if (port->fp_pm_busy_nocomp > 0) {
6516*7836SJohn.Forte@Sun.COM 		port->fp_pm_busy_nocomp--;
6517*7836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
6518*7836SJohn.Forte@Sun.COM 		return;
6519*7836SJohn.Forte@Sun.COM 	}
6520*7836SJohn.Forte@Sun.COM 
6521*7836SJohn.Forte@Sun.COM 	port->fp_pm_busy--;
6522*7836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
6523*7836SJohn.Forte@Sun.COM 
6524*7836SJohn.Forte@Sun.COM 	(void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT);
6525*7836SJohn.Forte@Sun.COM }
6526*7836SJohn.Forte@Sun.COM 
6527*7836SJohn.Forte@Sun.COM /*
6528*7836SJohn.Forte@Sun.COM  *     Function: fctl_tc_timer
6529*7836SJohn.Forte@Sun.COM  *
6530*7836SJohn.Forte@Sun.COM  *  Description: Resets the value of the timed counter.
6531*7836SJohn.Forte@Sun.COM  *
6532*7836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter
6533*7836SJohn.Forte@Sun.COM  *
6534*7836SJohn.Forte@Sun.COM  * Return Value: Nothing
6535*7836SJohn.Forte@Sun.COM  *
6536*7836SJohn.Forte@Sun.COM  *      Context: Kernel context.
6537*7836SJohn.Forte@Sun.COM  */
6538*7836SJohn.Forte@Sun.COM static void
6539*7836SJohn.Forte@Sun.COM fctl_tc_timer(
6540*7836SJohn.Forte@Sun.COM     void	*arg
6541*7836SJohn.Forte@Sun.COM )
6542*7836SJohn.Forte@Sun.COM {
6543*7836SJohn.Forte@Sun.COM 	timed_counter_t	*tc = (timed_counter_t *)arg;
6544*7836SJohn.Forte@Sun.COM 
6545*7836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
6546*7836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
6547*7836SJohn.Forte@Sun.COM 
6548*7836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
6549*7836SJohn.Forte@Sun.COM 	if (tc->active) {
6550*7836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
6551*7836SJohn.Forte@Sun.COM 		tc->counter = 0;
6552*7836SJohn.Forte@Sun.COM 	}
6553*7836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
6554*7836SJohn.Forte@Sun.COM }
6555*7836SJohn.Forte@Sun.COM 
6556*7836SJohn.Forte@Sun.COM /*
6557*7836SJohn.Forte@Sun.COM  *     Function: fctl_tc_constructor
6558*7836SJohn.Forte@Sun.COM  *
6559*7836SJohn.Forte@Sun.COM  *  Description: Constructs a timed counter.
6560*7836SJohn.Forte@Sun.COM  *
6561*7836SJohn.Forte@Sun.COM  *    Arguments: *tc		Address where the timed counter will reside.
6562*7836SJohn.Forte@Sun.COM  *		 max_value      Maximum value the counter is allowed to take.
6563*7836SJohn.Forte@Sun.COM  *		 timer		Number of microseconds after which the counter
6564*7836SJohn.Forte@Sun.COM  *				will be reset. The timer is started when the
6565*7836SJohn.Forte@Sun.COM  *				value of the counter goes from 0 to 1.
6566*7836SJohn.Forte@Sun.COM  *
6567*7836SJohn.Forte@Sun.COM  * Return Value: Nothing
6568*7836SJohn.Forte@Sun.COM  *
6569*7836SJohn.Forte@Sun.COM  *      Context: Kernel context.
6570*7836SJohn.Forte@Sun.COM  */
6571*7836SJohn.Forte@Sun.COM void
6572*7836SJohn.Forte@Sun.COM fctl_tc_constructor(
6573*7836SJohn.Forte@Sun.COM     timed_counter_t	*tc,
6574*7836SJohn.Forte@Sun.COM     uint32_t		max_value,
6575*7836SJohn.Forte@Sun.COM     clock_t		timer
6576*7836SJohn.Forte@Sun.COM )
6577*7836SJohn.Forte@Sun.COM {
6578*7836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
6579*7836SJohn.Forte@Sun.COM 	ASSERT(tc->sig != tc);
6580*7836SJohn.Forte@Sun.COM 
6581*7836SJohn.Forte@Sun.COM 	bzero(tc, sizeof (*tc));
6582*7836SJohn.Forte@Sun.COM 	mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL);
6583*7836SJohn.Forte@Sun.COM 	tc->timer = drv_usectohz(timer);
6584*7836SJohn.Forte@Sun.COM 	tc->active = B_FALSE;
6585*7836SJohn.Forte@Sun.COM 	tc->maxed_out = B_FALSE;
6586*7836SJohn.Forte@Sun.COM 	tc->max_value = max_value;
6587*7836SJohn.Forte@Sun.COM 	tc->sig = tc;
6588*7836SJohn.Forte@Sun.COM }
6589*7836SJohn.Forte@Sun.COM 
6590*7836SJohn.Forte@Sun.COM /*
6591*7836SJohn.Forte@Sun.COM  *     Function: fctl_tc_destructor
6592*7836SJohn.Forte@Sun.COM  *
6593*7836SJohn.Forte@Sun.COM  *  Description: Destroyes a timed counter.
6594*7836SJohn.Forte@Sun.COM  *
6595*7836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to destroy.
6596*7836SJohn.Forte@Sun.COM  *
6597*7836SJohn.Forte@Sun.COM  * Return Value: Nothing
6598*7836SJohn.Forte@Sun.COM  *
6599*7836SJohn.Forte@Sun.COM  *      Context: Kernel context.
6600*7836SJohn.Forte@Sun.COM  */
6601*7836SJohn.Forte@Sun.COM void
6602*7836SJohn.Forte@Sun.COM fctl_tc_destructor(
6603*7836SJohn.Forte@Sun.COM     timed_counter_t	*tc
6604*7836SJohn.Forte@Sun.COM )
6605*7836SJohn.Forte@Sun.COM {
6606*7836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
6607*7836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
6608*7836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&tc->mutex));
6609*7836SJohn.Forte@Sun.COM 
6610*7836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
6611*7836SJohn.Forte@Sun.COM 	if (tc->active) {
6612*7836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
6613*7836SJohn.Forte@Sun.COM 		(void) untimeout(tc->tid);
6614*7836SJohn.Forte@Sun.COM 		tc->sig = NULL;
6615*7836SJohn.Forte@Sun.COM 	}
6616*7836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
6617*7836SJohn.Forte@Sun.COM 	mutex_destroy(&tc->mutex);
6618*7836SJohn.Forte@Sun.COM }
6619*7836SJohn.Forte@Sun.COM 
6620*7836SJohn.Forte@Sun.COM /*
6621*7836SJohn.Forte@Sun.COM  *     Function: fctl_tc_increment
6622*7836SJohn.Forte@Sun.COM  *
6623*7836SJohn.Forte@Sun.COM  *  Description: Increments a timed counter
6624*7836SJohn.Forte@Sun.COM  *
6625*7836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to increment.
6626*7836SJohn.Forte@Sun.COM  *
6627*7836SJohn.Forte@Sun.COM  * Return Value: B_TRUE		Counter reached the max value.
6628*7836SJohn.Forte@Sun.COM  *		 B_FALSE	Counter hasn't reached the max value.
6629*7836SJohn.Forte@Sun.COM  *
6630*7836SJohn.Forte@Sun.COM  *      Context: Kernel or interrupt context.
6631*7836SJohn.Forte@Sun.COM  */
6632*7836SJohn.Forte@Sun.COM boolean_t
6633*7836SJohn.Forte@Sun.COM fctl_tc_increment(
6634*7836SJohn.Forte@Sun.COM     timed_counter_t *tc
6635*7836SJohn.Forte@Sun.COM )
6636*7836SJohn.Forte@Sun.COM {
6637*7836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
6638*7836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
6639*7836SJohn.Forte@Sun.COM 
6640*7836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
6641*7836SJohn.Forte@Sun.COM 	if (!tc->maxed_out) {
6642*7836SJohn.Forte@Sun.COM 		/* Hasn't maxed out yet. */
6643*7836SJohn.Forte@Sun.COM 		++tc->counter;
6644*7836SJohn.Forte@Sun.COM 		if (tc->counter >= tc->max_value) {
6645*7836SJohn.Forte@Sun.COM 			/* Just maxed out. */
6646*7836SJohn.Forte@Sun.COM 			tc->maxed_out = B_TRUE;
6647*7836SJohn.Forte@Sun.COM 		}
6648*7836SJohn.Forte@Sun.COM 		if (!tc->active) {
6649*7836SJohn.Forte@Sun.COM 			tc->tid = timeout(fctl_tc_timer, tc, tc->timer);
6650*7836SJohn.Forte@Sun.COM 			tc->active = B_TRUE;
6651*7836SJohn.Forte@Sun.COM 		}
6652*7836SJohn.Forte@Sun.COM 	}
6653*7836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
6654*7836SJohn.Forte@Sun.COM 
6655*7836SJohn.Forte@Sun.COM 	return (tc->maxed_out);
6656*7836SJohn.Forte@Sun.COM }
6657*7836SJohn.Forte@Sun.COM 
6658*7836SJohn.Forte@Sun.COM /*
6659*7836SJohn.Forte@Sun.COM  *     Function: fctl_tc_reset
6660*7836SJohn.Forte@Sun.COM  *
6661*7836SJohn.Forte@Sun.COM  *  Description: Resets a timed counter.  The caller of this function has to
6662*7836SJohn.Forte@Sun.COM  *		 to make sure that while in fctl_tc_reset() fctl_tc_increment()
6663*7836SJohn.Forte@Sun.COM  *		 is not called.
6664*7836SJohn.Forte@Sun.COM  *
6665*7836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to reset.
6666*7836SJohn.Forte@Sun.COM  *
6667*7836SJohn.Forte@Sun.COM  * Return Value: 0		Counter reached the max value.
6668*7836SJohn.Forte@Sun.COM  *		 Not 0		Counter hasn't reached the max value.
6669*7836SJohn.Forte@Sun.COM  *
6670*7836SJohn.Forte@Sun.COM  *      Context: Kernel or interrupt context.
6671*7836SJohn.Forte@Sun.COM  */
6672*7836SJohn.Forte@Sun.COM void
6673*7836SJohn.Forte@Sun.COM fctl_tc_reset(
6674*7836SJohn.Forte@Sun.COM     timed_counter_t *tc
6675*7836SJohn.Forte@Sun.COM )
6676*7836SJohn.Forte@Sun.COM {
6677*7836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
6678*7836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
6679*7836SJohn.Forte@Sun.COM 
6680*7836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
6681*7836SJohn.Forte@Sun.COM 	tc->counter = 0;
6682*7836SJohn.Forte@Sun.COM 	tc->maxed_out = B_FALSE;
6683*7836SJohn.Forte@Sun.COM 	if (tc->active) {
6684*7836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
6685*7836SJohn.Forte@Sun.COM 		(void) untimeout(tc->tid);
6686*7836SJohn.Forte@Sun.COM 	}
6687*7836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
6688*7836SJohn.Forte@Sun.COM }
6689*7836SJohn.Forte@Sun.COM 
6690*7836SJohn.Forte@Sun.COM void
6691*7836SJohn.Forte@Sun.COM fc_ulp_log_device_event(opaque_t port_handle, int type)
6692*7836SJohn.Forte@Sun.COM {
6693*7836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
6694*7836SJohn.Forte@Sun.COM 	nvlist_t *attr_list;
6695*7836SJohn.Forte@Sun.COM 
6696*7836SJohn.Forte@Sun.COM 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
6697*7836SJohn.Forte@Sun.COM 	    KM_SLEEP) != DDI_SUCCESS) {
6698*7836SJohn.Forte@Sun.COM 		return;
6699*7836SJohn.Forte@Sun.COM 	}
6700*7836SJohn.Forte@Sun.COM 
6701*7836SJohn.Forte@Sun.COM 	if (nvlist_add_uint32(attr_list, "instance",
6702*7836SJohn.Forte@Sun.COM 	    port->fp_instance) != DDI_SUCCESS) {
6703*7836SJohn.Forte@Sun.COM 		goto error;
6704*7836SJohn.Forte@Sun.COM 	}
6705*7836SJohn.Forte@Sun.COM 
6706*7836SJohn.Forte@Sun.COM 	if (nvlist_add_byte_array(attr_list, "port-wwn",
6707*7836SJohn.Forte@Sun.COM 	    port->fp_service_params.nport_ww_name.raw_wwn,
6708*7836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
6709*7836SJohn.Forte@Sun.COM 		goto error;
6710*7836SJohn.Forte@Sun.COM 	}
6711*7836SJohn.Forte@Sun.COM 
6712*7836SJohn.Forte@Sun.COM 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
6713*7836SJohn.Forte@Sun.COM 	    (type == FC_ULP_DEVICE_ONLINE) ?
6714*7836SJohn.Forte@Sun.COM 	    ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE,
6715*7836SJohn.Forte@Sun.COM 	    attr_list, NULL, DDI_SLEEP);
6716*7836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
6717*7836SJohn.Forte@Sun.COM 	return;
6718*7836SJohn.Forte@Sun.COM 
6719*7836SJohn.Forte@Sun.COM error:
6720*7836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
6721*7836SJohn.Forte@Sun.COM }
6722