1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Fibre channel Transport Library (fctl)
26  *
27  * Function naming conventions:
28  *		Functions called from ULPs begin with fc_ulp_
29  *		Functions called from FCAs begin with fc_fca_
30  *		Internal functions begin with fctl_
31  *
32  * Fibre channel packet layout:
33  *	  +---------------------+<--------+
34  *	  |			|	  |
35  *	  | ULP Packet private	|	  |
36  *	  |			|	  |
37  *	  +---------------------+	  |
38  *	  |			|---------+
39  *	  |  struct  fc_packet	|---------+
40  *	  |			|	  |
41  *	  +---------------------+<--------+
42  *	  |			|
43  *	  | FCA Packet private	|
44  *	  |			|
45  *	  +---------------------+
46  *
47  * So you  loved  the  ascii  art ?  It's  strongly  desirable	to  cache
48  * allocate the entire packet in one common  place.  So we define a set a
49  * of rules.  In a  contiguous	block of memory,  the top  portion of the
50  * block points to ulp packet  private	area, next follows the	fc_packet
51  * structure used  extensively by all the consumers and what follows this
52  * is the FCA packet private.  Note that given a packet	 structure, it is
53  * possible  to get to the  ULP	 and  FCA  Packet  private  fields  using
54  * ulp_private and fca_private fields (which hold pointers) respectively.
55  *
56  * It should be noted with a grain of salt that ULP Packet  private  size
57  * varies  between two different  ULP types, So this poses a challenge to
58  * compute the correct	size of the whole block on a per port basis.  The
59  * transport  layer  doesn't have a problem in dealing with  FCA   packet
60  * private  sizes as it is the sole  manager of ports  underneath.  Since
61  * it's not a good idea to cache allocate  different  sizes of memory for
62  * different ULPs and have the ability to choose from one of these caches
63  * based on ULP type during every packet  allocation,  the transport some
64  * what	 wisely (?)  hands off this job of cache  allocation  to the ULPs
65  * themselves.
66  *
67  * That means FCAs need to make their  packet  private size  known to the
68  * transport   to  pass	 it  up	 to  the   ULPs.  This	is  done   during
69  * fc_fca_attach().  And the transport passes this size up to ULPs during
70  * fc_ulp_port_attach() of each ULP.
71  *
72  * This	 leaves	 us with  another  possible  question;	How  are  packets
73  * allocated for ELS's started by the transport	 itself ?  Well, the port
74  * driver  during  attach  time, cache	allocates  on a per port basis to
75  * handle ELSs too.
76  */
77 
78 #include <sys/note.h>
79 #include <sys/types.h>
80 #include <sys/varargs.h>
81 #include <sys/param.h>
82 #include <sys/errno.h>
83 #include <sys/uio.h>
84 #include <sys/buf.h>
85 #include <sys/modctl.h>
86 #include <sys/open.h>
87 #include <sys/kmem.h>
88 #include <sys/poll.h>
89 #include <sys/conf.h>
90 #include <sys/cmn_err.h>
91 #include <sys/stat.h>
92 #include <sys/ddi.h>
93 #include <sys/sunddi.h>
94 #include <sys/promif.h>
95 #include <sys/byteorder.h>
96 #include <sys/fibre-channel/fc.h>
97 #include <sys/fibre-channel/impl/fc_ulpif.h>
98 #include <sys/fibre-channel/impl/fc_fcaif.h>
99 #include <sys/fibre-channel/impl/fctl_private.h>
100 #include <sys/fibre-channel/impl/fc_portif.h>
101 
102 /* These are referenced by fp.c!  */
103 int did_table_size = D_ID_HASH_TABLE_SIZE;
104 int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
105 
106 static fc_ulp_module_t	*fctl_ulp_modules;
107 static fc_fca_port_t	*fctl_fca_portlist;
108 static fc_ulp_list_t	*fctl_ulp_list;
109 
110 static char fctl_greeting[] =
111 	"fctl: %s ULP same type (0x%x) as existing module.\n";
112 
113 static char *fctl_undefined = "Undefined";
114 
115 /*
116  * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
117  */
118 
119 static krwlock_t fctl_ulp_lock;
120 
121 /*
122  * The fctl_mod_ports_lock protects the mod_ports element in the
123  * fc_ulp_ports_t structure
124  */
125 
126 static krwlock_t fctl_mod_ports_lock;
127 
128 /*
129  * fctl_port_lock protects the linked list of local port structures
130  * (fctl_fca_portlist).	 When walking the list, this lock must be obtained
131  * prior to any local port locks.
132  */
133 
134 static kmutex_t fctl_port_lock;
135 static kmutex_t	fctl_ulp_list_mutex;
136 
137 static fctl_nwwn_list_t		*fctl_nwwn_hash_table;
138 static kmutex_t			fctl_nwwn_hash_mutex;
139 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
140 
141 #if	!defined(lint)
142 _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
143 _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
144 _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
145 _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
146     ulp_ports::port_handle))
147 _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
148 _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
149     ulp_ports::port_dstate))
150 #endif /* lint */
151 
152 #define	FCTL_VERSION		"20090729-1.70"
153 #define	FCTL_NAME_VERSION	"SunFC Transport v" FCTL_VERSION
154 
155 char *fctl_version = FCTL_NAME_VERSION;
156 
157 extern struct mod_ops mod_miscops;
158 
159 static struct modlmisc modlmisc = {
160 	&mod_miscops,			/* type of module */
161 	FCTL_NAME_VERSION		/* Module name */
162 };
163 
164 static struct modlinkage modlinkage = {
165 	MODREV_1, (void *)&modlmisc, NULL
166 };
167 
168 static struct bus_ops fctl_fca_busops = {
169 	BUSO_REV,
170 	nullbusmap,			/* bus_map */
171 	NULL,				/* bus_get_intrspec */
172 	NULL,				/* bus_add_intrspec */
173 	NULL,				/* bus_remove_intrspec */
174 	i_ddi_map_fault,		/* bus_map_fault */
175 	ddi_dma_map,			/* bus_dma_map */
176 	ddi_dma_allochdl,		/* bus_dma_allochdl */
177 	ddi_dma_freehdl,		/* bus_dma_freehdl */
178 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
179 	ddi_dma_unbindhdl,		/* bus_unbindhdl */
180 	ddi_dma_flush,			/* bus_dma_flush */
181 	ddi_dma_win,			/* bus_dma_win */
182 	ddi_dma_mctl,			/* bus_dma_ctl */
183 	fctl_fca_bus_ctl,		/* bus_ctl */
184 	ddi_bus_prop_op,		/* bus_prop_op */
185 	NULL,				/* bus_get_eventcookie */
186 	NULL,				/* bus_add_eventcall */
187 	NULL,				/* bus_remove_event */
188 	NULL,				/* bus_post_event */
189 	NULL,				/* bus_intr_ctl */
190 	NULL,				/* bus_config */
191 	NULL,				/* bus_unconfig */
192 	NULL,				/* bus_fm_init */
193 	NULL,				/* bus_fm_fini */
194 	NULL,				/* bus_fm_access_enter */
195 	NULL,				/* bus_fm_access_exit */
196 	NULL,				/* bus_power */
197 	NULL
198 };
199 
200 struct kmem_cache *fctl_job_cache;
201 
202 static fc_errmap_t fc_errlist [] = {
203 	{ FC_FAILURE,		"Operation failed"			},
204 	{ FC_SUCCESS,		"Operation success"			},
205 	{ FC_CAP_ERROR,		"Capability error"			},
206 	{ FC_CAP_FOUND,		"Capability found"			},
207 	{ FC_CAP_SETTABLE,	"Capability settable"			},
208 	{ FC_UNBOUND,		"Port not bound"			},
209 	{ FC_NOMEM,		"No memory"				},
210 	{ FC_BADPACKET,		"Bad packet"				},
211 	{ FC_OFFLINE,		"Port offline"				},
212 	{ FC_OLDPORT,		"Old Port"				},
213 	{ FC_NO_MAP,		"No map available"			},
214 	{ FC_TRANSPORT_ERROR,	"Transport error"			},
215 	{ FC_ELS_FREJECT,	"ELS Frejected"				},
216 	{ FC_ELS_PREJECT,	"ELS PRejected"				},
217 	{ FC_ELS_BAD,		"Bad ELS request"			},
218 	{ FC_ELS_MALFORMED,	"Malformed ELS request"			},
219 	{ FC_TOOMANY,		"Too many commands"			},
220 	{ FC_UB_BADTOKEN,	"Bad Unsolicited buffer token"		},
221 	{ FC_UB_ERROR,		"Unsolicited buffer error"		},
222 	{ FC_UB_BUSY,		"Unsolicited buffer busy"		},
223 	{ FC_BADULP,		"Bad ULP"				},
224 	{ FC_BADTYPE,		"Bad Type"				},
225 	{ FC_UNCLAIMED,		"Not Claimed"				},
226 	{ FC_ULP_SAMEMODULE,	"Same ULP Module"			},
227 	{ FC_ULP_SAMETYPE,	"Same ULP Type"				},
228 	{ FC_ABORTED,		"Command Aborted"			},
229 	{ FC_ABORT_FAILED,	"Abort Failed"				},
230 	{ FC_BADEXCHANGE,	"Bad Exchange"				},
231 	{ FC_BADWWN,		"Bad World Wide Name"			},
232 	{ FC_BADDEV,		"Bad Device"				},
233 	{ FC_BADCMD,		"Bad Command"				},
234 	{ FC_BADOBJECT,		"Bad Object"				},
235 	{ FC_BADPORT,		"Bad Port"				},
236 	{ FC_NOTTHISPORT,	"Not on this Port"			},
237 	{ FC_PREJECT,		"Operation Prejected"			},
238 	{ FC_FREJECT,		"Operation Frejected"			},
239 	{ FC_PBUSY,		"Operation Pbusyed"			},
240 	{ FC_FBUSY,		"Operation Fbusyed"			},
241 	{ FC_ALREADY,		"Already done"				},
242 	{ FC_LOGINREQ,		"PLOGI Required"			},
243 	{ FC_RESETFAIL,		"Reset operation failed"		},
244 	{ FC_INVALID_REQUEST,	"Invalid Request"			},
245 	{ FC_OUTOFBOUNDS,	"Out of Bounds"				},
246 	{ FC_TRAN_BUSY,		"Command transport Busy"		},
247 	{ FC_STATEC_BUSY,	"State change Busy"			},
248 	{ FC_DEVICE_BUSY,	"Port driver is working on this device"	}
249 };
250 
251 fc_pkt_reason_t remote_stop_reasons [] = {
252 	{ FC_REASON_ABTS,	"Abort Sequence"	},
253 	{ FC_REASON_ABTX,	"Abort Exchange"	},
254 	{ FC_REASON_INVALID,	NULL			}
255 };
256 
257 fc_pkt_reason_t general_reasons [] = {
258 	{ FC_REASON_HW_ERROR,		"Hardware Error"		},
259 	{ FC_REASON_SEQ_TIMEOUT,	"Sequence Timeout"		},
260 	{ FC_REASON_ABORTED,		"Aborted"			},
261 	{ FC_REASON_ABORT_FAILED,	"Abort Failed"			},
262 	{ FC_REASON_NO_CONNECTION,	"No Connection"			},
263 	{ FC_REASON_XCHG_DROPPED,	"Exchange Dropped"		},
264 	{ FC_REASON_ILLEGAL_FRAME,	"Illegal Frame"			},
265 	{ FC_REASON_ILLEGAL_LENGTH,	"Illegal Length"		},
266 	{ FC_REASON_UNSUPPORTED,	"Unsuported"			},
267 	{ FC_REASON_RX_BUF_TIMEOUT,	"Receive Buffer Timeout"	},
268 	{ FC_REASON_FCAL_OPN_FAIL,	"FC AL Open Failed"		},
269 	{ FC_REASON_OVERRUN,		"Over run"			},
270 	{ FC_REASON_QFULL,		"Queue Full"			},
271 	{ FC_REASON_ILLEGAL_REQ,	"Illegal Request",		},
272 	{ FC_REASON_PKT_BUSY,		"Busy"				},
273 	{ FC_REASON_OFFLINE,		"Offline"			},
274 	{ FC_REASON_BAD_XID,		"Bad Exchange Id"		},
275 	{ FC_REASON_XCHG_BSY,		"Exchange Busy"			},
276 	{ FC_REASON_NOMEM,		"No Memory"			},
277 	{ FC_REASON_BAD_SID,		"Bad S_ID"			},
278 	{ FC_REASON_NO_SEQ_INIT,	"No Sequence Initiative"	},
279 	{ FC_REASON_DIAG_BUSY,		"Diagnostic Busy"		},
280 	{ FC_REASON_DMA_ERROR,		"DMA Error"			},
281 	{ FC_REASON_CRC_ERROR,		"CRC Error"			},
282 	{ FC_REASON_ABORT_TIMEOUT,	"Abort Timeout"			},
283 	{ FC_REASON_FCA_UNIQUE,		"FCA Unique"			},
284 	{ FC_REASON_INVALID,		NULL				}
285 };
286 
287 fc_pkt_reason_t rjt_reasons [] = {
288 	{ FC_REASON_INVALID_D_ID,	"Invalid D_ID"			},
289 	{ FC_REASON_INVALID_S_ID,	"Invalid S_ID"			},
290 	{ FC_REASON_TEMP_UNAVAILABLE,	"Temporarily Unavailable"	},
291 	{ FC_REASON_PERM_UNAVAILABLE,	"Permamnently Unavailable"	},
292 	{ FC_REASON_CLASS_NOT_SUPP,	"Class Not Supported",		},
293 	{ FC_REASON_DELIMTER_USAGE_ERROR,
294 	    "Delimeter Usage Error"		},
295 	{ FC_REASON_TYPE_NOT_SUPP,	"Type Not Supported"		},
296 	{ FC_REASON_INVALID_LINK_CTRL,	"Invalid Link Control"		},
297 	{ FC_REASON_INVALID_R_CTL,	"Invalid R_CTL"			},
298 	{ FC_REASON_INVALID_F_CTL,	"Invalid F_CTL"			},
299 	{ FC_REASON_INVALID_OX_ID,	"Invalid OX_ID"			},
300 	{ FC_REASON_INVALID_RX_ID,	"Invalid RX_ID"			},
301 	{ FC_REASON_INVALID_SEQ_ID,	"Invalid Sequence ID"		},
302 	{ FC_REASON_INVALID_DF_CTL,	"Invalid DF_CTL"		},
303 	{ FC_REASON_INVALID_SEQ_CNT,	"Invalid Sequence count"	},
304 	{ FC_REASON_INVALID_PARAM,	"Invalid Parameter"		},
305 	{ FC_REASON_EXCH_ERROR,		"Exchange Error"		},
306 	{ FC_REASON_PROTOCOL_ERROR,	"Protocol Error"		},
307 	{ FC_REASON_INCORRECT_LENGTH,	"Incorrect Length"		},
308 	{ FC_REASON_UNEXPECTED_ACK,	"Unexpected Ack"		},
309 	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset"		},
310 	{ FC_REASON_LOGIN_REQUIRED,	"Login Required"		},
311 	{ FC_REASON_EXCESSIVE_SEQS,	"Excessive Sequences"
312 	    " Attempted"			},
313 	{ FC_REASON_EXCH_UNABLE,	"Exchange incapable"		},
314 	{ FC_REASON_ESH_NOT_SUPP,	"Expiration Security Header "
315 	    "Not Supported"			},
316 	{ FC_REASON_NO_FABRIC_PATH,	"No Fabric Path"		},
317 	{ FC_REASON_VENDOR_UNIQUE,	"Vendor Unique"			},
318 	{ FC_REASON_INVALID,		NULL				}
319 };
320 
321 fc_pkt_reason_t n_port_busy_reasons [] = {
322 	{ FC_REASON_PHYSICAL_BUSY,		"Physical Busy"		},
323 	{ FC_REASON_N_PORT_RESOURCE_BSY,	"Resource Busy"		},
324 	{ FC_REASON_N_PORT_VENDOR_UNIQUE,	"Vendor Unique"		},
325 	{ FC_REASON_INVALID,			NULL			}
326 };
327 
328 fc_pkt_reason_t f_busy_reasons [] = {
329 	{ FC_REASON_FABRIC_BSY,		"Fabric Busy"			},
330 	{ FC_REASON_N_PORT_BSY,		"N_Port Busy"			},
331 	{ FC_REASON_INVALID,		NULL				}
332 };
333 
334 fc_pkt_reason_t ls_ba_rjt_reasons [] = {
335 	{ FC_REASON_INVALID_LA_CODE,	"Invalid Link Application Code"	},
336 	{ FC_REASON_LOGICAL_ERROR,	"Logical Error"			},
337 	{ FC_REASON_LOGICAL_BSY,	"Logical Busy"			},
338 	{ FC_REASON_PROTOCOL_ERROR_RJT,	"Protocol Error Reject"		},
339 	{ FC_REASON_CMD_UNABLE,		"Unable to Perform Command"	},
340 	{ FC_REASON_CMD_UNSUPPORTED,	"Unsupported Command"		},
341 	{ FC_REASON_VU_RJT,		"Vendor Unique"			},
342 	{ FC_REASON_INVALID,		NULL				}
343 };
344 
345 fc_pkt_reason_t fs_rjt_reasons [] = {
346 	{ FC_REASON_FS_INVALID_CMD,	"Invalid Command"		},
347 	{ FC_REASON_FS_INVALID_VER,	"Invalid Version"		},
348 	{ FC_REASON_FS_LOGICAL_ERR,	"Logical Error"			},
349 	{ FC_REASON_FS_INVALID_IUSIZE,	"Invalid IU Size"		},
350 	{ FC_REASON_FS_LOGICAL_BUSY,	"Logical Busy"			},
351 	{ FC_REASON_FS_PROTOCOL_ERR,	"Protocol Error"		},
352 	{ FC_REASON_FS_CMD_UNABLE,	"Unable to Perform Command"	},
353 	{ FC_REASON_FS_CMD_UNSUPPORTED,	"Unsupported Command"		},
354 	{ FC_REASON_FS_VENDOR_UNIQUE,	"Vendor Unique"			},
355 	{ FC_REASON_INVALID,		NULL				}
356 };
357 
358 fc_pkt_action_t	n_port_busy_actions [] = {
359 	{ FC_ACTION_SEQ_TERM_RETRY,	"Retry terminated Sequence"	},
360 	{ FC_ACTION_SEQ_ACTIVE_RETRY,	"Retry Active Sequence"		},
361 	{ FC_REASON_INVALID,		NULL				}
362 };
363 
364 fc_pkt_action_t rjt_timeout_actions [] = {
365 	{ FC_ACTION_RETRYABLE,		"Retryable"			},
366 	{ FC_ACTION_NON_RETRYABLE,	"Non Retryable"			},
367 	{ FC_REASON_INVALID,		NULL				}
368 };
369 
370 fc_pkt_expln_t ba_rjt_explns [] = {
371 	{ FC_EXPLN_NONE,		"No Explanation"		},
372 	{ FC_EXPLN_INVALID_OX_RX_ID,	"Invalid X_ID"			},
373 	{ FC_EXPLN_SEQ_ABORTED,		"Sequence Aborted"		},
374 	{ FC_EXPLN_INVALID,		NULL				}
375 };
376 
377 fc_pkt_error_t fc_pkt_errlist[] = {
378 	{
379 		FC_PKT_SUCCESS,
380 		"Operation Success",
381 		NULL,
382 		NULL,
383 		NULL
384 	},
385 	{	FC_PKT_REMOTE_STOP,
386 	    "Remote Stop",
387 	    remote_stop_reasons,
388 	    NULL,
389 	    NULL
390 	},
391 	{
392 		FC_PKT_LOCAL_RJT,
393 		"Local Reject",
394 		general_reasons,
395 		rjt_timeout_actions,
396 		NULL
397 	},
398 	{
399 		FC_PKT_NPORT_RJT,
400 		"N_Port Reject",
401 		rjt_reasons,
402 		rjt_timeout_actions,
403 		NULL
404 	},
405 	{
406 		FC_PKT_FABRIC_RJT,
407 		"Fabric Reject",
408 		rjt_reasons,
409 		rjt_timeout_actions,
410 		NULL
411 	},
412 	{
413 		FC_PKT_LOCAL_BSY,
414 		"Local Busy",
415 		general_reasons,
416 		NULL,
417 		NULL,
418 	},
419 	{
420 		FC_PKT_TRAN_BSY,
421 		"Transport Busy",
422 		general_reasons,
423 		NULL,
424 		NULL,
425 	},
426 	{
427 		FC_PKT_NPORT_BSY,
428 		"N_Port Busy",
429 		n_port_busy_reasons,
430 		n_port_busy_actions,
431 		NULL
432 	},
433 	{
434 		FC_PKT_FABRIC_BSY,
435 		"Fabric Busy",
436 		f_busy_reasons,
437 		NULL,
438 		NULL,
439 	},
440 	{
441 		FC_PKT_LS_RJT,
442 		"Link Service Reject",
443 		ls_ba_rjt_reasons,
444 		NULL,
445 		NULL,
446 	},
447 	{
448 		FC_PKT_BA_RJT,
449 		"Basic Reject",
450 		ls_ba_rjt_reasons,
451 		NULL,
452 		ba_rjt_explns,
453 	},
454 	{
455 		FC_PKT_TIMEOUT,
456 		"Timeout",
457 		general_reasons,
458 		rjt_timeout_actions,
459 		NULL
460 	},
461 	{
462 		FC_PKT_FS_RJT,
463 		"Fabric Switch Reject",
464 		fs_rjt_reasons,
465 		NULL,
466 		NULL
467 	},
468 	{
469 		FC_PKT_TRAN_ERROR,
470 		"Packet Transport error",
471 		general_reasons,
472 		NULL,
473 		NULL
474 	},
475 	{
476 		FC_PKT_FAILURE,
477 		"Packet Failure",
478 		general_reasons,
479 		NULL,
480 		NULL
481 	},
482 	{
483 		FC_PKT_PORT_OFFLINE,
484 		"Port Offline",
485 		NULL,
486 		NULL,
487 		NULL
488 	},
489 	{
490 		FC_PKT_ELS_IN_PROGRESS,
491 		"ELS is in Progress",
492 		NULL,
493 		NULL,
494 		NULL
495 	}
496 };
497 
498 int
499 _init()
500 {
501 	int rval;
502 
503 	rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
504 	rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
505 	mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
506 	mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
507 
508 	fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
509 	    fctl_nwwn_table_size, KM_SLEEP);
510 
511 	fctl_ulp_modules = NULL;
512 	fctl_fca_portlist = NULL;
513 
514 	fctl_job_cache = kmem_cache_create("fctl_cache",
515 	    sizeof (job_request_t), 8, fctl_cache_constructor,
516 	    fctl_cache_destructor, NULL, NULL, NULL, 0);
517 
518 	if (fctl_job_cache == NULL) {
519 		kmem_free(fctl_nwwn_hash_table,
520 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
521 		mutex_destroy(&fctl_nwwn_hash_mutex);
522 		mutex_destroy(&fctl_port_lock);
523 		rw_destroy(&fctl_ulp_lock);
524 		rw_destroy(&fctl_mod_ports_lock);
525 		return (ENOMEM);
526 	}
527 
528 	if ((rval = mod_install(&modlinkage)) != 0) {
529 		kmem_cache_destroy(fctl_job_cache);
530 		kmem_free(fctl_nwwn_hash_table,
531 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
532 		mutex_destroy(&fctl_nwwn_hash_mutex);
533 		mutex_destroy(&fctl_port_lock);
534 		rw_destroy(&fctl_ulp_lock);
535 		rw_destroy(&fctl_mod_ports_lock);
536 	}
537 
538 	return (rval);
539 }
540 
541 
542 /*
543  * The mod_uninstall code doesn't call _fini when
544  * there is living dependent module on fctl. So
545  * there is no need to be extra careful here ?
546  */
547 int
548 _fini()
549 {
550 	int rval;
551 
552 	if ((rval = mod_remove(&modlinkage)) != 0) {
553 		return (rval);
554 	}
555 
556 	kmem_cache_destroy(fctl_job_cache);
557 	kmem_free(fctl_nwwn_hash_table,
558 	    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
559 	mutex_destroy(&fctl_nwwn_hash_mutex);
560 	mutex_destroy(&fctl_port_lock);
561 	rw_destroy(&fctl_ulp_lock);
562 	rw_destroy(&fctl_mod_ports_lock);
563 
564 	return (rval);
565 }
566 
567 
568 int
569 _info(struct modinfo *modinfo_p)
570 {
571 	return (mod_info(&modlinkage, modinfo_p));
572 }
573 
574 
575 /* ARGSUSED */
576 static int
577 fctl_cache_constructor(void *buf, void *cdarg, int kmflag)
578 {
579 	job_request_t *job = (job_request_t *)buf;
580 
581 	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
582 	sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
583 	sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
584 
585 	return (0);
586 }
587 
588 
589 /* ARGSUSED */
590 static void
591 fctl_cache_destructor(void *buf, void *cdarg)
592 {
593 	job_request_t *job = (job_request_t *)buf;
594 
595 	sema_destroy(&job->job_fctl_sema);
596 	sema_destroy(&job->job_port_sema);
597 	mutex_destroy(&job->job_mutex);
598 }
599 
600 
601 /*
602  * fc_ulp_add:
603  *		Add a ULP module
604  *
605  * Return Codes:
606  *		FC_ULP_SAMEMODULE
607  *		FC_SUCCESS
608  *		FC_FAILURE
609  *
610  *   fc_ulp_add	 prints	 a warning message if there is	already a
611  *   similar ULP type  attached and this is unlikely to change as
612  *   we trudge along.  Further, this  function	returns a failure
613  *   code if the same  module  attempts to add more than once for
614  *   the same FC-4 type.
615  */
616 int
617 fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
618 {
619 	fc_ulp_module_t *mod;
620 	fc_ulp_module_t *prev;
621 	job_request_t	*job;
622 	fc_ulp_list_t	*new;
623 	fc_fca_port_t	*fca_port;
624 	int		ntry = 0;
625 
626 	ASSERT(ulp_info != NULL);
627 
628 	/*
629 	 * Make sure ulp_rev matches fctl version.
630 	 * Whenever non-private data structure or non-static interface changes,
631 	 * we should use an increased FCTL_ULP_MODREV_# number here and in all
632 	 * ulps to prevent version mismatch.
633 	 */
634 	if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
635 		cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
636 		    " ULP %s would not be loaded", ulp_info->ulp_name,
637 		    ulp_info->ulp_name);
638 		return (FC_BADULP);
639 	}
640 
641 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
642 	ASSERT(new != NULL);
643 
644 	mutex_enter(&fctl_ulp_list_mutex);
645 	new->ulp_info = ulp_info;
646 	if (fctl_ulp_list != NULL) {
647 		new->ulp_next = fctl_ulp_list;
648 	}
649 	fctl_ulp_list = new;
650 	mutex_exit(&fctl_ulp_list_mutex);
651 
652 	while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
653 		delay(drv_usectohz(1000000));
654 		if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
655 			fc_ulp_list_t	*list;
656 			fc_ulp_list_t	*last;
657 			mutex_enter(&fctl_ulp_list_mutex);
658 			for (last = NULL, list = fctl_ulp_list; list != NULL;
659 			    list = list->ulp_next) {
660 				if (list->ulp_info == ulp_info) {
661 					break;
662 				}
663 				last = list;
664 			}
665 
666 			if (list) {
667 				if (last) {
668 					last->ulp_next = list->ulp_next;
669 				} else {
670 					fctl_ulp_list = list->ulp_next;
671 				}
672 				kmem_free(list, sizeof (*list));
673 			}
674 			mutex_exit(&fctl_ulp_list_mutex);
675 			cmn_err(CE_WARN, "fctl: ULP %s unable to load",
676 			    ulp_info->ulp_name);
677 			return (FC_FAILURE);
678 		}
679 	}
680 
681 	for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
682 		ASSERT(mod->mod_info != NULL);
683 
684 		if (ulp_info == mod->mod_info &&
685 		    ulp_info->ulp_type == mod->mod_info->ulp_type) {
686 			rw_exit(&fctl_ulp_lock);
687 			return (FC_ULP_SAMEMODULE);
688 		}
689 
690 		if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
691 			cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
692 			    ulp_info->ulp_type);
693 		}
694 		prev = mod;
695 	}
696 
697 	mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
698 	mod->mod_info = ulp_info;
699 	mod->mod_next = NULL;
700 
701 	if (prev) {
702 		prev->mod_next = mod;
703 	} else {
704 		fctl_ulp_modules = mod;
705 	}
706 
707 	/*
708 	 * Schedule a job to each port's job_handler
709 	 * thread to attach their ports with this ULP.
710 	 */
711 	mutex_enter(&fctl_port_lock);
712 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
713 	    fca_port = fca_port->port_next) {
714 		job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
715 		    NULL, NULL, KM_SLEEP);
716 
717 		fctl_enque_job(fca_port->port_handle, job);
718 	}
719 	mutex_exit(&fctl_port_lock);
720 
721 	rw_exit(&fctl_ulp_lock);
722 
723 	return (FC_SUCCESS);
724 }
725 
726 
727 /*
728  * fc_ulp_remove
729  *	Remove a ULP module
730  *
731  * A misbehaving ULP may call this routine while I/Os are in progress.
732  * Currently there is no mechanism to detect it to fail such a request.
733  *
734  * Return Codes:
735  *		FC_SUCCESS
736  *		FC_FAILURE
737  */
738 int
739 fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
740 {
741 	fc_ulp_module_t *mod;
742 	fc_ulp_list_t	*list;
743 	fc_ulp_list_t	*last;
744 	fc_ulp_module_t *prev;
745 
746 	mutex_enter(&fctl_ulp_list_mutex);
747 
748 	for (last = NULL, list = fctl_ulp_list; list != NULL;
749 	    list = list->ulp_next) {
750 		if (list->ulp_info == ulp_info) {
751 			break;
752 		}
753 		last = list;
754 	}
755 
756 	if (list) {
757 		if (last) {
758 			last->ulp_next = list->ulp_next;
759 		} else {
760 			fctl_ulp_list = list->ulp_next;
761 		}
762 		kmem_free(list, sizeof (*list));
763 	}
764 
765 	mutex_exit(&fctl_ulp_list_mutex);
766 
767 	rw_enter(&fctl_ulp_lock, RW_WRITER);
768 
769 	for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
770 	    mod = mod->mod_next) {
771 		if (mod->mod_info == ulp_info) {
772 			break;
773 		}
774 		prev = mod;
775 	}
776 
777 	if (mod) {
778 		fc_ulp_ports_t *next;
779 
780 		if (prev) {
781 			prev->mod_next = mod->mod_next;
782 		} else {
783 			fctl_ulp_modules = mod->mod_next;
784 		}
785 
786 		rw_enter(&fctl_mod_ports_lock, RW_WRITER);
787 
788 		while ((next = mod->mod_ports) != NULL) {
789 			mod->mod_ports = next->port_next;
790 			fctl_dealloc_ulp_port(next);
791 		}
792 
793 		rw_exit(&fctl_mod_ports_lock);
794 		rw_exit(&fctl_ulp_lock);
795 
796 		kmem_free(mod, sizeof (*mod));
797 
798 		return (FC_SUCCESS);
799 	}
800 	rw_exit(&fctl_ulp_lock);
801 
802 	return (FC_FAILURE);
803 }
804 
805 
806 /*
807  * The callers typically cache allocate the packet, complete the
808  * DMA setup for pkt_cmd and pkt_resp fields of the packet and
809  * call this function to see if the FCA is interested in doing
810  * its own intialization. For example, socal may like to initialize
811  * the soc_hdr which is pointed to by the pkt_fca_private field
812  * and sitting right below fc_packet_t in memory.
813  *
814  * The caller is required to ensure that pkt_pd is populated with the
815  * handle that it was given when the transport notified it about the
816  * device this packet is associated with.  If there is no associated
817  * device, pkt_pd must be set to NULL.	A non-NULL pkt_pd will cause an
818  * increment of the reference count for said pd.  When the packet is freed,
819  * the reference count will be decremented.  This reference count, in
820  * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
821  * will not wink out of existence while there is a packet outstanding.
822  *
823  * This function and fca_init_pkt must not perform any operations that
824  * would result in a call back to the ULP, as the ULP may be required
825  * to hold a mutex across this call to ensure that the pd in question
826  * won't go away prior the call to fc_ulp_transport.
827  *
828  * ULPs are responsible for using the handles they are given during state
829  * change callback processing in a manner that ensures consistency.  That
830  * is, they must be aware that they could be processing a state change
831  * notification that tells them the device associated with a particular
832  * handle has gone away at the same time they are being asked to
833  * initialize a packet using that handle. ULPs must therefore ensure
834  * that their state change processing and packet initialization code
835  * paths are sufficiently synchronized to avoid the use of an
836  * invalidated handle in any fc_packet_t struct that is passed to the
837  * fc_ulp_init_packet() function.
838  */
839 int
840 fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
841 {
842 	int rval;
843 	fc_local_port_t *port = port_handle;
844 	fc_remote_port_t *pd;
845 
846 	ASSERT(pkt != NULL);
847 
848 	pd = pkt->pkt_pd;
849 
850 	/* Call the FCA driver's fca_init_pkt entry point function. */
851 	rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
852 
853 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
854 		/*
855 		 * A !NULL pd here must still be a valid
856 		 * reference to the fc_remote_port_t.
857 		 */
858 		mutex_enter(&pd->pd_mutex);
859 		ASSERT(pd->pd_ref_count >= 0);
860 		pd->pd_ref_count++;
861 		mutex_exit(&pd->pd_mutex);
862 	}
863 
864 	return (rval);
865 }
866 
867 
868 /*
869  * This function is called before destroying the cache allocated
870  * fc_packet to free up (and uninitialize) any resource specially
871  * allocated by the FCA driver during tran_init_pkt().
872  *
873  * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
874  * the pd_ref_count reference count is decremented for the indicated
875  * fc_remote_port_t struct.
876  */
877 int
878 fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
879 {
880 	int rval;
881 	fc_local_port_t *port = port_handle;
882 	fc_remote_port_t *pd;
883 
884 	ASSERT(pkt != NULL);
885 
886 	pd = pkt->pkt_pd;
887 
888 	/* Call the FCA driver's fca_un_init_pkt entry point function */
889 	rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
890 
891 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
892 		mutex_enter(&pd->pd_mutex);
893 
894 		ASSERT(pd->pd_ref_count > 0);
895 		pd->pd_ref_count--;
896 
897 		/*
898 		 * If at this point the state of this fc_remote_port_t
899 		 * struct is PORT_DEVICE_INVALID, it probably means somebody
900 		 * is cleaning up old (e.g. retried) packets. If the
901 		 * pd_ref_count has also dropped to zero, it's time to
902 		 * deallocate this fc_remote_port_t struct.
903 		 */
904 		if (pd->pd_state == PORT_DEVICE_INVALID &&
905 		    pd->pd_ref_count == 0) {
906 			fc_remote_node_t *node = pd->pd_remote_nodep;
907 
908 			mutex_exit(&pd->pd_mutex);
909 
910 			/*
911 			 * Also deallocate the associated fc_remote_node_t
912 			 * struct if it has no other associated
913 			 * fc_remote_port_t structs.
914 			 */
915 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
916 			    (node != NULL)) {
917 				fctl_destroy_remote_node(node);
918 			}
919 			return (rval);
920 		}
921 
922 		mutex_exit(&pd->pd_mutex);
923 	}
924 
925 	return (rval);
926 }
927 
928 
929 int
930 fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
931     int flag)
932 {
933 	int		job_code;
934 	fc_local_port_t *port;
935 	job_request_t	*job;
936 	fc_portmap_t	*tmp_map;
937 	uint32_t	tmp_len;
938 	fc_portmap_t	*change_list = NULL;
939 	uint32_t	listlen = 0;
940 
941 	port = port_handle;
942 
943 	mutex_enter(&port->fp_mutex);
944 	if (port->fp_statec_busy) {
945 		mutex_exit(&port->fp_mutex);
946 		return (FC_STATEC_BUSY);
947 	}
948 
949 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
950 		mutex_exit(&port->fp_mutex);
951 		return (FC_OFFLINE);
952 	}
953 
954 	if (port->fp_dev_count && (port->fp_dev_count ==
955 	    port->fp_total_devices)) {
956 		mutex_exit(&port->fp_mutex);
957 		fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
958 		if (listlen > *len) {
959 			tmp_map = (fc_portmap_t *)kmem_zalloc(
960 			    listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
961 			if (tmp_map == NULL) {
962 				return (FC_NOMEM);
963 			}
964 			if (*map) {
965 				kmem_free(*map, (*len) * sizeof (fc_portmap_t));
966 			}
967 			*map = tmp_map;
968 		}
969 		if (change_list) {
970 			bcopy(change_list, *map,
971 			    listlen * sizeof (fc_portmap_t));
972 			kmem_free(change_list, listlen * sizeof (fc_portmap_t));
973 		}
974 		*len = listlen;
975 	} else {
976 		mutex_exit(&port->fp_mutex);
977 
978 		switch (flag) {
979 		case FC_ULP_PLOGI_DONTCARE:
980 			job_code = JOB_PORT_GETMAP;
981 			break;
982 
983 		case FC_ULP_PLOGI_PRESERVE:
984 			job_code = JOB_PORT_GETMAP_PLOGI_ALL;
985 			break;
986 
987 		default:
988 			return (FC_INVALID_REQUEST);
989 		}
990 		/*
991 		 * Submit a job request to the job handler
992 		 * thread to get the map and wait
993 		 */
994 		job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
995 		job->job_private = (opaque_t)map;
996 		job->job_arg = (opaque_t)len;
997 		fctl_enque_job(port, job);
998 
999 		fctl_jobwait(job);
1000 		/*
1001 		 * The result of the last I/O operation is
1002 		 * in job_code. We don't care to look at it
1003 		 * Rather we look at the number of devices
1004 		 * that are found to fill out the map for
1005 		 * ULPs.
1006 		 */
1007 		fctl_dealloc_job(job);
1008 	}
1009 
1010 	/*
1011 	 * If we're here, we're returning a map to the caller, which means
1012 	 * we'd better make sure every pd in that map has the
1013 	 * PD_GIVEN_TO_ULPS flag set.
1014 	 */
1015 
1016 	tmp_len = *len;
1017 	tmp_map = *map;
1018 
1019 	while (tmp_len-- != 0) {
1020 		if (tmp_map->map_state != PORT_DEVICE_INVALID) {
1021 			fc_remote_port_t *pd =
1022 			    (fc_remote_port_t *)tmp_map->map_pd;
1023 			mutex_enter(&pd->pd_mutex);
1024 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1025 			mutex_exit(&pd->pd_mutex);
1026 		}
1027 		tmp_map++;
1028 	}
1029 
1030 	return (FC_SUCCESS);
1031 }
1032 
1033 
1034 int
1035 fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
1036 {
1037 	int			rval = FC_SUCCESS;
1038 	int			job_flags;
1039 	uint32_t		count;
1040 	fc_packet_t		**tmp_array;
1041 	job_request_t		*job;
1042 	fc_local_port_t		*port = port_handle;
1043 	fc_ulp_rscn_info_t	*rscnp =
1044 	    (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
1045 
1046 	/*
1047 	 * If the port is OFFLINE, or if the port driver is
1048 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1049 	 * PLOGI operations
1050 	 */
1051 	mutex_enter(&port->fp_mutex);
1052 	if (port->fp_statec_busy) {
1053 		mutex_exit(&port->fp_mutex);
1054 		return (FC_STATEC_BUSY);
1055 	}
1056 
1057 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1058 	    (port->fp_soft_state &
1059 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1060 		mutex_exit(&port->fp_mutex);
1061 		return (FC_OFFLINE);
1062 	}
1063 
1064 	/*
1065 	 * If the rscn count in the packet is not the same as the rscn count
1066 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1067 	 */
1068 	if ((rscnp != NULL) &&
1069 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1070 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1071 		mutex_exit(&port->fp_mutex);
1072 		return (FC_DEVICE_BUSY_NEW_RSCN);
1073 	}
1074 
1075 	mutex_exit(&port->fp_mutex);
1076 
1077 	tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
1078 	for (count = 0; count < listlen; count++) {
1079 		tmp_array[count] = ulp_pkt[count];
1080 	}
1081 
1082 	job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
1083 	    ? 0 : JOB_TYPE_FCTL_ASYNC;
1084 
1085 #ifdef	DEBUG
1086 	{
1087 		int next;
1088 		int count;
1089 		int polled;
1090 
1091 		polled = ((ulp_pkt[0]->pkt_tran_flags) &
1092 		    FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1093 
1094 		for (count = 0; count < listlen; count++) {
1095 			next = ((ulp_pkt[count]->pkt_tran_flags)
1096 			    & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1097 			ASSERT(next == polled);
1098 		}
1099 	}
1100 #endif
1101 
1102 	job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
1103 	job->job_ulp_pkts = tmp_array;
1104 	job->job_ulp_listlen = listlen;
1105 
1106 	while (listlen--) {
1107 		fc_packet_t *pkt;
1108 
1109 		pkt = tmp_array[listlen];
1110 		if (pkt->pkt_pd == NULL) {
1111 			pkt->pkt_state = FC_PKT_SUCCESS;
1112 			continue;
1113 		}
1114 
1115 		mutex_enter(&pkt->pkt_pd->pd_mutex);
1116 		if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
1117 		    pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
1118 			/*
1119 			 * Set the packet state and let the port
1120 			 * driver call the completion routine
1121 			 * from its thread
1122 			 */
1123 			mutex_exit(&pkt->pkt_pd->pd_mutex);
1124 			pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
1125 			continue;
1126 		}
1127 
1128 		if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
1129 		    pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
1130 			mutex_exit(&pkt->pkt_pd->pd_mutex);
1131 			pkt->pkt_state = FC_PKT_LOCAL_RJT;
1132 			continue;
1133 		}
1134 		mutex_exit(&pkt->pkt_pd->pd_mutex);
1135 		pkt->pkt_state = FC_PKT_SUCCESS;
1136 	}
1137 
1138 	fctl_enque_job(port, job);
1139 
1140 	if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
1141 		fctl_jobwait(job);
1142 		rval = job->job_result;
1143 		fctl_dealloc_job(job);
1144 	}
1145 
1146 	return (rval);
1147 }
1148 
1149 
1150 opaque_t
1151 fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
1152     int create)
1153 {
1154 	fc_local_port_t		*port;
1155 	job_request_t		*job;
1156 	fc_remote_port_t	*pd;
1157 
1158 	port = port_handle;
1159 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1160 
1161 	if (pd != NULL) {
1162 		*error = FC_SUCCESS;
1163 		/*
1164 		 * A ULP now knows about this pd, so mark it
1165 		 */
1166 		mutex_enter(&pd->pd_mutex);
1167 		pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1168 		mutex_exit(&pd->pd_mutex);
1169 		return (pd);
1170 	}
1171 
1172 	mutex_enter(&port->fp_mutex);
1173 	if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
1174 		uint32_t	d_id;
1175 		fctl_ns_req_t	*ns_cmd;
1176 
1177 		mutex_exit(&port->fp_mutex);
1178 
1179 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1180 
1181 		if (job == NULL) {
1182 			*error = FC_NOMEM;
1183 			return (pd);
1184 		}
1185 
1186 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
1187 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
1188 		    0, KM_SLEEP);
1189 
1190 		if (ns_cmd == NULL) {
1191 			fctl_dealloc_job(job);
1192 			*error = FC_NOMEM;
1193 			return (pd);
1194 		}
1195 		ns_cmd->ns_cmd_code = NS_GID_PN;
1196 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
1197 
1198 		job->job_result = FC_SUCCESS;
1199 		job->job_private = (void *)ns_cmd;
1200 		job->job_counter = 1;
1201 		fctl_enque_job(port, job);
1202 		fctl_jobwait(job);
1203 
1204 		if (job->job_result != FC_SUCCESS) {
1205 			*error = job->job_result;
1206 			fctl_free_ns_cmd(ns_cmd);
1207 			fctl_dealloc_job(job);
1208 			return (pd);
1209 		}
1210 		d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
1211 		fctl_free_ns_cmd(ns_cmd);
1212 
1213 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
1214 		    sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
1215 		    KM_SLEEP);
1216 		ASSERT(ns_cmd != NULL);
1217 
1218 		ns_cmd->ns_gan_max = 1;
1219 		ns_cmd->ns_cmd_code = NS_GA_NXT;
1220 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
1221 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
1222 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
1223 
1224 		job->job_result = FC_SUCCESS;
1225 		job->job_private = (void *)ns_cmd;
1226 		job->job_counter = 1;
1227 		fctl_enque_job(port, job);
1228 		fctl_jobwait(job);
1229 
1230 		fctl_free_ns_cmd(ns_cmd);
1231 		if (job->job_result != FC_SUCCESS) {
1232 			*error = job->job_result;
1233 			fctl_dealloc_job(job);
1234 			return (pd);
1235 		}
1236 		fctl_dealloc_job(job);
1237 
1238 		/*
1239 		 * Check if the port device is created now.
1240 		 */
1241 		pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1242 
1243 		if (pd == NULL) {
1244 			*error = FC_FAILURE;
1245 		} else {
1246 			*error = FC_SUCCESS;
1247 
1248 			/*
1249 			 * A ULP now knows about this pd, so mark it
1250 			 */
1251 			mutex_enter(&pd->pd_mutex);
1252 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1253 			mutex_exit(&pd->pd_mutex);
1254 		}
1255 	} else {
1256 		mutex_exit(&port->fp_mutex);
1257 		*error = FC_FAILURE;
1258 	}
1259 
1260 	return (pd);
1261 }
1262 
1263 
1264 /*
1265  * If a NS object exists in the host and query is performed
1266  * on that object, we should retrieve it from our basket
1267  * and return it right here, there by saving a request going
1268  * all the up to the Name Server.
1269  */
1270 int
1271 fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
1272 {
1273 	int		rval;
1274 	int		fabric;
1275 	job_request_t	*job;
1276 	fctl_ns_req_t	*ns_cmd;
1277 	fc_local_port_t	*port = port_handle;
1278 
1279 	mutex_enter(&port->fp_mutex);
1280 	fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
1281 	mutex_exit(&port->fp_mutex);
1282 
1283 	/*
1284 	 * Name server query can't be performed for devices not in Fabric
1285 	 */
1286 	if (!fabric && pd) {
1287 		return (FC_BADOBJECT);
1288 	}
1289 
1290 	if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
1291 		if (pd == NULL) {
1292 			rval = fctl_update_host_ns_values(port, ns_req);
1293 			if (rval != FC_SUCCESS) {
1294 				return (rval);
1295 			}
1296 		} else {
1297 			/*
1298 			 * Guess what, FC-GS-2 currently prohibits (not
1299 			 * in the strongest language though) setting of
1300 			 * NS object values by other ports. But we might
1301 			 * get that changed to at least accommodate setting
1302 			 * symbolic node/port names - But if disks/tapes
1303 			 * were going to provide a method to set these
1304 			 * values directly (which in turn might register
1305 			 * with the NS when they come up; yep, for that
1306 			 * to happen the disks will have to be very well
1307 			 * behaved Fabric citizen) we won't need to
1308 			 * register the symbolic port/node names for
1309 			 * other ports too (rather send down SCSI commands
1310 			 * to the devices to set the names)
1311 			 *
1312 			 * Be that as it may, let's continue to fail
1313 			 * registration requests for other ports. period.
1314 			 */
1315 			return (FC_BADOBJECT);
1316 		}
1317 
1318 		if (!fabric) {
1319 			return (FC_SUCCESS);
1320 		}
1321 	} else if (!fabric) {
1322 		return (fctl_retrieve_host_ns_values(port, ns_req));
1323 	}
1324 
1325 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1326 	ASSERT(job != NULL);
1327 
1328 	ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
1329 	    ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
1330 	ASSERT(ns_cmd != NULL);
1331 	ns_cmd->ns_cmd_code = ns_req->ns_cmd;
1332 	bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
1333 	    ns_req->ns_req_len);
1334 
1335 	job->job_private = (void *)ns_cmd;
1336 	fctl_enque_job(port, job);
1337 	fctl_jobwait(job);
1338 	rval = job->job_result;
1339 
1340 	if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
1341 		bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
1342 		    ns_cmd->ns_data_len);
1343 	}
1344 	bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
1345 	    sizeof (fc_ct_header_t));
1346 
1347 	fctl_free_ns_cmd(ns_cmd);
1348 	fctl_dealloc_job(job);
1349 
1350 	return (rval);
1351 }
1352 
1353 
1354 int
1355 fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
1356 {
1357 	int			rval;
1358 	fc_local_port_t		*port;
1359 	fc_remote_port_t	*pd, *newpd;
1360 	fc_ulp_rscn_info_t	*rscnp =
1361 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1362 
1363 	port = port_handle;
1364 
1365 	if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
1366 		return (port->fp_fca_tran->fca_transport(
1367 		    port->fp_fca_handle, pkt));
1368 	}
1369 
1370 	mutex_enter(&port->fp_mutex);
1371 	if (port->fp_statec_busy) {
1372 		mutex_exit(&port->fp_mutex);
1373 		return (FC_STATEC_BUSY);
1374 	}
1375 
1376 	/* A locus of race conditions */
1377 	if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
1378 	    (port->fp_soft_state &
1379 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1380 		mutex_exit(&port->fp_mutex);
1381 		return (FC_OFFLINE);
1382 	}
1383 
1384 	/*
1385 	 * If the rscn count in the packet is not the same as the rscn count
1386 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1387 	 */
1388 	if ((rscnp != NULL) &&
1389 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1390 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1391 		mutex_exit(&port->fp_mutex);
1392 		return (FC_DEVICE_BUSY_NEW_RSCN);
1393 	}
1394 
1395 	pd = pkt->pkt_pd;
1396 	if (pd) {
1397 		if (pd->pd_type == PORT_DEVICE_OLD ||
1398 		    pd->pd_state == PORT_DEVICE_INVALID) {
1399 
1400 			newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
1401 			    &pd->pd_port_name);
1402 
1403 			/*
1404 			 * The remote port (pd) in the packet is no longer
1405 			 * usable, as the old pd still exists we can use the
1406 			 * WWN to check if we have a current pd for the device
1407 			 * we want. Either way we continue with the old logic
1408 			 * whether we have a new pd or not, as the new pd
1409 			 * could be bad, or have become unusable.
1410 			 */
1411 			if ((newpd) && (newpd != pd)) {
1412 
1413 				/*
1414 				 * There is a better remote port (pd) to try,
1415 				 * so we need to fix the reference counts, etc.
1416 				 */
1417 				mutex_enter(&newpd->pd_mutex);
1418 				newpd->pd_ref_count++;
1419 				pkt->pkt_pd = newpd;
1420 				mutex_exit(&newpd->pd_mutex);
1421 
1422 				mutex_enter(&pd->pd_mutex);
1423 				pd->pd_ref_count--;
1424 				if ((pd->pd_state == PORT_DEVICE_INVALID) &&
1425 				    (pd->pd_ref_count == 0)) {
1426 					fc_remote_node_t *node =
1427 					    pd->pd_remote_nodep;
1428 
1429 					mutex_exit(&pd->pd_mutex);
1430 					mutex_exit(&port->fp_mutex);
1431 
1432 					/*
1433 					 * This will create another PD hole
1434 					 * where we have a reference to a pd,
1435 					 * but someone else could remove it.
1436 					 */
1437 					if ((fctl_destroy_remote_port(port, pd)
1438 					    == 0) && (node != NULL)) {
1439 						fctl_destroy_remote_node(node);
1440 					}
1441 					mutex_enter(&port->fp_mutex);
1442 				} else {
1443 					mutex_exit(&pd->pd_mutex);
1444 				}
1445 				pd = newpd;
1446 			}
1447 		}
1448 
1449 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1450 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1451 			    FC_LOGINREQ : FC_BADDEV;
1452 			mutex_exit(&port->fp_mutex);
1453 			return (rval);
1454 		}
1455 
1456 		if (pd->pd_flags != PD_IDLE) {
1457 			mutex_exit(&port->fp_mutex);
1458 			return (FC_DEVICE_BUSY);
1459 		}
1460 
1461 		if (pd->pd_type == PORT_DEVICE_OLD ||
1462 		    pd->pd_state == PORT_DEVICE_INVALID) {
1463 			mutex_exit(&port->fp_mutex);
1464 			return (FC_BADDEV);
1465 		}
1466 
1467 	} else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
1468 		mutex_exit(&port->fp_mutex);
1469 		return (FC_BADPACKET);
1470 	}
1471 	mutex_exit(&port->fp_mutex);
1472 
1473 	return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
1474 }
1475 
1476 
1477 int
1478 fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
1479 {
1480 	int			rval;
1481 	fc_local_port_t		*port = port_handle;
1482 	fc_remote_port_t	*pd;
1483 	fc_ulp_rscn_info_t	*rscnp =
1484 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1485 
1486 	/*
1487 	 * If the port is OFFLINE, or if the port driver is
1488 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1489 	 * ELS operations
1490 	 */
1491 	mutex_enter(&port->fp_mutex);
1492 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1493 	    (port->fp_soft_state &
1494 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1495 		mutex_exit(&port->fp_mutex);
1496 		return (FC_OFFLINE);
1497 	}
1498 
1499 	if (port->fp_statec_busy) {
1500 		mutex_exit(&port->fp_mutex);
1501 		return (FC_STATEC_BUSY);
1502 	}
1503 
1504 	/*
1505 	 * If the rscn count in the packet is not the same as the rscn count
1506 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
1507 	 */
1508 	if ((rscnp != NULL) &&
1509 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1510 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1511 		mutex_exit(&port->fp_mutex);
1512 		return (FC_DEVICE_BUSY_NEW_RSCN);
1513 	}
1514 
1515 	mutex_exit(&port->fp_mutex);
1516 
1517 	if ((pd = pkt->pkt_pd) != NULL) {
1518 		mutex_enter(&pd->pd_mutex);
1519 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1520 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1521 			    FC_LOGINREQ : FC_BADDEV;
1522 			mutex_exit(&pd->pd_mutex);
1523 			return (rval);
1524 		}
1525 
1526 		if (pd->pd_flags != PD_IDLE) {
1527 			mutex_exit(&pd->pd_mutex);
1528 			return (FC_DEVICE_BUSY);
1529 		}
1530 		if (pd->pd_type == PORT_DEVICE_OLD ||
1531 		    pd->pd_state == PORT_DEVICE_INVALID) {
1532 			mutex_exit(&pd->pd_mutex);
1533 			return (FC_BADDEV);
1534 		}
1535 		mutex_exit(&pd->pd_mutex);
1536 	}
1537 
1538 	return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
1539 }
1540 
1541 
1542 int
1543 fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
1544     uint32_t type, uint64_t *tokens)
1545 {
1546 	fc_local_port_t *port = port_handle;
1547 
1548 	return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
1549 	    tokens, size, count, type));
1550 }
1551 
1552 
1553 int
1554 fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1555 {
1556 	fc_local_port_t *port = port_handle;
1557 
1558 	return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
1559 	    count, tokens));
1560 }
1561 
1562 
1563 int
1564 fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1565 {
1566 	fc_local_port_t *port = port_handle;
1567 
1568 	return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
1569 	    count, tokens));
1570 }
1571 
1572 
1573 int
1574 fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
1575 {
1576 	fc_local_port_t *port = port_handle;
1577 
1578 	return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
1579 }
1580 
1581 
1582 /*
1583  * Submit an asynchronous request to the job handler if the sleep
1584  * flag is set to KM_NOSLEEP, as such calls could have been made
1585  * in interrupt contexts, and the goal is to avoid busy waiting,
1586  * blocking on a conditional variable, a semaphore or any of the
1587  * synchronization primitives. A noticeable draw back with this
1588  * asynchronous request is that an FC_SUCCESS is returned long
1589  * before the reset is complete (successful or not).
1590  */
1591 int
1592 fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
1593 {
1594 	int		rval;
1595 	fc_local_port_t *port;
1596 	job_request_t	*job;
1597 
1598 	port = port_handle;
1599 	/*
1600 	 * Many a times, this function is called from interrupt
1601 	 * contexts and there have been several dead locks and
1602 	 * hangs - One of the simplest work arounds is to fib
1603 	 * if a RESET is in progress.
1604 	 */
1605 	mutex_enter(&port->fp_mutex);
1606 	if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
1607 		mutex_exit(&port->fp_mutex);
1608 		return (FC_SUCCESS);
1609 	}
1610 
1611 	/*
1612 	 * Ward off this reset if a state change is in progress.
1613 	 */
1614 	if (port->fp_statec_busy) {
1615 		mutex_exit(&port->fp_mutex);
1616 		return (FC_STATEC_BUSY);
1617 	}
1618 	port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
1619 	mutex_exit(&port->fp_mutex);
1620 
1621 	if (fctl_busy_port(port) != 0) {
1622 		mutex_enter(&port->fp_mutex);
1623 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1624 		mutex_exit(&port->fp_mutex);
1625 		return (FC_FAILURE);
1626 	}
1627 
1628 	if (sleep == KM_SLEEP) {
1629 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
1630 		ASSERT(job != NULL);
1631 
1632 		job->job_private = (void *)pwwn;
1633 		job->job_counter = 1;
1634 		fctl_enque_job(port, job);
1635 		fctl_jobwait(job);
1636 
1637 		mutex_enter(&port->fp_mutex);
1638 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1639 		mutex_exit(&port->fp_mutex);
1640 
1641 		fctl_idle_port(port);
1642 
1643 		rval = job->job_result;
1644 		fctl_dealloc_job(job);
1645 	} else {
1646 		job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
1647 		    fctl_link_reset_done, port, sleep);
1648 		if (job == NULL) {
1649 			mutex_enter(&port->fp_mutex);
1650 			port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1651 			mutex_exit(&port->fp_mutex);
1652 			fctl_idle_port(port);
1653 			return (FC_NOMEM);
1654 		}
1655 		job->job_private = (void *)pwwn;
1656 		job->job_counter = 1;
1657 		fctl_priority_enque_job(port, job);
1658 		rval = FC_SUCCESS;
1659 	}
1660 
1661 	return (rval);
1662 }
1663 
1664 
1665 int
1666 fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
1667 {
1668 	int		rval = FC_SUCCESS;
1669 	fc_local_port_t *port = port_handle;
1670 
1671 	switch (cmd) {
1672 	case FC_RESET_PORT:
1673 		rval = port->fp_fca_tran->fca_reset(
1674 		    port->fp_fca_handle, FC_FCA_LINK_RESET);
1675 		break;
1676 
1677 	case FC_RESET_ADAPTER:
1678 		rval = port->fp_fca_tran->fca_reset(
1679 		    port->fp_fca_handle, FC_FCA_RESET);
1680 		break;
1681 
1682 	case FC_RESET_DUMP:
1683 		rval = port->fp_fca_tran->fca_reset(
1684 		    port->fp_fca_handle, FC_FCA_CORE);
1685 		break;
1686 
1687 	case FC_RESET_CRASH:
1688 		rval = port->fp_fca_tran->fca_reset(
1689 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
1690 		break;
1691 
1692 	default:
1693 		rval = FC_FAILURE;
1694 	}
1695 
1696 	return (rval);
1697 }
1698 
1699 
1700 int
1701 fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
1702 {
1703 	fc_local_port_t *port = port_handle;
1704 
1705 	/* Copy the login parameters */
1706 	*login_params = port->fp_service_params;
1707 	return (FC_SUCCESS);
1708 }
1709 
1710 
1711 int
1712 fc_ulp_get_port_instance(opaque_t port_handle)
1713 {
1714 	fc_local_port_t *port = port_handle;
1715 
1716 	return (port->fp_instance);
1717 }
1718 
1719 
1720 opaque_t
1721 fc_ulp_get_port_handle(int port_instance)
1722 {
1723 	opaque_t	port_handle = NULL;
1724 	fc_fca_port_t	*cur;
1725 
1726 	mutex_enter(&fctl_port_lock);
1727 	for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
1728 		if (cur->port_handle->fp_instance == port_instance) {
1729 			port_handle = (opaque_t)cur->port_handle;
1730 			break;
1731 		}
1732 	}
1733 	mutex_exit(&fctl_port_lock);
1734 
1735 	return (port_handle);
1736 }
1737 
1738 
1739 int
1740 fc_ulp_error(int fc_errno, char **errmsg)
1741 {
1742 	return (fctl_error(fc_errno, errmsg));
1743 }
1744 
1745 
1746 int
1747 fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
1748     char **action, char **expln)
1749 {
1750 	return (fctl_pkt_error(pkt, state, reason, action, expln));
1751 }
1752 
1753 
1754 /*
1755  * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
1756  */
1757 int
1758 fc_ulp_is_name_present(caddr_t ulp_name)
1759 {
1760 	int		rval = FC_FAILURE;
1761 	fc_ulp_list_t	*list;
1762 
1763 	mutex_enter(&fctl_ulp_list_mutex);
1764 	for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
1765 		if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
1766 			rval = FC_SUCCESS;
1767 			break;
1768 		}
1769 	}
1770 	mutex_exit(&fctl_ulp_list_mutex);
1771 
1772 	return (rval);
1773 }
1774 
1775 
1776 /*
1777  * Return port WWN for a port Identifier
1778  */
1779 int
1780 fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
1781 {
1782 	int			rval = FC_FAILURE;
1783 	fc_remote_port_t	*pd;
1784 	fc_local_port_t		*port = port_handle;
1785 
1786 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
1787 	if (pd != NULL) {
1788 		mutex_enter(&pd->pd_mutex);
1789 		*pwwn = pd->pd_port_name;
1790 		mutex_exit(&pd->pd_mutex);
1791 		rval = FC_SUCCESS;
1792 	}
1793 
1794 	return (rval);
1795 }
1796 
1797 
1798 /*
1799  * Return a port map for a port WWN
1800  */
1801 int
1802 fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
1803 {
1804 	fc_local_port_t		*port = port_handle;
1805 	fc_remote_node_t	*node;
1806 	fc_remote_port_t	*pd;
1807 
1808 	pd = fctl_get_remote_port_by_pwwn(port, bytes);
1809 	if (pd == NULL) {
1810 		return (FC_FAILURE);
1811 	}
1812 
1813 	mutex_enter(&pd->pd_mutex);
1814 	map->map_pwwn = pd->pd_port_name;
1815 	map->map_did = pd->pd_port_id;
1816 	map->map_hard_addr = pd->pd_hard_addr;
1817 	map->map_state = pd->pd_state;
1818 	map->map_type = pd->pd_type;
1819 	map->map_flags = 0;
1820 
1821 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
1822 
1823 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
1824 
1825 	node = pd->pd_remote_nodep;
1826 	mutex_exit(&pd->pd_mutex);
1827 
1828 	if (node) {
1829 		mutex_enter(&node->fd_mutex);
1830 		map->map_nwwn = node->fd_node_name;
1831 		mutex_exit(&node->fd_mutex);
1832 	}
1833 	map->map_pd = pd;
1834 
1835 	return (FC_SUCCESS);
1836 }
1837 
1838 
1839 opaque_t
1840 fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
1841 {
1842 	fc_local_port_t	*port = port_handle;
1843 
1844 	if (port->fp_fca_tran->fca_get_device == NULL) {
1845 		return (NULL);
1846 	}
1847 
1848 	return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
1849 }
1850 
1851 
1852 int
1853 fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
1854 {
1855 	int		rval = FC_SUCCESS;
1856 	fc_local_port_t	*port = port_handle;
1857 
1858 	if (port->fp_fca_tran->fca_notify) {
1859 		mutex_enter(&port->fp_mutex);
1860 		switch (cmd) {
1861 		case FC_NOTIFY_TARGET_MODE:
1862 			port->fp_options |= FP_TARGET_MODE;
1863 			break;
1864 		case FC_NOTIFY_NO_TARGET_MODE:
1865 			port->fp_options &= ~FP_TARGET_MODE;
1866 			break;
1867 		}
1868 		mutex_exit(&port->fp_mutex);
1869 		rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
1870 	}
1871 
1872 	return (rval);
1873 }
1874 
1875 
1876 void
1877 fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1878 {
1879 	fc_remote_port_t *pd =
1880 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1881 
1882 	if (pd) {
1883 		mutex_enter(&pd->pd_mutex);
1884 		pd->pd_aux_flags |= PD_DISABLE_RELOGIN;
1885 		mutex_exit(&pd->pd_mutex);
1886 	}
1887 }
1888 
1889 
1890 void
1891 fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1892 {
1893 	fc_remote_port_t *pd =
1894 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1895 
1896 	if (pd) {
1897 		mutex_enter(&pd->pd_mutex);
1898 		pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1899 		mutex_exit(&pd->pd_mutex);
1900 	}
1901 }
1902 
1903 
1904 /*
1905  * fc_fca_init
1906  *		Overload the FCA bus_ops vector in its dev_ops with
1907  *		fctl_fca_busops to handle all the INITchilds for "sf"
1908  *		in one common place.
1909  *
1910  *		Should be called from FCA _init routine.
1911  */
1912 void
1913 fc_fca_init(struct dev_ops *fca_devops_p)
1914 {
1915 #ifndef	__lock_lint
1916 	fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1917 #endif	/* __lock_lint */
1918 }
1919 
1920 
1921 /*
1922  * fc_fca_attach
1923  */
1924 int
1925 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1926 {
1927 	/*
1928 	 * When we are in a position to offer downward compatibility
1929 	 * we should change the following check to allow lower revision
1930 	 * of FCAs; But we aren't there right now.
1931 	 */
1932 	if (tran->fca_version != FCTL_FCA_MODREV_5) {
1933 		const char *name = ddi_driver_name(fca_dip);
1934 
1935 		ASSERT(name != NULL);
1936 
1937 		cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
1938 		    " please upgrade %s", name, name);
1939 		return (DDI_FAILURE);
1940 	}
1941 
1942 	ddi_set_driver_private(fca_dip, (caddr_t)tran);
1943 	return (DDI_SUCCESS);
1944 }
1945 
1946 
1947 /*
1948  * fc_fca_detach
1949  */
1950 int
1951 fc_fca_detach(dev_info_t *fca_dip)
1952 {
1953 	ddi_set_driver_private(fca_dip, NULL);
1954 	return (DDI_SUCCESS);
1955 }
1956 
1957 
1958 /*
1959  * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
1960  * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
1961  * Link Service responses such as BA_RJT and Extended Link Service response
1962  * such as LS_RJT. If the response is a Link_Data Frame or something that
1963  * this function doesn't understand return FC_FAILURE; Otherwise, fill out
1964  * various fields (state, action, reason, expln) from the response gotten
1965  * in the packet and return FC_SUCCESS.
1966  */
1967 int
1968 fc_fca_update_errors(fc_packet_t *pkt)
1969 {
1970 	int ret = FC_SUCCESS;
1971 
1972 	switch (pkt->pkt_resp_fhdr.r_ctl) {
1973 	case R_CTL_P_RJT: {
1974 		uint32_t prjt;
1975 
1976 		prjt = pkt->pkt_resp_fhdr.ro;
1977 		pkt->pkt_state = FC_PKT_NPORT_RJT;
1978 		pkt->pkt_action = (prjt & 0xFF000000) >> 24;
1979 		pkt->pkt_reason = (prjt & 0xFF0000) >> 16;
1980 		break;
1981 	}
1982 
1983 	case R_CTL_F_RJT: {
1984 		uint32_t frjt;
1985 
1986 		frjt = pkt->pkt_resp_fhdr.ro;
1987 		pkt->pkt_state = FC_PKT_FABRIC_RJT;
1988 		pkt->pkt_action = (frjt & 0xFF000000) >> 24;
1989 		pkt->pkt_reason = (frjt & 0xFF0000) >> 16;
1990 		break;
1991 	}
1992 
1993 	case R_CTL_P_BSY: {
1994 		uint32_t pbsy;
1995 
1996 		pbsy = pkt->pkt_resp_fhdr.ro;
1997 		pkt->pkt_state = FC_PKT_NPORT_BSY;
1998 		pkt->pkt_action = (pbsy & 0xFF000000) >> 24;
1999 		pkt->pkt_reason = (pbsy & 0xFF0000) >> 16;
2000 		break;
2001 	}
2002 
2003 	case R_CTL_F_BSY_LC:
2004 	case R_CTL_F_BSY_DF: {
2005 		uchar_t fbsy;
2006 
2007 		fbsy = pkt->pkt_resp_fhdr.type;
2008 		pkt->pkt_state = FC_PKT_FABRIC_BSY;
2009 		pkt->pkt_reason = (fbsy & 0xF0) >> 4;
2010 		break;
2011 	}
2012 
2013 	case R_CTL_LS_BA_RJT: {
2014 		uint32_t brjt;
2015 
2016 		brjt = *(uint32_t *)pkt->pkt_resp;
2017 		pkt->pkt_state = FC_PKT_BA_RJT;
2018 		pkt->pkt_reason = (brjt & 0xFF0000) >> 16;
2019 		pkt->pkt_expln = (brjt & 0xFF00) >> 8;
2020 		break;
2021 	}
2022 
2023 	case R_CTL_ELS_RSP: {
2024 		la_els_rjt_t *lsrjt;
2025 
2026 		lsrjt = (la_els_rjt_t *)pkt->pkt_resp;
2027 		if (lsrjt->ls_code.ls_code == LA_ELS_RJT) {
2028 			pkt->pkt_state = FC_PKT_LS_RJT;
2029 			pkt->pkt_reason = lsrjt->reason;
2030 			pkt->pkt_action = lsrjt->action;
2031 			break;
2032 		}
2033 		/* FALLTHROUGH */
2034 	}
2035 
2036 	default:
2037 		ret = FC_FAILURE;
2038 		break;
2039 	}
2040 
2041 	return (ret);
2042 }
2043 
2044 
2045 int
2046 fc_fca_error(int fc_errno, char **errmsg)
2047 {
2048 	return (fctl_error(fc_errno, errmsg));
2049 }
2050 
2051 
2052 int
2053 fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
2054     char **action, char **expln)
2055 {
2056 	return (fctl_pkt_error(pkt, state, reason, action, expln));
2057 }
2058 
2059 
2060 /*
2061  * WWN to string goodie. Unpredictable results will happen
2062  * if enough memory isn't supplied in str argument. If you
2063  * are wondering how much does this routine need, it is just
2064  * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
2065  * argument should have atleast 17 bytes allocated.
2066  */
2067 void
2068 fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
2069 {
2070 	int count;
2071 
2072 	for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
2073 		(void) sprintf(str, "%02x", wwn->raw_wwn[count]);
2074 	}
2075 	*str = '\0';
2076 }
2077 
2078 #define	FC_ATOB(x)	(((x) >= '0' && (x) <= '9') ? ((x) - '0') :	\
2079 			((x) >= 'a' && (x) <= 'f') ?			\
2080 			((x) - 'a' + 10) : ((x) - 'A' + 10))
2081 
2082 void
2083 fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
2084 {
2085 	int count = 0;
2086 	uchar_t byte;
2087 
2088 	while (*str) {
2089 		byte = FC_ATOB(*str);
2090 		str++;
2091 		byte = byte << 4 | FC_ATOB(*str);
2092 		str++;
2093 		wwn->raw_wwn[count++] = byte;
2094 	}
2095 }
2096 
2097 /*
2098  * FCA driver's intercepted bus control operations.
2099  */
2100 static int
2101 fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
2102     ddi_ctl_enum_t op, void *arg, void *result)
2103 {
2104 	switch (op) {
2105 	case DDI_CTLOPS_REPORTDEV:
2106 		break;
2107 
2108 	case DDI_CTLOPS_IOMIN:
2109 		break;
2110 
2111 	case DDI_CTLOPS_INITCHILD:
2112 		return (fctl_initchild(fca_dip, (dev_info_t *)arg));
2113 
2114 	case DDI_CTLOPS_UNINITCHILD:
2115 		return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
2116 
2117 	default:
2118 		return (ddi_ctlops(fca_dip, rip, op, arg, result));
2119 	}
2120 
2121 	return (DDI_SUCCESS);
2122 }
2123 
2124 
2125 /*
2126  * FCAs indicate the maximum number of ports supported in their
2127  * tran structure. Fail the INITCHILD if the child port number
2128  * is any greater than the maximum number of ports supported
2129  * by the FCA.
2130  */
2131 static int
2132 fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2133 {
2134 	int		rval;
2135 	int		port_no;
2136 	int		port_len;
2137 	char		name[20];
2138 	fc_fca_tran_t	*tran;
2139 	dev_info_t	*dip;
2140 	int		portprop;
2141 
2142 	port_len = sizeof (port_no);
2143 
2144 	/* physical port do not has this property */
2145 	portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
2146 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2147 	    "phyport-instance", -1);
2148 
2149 	if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
2150 		/*
2151 		 * Clear any addr bindings created by fcode interpreter
2152 		 * in devi_last_addr so that a ndi_devi_find should never
2153 		 * return this fcode node.
2154 		 */
2155 		ddi_set_name_addr(port_dip, NULL);
2156 		return (DDI_FAILURE);
2157 	}
2158 
2159 	rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
2160 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
2161 	    (caddr_t)&port_no, &port_len);
2162 
2163 	if (rval != DDI_SUCCESS) {
2164 		return (DDI_FAILURE);
2165 	}
2166 
2167 	tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
2168 	ASSERT(tran != NULL);
2169 
2170 	(void) sprintf((char *)name, "%x,0", port_no);
2171 	ddi_set_name_addr(port_dip, name);
2172 
2173 	dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2174 
2175 	/*
2176 	 * Even though we never initialize FCode nodes of fp, such a node
2177 	 * could still be there after a DR operation. There will only be
2178 	 * one FCode node, so if this is the one, clear it and issue a
2179 	 * ndi_devi_find again.
2180 	 */
2181 	if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
2182 		ddi_set_name_addr(dip, NULL);
2183 		dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2184 	}
2185 
2186 	if ((portprop == -1) && dip && (dip != port_dip)) {
2187 		/*
2188 		 * Here we have a duplicate .conf entry. Clear the addr
2189 		 * set previously and return failure.
2190 		 */
2191 		ddi_set_name_addr(port_dip, NULL);
2192 		return (DDI_FAILURE);
2193 	}
2194 
2195 	return (DDI_SUCCESS);
2196 }
2197 
2198 
2199 /* ARGSUSED */
2200 static int
2201 fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2202 {
2203 	ddi_set_name_addr(port_dip, NULL);
2204 	return (DDI_SUCCESS);
2205 }
2206 
2207 
2208 static dev_info_t *
2209 fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
2210 {
2211 	dev_info_t *dip;
2212 	char *addr;
2213 
2214 	ASSERT(cname != NULL && caddr != NULL);
2215 	/* ASSERT(DEVI_BUSY_OWNED(pdip)); */
2216 
2217 	for (dip = ddi_get_child(pdip); dip != NULL;
2218 	    dip = ddi_get_next_sibling(dip)) {
2219 		if (strcmp(cname, ddi_node_name(dip)) != 0) {
2220 			continue;
2221 		}
2222 
2223 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
2224 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
2225 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2226 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2227 				if (strcmp(caddr, addr) == 0) {
2228 					ddi_prop_free(addr);
2229 					return (dip);
2230 				}
2231 				ddi_prop_free(addr);
2232 			}
2233 		} else {
2234 			if (strcmp(caddr, addr) == 0) {
2235 				return (dip);
2236 			}
2237 		}
2238 	}
2239 
2240 	return (NULL);
2241 }
2242 
2243 int
2244 fctl_check_npiv_portindex(dev_info_t *dip, int vindex)
2245 {
2246 	int i, instance;
2247 	fc_local_port_t *port;
2248 
2249 	instance = ddi_get_instance(dip);
2250 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2251 	if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
2252 		return (0);
2253 	}
2254 
2255 	i = vindex-1;
2256 	mutex_enter(&port->fp_mutex);
2257 	if (port->fp_npiv_portindex[i] == 0) {
2258 		mutex_exit(&port->fp_mutex);
2259 		return (vindex);
2260 	}
2261 	mutex_exit(&port->fp_mutex);
2262 	return (0);
2263 }
2264 
2265 int
2266 fctl_get_npiv_portindex(dev_info_t *dip)
2267 {
2268 	int i, instance;
2269 	fc_local_port_t *port;
2270 
2271 	instance = ddi_get_instance(dip);
2272 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2273 	if (!port) {
2274 		return (0);
2275 	}
2276 
2277 	mutex_enter(&port->fp_mutex);
2278 	for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
2279 		if (port->fp_npiv_portindex[i] == 0) {
2280 			mutex_exit(&port->fp_mutex);
2281 			return (i+1);
2282 		}
2283 	}
2284 	mutex_exit(&port->fp_mutex);
2285 	return (0);
2286 }
2287 
2288 
2289 void
2290 fctl_set_npiv_portindex(dev_info_t *dip, int index)
2291 {
2292 	int instance;
2293 	fc_local_port_t *port;
2294 
2295 	instance = ddi_get_instance(dip);
2296 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2297 	if (!port) {
2298 		return;
2299 	}
2300 	mutex_enter(&port->fp_mutex);
2301 	port->fp_npiv_portindex[index - 1] = 1;
2302 	mutex_exit(&port->fp_mutex);
2303 }
2304 
2305 
2306 int
2307 fctl_fca_create_npivport(dev_info_t *parent,
2308     dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
2309 {
2310 	int rval = 0, devstrlen;
2311 	char	*devname, *cname, *caddr, *devstr;
2312 	dev_info_t	*child = NULL;
2313 	int		portnum;
2314 
2315 	if (*vindex == 0) {
2316 		portnum = fctl_get_npiv_portindex(phydip);
2317 		*vindex = portnum;
2318 	} else {
2319 		portnum = fctl_check_npiv_portindex(phydip, *vindex);
2320 	}
2321 
2322 	if (portnum == 0) {
2323 		cmn_err(CE_WARN,
2324 		    "Cann't find valid port index, fail to create devnode");
2325 		return (NDI_FAILURE);
2326 	}
2327 
2328 	devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2329 	(void) sprintf(devname, "fp@%x,0", portnum);
2330 	devstrlen = strlen(devname) + 1;
2331 	devstr = i_ddi_strdup(devname, KM_SLEEP);
2332 	i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2333 
2334 	if (fctl_findchild(parent, cname, caddr) != NULL) {
2335 		rval = NDI_FAILURE;
2336 		goto freememory;
2337 	}
2338 
2339 	ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
2340 	if (child == NULL) {
2341 		cmn_err(CE_WARN,
2342 		    "fctl_create_npiv_port fail to create new devinfo");
2343 		rval = NDI_FAILURE;
2344 		goto freememory;
2345 	}
2346 
2347 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2348 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2349 		cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
2350 		    ddi_get_instance(parent), cname, caddr);
2351 		(void) ndi_devi_free(child);
2352 		rval = NDI_FAILURE;
2353 		goto freememory;
2354 	}
2355 
2356 	if (strlen(nname) != 0) {
2357 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2358 		    "node-name", nname) != DDI_PROP_SUCCESS) {
2359 			(void) ndi_devi_free(child);
2360 			rval = NDI_FAILURE;
2361 			goto freememory;
2362 		}
2363 	}
2364 
2365 	if (strlen(pname) != 0) {
2366 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2367 		    "port-name", pname) != DDI_PROP_SUCCESS) {
2368 			(void) ndi_devi_free(child);
2369 			rval = NDI_FAILURE;
2370 			goto freememory;
2371 		}
2372 	}
2373 
2374 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2375 	    "port", portnum) != DDI_PROP_SUCCESS) {
2376 		cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
2377 		    ddi_get_instance(parent), cname, caddr);
2378 		(void) ndi_devi_free(child);
2379 		rval = NDI_FAILURE;
2380 		goto freememory;
2381 	}
2382 
2383 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2384 	    "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
2385 		cmn_err(CE_WARN,
2386 		    "fp%d: prop_update phyport-instance %s@%s failed",
2387 		    ddi_get_instance(parent), cname, caddr);
2388 		(void) ndi_devi_free(child);
2389 		rval = NDI_FAILURE;
2390 		goto freememory;
2391 	}
2392 
2393 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
2394 	if (rval != NDI_SUCCESS) {
2395 		cmn_err(CE_WARN, "fp%d: online_driver %s failed",
2396 		    ddi_get_instance(parent), cname);
2397 		rval = NDI_FAILURE;
2398 		goto freememory;
2399 	}
2400 
2401 	fctl_set_npiv_portindex(phydip, portnum);
2402 freememory:
2403 	kmem_free(devstr, devstrlen);
2404 	kmem_free(devname, MAXNAMELEN);
2405 
2406 	return (rval);
2407 }
2408 
2409 
2410 void
2411 fctl_add_port(fc_local_port_t *port)
2412 {
2413 	fc_fca_port_t *new;
2414 
2415 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2416 
2417 	mutex_enter(&fctl_port_lock);
2418 	new->port_handle = port;
2419 	new->port_next = fctl_fca_portlist;
2420 	fctl_fca_portlist = new;
2421 	mutex_exit(&fctl_port_lock);
2422 }
2423 
2424 
2425 void
2426 fctl_remove_port(fc_local_port_t *port)
2427 {
2428 	fc_ulp_module_t		*mod;
2429 	fc_fca_port_t		*prev;
2430 	fc_fca_port_t		*list;
2431 	fc_ulp_ports_t		*ulp_port;
2432 
2433 	rw_enter(&fctl_ulp_lock, RW_WRITER);
2434 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2435 
2436 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2437 		ulp_port = fctl_get_ulp_port(mod, port);
2438 		if (ulp_port == NULL) {
2439 			continue;
2440 		}
2441 
2442 #ifndef	__lock_lint
2443 		ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2444 #endif /* __lock_lint */
2445 
2446 		(void) fctl_remove_ulp_port(mod, port);
2447 	}
2448 
2449 	rw_exit(&fctl_mod_ports_lock);
2450 	rw_exit(&fctl_ulp_lock);
2451 
2452 	mutex_enter(&fctl_port_lock);
2453 
2454 	list = fctl_fca_portlist;
2455 	prev = NULL;
2456 	while (list != NULL) {
2457 		if (list->port_handle == port) {
2458 			if (prev == NULL) {
2459 				fctl_fca_portlist = list->port_next;
2460 			} else {
2461 				prev->port_next = list->port_next;
2462 			}
2463 			kmem_free(list, sizeof (*list));
2464 			break;
2465 		}
2466 		prev = list;
2467 		list = list->port_next;
2468 	}
2469 	mutex_exit(&fctl_port_lock);
2470 }
2471 
2472 
2473 void
2474 fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
2475     struct modlinkage *linkage)
2476 {
2477 	int			rval;
2478 	uint32_t		s_id;
2479 	uint32_t		state;
2480 	fc_ulp_module_t		*mod;
2481 	fc_ulp_port_info_t	info;
2482 	fc_ulp_ports_t		*ulp_port;
2483 
2484 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
2485 
2486 	info.port_linkage = linkage;
2487 	info.port_dip = port->fp_port_dip;
2488 	info.port_handle = (opaque_t)port;
2489 	info.port_dma_behavior = port->fp_dma_behavior;
2490 	info.port_fcp_dma = port->fp_fcp_dma;
2491 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2492 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2493 	info.port_reset_action = port->fp_reset_action;
2494 
2495 	mutex_enter(&port->fp_mutex);
2496 
2497 	/*
2498 	 * It is still possible that another thread could have gotten
2499 	 * into the detach process before we got here.
2500 	 */
2501 	if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
2502 		mutex_exit(&port->fp_mutex);
2503 		return;
2504 	}
2505 
2506 	s_id = port->fp_port_id.port_id;
2507 	if (port->fp_statec_busy) {
2508 		info.port_state = port->fp_bind_state;
2509 	} else {
2510 		info.port_state = port->fp_state;
2511 	}
2512 
2513 	switch (state = FC_PORT_STATE_MASK(info.port_state)) {
2514 	case FC_STATE_LOOP:
2515 	case FC_STATE_NAMESERVICE:
2516 		info.port_state &= ~state;
2517 		info.port_state |= FC_STATE_ONLINE;
2518 		break;
2519 
2520 	default:
2521 		break;
2522 	}
2523 	ASSERT((info.port_state & FC_STATE_LOOP) == 0);
2524 
2525 	info.port_flags = port->fp_topology;
2526 	info.port_pwwn = port->fp_service_params.nport_ww_name;
2527 	info.port_nwwn = port->fp_service_params.node_ww_name;
2528 	mutex_exit(&port->fp_mutex);
2529 
2530 	rw_enter(&fctl_ulp_lock, RW_READER);
2531 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2532 
2533 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2534 		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2535 		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2536 			/*
2537 			 * We don't support IP over FC on FCOE HBA
2538 			 */
2539 			continue;
2540 		}
2541 
2542 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2543 			ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
2544 			ASSERT(ulp_port != NULL);
2545 
2546 			mutex_enter(&ulp_port->port_mutex);
2547 			ulp_port->port_statec = ((info.port_state &
2548 			    FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
2549 			    FC_ULP_STATEC_OFFLINE);
2550 			mutex_exit(&ulp_port->port_mutex);
2551 		}
2552 	}
2553 
2554 	rw_downgrade(&fctl_mod_ports_lock);
2555 
2556 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2557 		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2558 		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2559 			/*
2560 			 * We don't support IP over FC on FCOE HBA
2561 			 */
2562 			continue;
2563 		}
2564 
2565 		ulp_port = fctl_get_ulp_port(mod, port);
2566 		ASSERT(ulp_port != NULL);
2567 
2568 		if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
2569 			continue;
2570 		}
2571 
2572 		fctl_init_dma_attr(port, mod, &info);
2573 
2574 		rval = mod->mod_info->ulp_port_attach(
2575 		    mod->mod_info->ulp_handle, &info, cmd, s_id);
2576 
2577 		fctl_post_attach(mod, ulp_port, cmd, rval);
2578 
2579 		if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
2580 		    strcmp(mod->mod_info->ulp_name, "fcp") == 0) {
2581 			ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
2582 		}
2583 	}
2584 
2585 	rw_exit(&fctl_mod_ports_lock);
2586 	rw_exit(&fctl_ulp_lock);
2587 }
2588 
2589 
2590 static int
2591 fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
2592 {
2593 	int rval = FC_SUCCESS;
2594 
2595 	mutex_enter(&ulp_port->port_mutex);
2596 
2597 	switch (cmd) {
2598 	case FC_CMD_ATTACH:
2599 		if (ulp_port->port_dstate & ULP_PORT_ATTACH) {
2600 			rval = FC_FAILURE;
2601 		}
2602 		break;
2603 
2604 	case FC_CMD_RESUME:
2605 		ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
2606 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2607 		    !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) {
2608 			rval = FC_FAILURE;
2609 		}
2610 		break;
2611 
2612 	case FC_CMD_POWER_UP:
2613 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2614 		    !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
2615 			rval = FC_FAILURE;
2616 		}
2617 		break;
2618 	}
2619 
2620 	if (rval == FC_SUCCESS) {
2621 		ulp_port->port_dstate |= ULP_PORT_BUSY;
2622 	}
2623 	mutex_exit(&ulp_port->port_mutex);
2624 
2625 	return (rval);
2626 }
2627 
2628 
2629 static void
2630 fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2631     fc_attach_cmd_t cmd, int rval)
2632 {
2633 	int	be_chatty;
2634 
2635 	ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
2636 	    cmd == FC_CMD_POWER_UP);
2637 
2638 	mutex_enter(&ulp_port->port_mutex);
2639 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2640 
2641 	be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1;
2642 
2643 	if (rval != FC_SUCCESS) {
2644 		caddr_t		op;
2645 		fc_local_port_t *port = ulp_port->port_handle;
2646 
2647 		mutex_exit(&ulp_port->port_mutex);
2648 
2649 		switch (cmd) {
2650 		case FC_CMD_ATTACH:
2651 			op = "attach";
2652 			break;
2653 
2654 		case FC_CMD_RESUME:
2655 			op = "resume";
2656 			break;
2657 
2658 		case FC_CMD_POWER_UP:
2659 			op = "power up";
2660 			break;
2661 		}
2662 
2663 		if (be_chatty) {
2664 			cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2665 			    port->fp_instance, op, mod->mod_info->ulp_name);
2666 		}
2667 
2668 		return;
2669 	}
2670 
2671 	switch (cmd) {
2672 	case FC_CMD_ATTACH:
2673 		ulp_port->port_dstate |= ULP_PORT_ATTACH;
2674 		break;
2675 
2676 	case FC_CMD_RESUME:
2677 		ulp_port->port_dstate &= ~ULP_PORT_SUSPEND;
2678 		break;
2679 
2680 	case FC_CMD_POWER_UP:
2681 		ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN;
2682 		break;
2683 	}
2684 	mutex_exit(&ulp_port->port_mutex);
2685 }
2686 
2687 
2688 int
2689 fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
2690     struct modlinkage *linkage)
2691 {
2692 	int			rval = FC_SUCCESS;
2693 	fc_ulp_module_t		*mod;
2694 	fc_ulp_port_info_t	info;
2695 	fc_ulp_ports_t		*ulp_port;
2696 
2697 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
2698 
2699 	info.port_linkage = linkage;
2700 	info.port_dip = port->fp_port_dip;
2701 	info.port_handle = (opaque_t)port;
2702 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2703 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2704 
2705 	rw_enter(&fctl_ulp_lock, RW_READER);
2706 	rw_enter(&fctl_mod_ports_lock, RW_READER);
2707 
2708 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2709 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2710 			continue;
2711 		}
2712 
2713 		if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
2714 			continue;
2715 		}
2716 
2717 		fctl_init_dma_attr(port, mod, &info);
2718 
2719 		rval = mod->mod_info->ulp_port_detach(
2720 		    mod->mod_info->ulp_handle, &info, cmd);
2721 
2722 		fctl_post_detach(mod, ulp_port, cmd, rval);
2723 
2724 		if (rval != FC_SUCCESS) {
2725 			break;
2726 		}
2727 
2728 		if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
2729 		    "fcp") == 0) {
2730 			ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
2731 		}
2732 
2733 		mutex_enter(&ulp_port->port_mutex);
2734 		ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE;
2735 		mutex_exit(&ulp_port->port_mutex);
2736 	}
2737 
2738 	rw_exit(&fctl_mod_ports_lock);
2739 	rw_exit(&fctl_ulp_lock);
2740 
2741 	return (rval);
2742 }
2743 
2744 static	void
2745 fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
2746     fc_ulp_port_info_t	*info)
2747 {
2748 
2749 	if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
2750 	    (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
2751 		info->port_cmd_dma_attr =
2752 		    port->fp_fca_tran->fca_dma_fcp_cmd_attr;
2753 		info->port_data_dma_attr =
2754 		    port->fp_fca_tran->fca_dma_fcp_data_attr;
2755 		info->port_resp_dma_attr =
2756 		    port->fp_fca_tran->fca_dma_fcp_rsp_attr;
2757 	} else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
2758 		info->port_cmd_dma_attr =
2759 		    port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
2760 		info->port_data_dma_attr =
2761 		    port->fp_fca_tran->fca_dma_attr;
2762 		info->port_resp_dma_attr =
2763 		    port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
2764 	} else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
2765 		info->port_cmd_dma_attr =
2766 		    port->fp_fca_tran->fca_dma_fcip_cmd_attr;
2767 		info->port_data_dma_attr =
2768 		    port->fp_fca_tran->fca_dma_attr;
2769 		info->port_resp_dma_attr =
2770 		    port->fp_fca_tran->fca_dma_fcip_rsp_attr;
2771 	} else {
2772 		info->port_cmd_dma_attr = info->port_data_dma_attr =
2773 		    info->port_resp_dma_attr =
2774 		    port->fp_fca_tran->fca_dma_attr; /* default */
2775 	}
2776 }
2777 
2778 static int
2779 fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
2780 {
2781 	int rval = FC_SUCCESS;
2782 
2783 	mutex_enter(&ulp_port->port_mutex);
2784 
2785 	switch (cmd) {
2786 	case FC_CMD_DETACH:
2787 		if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
2788 			rval = FC_FAILURE;
2789 		}
2790 		break;
2791 
2792 	case FC_CMD_SUSPEND:
2793 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2794 		    ulp_port->port_dstate & ULP_PORT_SUSPEND) {
2795 			rval = FC_FAILURE;
2796 		}
2797 		break;
2798 
2799 	case FC_CMD_POWER_DOWN:
2800 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2801 		    ulp_port->port_dstate & ULP_PORT_POWER_DOWN) {
2802 			rval = FC_FAILURE;
2803 		}
2804 		break;
2805 	}
2806 
2807 	if (rval == FC_SUCCESS) {
2808 		ulp_port->port_dstate |= ULP_PORT_BUSY;
2809 	}
2810 	mutex_exit(&ulp_port->port_mutex);
2811 
2812 	return (rval);
2813 }
2814 
2815 
2816 static void
2817 fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2818     fc_detach_cmd_t cmd, int rval)
2819 {
2820 	ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
2821 	    cmd == FC_CMD_POWER_DOWN);
2822 
2823 	mutex_enter(&ulp_port->port_mutex);
2824 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2825 
2826 	if (rval != FC_SUCCESS) {
2827 		caddr_t		op;
2828 		fc_local_port_t *port = ulp_port->port_handle;
2829 
2830 		mutex_exit(&ulp_port->port_mutex);
2831 
2832 		switch (cmd) {
2833 		case FC_CMD_DETACH:
2834 			op = "detach";
2835 			break;
2836 
2837 		case FC_CMD_SUSPEND:
2838 			op = "suspend";
2839 			break;
2840 
2841 		case FC_CMD_POWER_DOWN:
2842 			op = "power down";
2843 			break;
2844 		}
2845 
2846 		cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2847 		    port->fp_instance, op, mod->mod_info->ulp_name);
2848 
2849 		return;
2850 	}
2851 
2852 	switch (cmd) {
2853 	case FC_CMD_DETACH:
2854 		ulp_port->port_dstate &= ~ULP_PORT_ATTACH;
2855 		break;
2856 
2857 	case FC_CMD_SUSPEND:
2858 		ulp_port->port_dstate |= ULP_PORT_SUSPEND;
2859 		break;
2860 
2861 	case FC_CMD_POWER_DOWN:
2862 		ulp_port->port_dstate |= ULP_PORT_POWER_DOWN;
2863 		break;
2864 	}
2865 	mutex_exit(&ulp_port->port_mutex);
2866 }
2867 
2868 
2869 static fc_ulp_ports_t *
2870 fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
2871     int sleep)
2872 {
2873 	fc_ulp_ports_t *last;
2874 	fc_ulp_ports_t *next;
2875 	fc_ulp_ports_t *new;
2876 
2877 	ASSERT(RW_READ_HELD(&fctl_ulp_lock));
2878 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2879 
2880 	last = NULL;
2881 	next = ulp_module->mod_ports;
2882 
2883 	while (next != NULL) {
2884 		last = next;
2885 		next = next->port_next;
2886 	}
2887 
2888 	new = fctl_alloc_ulp_port(sleep);
2889 	if (new == NULL) {
2890 		return (new);
2891 	}
2892 
2893 	new->port_handle = port_handle;
2894 	if (last == NULL) {
2895 		ulp_module->mod_ports = new;
2896 	} else {
2897 		last->port_next = new;
2898 	}
2899 
2900 	return (new);
2901 }
2902 
2903 
2904 static fc_ulp_ports_t *
2905 fctl_alloc_ulp_port(int sleep)
2906 {
2907 	fc_ulp_ports_t *new;
2908 
2909 	new = kmem_zalloc(sizeof (*new), sleep);
2910 	if (new == NULL) {
2911 		return (new);
2912 	}
2913 	mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
2914 
2915 	return (new);
2916 }
2917 
2918 
2919 static int
2920 fctl_remove_ulp_port(struct ulp_module *ulp_module,
2921     fc_local_port_t *port_handle)
2922 {
2923 	fc_ulp_ports_t *last;
2924 	fc_ulp_ports_t *next;
2925 
2926 	ASSERT(RW_WRITE_HELD(&fctl_ulp_lock));
2927 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2928 
2929 	last = NULL;
2930 	next = ulp_module->mod_ports;
2931 
2932 	while (next != NULL) {
2933 		if (next->port_handle == port_handle) {
2934 			if (next->port_dstate & ULP_PORT_ATTACH) {
2935 				return (FC_FAILURE);
2936 			}
2937 			break;
2938 		}
2939 		last = next;
2940 		next = next->port_next;
2941 	}
2942 
2943 	if (next != NULL) {
2944 		ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
2945 
2946 		if (last == NULL) {
2947 			ulp_module->mod_ports = next->port_next;
2948 		} else {
2949 			last->port_next = next->port_next;
2950 		}
2951 		fctl_dealloc_ulp_port(next);
2952 
2953 		return (FC_SUCCESS);
2954 	} else {
2955 		return (FC_FAILURE);
2956 	}
2957 }
2958 
2959 
2960 static void
2961 fctl_dealloc_ulp_port(fc_ulp_ports_t *next)
2962 {
2963 	mutex_destroy(&next->port_mutex);
2964 	kmem_free(next, sizeof (*next));
2965 }
2966 
2967 
2968 static fc_ulp_ports_t *
2969 fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
2970 {
2971 	fc_ulp_ports_t *next;
2972 
2973 	ASSERT(RW_LOCK_HELD(&fctl_ulp_lock));
2974 	ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock));
2975 
2976 	for (next = ulp_module->mod_ports; next != NULL;
2977 	    next = next->port_next) {
2978 		if (next->port_handle == port_handle) {
2979 			return (next);
2980 		}
2981 	}
2982 
2983 	return (NULL);
2984 }
2985 
2986 
2987 /*
2988  * Pass state change notfications on to registered ULPs.
2989  *
2990  * Can issue wakeups to client callers who might be waiting for completions
2991  * on other threads.
2992  *
2993  * Caution: will silently deallocate any fc_remote_port_t and/or
2994  * fc_remote_node_t structs it finds that are not in use.
2995  */
2996 void
2997 fctl_ulp_statec_cb(void *arg)
2998 {
2999 	uint32_t		s_id;
3000 	uint32_t		new_state;
3001 	fc_local_port_t		*port;
3002 	fc_ulp_ports_t		*ulp_port;
3003 	fc_ulp_module_t		*mod;
3004 	fc_port_clist_t		*clist = (fc_port_clist_t *)arg;
3005 
3006 	ASSERT(clist != NULL);
3007 
3008 	port = clist->clist_port;
3009 
3010 	mutex_enter(&port->fp_mutex);
3011 	s_id = port->fp_port_id.port_id;
3012 	mutex_exit(&port->fp_mutex);
3013 
3014 	switch (clist->clist_state) {
3015 	case FC_STATE_ONLINE:
3016 		new_state = FC_ULP_STATEC_ONLINE;
3017 		break;
3018 
3019 	case FC_STATE_OFFLINE:
3020 		if (clist->clist_len) {
3021 			new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT;
3022 		} else {
3023 			new_state = FC_ULP_STATEC_OFFLINE;
3024 		}
3025 		break;
3026 
3027 	default:
3028 		new_state = FC_ULP_STATEC_DONT_CARE;
3029 		break;
3030 	}
3031 
3032 #ifdef	DEBUG
3033 	/*
3034 	 * sanity check for presence of OLD devices in the hash lists
3035 	 */
3036 	if (clist->clist_size) {
3037 		int			count;
3038 		fc_remote_port_t	*pd;
3039 
3040 		ASSERT(clist->clist_map != NULL);
3041 		for (count = 0; count < clist->clist_len; count++) {
3042 			if (clist->clist_map[count].map_state ==
3043 			    PORT_DEVICE_INVALID) {
3044 				la_wwn_t	pwwn;
3045 				fc_portid_t	d_id;
3046 
3047 				pd = clist->clist_map[count].map_pd;
3048 				if (pd != NULL) {
3049 					mutex_enter(&pd->pd_mutex);
3050 					pwwn = pd->pd_port_name;
3051 					d_id = pd->pd_port_id;
3052 					mutex_exit(&pd->pd_mutex);
3053 
3054 					pd = fctl_get_remote_port_by_pwwn(port,
3055 					    &pwwn);
3056 
3057 					ASSERT(pd != clist->clist_map[count].
3058 					    map_pd);
3059 
3060 					pd = fctl_get_remote_port_by_did(port,
3061 					    d_id.port_id);
3062 					ASSERT(pd != clist->clist_map[count].
3063 					    map_pd);
3064 				}
3065 			}
3066 		}
3067 	}
3068 #endif
3069 
3070 	/*
3071 	 * Check for duplicate map entries
3072 	 */
3073 	if (clist->clist_size) {
3074 		int			count;
3075 		fc_remote_port_t	*pd1, *pd2;
3076 
3077 		ASSERT(clist->clist_map != NULL);
3078 		for (count = 0; count < clist->clist_len-1; count++) {
3079 			int count2;
3080 
3081 			pd1 = clist->clist_map[count].map_pd;
3082 			if (pd1 == NULL) {
3083 				continue;
3084 			}
3085 
3086 			for (count2 = count+1;
3087 			    count2 < clist->clist_len;
3088 			    count2++) {
3089 
3090 				pd2 = clist->clist_map[count2].map_pd;
3091 				if (pd2 == NULL) {
3092 					continue;
3093 				}
3094 
3095 				if (pd1 == pd2) {
3096 					clist->clist_map[count].map_flags |=
3097 					    PORT_DEVICE_DUPLICATE_MAP_ENTRY;
3098 					break;
3099 				}
3100 			}
3101 		}
3102 	}
3103 
3104 
3105 	rw_enter(&fctl_ulp_lock, RW_READER);
3106 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
3107 		rw_enter(&fctl_mod_ports_lock, RW_READER);
3108 		ulp_port = fctl_get_ulp_port(mod, port);
3109 		rw_exit(&fctl_mod_ports_lock);
3110 
3111 		if (ulp_port == NULL) {
3112 			continue;
3113 		}
3114 
3115 		mutex_enter(&ulp_port->port_mutex);
3116 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
3117 			mutex_exit(&ulp_port->port_mutex);
3118 			continue;
3119 		}
3120 
3121 		switch (ulp_port->port_statec) {
3122 		case FC_ULP_STATEC_DONT_CARE:
3123 			if (ulp_port->port_statec != new_state) {
3124 				ulp_port->port_statec = new_state;
3125 			}
3126 			break;
3127 
3128 		case FC_ULP_STATEC_ONLINE:
3129 		case FC_ULP_STATEC_OFFLINE:
3130 			if (ulp_port->port_statec == new_state) {
3131 				mutex_exit(&ulp_port->port_mutex);
3132 				continue;
3133 			}
3134 			ulp_port->port_statec = new_state;
3135 			break;
3136 
3137 		case FC_ULP_STATEC_OFFLINE_TIMEOUT:
3138 			if (ulp_port->port_statec == new_state ||
3139 			    new_state == FC_ULP_STATEC_OFFLINE) {
3140 				mutex_exit(&ulp_port->port_mutex);
3141 				continue;
3142 			}
3143 			ulp_port->port_statec = new_state;
3144 			break;
3145 
3146 		default:
3147 			ASSERT(0);
3148 			break;
3149 		}
3150 
3151 		mod->mod_info->ulp_statec_callback(
3152 		    mod->mod_info->ulp_handle, (opaque_t)port,
3153 		    clist->clist_state, clist->clist_flags,
3154 		    clist->clist_map, clist->clist_len, s_id);
3155 
3156 		mutex_exit(&ulp_port->port_mutex);
3157 	}
3158 	rw_exit(&fctl_ulp_lock);
3159 
3160 	if (clist->clist_size) {
3161 		int			count;
3162 		fc_remote_node_t	*node;
3163 		fc_remote_port_t	*pd;
3164 
3165 		ASSERT(clist->clist_map != NULL);
3166 		for (count = 0; count < clist->clist_len; count++) {
3167 
3168 			if ((pd = clist->clist_map[count].map_pd) == NULL) {
3169 				continue;
3170 			}
3171 
3172 			mutex_enter(&pd->pd_mutex);
3173 
3174 			pd->pd_ref_count--;
3175 			ASSERT(pd->pd_ref_count >= 0);
3176 
3177 			if (clist->clist_map[count].map_state !=
3178 			    PORT_DEVICE_INVALID) {
3179 				mutex_exit(&pd->pd_mutex);
3180 				continue;
3181 			}
3182 
3183 			node = pd->pd_remote_nodep;
3184 			pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS;
3185 
3186 			mutex_exit(&pd->pd_mutex);
3187 
3188 			/*
3189 			 * This fc_remote_port_t is no longer referenced
3190 			 * by any ULPs. Deallocate it if its pd_ref_count
3191 			 * has reached zero.
3192 			 */
3193 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
3194 			    (node != NULL)) {
3195 				fctl_destroy_remote_node(node);
3196 			}
3197 		}
3198 
3199 		kmem_free(clist->clist_map,
3200 		    sizeof (*(clist->clist_map)) * clist->clist_size);
3201 	}
3202 
3203 	if (clist->clist_wait) {
3204 		mutex_enter(&clist->clist_mutex);
3205 		clist->clist_wait = 0;
3206 		cv_signal(&clist->clist_cv);
3207 		mutex_exit(&clist->clist_mutex);
3208 	} else {
3209 		kmem_free(clist, sizeof (*clist));
3210 	}
3211 }
3212 
3213 
3214 /*
3215  * Allocate an fc_remote_node_t struct to represent a remote node for the
3216  * given nwwn.	This will also add the nwwn to the global nwwn table.
3217  *
3218  * Returns a pointer to the newly-allocated struct.  Returns NULL if
3219  * the kmem_zalloc fails or if the enlist_wwn attempt fails.
3220  */
3221 fc_remote_node_t *
3222 fctl_create_remote_node(la_wwn_t *nwwn, int sleep)
3223 {
3224 	fc_remote_node_t *rnodep;
3225 
3226 	if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
3227 		return (NULL);
3228 	}
3229 
3230 	mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
3231 
3232 	rnodep->fd_node_name = *nwwn;
3233 	rnodep->fd_flags = FC_REMOTE_NODE_VALID;
3234 	rnodep->fd_numports = 1;
3235 
3236 	if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
3237 		mutex_destroy(&rnodep->fd_mutex);
3238 		kmem_free(rnodep, sizeof (*rnodep));
3239 		return (NULL);
3240 	}
3241 
3242 	return (rnodep);
3243 }
3244 
3245 /*
3246  * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
3247  * Silently skips the deconstruct/free if there are any fc_remote_port_t
3248  * (remote port device) structs still referenced by the given
3249  * fc_remote_node_t struct.
3250  */
3251 void
3252 fctl_destroy_remote_node(fc_remote_node_t *rnodep)
3253 {
3254 	mutex_enter(&rnodep->fd_mutex);
3255 
3256 	/*
3257 	 * Look at the count and linked list of of remote ports
3258 	 * (fc_remote_port_t structs); bail if these indicate that
3259 	 * given fc_remote_node_t may be in use.
3260 	 */
3261 	if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
3262 		mutex_exit(&rnodep->fd_mutex);
3263 		return;
3264 	}
3265 
3266 	mutex_exit(&rnodep->fd_mutex);
3267 
3268 	mutex_destroy(&rnodep->fd_mutex);
3269 	kmem_free(rnodep, sizeof (*rnodep));
3270 }
3271 
3272 
3273 /*
3274  * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
3275  * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3276  * This only fails if the kmem_zalloc fails.  This does not check for a
3277  * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
3278  * This is only called from fctl_create_remote_node().
3279  */
3280 int
3281 fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
3282 {
3283 	int			index;
3284 	fctl_nwwn_elem_t	*new;
3285 	fctl_nwwn_list_t	*head;
3286 
3287 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3288 
3289 	if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
3290 		return (FC_FAILURE);
3291 	}
3292 
3293 	mutex_enter(&fctl_nwwn_hash_mutex);
3294 	new->fne_nodep = rnodep;
3295 
3296 	mutex_enter(&rnodep->fd_mutex);
3297 	ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
3298 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3299 	    fctl_nwwn_table_size);
3300 	mutex_exit(&rnodep->fd_mutex);
3301 
3302 	head = &fctl_nwwn_hash_table[index];
3303 
3304 	/* Link it in at the head of the hash list */
3305 	new->fne_nextp = head->fnl_headp;
3306 	head->fnl_headp = new;
3307 
3308 	mutex_exit(&fctl_nwwn_hash_mutex);
3309 
3310 	return (FC_SUCCESS);
3311 }
3312 
3313 
3314 /*
3315  * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
3316  * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3317  */
3318 void
3319 fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
3320 {
3321 	int			index;
3322 	fctl_nwwn_list_t	*head;
3323 	fctl_nwwn_elem_t	*elem;
3324 	fctl_nwwn_elem_t	*prev;
3325 
3326 	ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
3327 	ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
3328 
3329 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3330 	    fctl_nwwn_table_size);
3331 
3332 	head = &fctl_nwwn_hash_table[index];
3333 	elem = head->fnl_headp;
3334 	prev = NULL;
3335 
3336 	while (elem != NULL) {
3337 		if (elem->fne_nodep == rnodep) {
3338 			/*
3339 			 * Found it -- unlink it from the list & decrement
3340 			 * the count for the hash chain.
3341 			 */
3342 			if (prev == NULL) {
3343 				head->fnl_headp = elem->fne_nextp;
3344 			} else {
3345 				prev->fne_nextp = elem->fne_nextp;
3346 			}
3347 			break;
3348 		}
3349 		prev = elem;
3350 		elem = elem->fne_nextp;
3351 	}
3352 
3353 	if (elem != NULL) {
3354 		kmem_free(elem, sizeof (*elem));
3355 	}
3356 }
3357 
3358 
3359 /*
3360  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3361  * Looks in the global fctl_nwwn_hash_table[]. Identical to the
3362  * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
3363  * the fc_count reference count in the f_device_t before returning.
3364  *
3365  * This function is called by: fctl_create_remote_port_t().
3366  *
3367  * OLD COMMENT:
3368  * Note: The calling thread needs to make sure it isn't holding any device
3369  * mutex (more so the fc_remote_node_t that could potentially have this wwn).
3370  */
3371 fc_remote_node_t *
3372 fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
3373 {
3374 	int			index;
3375 	fctl_nwwn_elem_t	*elem;
3376 	fc_remote_node_t	*next;
3377 	fc_remote_node_t	*rnodep = NULL;
3378 
3379 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3380 	    fctl_nwwn_table_size);
3381 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3382 
3383 	mutex_enter(&fctl_nwwn_hash_mutex);
3384 	elem = fctl_nwwn_hash_table[index].fnl_headp;
3385 	while (elem != NULL) {
3386 		next = elem->fne_nodep;
3387 		if (next != NULL) {
3388 			mutex_enter(&next->fd_mutex);
3389 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3390 				rnodep = next;
3391 				mutex_exit(&next->fd_mutex);
3392 				break;
3393 			}
3394 			mutex_exit(&next->fd_mutex);
3395 		}
3396 		elem = elem->fne_nextp;
3397 	}
3398 	mutex_exit(&fctl_nwwn_hash_mutex);
3399 
3400 	return (rnodep);
3401 }
3402 
3403 
3404 /*
3405  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3406  * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
3407  * reference count in the f_device_t before returning.
3408  *
3409  * This function is only called by fctl_create_remote_port_t().
3410  */
3411 fc_remote_node_t *
3412 fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
3413 {
3414 	int			index;
3415 	fctl_nwwn_elem_t	*elem;
3416 	fc_remote_node_t	*next;
3417 	fc_remote_node_t	*rnodep = NULL;
3418 
3419 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3420 	    fctl_nwwn_table_size);
3421 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3422 
3423 	mutex_enter(&fctl_nwwn_hash_mutex);
3424 	elem = fctl_nwwn_hash_table[index].fnl_headp;
3425 	while (elem != NULL) {
3426 		next = elem->fne_nodep;
3427 		if (next != NULL) {
3428 			mutex_enter(&next->fd_mutex);
3429 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3430 				rnodep = next;
3431 				rnodep->fd_numports++;
3432 				mutex_exit(&next->fd_mutex);
3433 				break;
3434 			}
3435 			mutex_exit(&next->fd_mutex);
3436 		}
3437 		elem = elem->fne_nextp;
3438 	}
3439 	mutex_exit(&fctl_nwwn_hash_mutex);
3440 
3441 	return (rnodep);
3442 }
3443 
3444 
3445 /*
3446  * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
3447  * the newly allocated struct.	Only fails if the kmem_zalloc() fails.
3448  */
3449 fc_remote_port_t *
3450 fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
3451     uint32_t d_id, uchar_t recepient, int sleep)
3452 {
3453 	fc_remote_port_t *pd;
3454 
3455 	ASSERT(MUTEX_HELD(&port->fp_mutex));
3456 	ASSERT(FC_IS_REAL_DEVICE(d_id));
3457 
3458 	if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
3459 		return (NULL);
3460 	}
3461 	fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
3462 	    FC_LOGO_TOLERANCE_TIME_LIMIT);
3463 
3464 	mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
3465 
3466 	pd->pd_port_id.port_id = d_id;
3467 	pd->pd_port_name = *port_wwn;
3468 	pd->pd_port = port;
3469 	pd->pd_state = PORT_DEVICE_VALID;
3470 	pd->pd_type = PORT_DEVICE_NEW;
3471 	pd->pd_recepient = recepient;
3472 
3473 	return (pd);
3474 }
3475 
3476 
3477 /*
3478  * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
3479  */
3480 void
3481 fctl_dealloc_remote_port(fc_remote_port_t *pd)
3482 {
3483 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3484 
3485 	fctl_tc_destructor(&pd->pd_logo_tc);
3486 	mutex_destroy(&pd->pd_mutex);
3487 	kmem_free(pd, sizeof (*pd));
3488 }
3489 
3490 /*
3491  * Add the given fc_remote_port_t onto the linked list of remote port
3492  * devices associated with the given fc_remote_node_t. Does NOT add the
3493  * fc_remote_port_t to the list if already exists on the list.
3494  */
3495 void
3496 fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
3497     fc_remote_port_t *pd)
3498 {
3499 	fc_remote_port_t *last;
3500 	fc_remote_port_t *ports;
3501 
3502 	mutex_enter(&rnodep->fd_mutex);
3503 
3504 	last = NULL;
3505 	for (ports = rnodep->fd_portlistp; ports != NULL;
3506 	    ports = ports->pd_port_next) {
3507 		if (ports == pd) {
3508 			/*
3509 			 * The given fc_remote_port_t is already on the linked
3510 			 * list chain for the given remote node, so bail now.
3511 			 */
3512 			mutex_exit(&rnodep->fd_mutex);
3513 			return;
3514 		}
3515 		last = ports;
3516 	}
3517 
3518 	/* Add the fc_remote_port_t to the tail of the linked list */
3519 	if (last != NULL) {
3520 		last->pd_port_next = pd;
3521 	} else {
3522 		rnodep->fd_portlistp = pd;
3523 	}
3524 	pd->pd_port_next = NULL;
3525 
3526 	/*
3527 	 * Link the fc_remote_port_t back to the associated fc_remote_node_t.
3528 	 */
3529 	mutex_enter(&pd->pd_mutex);
3530 	pd->pd_remote_nodep = rnodep;
3531 	mutex_exit(&pd->pd_mutex);
3532 
3533 	mutex_exit(&rnodep->fd_mutex);
3534 }
3535 
3536 
3537 /*
3538  * Remove the specified fc_remote_port_t from the linked list of remote ports
3539  * for the given fc_remote_node_t.
3540  *
3541  * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
3542  * list of the fc_remote_node_t.
3543  *
3544  * The fd_numports on the given fc_remote_node_t is decremented, and if
3545  * it hits zero then this function also removes the fc_remote_node_t from the
3546  * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
3547  * are removed from the fctl_nwwn_hash_table[].
3548  */
3549 int
3550 fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
3551     fc_remote_port_t *pd)
3552 {
3553 	int			rcount = 0;
3554 	fc_remote_port_t	*last;
3555 	fc_remote_port_t	*ports;
3556 
3557 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3558 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3559 
3560 	last = NULL;
3561 
3562 	mutex_enter(&fctl_nwwn_hash_mutex);
3563 
3564 	mutex_enter(&rnodep->fd_mutex);
3565 
3566 	/*
3567 	 * Go thru the linked list of fc_remote_port_t structs for the given
3568 	 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
3569 	 */
3570 	ports = rnodep->fd_portlistp;
3571 	while (ports != NULL) {
3572 		if (ports == pd) {
3573 			break;	/* Found the requested fc_remote_port_t */
3574 		}
3575 		last = ports;
3576 		ports = ports->pd_port_next;
3577 	}
3578 
3579 	if (ports) {
3580 		rcount = --rnodep->fd_numports;
3581 		if (rcount == 0) {
3582 			/* Note: this is only ever called from here */
3583 			fctl_delist_nwwn_table(rnodep);
3584 		}
3585 		if (last) {
3586 			last->pd_port_next = pd->pd_port_next;
3587 		} else {
3588 			rnodep->fd_portlistp = pd->pd_port_next;
3589 		}
3590 		mutex_enter(&pd->pd_mutex);
3591 		pd->pd_remote_nodep = NULL;
3592 		mutex_exit(&pd->pd_mutex);
3593 	}
3594 
3595 	pd->pd_port_next = NULL;
3596 
3597 	mutex_exit(&rnodep->fd_mutex);
3598