1fcf3ce4John Forte/*
2fcf3ce4John Forte * CDDL HEADER START
3fcf3ce4John Forte *
4fcf3ce4John Forte * The contents of this file are subject to the terms of the
5fcf3ce4John Forte * Common Development and Distribution License (the "License").
6fcf3ce4John Forte * You may not use this file except in compliance with the License.
7fcf3ce4John Forte *
8fcf3ce4John Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce4John Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce4John Forte * See the License for the specific language governing permissions
11fcf3ce4John Forte * and limitations under the License.
12fcf3ce4John Forte *
13fcf3ce4John Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce4John Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce4John Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce4John Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce4John Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce4John Forte *
19fcf3ce4John Forte * CDDL HEADER END
20fcf3ce4John Forte */
21fcf3ce4John Forte/*
221641617Sriram Popuri * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce4John Forte * Use is subject to license terms.
24cd21e7cGarrett D'Amore */
25cd21e7cGarrett D'Amore/*
26cd21e7cGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
27d158018Bryan Cantrill * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
28cd21e7cGarrett D'Amore */
29cd21e7cGarrett D'Amore/*
30fcf3ce4John Forte * Fibre channel Transport Library (fctl)
31fcf3ce4John Forte *
32fcf3ce4John Forte * Function naming conventions:
33fcf3ce4John Forte *		Functions called from ULPs begin with fc_ulp_
34fcf3ce4John Forte *		Functions called from FCAs begin with fc_fca_
35fcf3ce4John Forte *		Internal functions begin with fctl_
36fcf3ce4John Forte *
37fcf3ce4John Forte * Fibre channel packet layout:
387ff8366Zhong Wang *	  +---------------------+<--------+
397ff8366Zhong Wang *	  |			|	  |
407ff8366Zhong Wang *	  | ULP Packet private	|	  |
417ff8366Zhong Wang *	  |			|	  |
427ff8366Zhong Wang *	  +---------------------+	  |
437ff8366Zhong Wang *	  |			|---------+
447ff8366Zhong Wang *	  |  struct  fc_packet	|---------+
457ff8366Zhong Wang *	  |			|	  |
467ff8366Zhong Wang *	  +---------------------+<--------+
477ff8366Zhong Wang *	  |			|
487ff8366Zhong Wang *	  | FCA Packet private	|
497ff8366Zhong Wang *	  |			|
507ff8366Zhong Wang *	  +---------------------+
51fcf3ce4John Forte *
527ff8366Zhong Wang * So you  loved  the  ascii  art ?  It's  strongly  desirable	to  cache
53fcf3ce4John Forte * allocate the entire packet in one common  place.  So we define a set a
547ff8366Zhong Wang * of rules.  In a  contiguous	block of memory,  the top  portion of the
557ff8366Zhong Wang * block points to ulp packet  private	area, next follows the	fc_packet
56fcf3ce4John Forte * structure used  extensively by all the consumers and what follows this
577ff8366Zhong Wang * is the FCA packet private.  Note that given a packet	 structure, it is
587ff8366Zhong Wang * possible  to get to the  ULP	 and  FCA  Packet  private  fields  using
59fcf3ce4John Forte * ulp_private and fca_private fields (which hold pointers) respectively.
60fcf3ce4John Forte *
61fcf3ce4John Forte * It should be noted with a grain of salt that ULP Packet  private  size
62fcf3ce4John Forte * varies  between two different  ULP types, So this poses a challenge to
637ff8366Zhong Wang * compute the correct	size of the whole block on a per port basis.  The
64fcf3ce4John Forte * transport  layer  doesn't have a problem in dealing with  FCA   packet
65fcf3ce4John Forte * private  sizes as it is the sole  manager of ports  underneath.  Since
66fcf3ce4John Forte * it's not a good idea to cache allocate  different  sizes of memory for
67fcf3ce4John Forte * different ULPs and have the ability to choose from one of these caches
68fcf3ce4John Forte * based on ULP type during every packet  allocation,  the transport some
697ff8366Zhong Wang * what	 wisely (?)  hands off this job of cache  allocation  to the ULPs
70fcf3ce4John Forte * themselves.
71fcf3ce4John Forte *
72fcf3ce4John Forte * That means FCAs need to make their  packet  private size  known to the
737ff8366Zhong Wang * transport   to  pass	 it  up	 to  the   ULPs.  This	is  done   during
74fcf3ce4John Forte * fc_fca_attach().  And the transport passes this size up to ULPs during
75fcf3ce4John Forte * fc_ulp_port_attach() of each ULP.
76fcf3ce4John Forte *
777ff8366Zhong Wang * This	 leaves	 us with  another  possible  question;	How  are  packets
787ff8366Zhong Wang * allocated for ELS's started by the transport	 itself ?  Well, the port
797ff8366Zhong Wang * driver  during  attach  time, cache	allocates  on a per port basis to
80fcf3ce4John Forte * handle ELSs too.
81fcf3ce4John Forte */
82fcf3ce4John Forte
83fcf3ce4John Forte#include <sys/note.h>
84fcf3ce4John Forte#include <sys/types.h>
85fcf3ce4John Forte#include <sys/varargs.h>
86fcf3ce4John Forte#include <sys/param.h>
87fcf3ce4John Forte#include <sys/errno.h>
88fcf3ce4John Forte#include <sys/uio.h>
89fcf3ce4John Forte#include <sys/buf.h>
90fcf3ce4John Forte#include <sys/modctl.h>
91fcf3ce4John Forte#include <sys/open.h>
92fcf3ce4John Forte#include <sys/kmem.h>
93fcf3ce4John Forte#include <sys/poll.h>
94fcf3ce4John Forte#include <sys/conf.h>
95fcf3ce4John Forte#include <sys/cmn_err.h>
96fcf3ce4John Forte#include <sys/stat.h>
97fcf3ce4John Forte#include <sys/ddi.h>
98fcf3ce4John Forte#include <sys/sunddi.h>
99fcf3ce4John Forte#include <sys/promif.h>
100fcf3ce4John Forte#include <sys/byteorder.h>
101fcf3ce4John Forte#include <sys/fibre-channel/fc.h>
102fcf3ce4John Forte#include <sys/fibre-channel/impl/fc_ulpif.h>
103fcf3ce4John Forte#include <sys/fibre-channel/impl/fc_fcaif.h>
104fcf3ce4John Forte#include <sys/fibre-channel/impl/fctl_private.h>
105fcf3ce4John Forte#include <sys/fibre-channel/impl/fc_portif.h>
106fcf3ce4John Forte
107fcf3ce4John Forte/* These are referenced by fp.c!  */
108fcf3ce4John Forteint did_table_size = D_ID_HASH_TABLE_SIZE;
109fcf3ce4John Forteint pwwn_table_size = PWWN_HASH_TABLE_SIZE;
110fcf3ce4John Forte
1117ff8366Zhong Wangstatic fc_ulp_module_t	*fctl_ulp_modules;
1127ff8366Zhong Wangstatic fc_fca_port_t	*fctl_fca_portlist;
113fcf3ce4John Fortestatic fc_ulp_list_t	*fctl_ulp_list;
114fcf3ce4John Forte
115fcf3ce4John Fortestatic char fctl_greeting[] =
116fcf3ce4John Forte	"fctl: %s ULP same type (0x%x) as existing module.\n";
117fcf3ce4John Forte
118fcf3ce4John Fortestatic char *fctl_undefined = "Undefined";
119fcf3ce4John Forte
120fcf3ce4John Forte/*
121fcf3ce4John Forte * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
122fcf3ce4John Forte */
123fcf3ce4John Forte
124fcf3ce4John Fortestatic krwlock_t fctl_ulp_lock;
125fcf3ce4John Forte
126fcf3ce4John Forte/*
127fcf3ce4John Forte * The fctl_mod_ports_lock protects the mod_ports element in the
128fcf3ce4John Forte * fc_ulp_ports_t structure
129fcf3ce4John Forte */
130fcf3ce4John Forte
131fcf3ce4John Fortestatic krwlock_t fctl_mod_ports_lock;
132fcf3ce4John Forte
133fcf3ce4John Forte/*
134fcf3ce4John Forte * fctl_port_lock protects the linked list of local port structures
1357ff8366Zhong Wang * (fctl_fca_portlist).	 When walking the list, this lock must be obtained
136fcf3ce4John Forte * prior to any local port locks.
137fcf3ce4John Forte */
138fcf3ce4John Forte
139fcf3ce4John Fortestatic kmutex_t fctl_port_lock;
140fcf3ce4John Fortestatic kmutex_t	fctl_ulp_list_mutex;
141fcf3ce4John Forte
142fcf3ce4John Fortestatic fctl_nwwn_list_t		*fctl_nwwn_hash_table;
143fcf3ce4John Fortestatic kmutex_t			fctl_nwwn_hash_mutex;
144fcf3ce4John Forteint fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
145fcf3ce4John Forte
146fcf3ce4John Forte#if	!defined(lint)
147fcf3ce4John Forte_NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
148fcf3ce4John Forte_NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
149fcf3ce4John Forte_NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
150fcf3ce4John Forte_NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
151fcf3ce4John Forte    ulp_ports::port_handle))
152fcf3ce4John Forte_NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
153fcf3ce4John Forte_NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
154fcf3ce4John Forte    ulp_ports::port_dstate))
155fcf3ce4John Forte#endif /* lint */
156fcf3ce4John Forte
1577ff8366Zhong Wang#define	FCTL_VERSION		"20090729-1.70"
158fcf3ce4John Forte#define	FCTL_NAME_VERSION	"SunFC Transport v" FCTL_VERSION
159fcf3ce4John Forte
160fcf3ce4John Fortechar *fctl_version = FCTL_NAME_VERSION;
161fcf3ce4John Forte
162fcf3ce4John Forteextern struct mod_ops mod_miscops;
163fcf3ce4John Forte
164fcf3ce4John Fortestatic struct modlmisc modlmisc = {
165fcf3ce4John Forte	&mod_miscops,			/* type of module */
166fcf3ce4John Forte	FCTL_NAME_VERSION		/* Module name */
167fcf3ce4John Forte};
168fcf3ce4John Forte
169fcf3ce4John Fortestatic struct modlinkage modlinkage = {
170fcf3ce4John Forte	MODREV_1, (void *)&modlmisc, NULL
171fcf3ce4John Forte};
172fcf3ce4John Forte
173fcf3ce4John Fortestatic struct bus_ops fctl_fca_busops = {
174fcf3ce4John Forte	BUSO_REV,
175fcf3ce4John Forte	nullbusmap,			/* bus_map */
176fcf3ce4John Forte	NULL,				/* bus_get_intrspec */
177fcf3ce4John Forte	NULL,				/* bus_add_intrspec */
178fcf3ce4John Forte	NULL,				/* bus_remove_intrspec */
179fcf3ce4John Forte	i_ddi_map_fault,		/* bus_map_fault */
180cd21e7cGarrett D'Amore	NULL,				/* bus_dma_map */
181fcf3ce4John Forte	ddi_dma_allochdl,		/* bus_dma_allochdl */
182fcf3ce4John Forte	ddi_dma_freehdl,		/* bus_dma_freehdl */
183fcf3ce4John Forte	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
184fcf3ce4John Forte	ddi_dma_unbindhdl,		/* bus_unbindhdl */
185fcf3ce4John Forte	ddi_dma_flush,			/* bus_dma_flush */
186fcf3ce4John Forte	ddi_dma_win,			/* bus_dma_win */
187fcf3ce4John Forte	ddi_dma_mctl,			/* bus_dma_ctl */
188fcf3ce4John Forte	fctl_fca_bus_ctl,		/* bus_ctl */
189fcf3ce4John Forte	ddi_bus_prop_op,		/* bus_prop_op */
190fcf3ce4John Forte	NULL,				/* bus_get_eventcookie */
191fcf3ce4John Forte	NULL,				/* bus_add_eventcall */
192fcf3ce4John Forte	NULL,				/* bus_remove_event */
193fcf3ce4John Forte	NULL,				/* bus_post_event */
194fcf3ce4John Forte	NULL,				/* bus_intr_ctl */
195fcf3ce4John Forte	NULL,				/* bus_config */
196fcf3ce4John Forte	NULL,				/* bus_unconfig */
197fcf3ce4John Forte	NULL,				/* bus_fm_init */
198fcf3ce4John Forte	NULL,				/* bus_fm_fini */
199fcf3ce4John Forte	NULL,				/* bus_fm_access_enter */
200fcf3ce4John Forte	NULL,				/* bus_fm_access_exit */
201fcf3ce4John Forte	NULL,				/* bus_power */
202fcf3ce4John Forte	NULL
203fcf3ce4John Forte};
204fcf3ce4John Forte
205fcf3ce4John Fortestruct kmem_cache *fctl_job_cache;
206fcf3ce4John Forte
207fcf3ce4John Fortestatic fc_errmap_t fc_errlist [] = {
2087ff8366Zhong Wang	{ FC_FAILURE,		"Operation failed"			},
2097ff8366Zhong Wang	{ FC_SUCCESS,		"Operation success"			},
2107ff8366Zhong Wang	{ FC_CAP_ERROR,		"Capability error"			},
2117ff8366Zhong Wang	{ FC_CAP_FOUND,		"Capability found"			},
2127ff8366Zhong Wang	{ FC_CAP_SETTABLE,	"Capability settable"			},
2137ff8366Zhong Wang	{ FC_UNBOUND,		"Port not bound"			},
2147ff8366Zhong Wang	{ FC_NOMEM,		"No memory"				},
2157ff8366Zhong Wang	{ FC_BADPACKET,		"Bad packet"				},
2167ff8366Zhong Wang	{ FC_OFFLINE,		"Port offline"				},
2177ff8366Zhong Wang	{ FC_OLDPORT,		"Old Port"				},
2187ff8366Zhong Wang	{ FC_NO_MAP,		"No map available"			},
2197ff8366Zhong Wang	{ FC_TRANSPORT_ERROR,	"Transport error"			},
2207ff8366Zhong Wang	{ FC_ELS_FREJECT,	"ELS Frejected"				},
2217ff8366Zhong Wang	{ FC_ELS_PREJECT,	"ELS PRejected"				},
2227ff8366Zhong Wang	{ FC_ELS_BAD,		"Bad ELS request"			},
2237ff8366Zhong Wang	{ FC_ELS_MALFORMED,	"Malformed ELS request"			},
2247ff8366Zhong Wang	{ FC_TOOMANY,		"Too many commands"			},
2257ff8366Zhong Wang	{ FC_UB_BADTOKEN,	"Bad Unsolicited buffer token"		},
2267ff8366Zhong Wang	{ FC_UB_ERROR,		"Unsolicited buffer error"		},
2277ff8366Zhong Wang	{ FC_UB_BUSY,		"Unsolicited buffer busy"		},
2287ff8366Zhong Wang	{ FC_BADULP,		"Bad ULP"				},
2297ff8366Zhong Wang	{ FC_BADTYPE,		"Bad Type"				},
2307ff8366Zhong Wang	{ FC_UNCLAIMED,		"Not Claimed"				},
2317ff8366Zhong Wang	{ FC_ULP_SAMEMODULE,	"Same ULP Module"			},
2327ff8366Zhong Wang	{ FC_ULP_SAMETYPE,	"Same ULP Type"				},
2337ff8366Zhong Wang	{ FC_ABORTED,		"Command Aborted"			},
2347ff8366Zhong Wang	{ FC_ABORT_FAILED,	"Abort Failed"				},
2357ff8366Zhong Wang	{ FC_BADEXCHANGE,	"Bad Exchange"				},
2367ff8366Zhong Wang	{ FC_BADWWN,		"Bad World Wide Name"			},
2377ff8366Zhong Wang	{ FC_BADDEV,		"Bad Device"				},
2387ff8366Zhong Wang	{ FC_BADCMD,		"Bad Command"				},
2397ff8366Zhong Wang	{ FC_BADOBJECT,		"Bad Object"				},
2407ff8366Zhong Wang	{ FC_BADPORT,		"Bad Port"				},
2417ff8366Zhong Wang	{ FC_NOTTHISPORT,	"Not on this Port"			},
2427ff8366Zhong Wang	{ FC_PREJECT,		"Operation Prejected"			},
2437ff8366Zhong Wang	{ FC_FREJECT,		"Operation Frejected"			},
2447ff8366Zhong Wang	{ FC_PBUSY,		"Operation Pbusyed"			},
2457ff8366Zhong Wang	{ FC_FBUSY,		"Operation Fbusyed"			},
2467ff8366Zhong Wang	{ FC_ALREADY,		"Already done"				},
2477ff8366Zhong Wang	{ FC_LOGINREQ,		"PLOGI Required"			},
2487ff8366Zhong Wang	{ FC_RESETFAIL,		"Reset operation failed"		},
2497ff8366Zhong Wang	{ FC_INVALID_REQUEST,	"Invalid Request"			},
2507ff8366Zhong Wang	{ FC_OUTOFBOUNDS,	"Out of Bounds"				},
2517ff8366Zhong Wang	{ FC_TRAN_BUSY,		"Command transport Busy"		},
2527ff8366Zhong Wang	{ FC_STATEC_BUSY,	"State change Busy"			},
253fcf3ce4John Forte	{ FC_DEVICE_BUSY,	"Port driver is working on this device"	}
254fcf3ce4John Forte};
255fcf3ce4John Forte
256fcf3ce4John Fortefc_pkt_reason_t remote_stop_reasons [] = {
257fcf3ce4John Forte	{ FC_REASON_ABTS,	"Abort Sequence"	},
258fcf3ce4John Forte	{ FC_REASON_ABTX,	"Abort Exchange"	},
259fcf3ce4John Forte	{ FC_REASON_INVALID,	NULL			}
260fcf3ce4John Forte};
261fcf3ce4John Forte
262fcf3ce4John Fortefc_pkt_reason_t general_reasons [] = {
2637ff8366Zhong Wang	{ FC_REASON_HW_ERROR,		"Hardware Error"		},
264fcf3ce4John Forte	{ FC_REASON_SEQ_TIMEOUT,	"Sequence Timeout"		},
265fcf3ce4John Forte	{ FC_REASON_ABORTED,		"Aborted"			},
266fcf3ce4John Forte	{ FC_REASON_ABORT_FAILED,	"Abort Failed"			},
267fcf3ce4John Forte	{ FC_REASON_NO_CONNECTION,	"No Connection"			},
268fcf3ce4John Forte	{ FC_REASON_XCHG_DROPPED,	"Exchange Dropped"		},
269fcf3ce4John Forte	{ FC_REASON_ILLEGAL_FRAME,	"Illegal Frame"			},
270fcf3ce4John Forte	{ FC_REASON_ILLEGAL_LENGTH,	"Illegal Length"		},
271fcf3ce4John Forte	{ FC_REASON_UNSUPPORTED,	"Unsuported"			},
272fcf3ce4John Forte	{ FC_REASON_RX_BUF_TIMEOUT,	"Receive Buffer Timeout"	},
273fcf3ce4John Forte	{ FC_REASON_FCAL_OPN_FAIL,	"FC AL Open Failed"		},
274fcf3ce4John Forte	{ FC_REASON_OVERRUN,		"Over run"			},
275fcf3ce4John Forte	{ FC_REASON_QFULL,		"Queue Full"			},
276fcf3ce4John Forte	{ FC_REASON_ILLEGAL_REQ,	"Illegal Request",		},
277fcf3ce4John Forte	{ FC_REASON_PKT_BUSY,		"Busy"				},
278fcf3ce4John Forte	{ FC_REASON_OFFLINE,		"Offline"			},
279fcf3ce4John Forte	{ FC_REASON_BAD_XID,		"Bad Exchange Id"		},
280fcf3ce4John Forte	{ FC_REASON_XCHG_BSY,		"Exchange Busy"			},
281fcf3ce4John Forte	{ FC_REASON_NOMEM,		"No Memory"			},
282fcf3ce4John Forte	{ FC_REASON_BAD_SID,		"Bad S_ID"			},
283fcf3ce4John Forte	{ FC_REASON_NO_SEQ_INIT,	"No Sequence Initiative"	},
284fcf3ce4John Forte	{ FC_REASON_DIAG_BUSY,		"Diagnostic Busy"		},
285fcf3ce4John Forte	{ FC_REASON_DMA_ERROR,		"DMA Error"			},
286fcf3ce4John Forte	{ FC_REASON_CRC_ERROR,		"CRC Error"			},
287fcf3ce4John Forte	{ FC_REASON_ABORT_TIMEOUT,	"Abort Timeout"			},
288fcf3ce4John Forte	{ FC_REASON_FCA_UNIQUE,		"FCA Unique"			},
289fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
290fcf3ce4John Forte};
291fcf3ce4John Forte
292fcf3ce4John Fortefc_pkt_reason_t rjt_reasons [] = {
293fcf3ce4John Forte	{ FC_REASON_INVALID_D_ID,	"Invalid D_ID"			},
294fcf3ce4John Forte	{ FC_REASON_INVALID_S_ID,	"Invalid S_ID"			},
295fcf3ce4John Forte	{ FC_REASON_TEMP_UNAVAILABLE,	"Temporarily Unavailable"	},
296fcf3ce4John Forte	{ FC_REASON_PERM_UNAVAILABLE,	"Permamnently Unavailable"	},
297fcf3ce4John Forte	{ FC_REASON_CLASS_NOT_SUPP,	"Class Not Supported",		},
2997ff8366Zhong Wang	    "Delimeter Usage Error"		},
300fcf3ce4John Forte	{ FC_REASON_TYPE_NOT_SUPP,	"Type Not Supported"		},
301fcf3ce4John Forte	{ FC_REASON_INVALID_LINK_CTRL,	"Invalid Link Control"		},
302fcf3ce4John Forte	{ FC_REASON_INVALID_R_CTL,	"Invalid R_CTL"			},
303fcf3ce4John Forte	{ FC_REASON_INVALID_F_CTL,	"Invalid F_CTL"			},
304fcf3ce4John Forte	{ FC_REASON_INVALID_OX_ID,	"Invalid OX_ID"			},
305fcf3ce4John Forte	{ FC_REASON_INVALID_RX_ID,	"Invalid RX_ID"			},
306fcf3ce4John Forte	{ FC_REASON_INVALID_SEQ_ID,	"Invalid Sequence ID"		},
307fcf3ce4John Forte	{ FC_REASON_INVALID_DF_CTL,	"Invalid DF_CTL"		},
308fcf3ce4John Forte	{ FC_REASON_INVALID_SEQ_CNT,	"Invalid Sequence count"	},
309fcf3ce4John Forte	{ FC_REASON_INVALID_PARAM,	"Invalid Parameter"		},
310fcf3ce4John Forte	{ FC_REASON_EXCH_ERROR,		"Exchange Error"		},
311fcf3ce4John Forte	{ FC_REASON_PROTOCOL_ERROR,	"Protocol Error"		},
312fcf3ce4John Forte	{ FC_REASON_INCORRECT_LENGTH,	"Incorrect Length"		},
313fcf3ce4John Forte	{ FC_REASON_UNEXPECTED_ACK,	"Unexpected Ack"		},
3147ff8366Zhong Wang	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset"		},
315fcf3ce4John Forte	{ FC_REASON_LOGIN_REQUIRED,	"Login Required"		},
316fcf3ce4John Forte	{ FC_REASON_EXCESSIVE_SEQS,	"Excessive Sequences"
3177ff8366Zhong Wang	    " Attempted"			},
318fcf3ce4John Forte	{ FC_REASON_EXCH_UNABLE,	"Exchange incapable"		},
319fcf3ce4John Forte	{ FC_REASON_ESH_NOT_SUPP,	"Expiration Security Header "
3207ff8366Zhong Wang	    "Not Supported"			},
321fcf3ce4John Forte	{ FC_REASON_NO_FABRIC_PATH,	"No Fabric Path"		},
322fcf3ce4John Forte	{ FC_REASON_VENDOR_UNIQUE,	"Vendor Unique"			},
323fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
324fcf3ce4John Forte};
325fcf3ce4John Forte
326fcf3ce4John Fortefc_pkt_reason_t n_port_busy_reasons [] = {
327fcf3ce4John Forte	{ FC_REASON_PHYSICAL_BUSY,		"Physical Busy"		},
328fcf3ce4John Forte	{ FC_REASON_N_PORT_RESOURCE_BSY,	"Resource Busy"		},
329fcf3ce4John Forte	{ FC_REASON_N_PORT_VENDOR_UNIQUE,	"Vendor Unique"		},
330fcf3ce4John Forte	{ FC_REASON_INVALID,			NULL			}
331fcf3ce4John Forte};
332fcf3ce4John Forte
333fcf3ce4John Fortefc_pkt_reason_t f_busy_reasons [] = {
334fcf3ce4John Forte	{ FC_REASON_FABRIC_BSY,		"Fabric Busy"			},
335fcf3ce4John Forte	{ FC_REASON_N_PORT_BSY,		"N_Port Busy"			},
336fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
337fcf3ce4John Forte};
338fcf3ce4John Forte
339fcf3ce4John Fortefc_pkt_reason_t ls_ba_rjt_reasons [] = {
340fcf3ce4John Forte	{ FC_REASON_INVALID_LA_CODE,	"Invalid Link Application Code"	},
341fcf3ce4John Forte	{ FC_REASON_LOGICAL_ERROR,	"Logical Error"			},
342fcf3ce4John Forte	{ FC_REASON_LOGICAL_BSY,	"Logical Busy"			},
343fcf3ce4John Forte	{ FC_REASON_PROTOCOL_ERROR_RJT,	"Protocol Error Reject"		},
344fcf3ce4John Forte	{ FC_REASON_CMD_UNABLE,		"Unable to Perform Command"	},
345fcf3ce4John Forte	{ FC_REASON_CMD_UNSUPPORTED,	"Unsupported Command"		},
346fcf3ce4John Forte	{ FC_REASON_VU_RJT,		"Vendor Unique"			},
347fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
348fcf3ce4John Forte};
349fcf3ce4John Forte
350fcf3ce4John Fortefc_pkt_reason_t fs_rjt_reasons [] = {
351fcf3ce4John Forte	{ FC_REASON_FS_INVALID_CMD,	"Invalid Command"		},
352fcf3ce4John Forte	{ FC_REASON_FS_INVALID_VER,	"Invalid Version"		},
353fcf3ce4John Forte	{ FC_REASON_FS_LOGICAL_ERR,	"Logical Error"			},
354fcf3ce4John Forte	{ FC_REASON_FS_INVALID_IUSIZE,	"Invalid IU Size"		},
355fcf3ce4John Forte	{ FC_REASON_FS_LOGICAL_BUSY,	"Logical Busy"			},
356fcf3ce4John Forte	{ FC_REASON_FS_PROTOCOL_ERR,	"Protocol Error"		},
357fcf3ce4John Forte	{ FC_REASON_FS_CMD_UNABLE,	"Unable to Perform Command"	},
358fcf3ce4John Forte	{ FC_REASON_FS_CMD_UNSUPPORTED,	"Unsupported Command"		},
359fcf3ce4John Forte	{ FC_REASON_FS_VENDOR_UNIQUE,	"Vendor Unique"			},
360fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
361fcf3ce4John Forte};
362fcf3ce4John Forte
363fcf3ce4John Fortefc_pkt_action_t	n_port_busy_actions [] = {
364fcf3ce4John Forte	{ FC_ACTION_SEQ_TERM_RETRY,	"Retry terminated Sequence"	},
365fcf3ce4John Forte	{ FC_ACTION_SEQ_ACTIVE_RETRY,	"Retry Active Sequence"		},
366fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
367fcf3ce4John Forte};
368fcf3ce4John Forte
369fcf3ce4John Fortefc_pkt_action_t rjt_timeout_actions [] = {
370fcf3ce4John Forte	{ FC_ACTION_RETRYABLE,		"Retryable"			},
371fcf3ce4John Forte	{ FC_ACTION_NON_RETRYABLE,	"Non Retryable"			},
372fcf3ce4John Forte	{ FC_REASON_INVALID,		NULL				}
373fcf3ce4John Forte};
374fcf3ce4John Forte
375fcf3ce4John Fortefc_pkt_expln_t ba_rjt_explns [] = {
376fcf3ce4John Forte	{ FC_EXPLN_NONE,		"No Explanation"		},
377fcf3ce4John Forte	{ FC_EXPLN_INVALID_OX_RX_ID,	"Invalid X_ID"			},
378fcf3ce4John Forte	{ FC_EXPLN_SEQ_ABORTED,		"Sequence Aborted"		},
379fcf3ce4John Forte	{ FC_EXPLN_INVALID,		NULL				}
380fcf3ce4John Forte};
381fcf3ce4John Forte
382fcf3ce4John Fortefc_pkt_error_t fc_pkt_errlist[] = {
383fcf3ce4John Forte	{
384fcf3ce4John Forte		FC_PKT_SUCCESS,
385fcf3ce4John Forte		"Operation Success",
386fcf3ce4John Forte		NULL,
387fcf3ce4John Forte		NULL,
388fcf3ce4John Forte		NULL
389fcf3ce4John Forte	},
390fcf3ce4John Forte	{	FC_PKT_REMOTE_STOP,
3917ff8366Zhong Wang	    "Remote Stop",
3927ff8366Zhong Wang	    remote_stop_reasons,
3937ff8366Zhong Wang	    NULL,
3947ff8366Zhong Wang	    NULL
395fcf3ce4John Forte	},
396fcf3ce4John Forte	{
397fcf3ce4John Forte		FC_PKT_LOCAL_RJT,
398fcf3ce4John Forte		"Local Reject",
399fcf3ce4John Forte		general_reasons,
400fcf3ce4John Forte		rjt_timeout_actions,
401fcf3ce4John Forte		NULL
402fcf3ce4John Forte	},
403fcf3ce4John Forte	{
404fcf3ce4John Forte		FC_PKT_NPORT_RJT,
405fcf3ce4John Forte		"N_Port Reject",
406fcf3ce4John Forte		rjt_reasons,
407fcf3ce4John Forte		rjt_timeout_actions,
408fcf3ce4John Forte		NULL
409fcf3ce4John Forte	},
410fcf3ce4John Forte	{
411fcf3ce4John Forte		FC_PKT_FABRIC_RJT,
412fcf3ce4John Forte		"Fabric Reject",
413fcf3ce4John Forte		rjt_reasons,
414fcf3ce4John Forte		rjt_timeout_actions,
415fcf3ce4John Forte		NULL
416fcf3ce4John Forte	},
417fcf3ce4John Forte	{
418fcf3ce4John Forte		FC_PKT_LOCAL_BSY,
419fcf3ce4John Forte		"Local Busy",
420fcf3ce4John Forte		general_reasons,
421fcf3ce4John Forte		NULL,
422fcf3ce4John Forte		NULL,
423fcf3ce4John Forte	},
424fcf3ce4John Forte	{
425fcf3ce4John Forte		FC_PKT_TRAN_BSY,
426fcf3ce4John Forte		"Transport Busy",
427fcf3ce4John Forte		general_reasons,
428fcf3ce4John Forte		NULL,
429fcf3ce4John Forte		NULL,
430fcf3ce4John Forte	},
431fcf3ce4John Forte	{
432fcf3ce4John Forte		FC_PKT_NPORT_BSY,
433fcf3ce4John Forte		"N_Port Busy",
434fcf3ce4John Forte		n_port_busy_reasons,
435fcf3ce4John Forte		n_port_busy_actions,
436fcf3ce4John Forte		NULL
437fcf3ce4John Forte	},
438fcf3ce4John Forte	{
439fcf3ce4John Forte		FC_PKT_FABRIC_BSY,
440fcf3ce4John Forte		"Fabric Busy",
441fcf3ce4John Forte		f_busy_reasons,
442fcf3ce4John Forte		NULL,
443fcf3ce4John Forte		NULL,
444fcf3ce4John Forte	},
445fcf3ce4John Forte	{
446fcf3ce4John Forte		FC_PKT_LS_RJT,
447fcf3ce4John Forte		"Link Service Reject",
448fcf3ce4John Forte		ls_ba_rjt_reasons,
449fcf3ce4John Forte		NULL,
450fcf3ce4John Forte		NULL,
451fcf3ce4John Forte	},
452fcf3ce4John Forte	{
453fcf3ce4John Forte		FC_PKT_BA_RJT,
454fcf3ce4John Forte		"Basic Reject",
455fcf3ce4John Forte		ls_ba_rjt_reasons,
456fcf3ce4John Forte		NULL,
457fcf3ce4John Forte		ba_rjt_explns,
458fcf3ce4John Forte	},
459fcf3ce4John Forte	{
460fcf3ce4John Forte		FC_PKT_TIMEOUT,
461fcf3ce4John Forte		"Timeout",
462fcf3ce4John Forte		general_reasons,
463fcf3ce4John Forte		rjt_timeout_actions,
464fcf3ce4John Forte		NULL
465fcf3ce4John Forte	},
466fcf3ce4John Forte	{
467fcf3ce4John Forte		FC_PKT_FS_RJT,
468fcf3ce4John Forte		"Fabric Switch Reject",
469fcf3ce4John Forte		fs_rjt_reasons,
470fcf3ce4John Forte		NULL,
471fcf3ce4John Forte		NULL
472fcf3ce4John Forte	},
473fcf3ce4John Forte	{
474fcf3ce4John Forte		FC_PKT_TRAN_ERROR,
475fcf3ce4John Forte		"Packet Transport error",
476fcf3ce4John Forte		general_reasons,
477fcf3ce4John Forte		NULL,
478fcf3ce4John Forte		NULL
479fcf3ce4John Forte	},
480fcf3ce4John Forte	{
481fcf3ce4John Forte		FC_PKT_FAILURE,
482fcf3ce4John Forte		"Packet Failure",
483fcf3ce4John Forte		general_reasons,
484fcf3ce4John Forte		NULL,
485fcf3ce4John Forte		NULL
486fcf3ce4John Forte	},
487fcf3ce4John Forte	{
488fcf3ce4John Forte		FC_PKT_PORT_OFFLINE,
489fcf3ce4John Forte		"Port Offline",
490fcf3ce4John Forte		NULL,
491fcf3ce4John Forte		NULL,
492fcf3ce4John Forte		NULL
493fcf3ce4John Forte	},
494fcf3ce4John Forte	{
495fcf3ce4John Forte		FC_PKT_ELS_IN_PROGRESS,
496fcf3ce4John Forte		"ELS is in Progress",
497fcf3ce4John Forte		NULL,
498fcf3ce4John Forte		NULL,
499fcf3ce4John Forte		NULL
500fcf3ce4John Forte	}
501fcf3ce4John Forte};
502fcf3ce4John Forte
503fcf3ce4John Forteint
504fcf3ce4John Forte_init()
505fcf3ce4John Forte{
506fcf3ce4John Forte	int rval;
507fcf3ce4John Forte
508fcf3ce4John Forte	rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
509fcf3ce4John Forte	rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
510fcf3ce4John Forte	mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
511fcf3ce4John Forte	mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
512fcf3ce4John Forte
513fcf3ce4John Forte	fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
514fcf3ce4John Forte	    fctl_nwwn_table_size, KM_SLEEP);
515fcf3ce4John Forte
516fcf3ce4John Forte	fctl_ulp_modules = NULL;
517fcf3ce4John Forte	fctl_fca_portlist = NULL;
518fcf3ce4John Forte
519fcf3ce4John Forte	fctl_job_cache = kmem_cache_create("fctl_cache",
520fcf3ce4John Forte	    sizeof (job_request_t), 8, fctl_cache_constructor,
521fcf3ce4John Forte	    fctl_cache_destructor, NULL, NULL, NULL, 0);
522fcf3ce4John Forte
523fcf3ce4John Forte	if (fctl_job_cache == NULL) {
524fcf3ce4John Forte		kmem_free(fctl_nwwn_hash_table,
525fcf3ce4John Forte		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
526fcf3ce4John Forte		mutex_destroy(&fctl_nwwn_hash_mutex);
527fcf3ce4John Forte		mutex_destroy(&fctl_port_lock);
528fcf3ce4John Forte		rw_destroy(&fctl_ulp_lock);
529fcf3ce4John Forte		rw_destroy(&fctl_mod_ports_lock);
530fcf3ce4John Forte		return (ENOMEM);
531fcf3ce4John Forte	}
532fcf3ce4John Forte
533fcf3ce4John Forte	if ((rval = mod_install(&modlinkage)) != 0) {
534fcf3ce4John Forte		kmem_cache_destroy(fctl_job_cache);
535fcf3ce4John Forte		kmem_free(fctl_nwwn_hash_table,
536fcf3ce4John Forte		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
537fcf3ce4John Forte		mutex_destroy(&fctl_nwwn_hash_mutex);
538fcf3ce4John Forte		mutex_destroy(&fctl_port_lock);
539fcf3ce4John Forte		rw_destroy(&fctl_ulp_lock);
540fcf3ce4John Forte		rw_destroy(&fctl_mod_ports_lock);
541fcf3ce4John Forte	}
542fcf3ce4John Forte
543fcf3ce4John Forte	return (rval);
544fcf3ce4John Forte}
545fcf3ce4John Forte
546fcf3ce4John Forte
547fcf3ce4John Forte/*
548fcf3ce4John Forte * The mod_uninstall code doesn't call _fini when
549fcf3ce4John Forte * there is living dependent module on fctl. So
550fcf3ce4John Forte * there is no need to be extra careful here ?
551fcf3ce4John Forte */
552fcf3ce4John Forteint
553fcf3ce4John Forte_fini()
554fcf3ce4John Forte{
555fcf3ce4John Forte	int rval;
556fcf3ce4John Forte
557fcf3ce4John Forte	if ((rval = mod_remove(&modlinkage)) != 0) {
558fcf3ce4John Forte		return (rval);
559fcf3ce4John Forte	}
560fcf3ce4John Forte
561fcf3ce4John Forte	kmem_cache_destroy(fctl_job_cache);
562fcf3ce4John Forte	kmem_free(fctl_nwwn_hash_table,
563fcf3ce4John Forte	    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
564fcf3ce4John Forte	mutex_destroy(&fctl_nwwn_hash_mutex);
565fcf3ce4John Forte	mutex_destroy(&fctl_port_lock);
566fcf3ce4John Forte	rw_destroy(&fctl_ulp_lock);
567fcf3ce4John Forte	rw_destroy(&fctl_mod_ports_lock);
568fcf3ce4John Forte
569fcf3ce4John Forte	return (rval);
570fcf3ce4John Forte}
571fcf3ce4John Forte
572fcf3ce4John Forte
573fcf3ce4John Forteint
574fcf3ce4John Forte_info(struct modinfo *modinfo_p)
575fcf3ce4John Forte{
576fcf3ce4John Forte	return (mod_info(&modlinkage, modinfo_p));
577fcf3ce4John Forte}
578fcf3ce4John Forte
579fcf3ce4John Forte
580fcf3ce4John Forte/* ARGSUSED */
581fcf3ce4John Fortestatic int
582fcf3ce4John Fortefctl_cache_constructor(void *buf, void *cdarg, int kmflag)
583fcf3ce4John Forte{
584fcf3ce4John Forte	job_request_t *job = (job_request_t *)buf;
585fcf3ce4John Forte
586fcf3ce4John Forte	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
587fcf3ce4John Forte	sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
588fcf3ce4John Forte	sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
589fcf3ce4John Forte
590fcf3ce4John Forte	return (0);
591fcf3ce4John Forte}
592fcf3ce4John Forte
593fcf3ce4John Forte
594fcf3ce4John Forte/* ARGSUSED */
595fcf3ce4John Fortestatic void
596fcf3ce4John Fortefctl_cache_destructor(void *buf, void *cdarg)
597fcf3ce4John Forte{
598fcf3ce4John Forte	job_request_t *job = (job_request_t *)buf;
599fcf3ce4John Forte
600fcf3ce4John Forte	sema_destroy(&job->job_fctl_sema);
601fcf3ce4John Forte	sema_destroy(&job->job_port_sema);
602fcf3ce4John Forte	mutex_destroy(&job->job_mutex);
603fcf3ce4John Forte}
604fcf3ce4John Forte
605fcf3ce4John Forte
606fcf3ce4John Forte/*
607fcf3ce4John Forte * fc_ulp_add:
608fcf3ce4John Forte *		Add a ULP module
609fcf3ce4John Forte *
610fcf3ce4John Forte * Return Codes:
611fcf3ce4John Forte *		FC_ULP_SAMEMODULE
612fcf3ce4John Forte *		FC_SUCCESS
613fcf3ce4John Forte *		FC_FAILURE
614fcf3ce4John Forte *
6157ff8366Zhong Wang *   fc_ulp_add	 prints	 a warning message if there is	already a
616fcf3ce4John Forte *   similar ULP type  attached and this is unlikely to change as
6177ff8366Zhong Wang *   we trudge along.  Further, this  function	returns a failure
618fcf3ce4John Forte *   code if the same  module  attempts to add more than once for
619fcf3ce4John Forte *   the same FC-4 type.
620fcf3ce4John Forte */
621fcf3ce4John Forteint
622fcf3ce4John Fortefc_ulp_add(fc_ulp_modinfo_t *ulp_info)
623fcf3ce4John Forte{
624fcf3ce4John Forte	fc_ulp_module_t *mod;
625fcf3ce4John Forte	fc_ulp_module_t *prev;
6267ff8366Zhong Wang	job_request_t	*job;
627fcf3ce4John Forte	fc_ulp_list_t	*new;
6287ff8366Zhong Wang	fc_fca_port_t	*fca_port;
629fcf3ce4John Forte	int		ntry = 0;
630fcf3ce4John Forte
631fcf3ce4John Forte	ASSERT(ulp_info != NULL);
632fcf3ce4John Forte
633fcf3ce4John Forte	/*
634fcf3ce4John Forte	 * Make sure ulp_rev matches fctl version.
635fcf3ce4John Forte	 * Whenever non-private data structure or non-static interface changes,
636fcf3ce4John Forte	 * we should use an increased FCTL_ULP_MODREV_# number here and in all
637fcf3ce4John Forte	 * ulps to prevent version mismatch.
638fcf3ce4John Forte	 */
639fcf3ce4John Forte	if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
640fcf3ce4John Forte		cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
641fcf3ce4John Forte		    " ULP %s would not be loaded", ulp_info->ulp_name,
642fcf3ce4John Forte		    ulp_info->ulp_name);
643fcf3ce4John Forte		return (FC_BADULP);
644fcf3ce4John Forte	}
645fcf3ce4John Forte
646fcf3ce4John Forte	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
647fcf3ce4John Forte	ASSERT(new != NULL);
648fcf3ce4John Forte
649fcf3ce4John Forte	mutex_enter(&fctl_ulp_list_mutex);
650fcf3ce4John Forte	new->ulp_info = ulp_info;
651fcf3ce4John Forte	if (fctl_ulp_list != NULL) {
652fcf3ce4John Forte		new->ulp_next = fctl_ulp_list;
653fcf3ce4John Forte	}
654fcf3ce4John Forte	fctl_ulp_list = new;
655fcf3ce4John Forte	mutex_exit(&fctl_ulp_list_mutex);
656fcf3ce4John Forte
657fcf3ce4John Forte	while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
658fcf3ce4John Forte		delay(drv_usectohz(1000000));
659fcf3ce4John Forte		if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
6607ff8366Zhong Wang			fc_ulp_list_t	*list;
6617ff8366Zhong Wang			fc_ulp_list_t	*last;
662fcf3ce4John Forte			mutex_enter(&fctl_ulp_list_mutex);
663fcf3ce4John Forte			for (last = NULL, list = fctl_ulp_list; list != NULL;
664fcf3ce4John Forte			    list = list->ulp_next) {
665fcf3ce4John Forte				if (list->ulp_info == ulp_info) {
666fcf3ce4John Forte					break;
667fcf3ce4John Forte				}
668fcf3ce4John Forte				last = list;
669fcf3ce4John Forte			}
670fcf3ce4John Forte
671fcf3ce4John Forte			if (list) {
672fcf3ce4John Forte				if (last) {
673fcf3ce4John Forte					last->ulp_next = list->ulp_next;
674fcf3ce4John Forte				} else {
675fcf3ce4John Forte					fctl_ulp_list = list->ulp_next;
676fcf3ce4John Forte				}
677fcf3ce4John Forte				kmem_free(list, sizeof (*list));
678fcf3ce4John Forte			}
679fcf3ce4John Forte			mutex_exit(&fctl_ulp_list_mutex);
680fcf3ce4John Forte			cmn_err(CE_WARN, "fctl: ULP %s unable to load",
681fcf3ce4John Forte			    ulp_info->ulp_name);
682fcf3ce4John Forte			return (FC_FAILURE);
683fcf3ce4John Forte		}
684fcf3ce4John Forte	}
685fcf3ce4John Forte
686fcf3ce4John Forte	for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
687fcf3ce4John Forte		ASSERT(mod->mod_info != NULL);
688fcf3ce4John Forte
689fcf3ce4John Forte		if (ulp_info == mod->mod_info &&
690fcf3ce4John Forte		    ulp_info->ulp_type == mod->mod_info->ulp_type) {
691fcf3ce4John Forte			rw_exit(&fctl_ulp_lock);
692fcf3ce4John Forte			return (FC_ULP_SAMEMODULE);
693fcf3ce4John Forte		}
694fcf3ce4John Forte
695fcf3ce4John Forte		if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
696fcf3ce4John Forte			cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
697fcf3ce4John Forte			    ulp_info->ulp_type);
698fcf3ce4John Forte		}
699fcf3ce4John Forte		prev = mod;
700fcf3ce4John Forte	}
701fcf3ce4John Forte
702fcf3ce4John Forte	mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
703fcf3ce4John Forte	mod->mod_info = ulp_info;
704fcf3ce4John Forte	mod->mod_next = NULL;
705fcf3ce4John Forte
706fcf3ce4John Forte	if (prev) {
707fcf3ce4John Forte		prev->mod_next = mod;
708fcf3ce4John Forte	} else {
709fcf3ce4John Forte		fctl_ulp_modules = mod;
710fcf3ce4John Forte	}
711fcf3ce4John Forte
712fcf3ce4John Forte	/*
713fcf3ce4John Forte	 * Schedule a job to each port's job_handler
714fcf3ce4John Forte	 * thread to attach their ports with this ULP.
715fcf3ce4John Forte	 */
716fcf3ce4John Forte	mutex_enter(&fctl_port_lock);
717fcf3ce4John Forte	for (fca_port = fctl_fca_portlist; fca_port != NULL;
718fcf3ce4John Forte	    fca_port = fca_port->port_next) {
719fcf3ce4John Forte		job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
720fcf3ce4John Forte		    NULL, NULL, KM_SLEEP);
721fcf3ce4John Forte
722fcf3ce4John Forte		fctl_enque_job(fca_port->port_handle, job);
723fcf3ce4John Forte	}
724fcf3ce4John Forte	mutex_exit(&fctl_port_lock);
725fcf3ce4John Forte
726fcf3ce4John Forte	rw_exit(&fctl_ulp_lock);
727fcf3ce4John Forte
728fcf3ce4John Forte	return (FC_SUCCESS);
729fcf3ce4John Forte}
730fcf3ce4John Forte
731fcf3ce4John Forte
732fcf3ce4John Forte/*
733fcf3ce4John Forte * fc_ulp_remove
734fcf3ce4John Forte *	Remove a ULP module
735fcf3ce4John Forte *
736fcf3ce4John Forte * A misbehaving ULP may call this routine while I/Os are in progress.
737fcf3ce4John Forte * Currently there is no mechanism to detect it to fail such a request.
738fcf3ce4John Forte *
739fcf3ce4John Forte * Return Codes:
740fcf3ce4John Forte *		FC_SUCCESS
741fcf3ce4John Forte *		FC_FAILURE
742fcf3ce4John Forte */
743fcf3ce4John Forteint
744fcf3ce4John Fortefc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
745fcf3ce4John Forte{
746fcf3ce4John Forte	fc_ulp_module_t *mod;
747fcf3ce4John Forte	fc_ulp_list_t	*list;
748fcf3ce4John Forte	fc_ulp_list_t	*last;
749fcf3ce4John Forte	fc_ulp_module_t *prev;
750fcf3ce4John Forte
751fcf3ce4John Forte	mutex_enter(&fctl_ulp_list_mutex);
752fcf3ce4John Forte
753fcf3ce4John Forte	for (last = NULL, list = fctl_ulp_list; list != NULL;
754fcf3ce4John Forte	    list = list->ulp_next) {
755fcf3ce4John Forte		if (list->ulp_info == ulp_info) {
756fcf3ce4John Forte			break;
757fcf3ce4John Forte		}
758fcf3ce4John Forte		last = list;
759fcf3ce4John Forte	}
760fcf3ce4John Forte
761fcf3ce4John Forte	if (list) {
762fcf3ce4John Forte		if (last) {
763fcf3ce4John Forte			last->ulp_next = list->ulp_next;
764fcf3ce4John Forte		} else {
765fcf3ce4John Forte			fctl_ulp_list = list->ulp_next;
766fcf3ce4John Forte		}
767fcf3ce4John Forte		kmem_free(list, sizeof (*list));
768fcf3ce4John Forte	}
769fcf3ce4John Forte
770fcf3ce4John Forte	mutex_exit(&fctl_ulp_list_mutex);
771fcf3ce4John Forte
772fcf3ce4John Forte	rw_enter(&fctl_ulp_lock, RW_WRITER);
773fcf3ce4John Forte
774fcf3ce4John Forte	for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
775fcf3ce4John Forte	    mod = mod->mod_next) {
776fcf3ce4John Forte		if (mod->mod_info == ulp_info) {
777fcf3ce4John Forte			break;
778fcf3ce4John Forte		}
779fcf3ce4John Forte		prev = mod;
780fcf3ce4John Forte	}
781fcf3ce4John Forte
782fcf3ce4John Forte	if (mod) {
783fcf3ce4John Forte		fc_ulp_ports_t *next;
784fcf3ce4John Forte
785fcf3ce4John Forte		if (prev) {
786fcf3ce4John Forte			prev->mod_next = mod->mod_next;
787fcf3ce4John Forte		} else {
788fcf3ce4John Forte			fctl_ulp_modules = mod->mod_next;
789fcf3ce4John Forte		}
790fcf3ce4John Forte
791fcf3ce4John Forte		rw_enter(&fctl_mod_ports_lock, RW_WRITER);
792fcf3ce4John Forte
793fcf3ce4John Forte		while ((next = mod->mod_ports) != NULL) {
794fcf3ce4John Forte			mod->mod_ports = next->port_next;
795fcf3ce4John Forte			fctl_dealloc_ulp_port(next);
796fcf3ce4John Forte		}
797fcf3ce4John Forte
798fcf3ce4John Forte		rw_exit(&fctl_mod_ports_lock);
799fcf3ce4John Forte		rw_exit(&fctl_ulp_lock);
800fcf3ce4John Forte
801fcf3ce4John Forte		kmem_free(mod, sizeof (*mod));
802fcf3ce4John Forte
803fcf3ce4John Forte		return (FC_SUCCESS);
804fcf3ce4John Forte	}
805fcf3ce4John Forte	rw_exit(&fctl_ulp_lock);
806fcf3ce4John Forte
807fcf3ce4John Forte	return (FC_FAILURE);
808fcf3ce4John Forte}
809fcf3ce4John Forte
810fcf3ce4John Forte
811fcf3ce4John Forte/*
812fcf3ce4John Forte * The callers typically cache allocate the packet, complete the
813fcf3ce4John Forte * DMA setup for pkt_cmd and pkt_resp fields of the packet and
814fcf3ce4John Forte * call this function to see if the FCA is interested in doing
815fcf3ce4John Forte * its own intialization. For example, socal may like to initialize
816fcf3ce4John Forte * the soc_hdr which is pointed to by the pkt_fca_private field
817fcf3ce4John Forte * and sitting right below fc_packet_t in memory.
818fcf3ce4John Forte *
819fcf3ce4John Forte * The caller is required to ensure that pkt_pd is populated with the
820fcf3ce4John Forte * handle that it was given when the transport notified it about the
821fcf3ce4John Forte * device this packet is associated with.  If there is no associated
8227ff8366Zhong Wang * device, pkt_pd must be set to NULL.	A non-NULL pkt_pd will cause an
823fcf3ce4John Forte * increment of the reference count for said pd.  When the packet is freed,
824fcf3ce4John Forte * the reference count will be decremented.  This reference count, in
825fcf3ce4John Forte * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
826fcf3ce4John Forte * will not wink out of existence while there is a packet outstanding.
827fcf3ce4John Forte *
828fcf3ce4John Forte * This function and fca_init_pkt must not perform any operations that
829fcf3ce4John Forte * would result in a call back to the ULP, as the ULP may be required
830fcf3ce4John Forte * to hold a mutex across this call to ensure that the pd in question
831fcf3ce4John Forte * won't go away prior the call to fc_ulp_transport.
832fcf3ce4John Forte *
833fcf3ce4John Forte * ULPs are responsible for using the handles they are given during state
834fcf3ce4John Forte * change callback processing in a manner that ensures consistency.  That
835fcf3ce4John Forte * is, they must be aware that they could be processing a state change
836fcf3ce4John Forte * notification that tells them the device associated with a particular
837fcf3ce4John Forte * handle has gone away at the same time they are being asked to
838fcf3ce4John Forte * initialize a packet using that handle. ULPs must therefore ensure
839fcf3ce4John Forte * that their state change processing and packet initialization code
840fcf3ce4John Forte * paths are sufficiently synchronized to avoid the use of an
841fcf3ce4John Forte * invalidated handle in any fc_packet_t struct that is passed to the
842fcf3ce4John Forte * fc_ulp_init_packet() function.
843fcf3ce4John Forte */
844fcf3ce4John Forteint
845fcf3ce4John Fortefc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
846fcf3ce4John Forte{
847fcf3ce4John Forte	int rval;
848fcf3ce4John Forte	fc_local_port_t *port = port_handle;
849fcf3ce4John Forte	fc_remote_port_t *pd;
850fcf3ce4John Forte
851fcf3ce4John Forte	ASSERT(pkt != NULL);
852fcf3ce4John Forte
853fcf3ce4John Forte	pd = pkt->pkt_pd;
854fcf3ce4John Forte
855fcf3ce4John Forte	/* Call the FCA driver's fca_init_pkt entry point function. */
856fcf3ce4John Forte	rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
857fcf3ce4John Forte
858fcf3ce4John Forte	if ((rval == FC_SUCCESS) && (pd != NULL)) {
859fcf3ce4John Forte		/*
860fcf3ce4John Forte		 * A !NULL pd here must still be a valid
861fcf3ce4John Forte		 * reference to the fc_remote_port_t.
862fcf3ce4John Forte		 */
863fcf3ce4John Forte		mutex_enter(&pd->pd_mutex);
864fcf3ce4John Forte		ASSERT(pd->pd_ref_count >= 0);
865fcf3ce4John Forte		pd->pd_ref_count++;
866fcf3ce4John Forte		mutex_exit(&pd->pd_mutex);
867fcf3ce4John Forte	}
868fcf3ce4John Forte
869fcf3ce4John Forte	return (rval);
870fcf3ce4John Forte}
871fcf3ce4John Forte
872fcf3ce4John Forte
873fcf3ce4John Forte/*
874fcf3ce4John Forte * This function is called before destroying the cache allocated
875fcf3ce4John Forte * fc_packet to free up (and uninitialize) any resource specially
876fcf3ce4John Forte * allocated by the FCA driver during tran_init_pkt().
877fcf3ce4John Forte *
878fcf3ce4John Forte * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
879fcf3ce4John Forte * the pd_ref_count reference count is decremented for the indicated
880fcf3ce4John Forte * fc_remote_port_t struct.
881fcf3ce4John Forte */
882fcf3ce4John Forteint
883fcf3ce4John Fortefc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
884fcf3ce4John Forte{
885fcf3ce4John Forte	int rval;
886fcf3ce4John Forte	fc_local_port_t *port = port_handle;
887fcf3ce4John Forte	fc_remote_port_t *pd;
888fcf3ce4John Forte
889fcf3ce4John Forte	ASSERT(pkt != NULL);
890fcf3ce4John Forte
891fcf3ce4John Forte	pd = pkt->pkt_pd;
892fcf3ce4John Forte
893fcf3ce4John Forte	/* Call the FCA driver's fca_un_init_pkt entry point function */
894fcf3ce4John Forte	rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
895fcf3ce4John Forte
896fcf3ce4John Forte	if ((rval == FC_SUCCESS) && (pd != NULL)) {
897fcf3ce4John Forte		mutex_enter(&pd->pd_mutex);
898fcf3ce4John Forte
899fcf3ce4John Forte		ASSERT(pd->pd_ref_count > 0);
900fcf3ce4John Forte		pd->pd_ref_count--;
901fcf3ce4John Forte
902fcf3ce4John Forte		/*
903fcf3ce4John Forte		 * If at this point the state of this fc_remote_port_t
904fcf3ce4John Forte		 * struct is PORT_DEVICE_INVALID, it probably means somebody
905fcf3ce4John Forte		 * is cleaning up old (e.g. retried) packets. If the
906fcf3ce4John Forte		 * pd_ref_count has also dropped to zero, it's time to
907fcf3ce4John Forte		 * deallocate this fc_remote_port_t struct.
908fcf3ce4John Forte		 */
909fcf3ce4John Forte		if (pd->pd_state == PORT_DEVICE_INVALID &&
910fcf3ce4John Forte		    pd->pd_ref_count == 0) {
911fcf3ce4John Forte			fc_remote_node_t *node = pd->pd_remote_nodep;
912fcf3ce4John Forte
913fcf3ce4John Forte			mutex_exit(&pd->pd_mutex);
914fcf3ce4John Forte
915fcf3ce4John Forte			/*
916fcf3ce4John Forte			 * Also deallocate the associated fc_remote_node_t
917fcf3ce4John Forte			 * struct if it has no other associated
918fcf3ce4John Forte			 * fc_remote_port_t structs.
919fcf3ce4John Forte			 */
920fcf3ce4John Forte			if ((fctl_destroy_remote_port(port, pd) == 0) &&
921fcf3ce4John Forte			    (node != NULL)) {
922fcf3ce4John Forte				fctl_destroy_remote_node(node);
923fcf3ce4John Forte			}
924fcf3ce4John Forte			return (rval);
925fcf3ce4John Forte		}
926fcf3ce4John Forte
927fcf3ce4John Forte		mutex_exit(&pd->pd_mutex);
928fcf3ce4John Forte	}
929fcf3ce4John Forte
930fcf3ce4John Forte	return (rval);
931fcf3ce4John Forte}
932fcf3ce4John Forte
933fcf3ce4John Forte
934fcf3ce4John Forteint
935fcf3ce4John Fortefc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
936fcf3ce4John Forte    int flag)
937fcf3ce4John Forte{
938fcf3ce4John Forte	int		job_code;
939fcf3ce4John Forte	fc_local_port_t *port;
940fcf3ce4John Forte	job_request_t	*job;
941fcf3ce4John Forte	fc_portmap_t	*tmp_map;
942fcf3ce4John Forte	uint32_t	tmp_len;
943fcf3ce4John Forte	fc_portmap_t	*change_list = NULL;
944fcf3ce4John Forte	uint32_t	listlen = 0;
945fcf3ce4John Forte
946fcf3ce4John Forte	port = port_handle;
947fcf3ce4John Forte
948fcf3ce4John Forte	mutex_enter(&port->fp_mutex);
949fcf3ce4John Forte	if (port->fp_statec_busy) {
950fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
951fcf3ce4John Forte		return (FC_STATEC_BUSY);
952fcf3ce4John Forte	}
953fcf3ce4John Forte
954fcf3ce4John Forte	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
955fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
956fcf3ce4John Forte		return (FC_OFFLINE);
957fcf3ce4John Forte	}
958fcf3ce4John Forte
959fcf3ce4John Forte	if (port->fp_dev_count && (port->fp_dev_count ==
960fcf3ce4John Forte	    port->fp_total_devices)) {
961fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
962fcf3ce4John Forte		fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
963fcf3ce4John Forte		if (listlen > *len) {
964fcf3ce4John Forte			tmp_map = (fc_portmap_t *)kmem_zalloc(
965fcf3ce4John Forte			    listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
966fcf3ce4John Forte			if (tmp_map == NULL) {
967fcf3ce4John Forte				return (FC_NOMEM);
968fcf3ce4John Forte			}
969fcf3ce4John Forte			if (*map) {
970fcf3ce4John Forte				kmem_free(*map, (*len) * sizeof (fc_portmap_t));
971fcf3ce4John Forte			}
972fcf3ce4John Forte			*map = tmp_map;
973fcf3ce4John Forte		}
974fcf3ce4John Forte		if (change_list) {
975fcf3ce4John Forte			bcopy(change_list, *map,
976fcf3ce4John Forte			    listlen * sizeof (fc_portmap_t));
977fcf3ce4John Forte			kmem_free(change_list, listlen * sizeof (fc_portmap_t));
978fcf3ce4John Forte		}
979fcf3ce4John Forte		*len = listlen;
980fcf3ce4John Forte	} else {
981fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
982fcf3ce4John Forte
983fcf3ce4John Forte		switch (flag) {
984fcf3ce4John Forte		case FC_ULP_PLOGI_DONTCARE:
985fcf3ce4John Forte			job_code = JOB_PORT_GETMAP;
986fcf3ce4John Forte			break;
987fcf3ce4John Forte
988fcf3ce4John Forte		case FC_ULP_PLOGI_PRESERVE:
989fcf3ce4John Forte			job_code = JOB_PORT_GETMAP_PLOGI_ALL;
990fcf3ce4John Forte			break;
991fcf3ce4John Forte
992fcf3ce4John Forte		default:
993fcf3ce4John Forte			return (FC_INVALID_REQUEST);
994fcf3ce4John Forte		}
995fcf3ce4John Forte		/*
996fcf3ce4John Forte		 * Submit a job request to the job handler
997fcf3ce4John Forte		 * thread to get the map and wait
998fcf3ce4John Forte		 */
999fcf3ce4John Forte		job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
1000fcf3ce4John Forte		job->job_private = (opaque_t)map;
1001fcf3ce4John Forte		job->job_arg = (opaque_t)len;
1002fcf3ce4John Forte		fctl_enque_job(port, job);
1003fcf3ce4John Forte
1004fcf3ce4John Forte		fctl_jobwait(job);
1005fcf3ce4John Forte		/*
1006fcf3ce4John Forte		 * The result of the last I/O operation is
1007fcf3ce4John Forte		 * in job_code. We don't care to look at it
1008fcf3ce4John Forte		 * Rather we look at the number of devices
1009fcf3ce4John Forte		 * that are found to fill out the map for
1010fcf3ce4John Forte		 * ULPs.
1011fcf3ce4John Forte		 */
1012fcf3ce4John Forte		fctl_dealloc_job(job);
1013fcf3ce4John Forte	}
1014fcf3ce4John Forte
1015fcf3ce4John Forte	/*
1016fcf3ce4John Forte	 * If we're here, we're returning a map to the caller, which means
1017fcf3ce4John Forte	 * we'd better make sure every pd in that map has the
1018fcf3ce4John Forte	 * PD_GIVEN_TO_ULPS flag set.
1019fcf3ce4John Forte	 */
1020fcf3ce4John Forte
1021fcf3ce4John Forte	tmp_len = *len;
1022fcf3ce4John Forte	tmp_map = *map;
1023fcf3ce4John Forte
1024fcf3ce4John Forte	while (tmp_len-- != 0) {
1025fcf3ce4John Forte		if (tmp_map->map_state != PORT_DEVICE_INVALID) {
1026fcf3ce4John Forte			fc_remote_port_t *pd =
1027fcf3ce4John Forte			    (fc_remote_port_t *)tmp_map->map_pd;
1028fcf3ce4John Forte			mutex_enter(&pd->pd_mutex);
1029fcf3ce4John Forte			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1030fcf3ce4John Forte			mutex_exit(&pd->pd_mutex);
1031fcf3ce4John Forte		}
1032fcf3ce4John Forte		tmp_map++;
1033fcf3ce4John Forte	}
1034fcf3ce4John Forte
1035fcf3ce4John Forte	return (FC_SUCCESS);
1036fcf3ce4John Forte}
1037fcf3ce4John Forte
1038fcf3ce4John Forte
1039fcf3ce4John Forteint
1040fcf3ce4John Fortefc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
1041fcf3ce4John Forte{
1042fcf3ce4John Forte	int			rval = FC_SUCCESS;
10437ff8366Zhong Wang	int			job_flags;
1044fcf3ce4John Forte	uint32_t		count;
1045fcf3ce4John Forte	fc_packet_t		**tmp_array;
10467ff8366Zhong Wang	job_request_t		*job;
10477ff8366Zhong Wang	fc_local_port_t		*port = port_handle;
1048fcf3ce4John Forte	fc_ulp_rscn_info_t	*rscnp =
1049fcf3ce4John Forte	    (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
1050fcf3ce4John Forte
1051fcf3ce4John Forte	/*
1052fcf3ce4John Forte	 * If the port is OFFLINE, or if the port driver is
1053fcf3ce4John Forte	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1054fcf3ce4John Forte	 * PLOGI operations
1055fcf3ce4John Forte	 */
1056fcf3ce4John Forte	mutex_enter(&port->fp_mutex);
1057fcf3ce4John Forte	if (port->fp_statec_busy) {
1058fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1059fcf3ce4John Forte		return (FC_STATEC_BUSY);
1060fcf3ce4John Forte	}
1061fcf3ce4John Forte
1062fcf3ce4John Forte	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1063fcf3ce4John Forte	    (port->fp_soft_state &
1064fcf3ce4John Forte	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1065fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1066fcf3ce4John Forte		return (FC_OFFLINE);
1067fcf3ce4John Forte	}
1068fcf3ce4John Forte
1069fcf3ce4John Forte	/*
1070fcf3ce4John Forte	 * If the rscn count in the packet is not the same as the rscn count
1071fcf3ce4John Forte	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1072fcf3ce4John Forte	 */
1073fcf3ce4John Forte	if ((rscnp != NULL) &&
1074fcf3ce4John Forte	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1075fcf3ce4John Forte	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1076fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1077fcf3ce4John Forte		return (FC_DEVICE_BUSY_NEW_RSCN);
1078fcf3ce4John Forte	}
1079fcf3ce4John Forte
1080fcf3ce4John Forte	mutex_exit(&port->fp_mutex);
1081fcf3ce4John Forte
1082fcf3ce4John Forte	tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
1083fcf3ce4John Forte	for (count = 0; count < listlen; count++) {
1084fcf3ce4John Forte		tmp_array[count] = ulp_pkt[count];
1085fcf3ce4John Forte	}
1086fcf3ce4John Forte
1087fcf3ce4John Forte	job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
1088fcf3ce4John Forte	    ? 0 : JOB_TYPE_FCTL_ASYNC;
1089fcf3ce4John Forte
1090fcf3ce4John Forte#ifdef	DEBUG
1091fcf3ce4John Forte	{
1092fcf3ce4John Forte		int next;
1093fcf3ce4John Forte		int count;
1094fcf3ce4John Forte		int polled;
1095fcf3ce4John Forte
1096fcf3ce4John Forte		polled = ((ulp_pkt[0]->pkt_tran_flags) &
1097fcf3ce4John Forte		    FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1098fcf3ce4John Forte
1099fcf3ce4John Forte		for (count = 0; count < listlen; count++) {
1100fcf3ce4John Forte			next = ((ulp_pkt[count]->pkt_tran_flags)
1101fcf3ce4John Forte			    & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1102fcf3ce4John Forte			ASSERT(next == polled);
1103fcf3ce4John Forte		}
1104fcf3ce4John Forte	}
1105fcf3ce4John Forte#endif
1106fcf3ce4John Forte
1107fcf3ce4John Forte	job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
1108fcf3ce4John Forte	job->job_ulp_pkts = tmp_array;
1109fcf3ce4John Forte	job->job_ulp_listlen = listlen;
1110fcf3ce4John Forte
1111fcf3ce4John Forte	while (listlen--) {
1112fcf3ce4John Forte		fc_packet_t *pkt;
1113fcf3ce4John Forte
1114fcf3ce4John Forte		pkt = tmp_array[listlen];
1115fcf3ce4John Forte		if (pkt->pkt_pd == NULL) {
1116fcf3ce4John Forte			pkt->pkt_state = FC_PKT_SUCCESS;
1117fcf3ce4John Forte			continue;
1118fcf3ce4John Forte		}
1119fcf3ce4John Forte
1120fcf3ce4John Forte		mutex_enter(&pkt->pkt_pd->pd_mutex);
1121fcf3ce4John Forte		if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
1122fcf3ce4John Forte		    pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
1123fcf3ce4John Forte			/*
1124fcf3ce4John Forte			 * Set the packet state and let the port
1125fcf3ce4John Forte			 * driver call the completion routine
1126fcf3ce4John Forte			 * from its thread
1127fcf3ce4John Forte			 */
1128fcf3ce4John Forte			mutex_exit(&pkt->pkt_pd->pd_mutex);
1129fcf3ce4John Forte			pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
1130fcf3ce4John Forte			continue;
1131fcf3ce4John Forte		}
1132fcf3ce4John Forte
1133fcf3ce4John Forte		if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
1134fcf3ce4John Forte		    pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
1135fcf3ce4John Forte			mutex_exit(&pkt->pkt_pd->pd_mutex);
1136fcf3ce4John Forte			pkt->pkt_state = FC_PKT_LOCAL_RJT;
1137fcf3ce4John Forte			continue;
1138fcf3ce4John Forte		}
1139fcf3ce4John Forte		mutex_exit(&pkt->pkt_pd->pd_mutex);
1140fcf3ce4John Forte		pkt->pkt_state = FC_PKT_SUCCESS;
1141fcf3ce4John Forte	}
1142fcf3ce4John Forte
1143fcf3ce4John Forte	fctl_enque_job(port, job);
1144fcf3ce4John Forte
1145fcf3ce4John Forte	if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
1146fcf3ce4John Forte		fctl_jobwait(job);
1147fcf3ce4John Forte		rval = job->job_result;
1148fcf3ce4John Forte		fctl_dealloc_job(job);
1149fcf3ce4John Forte	}
1150fcf3ce4John Forte
1151fcf3ce4John Forte	return (rval);
1152fcf3ce4John Forte}
1153fcf3ce4John Forte
1154fcf3ce4John Forte
1155fcf3ce4John Forteopaque_t
1156fcf3ce4John Fortefc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
1157fcf3ce4John Forte    int create)
1158fcf3ce4John Forte{
11597ff8366Zhong Wang	fc_local_port_t		*port;
1160fcf3ce4John Forte	job_request_t		*job;
11617ff8366Zhong Wang	fc_remote_port_t	*pd;
1162fcf3ce4John Forte
1163fcf3ce4John Forte	port = port_handle;
1164fcf3ce4John Forte	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1165fcf3ce4John Forte
1166fcf3ce4John Forte	if (pd != NULL) {
1167fcf3ce4John Forte		*error = FC_SUCCESS;
1168fcf3ce4John Forte		/*
1169fcf3ce4John Forte		 * A ULP now knows about this pd, so mark it
1170fcf3ce4John Forte		 */
1171fcf3ce4John Forte		mutex_enter(&pd->pd_mutex);
1172fcf3ce4John Forte		pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1173fcf3ce4John Forte		mutex_exit(&pd->pd_mutex);
1174fcf3ce4John Forte		return (pd);
1175fcf3ce4John Forte	}
1176fcf3ce4John Forte
1177fcf3ce4John Forte	mutex_enter(&port->fp_mutex);
1178fcf3ce4John Forte	if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
1179fcf3ce4John Forte		uint32_t	d_id;
11807ff8366Zhong Wang		fctl_ns_req_t	*ns_cmd;
1181fcf3ce4John Forte
1182fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1183fcf3ce4John Forte
1184fcf3ce4John Forte		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1185fcf3ce4John Forte
1186fcf3ce4John Forte		if (job == NULL) {
1187fcf3ce4John Forte			*error = FC_NOMEM;
1188fcf3ce4John Forte			return (pd);
1189fcf3ce4John Forte		}
1190fcf3ce4John Forte
1191fcf3ce4John Forte		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
1192fcf3ce4John Forte		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
1193fcf3ce4John Forte		    0, KM_SLEEP);
1194fcf3ce4John Forte
1195fcf3ce4John Forte		if (ns_cmd == NULL) {
1196fcf3ce4John Forte			fctl_dealloc_job(job);
1197fcf3ce4John Forte			*error = FC_NOMEM;
1198fcf3ce4John Forte			return (pd);
1199fcf3ce4John Forte		}
1200fcf3ce4John Forte		ns_cmd->ns_cmd_code = NS_GID_PN;
1201fcf3ce4John Forte		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
1202fcf3ce4John Forte
1203fcf3ce4John Forte		job->job_result = FC_SUCCESS;
1204fcf3ce4John Forte		job->job_private = (void *)ns_cmd;
1205fcf3ce4John Forte		job->job_counter = 1;
1206fcf3ce4John Forte		fctl_enque_job(port, job);
1207fcf3ce4John Forte		fctl_jobwait(job);
1208fcf3ce4John Forte
1209fcf3ce4John Forte		if (job->job_result != FC_SUCCESS) {
1210fcf3ce4John Forte			*error = job->job_result;
1211fcf3ce4John Forte			fctl_free_ns_cmd(ns_cmd);
1212fcf3ce4John Forte			fctl_dealloc_job(job);
1213fcf3ce4John Forte			return (pd);
1214fcf3ce4John Forte		}
1215fcf3ce4John Forte		d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
1216fcf3ce4John Forte		fctl_free_ns_cmd(ns_cmd);
1217fcf3ce4John Forte
1218fcf3ce4John Forte		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
1219fcf3ce4John Forte		    sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
1220fcf3ce4John Forte		    KM_SLEEP);
1221fcf3ce4John Forte		ASSERT(ns_cmd != NULL);
1222fcf3ce4John Forte
1223fcf3ce4John Forte		ns_cmd->ns_gan_max = 1;
1224fcf3ce4John Forte		ns_cmd->ns_cmd_code = NS_GA_NXT;
1225fcf3ce4John Forte		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
1226fcf3ce4John Forte		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
1227fcf3ce4John Forte		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
1228fcf3ce4John Forte
1229fcf3ce4John Forte		job->job_result = FC_SUCCESS;
1230fcf3ce4John Forte		job->job_private = (void *)ns_cmd;
1231fcf3ce4John Forte		job->job_counter = 1;
1232fcf3ce4John Forte		fctl_enque_job(port, job);
1233fcf3ce4John Forte		fctl_jobwait(job);
1234fcf3ce4John Forte
1235fcf3ce4John Forte		fctl_free_ns_cmd(ns_cmd);
1236fcf3ce4John Forte		if (job->job_result != FC_SUCCESS) {
1237fcf3ce4John Forte			*error = job->job_result;
1238fcf3ce4John Forte			fctl_dealloc_job(job);
1239fcf3ce4John Forte			return (pd);
1240fcf3ce4John Forte		}
1241fcf3ce4John Forte		fctl_dealloc_job(job);
1242fcf3ce4John Forte
1243fcf3ce4John Forte		/*
1244fcf3ce4John Forte		 * Check if the port device is created now.
1245fcf3ce4John Forte		 */
1246fcf3ce4John Forte		pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1247fcf3ce4John Forte
1248fcf3ce4John Forte		if (pd == NULL) {
1249fcf3ce4John Forte			*error = FC_FAILURE;
1250fcf3ce4John Forte		} else {
1251fcf3ce4John Forte			*error = FC_SUCCESS;
1252fcf3ce4John Forte
1253fcf3ce4John Forte			/*
1254fcf3ce4John Forte			 * A ULP now knows about this pd, so mark it
1255fcf3ce4John Forte			 */
1256fcf3ce4John Forte			mutex_enter(&pd->pd_mutex);
1257fcf3ce4John Forte			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1258fcf3ce4John Forte			mutex_exit(&pd->pd_mutex);
1259fcf3ce4John Forte		}
1260fcf3ce4John Forte	} else {
1261fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1262fcf3ce4John Forte		*error = FC_FAILURE;
1263fcf3ce4John Forte	}
1264fcf3ce4John Forte
1265fcf3ce4John Forte	return (pd);
1266fcf3ce4John Forte}
1267fcf3ce4John Forte
1268fcf3ce4John Forte
1269fcf3ce4John Forte/*
1270fcf3ce4John Forte * If a NS object exists in the host and query is performed
1271fcf3ce4John Forte * on that object, we should retrieve it from our basket
1272fcf3ce4John Forte * and return it right here, there by saving a request going
1273fcf3ce4John Forte * all the up to the Name Server.
1274fcf3ce4John Forte */
1275fcf3ce4John Forteint
1276fcf3ce4John Fortefc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
1277fcf3ce4John Forte{
12787ff8366Zhong Wang	int		rval;
1279fcf3ce4John Forte	int		fabric;
1280fcf3ce4John Forte	job_request_t	*job;
1281fcf3ce4John Forte	fctl_ns_req_t	*ns_cmd;
1282fcf3ce4John Forte	fc_local_port_t	*port = port_handle;
1283fcf3ce4John Forte
1284fcf3ce4John Forte	mutex_enter(&port->fp_mutex);
1285fcf3ce4John Forte	fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
1286fcf3ce4John Forte	mutex_exit(&port->fp_mutex);
1287fcf3ce4John Forte
1288fcf3ce4John Forte	/*
1289fcf3ce4John Forte	 * Name server query can't be performed for devices not in Fabric
1290fcf3ce4John Forte	 */
1291fcf3ce4John Forte	if (!fabric && pd) {
1292fcf3ce4John Forte		return (FC_BADOBJECT);
1293fcf3ce4John Forte	}
1294fcf3ce4John Forte
1295fcf3ce4John Forte	if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
1296fcf3ce4John Forte		if (pd == NULL) {
1297fcf3ce4John Forte			rval = fctl_update_host_ns_values(port, ns_req);
1298fcf3ce4John Forte			if (rval != FC_SUCCESS) {
1299fcf3ce4John Forte				return (rval);
1300fcf3ce4John Forte			}
1301fcf3ce4John Forte		} else {
1302fcf3ce4John Forte			/*
1303fcf3ce4John Forte			 * Guess what, FC-GS-2 currently prohibits (not
1304fcf3ce4John Forte			 * in the strongest language though) setting of
1305fcf3ce4John Forte			 * NS object values by other ports. But we might
1306fcf3ce4John Forte			 * get that changed to at least accommodate setting
1307fcf3ce4John Forte			 * symbolic node/port names - But if disks/tapes
1308fcf3ce4John Forte			 * were going to provide a method to set these
1309fcf3ce4John Forte			 * values directly (which in turn might register
1310fcf3ce4John Forte			 * with the NS when they come up; yep, for that
1311fcf3ce4John Forte			 * to happen the disks will have to be very well
1312fcf3ce4John Forte			 * behaved Fabric citizen) we won't need to
1313fcf3ce4John Forte			 * register the symbolic port/node names for
1314fcf3ce4John Forte			 * other ports too (rather send down SCSI commands
1315fcf3ce4John Forte			 * to the devices to set the names)
1316fcf3ce4John Forte			 *
1317fcf3ce4John Forte			 * Be that as it may, let's continue to fail
1318fcf3ce4John Forte			 * registration requests for other ports. period.
1319fcf3ce4John Forte			 */
1320fcf3ce4John Forte			return (FC_BADOBJECT);
1321fcf3ce4John Forte		}
1322fcf3ce4John Forte
1323fcf3ce4John Forte		if (!fabric) {
1324fcf3ce4John Forte			return (FC_SUCCESS);
1325fcf3ce4John Forte		}
1326fcf3ce4John Forte	} else if (!fabric) {
1327fcf3ce4John Forte		return (fctl_retrieve_host_ns_values(port, ns_req));
1328fcf3ce4John Forte	}
1329fcf3ce4John Forte
1330fcf3ce4John Forte	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1331fcf3ce4John Forte	ASSERT(job != NULL);
1332fcf3ce4John Forte
1333fcf3ce4John Forte	ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
1334fcf3ce4John Forte	    ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
1335fcf3ce4John Forte	ASSERT(ns_cmd != NULL);
1336fcf3ce4John Forte	ns_cmd->ns_cmd_code = ns_req->ns_cmd;
1337fcf3ce4John Forte	bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
1338fcf3ce4John Forte	    ns_req->ns_req_len);
1339fcf3ce4John Forte
1340fcf3ce4John Forte	job->job_private = (void *)ns_cmd;
1341fcf3ce4John Forte	fctl_enque_job(port, job);
1342fcf3ce4John Forte	fctl_jobwait(job);
1343fcf3ce4John Forte	rval = job->job_result;
1344fcf3ce4John Forte
1345fcf3ce4John Forte	if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
1346fcf3ce4John Forte		bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
1347fcf3ce4John Forte		    ns_cmd->ns_data_len);
1348fcf3ce4John Forte	}
1349fcf3ce4John Forte	bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
1350fcf3ce4John Forte	    sizeof (fc_ct_header_t));
1351fcf3ce4John Forte
1352fcf3ce4John Forte	fctl_free_ns_cmd(ns_cmd);
1353fcf3ce4John Forte	fctl_dealloc_job(job);
1354fcf3ce4John Forte
1355fcf3ce4John Forte	return (rval);
1356fcf3ce4John Forte}
1357fcf3ce4John Forte
1358fcf3ce4John Forte
1359fcf3ce4John Forteint
1360fcf3ce4John Fortefc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
1361fcf3ce4John Forte{
1362fcf3ce4John Forte	int			rval;
13637ff8366Zhong Wang	fc_local_port_t		*port;
1364fcf3ce4John Forte	fc_remote_port_t	*pd, *newpd;
1365fcf3ce4John Forte	fc_ulp_rscn_info_t	*rscnp =
1366fcf3ce4John Forte	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1367fcf3ce4John Forte
1368fcf3ce4John Forte	port = port_handle;
1369fcf3ce4John Forte
1370fcf3ce4John Forte	if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
1371fcf3ce4John Forte		return (port->fp_fca_tran->fca_transport(
1372fcf3ce4John Forte		    port->fp_fca_handle, pkt));
1373fcf3ce4John Forte	}
1374fcf3ce4John Forte
1375fcf3ce4John Forte	mutex_enter(&port->fp_mutex);
1376fcf3ce4John Forte	if (port->fp_statec_busy) {
1377fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1378fcf3ce4John Forte		return (FC_STATEC_BUSY);
1379fcf3ce4John Forte	}
1380fcf3ce4John Forte
1381fcf3ce4John Forte	/* A locus of race conditions */
1382fcf3ce4John Forte	if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
1383fcf3ce4John Forte	    (port->fp_soft_state &
1384fcf3ce4John Forte	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1385fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1386fcf3ce4John Forte		return (FC_OFFLINE);
1387fcf3ce4John Forte	}
1388fcf3ce4John Forte
1389fcf3ce4John Forte	/*
1390fcf3ce4John Forte	 * If the rscn count in the packet is not the same as the rscn count
1391fcf3ce4John Forte	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1392fcf3ce4John Forte	 */
1393fcf3ce4John Forte	if ((rscnp != NULL) &&
1394fcf3ce4John Forte	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1395fcf3ce4John Forte	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1396fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1397fcf3ce4John Forte		return (FC_DEVICE_BUSY_NEW_RSCN);
1398fcf3ce4John Forte	}
1399fcf3ce4John Forte
1400fcf3ce4John Forte	pd = pkt->pkt_pd;
1401fcf3ce4John Forte	if (pd) {
1402fcf3ce4John Forte		if (pd->pd_type == PORT_DEVICE_OLD ||
1403fcf3ce4John Forte		    pd->pd_state == PORT_DEVICE_INVALID) {
1404fcf3ce4John Forte
1405fcf3ce4John Forte			newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
1406fcf3ce4John Forte			    &pd->pd_port_name);
1407fcf3ce4John Forte
1408fcf3ce4John Forte			/*
1409fcf3ce4John Forte			 * The remote port (pd) in the packet is no longer
1410fcf3ce4John Forte			 * usable, as the old pd still exists we can use the
1411fcf3ce4John Forte			 * WWN to check if we have a current pd for the device
1412fcf3ce4John Forte			 * we want. Either way we continue with the old logic
1413fcf3ce4John Forte			 * whether we have a new pd or not, as the new pd
1414fcf3ce4John Forte			 * could be bad, or have become unusable.
1415fcf3ce4John Forte			 */
1416fcf3ce4John Forte			if ((newpd) && (newpd != pd)) {
1417fcf3ce4John Forte
1418fcf3ce4John Forte				/*
1419fcf3ce4John Forte				 * There is a better remote port (pd) to try,
1420fcf3ce4John Forte				 * so we need to fix the reference counts, etc.
1421fcf3ce4John Forte				 */
1422fcf3ce4John Forte				mutex_enter(&newpd->pd_mutex);
1423fcf3ce4John Forte				newpd->pd_ref_count++;
1424fcf3ce4John Forte				pkt->pkt_pd = newpd;
1425fcf3ce4John Forte				mutex_exit(&newpd->pd_mutex);
1426fcf3ce4John Forte
1427fcf3ce4John Forte				mutex_enter(&pd->pd_mutex);
1428fcf3ce4John Forte				pd->pd_ref_count--;
1429fcf3ce4John Forte				if ((pd->pd_state == PORT_DEVICE_INVALID) &&
1430fcf3ce4John Forte				    (pd->pd_ref_count == 0)) {
1431fcf3ce4John Forte					fc_remote_node_t *node =
1432fcf3ce4John Forte					    pd->pd_remote_nodep;
1433fcf3ce4John Forte
1434fcf3ce4John Forte					mutex_exit(&pd->pd_mutex);
1435fcf3ce4John Forte					mutex_exit(&port->fp_mutex);
1436fcf3ce4John Forte
1437fcf3ce4John Forte					/*
1438fcf3ce4John Forte					 * This will create another PD hole
1439fcf3ce4John Forte					 * where we have a reference to a pd,
1440fcf3ce4John Forte					 * but someone else could remove it.
1441fcf3ce4John Forte					 */
1442fcf3ce4John Forte					if ((fctl_destroy_remote_port(port, pd)
1443fcf3ce4John Forte					    == 0) && (node != NULL)) {
1444fcf3ce4John Forte						fctl_destroy_remote_node(node);
1445fcf3ce4John Forte					}
1446fcf3ce4John Forte					mutex_enter(&port->fp_mutex);
1447fcf3ce4John Forte				} else {
1448fcf3ce4John Forte					mutex_exit(&pd->pd_mutex);
1449fcf3ce4John Forte				}
1450fcf3ce4John Forte				pd = newpd;
1451fcf3ce4John Forte			}
1452fcf3ce4John Forte		}
1453fcf3ce4John Forte
1454fcf3ce4John Forte		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1455fcf3ce4John Forte			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1456fcf3ce4John Forte			    FC_LOGINREQ : FC_BADDEV;
1457fcf3ce4John Forte			mutex_exit(&port->fp_mutex);
1458fcf3ce4John Forte			return (rval);
1459fcf3ce4John Forte		}
1460fcf3ce4John Forte
1461fcf3ce4John Forte		if (pd->pd_flags != PD_IDLE) {
1462fcf3ce4John Forte			mutex_exit(&port->fp_mutex);
1463fcf3ce4John Forte			return (FC_DEVICE_BUSY);
1464fcf3ce4John Forte		}
1465fcf3ce4John Forte
1466fcf3ce4John Forte		if (pd->pd_type == PORT_DEVICE_OLD ||
1467fcf3ce4John Forte		    pd->pd_state == PORT_DEVICE_INVALID) {
1468fcf3ce4John Forte			mutex_exit(&port->fp_mutex);
1469fcf3ce4John Forte			return (FC_BADDEV);
1470fcf3ce4John Forte		}
1471fcf3ce4John Forte
1472fcf3ce4John Forte	} else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
1473fcf3ce4John Forte		mutex_exit(&port->fp_mutex);
1474fcf3ce4John Forte		return (FC_BADPACKET);
1475fcf3ce4John Forte	}
1476fcf3ce4John Forte	mutex_exit(&port->fp_mutex);
1477fcf3ce4John Forte
1478fcf3ce4John Forte	return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
1479fcf3ce4John Forte}
1480fcf3ce4John Forte
1481fcf3ce4John Forte
1482fcf3ce4John Forteint
1483fcf3ce4John Fortefc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
1484fcf3ce4John Forte{
1485fcf3ce4John Forte	int			rval;
14867ff8366Zhong Wang	fc_local_port_t		*port = port_handle;
1487fcf3ce4John Forte	fc_remote_port_t	*pd;
1488fcf3ce4John Forte	fc_ulp_rscn_info_t	*rscnp =