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