xref: /onnv-gate/usr/src/uts/common/io/fibre-channel/impl/fctl.c (revision 11922:56b5cca5a009)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*11922SSriram.Popuri@sun.com  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  *
257836SJohn.Forte@Sun.COM  * Fibre channel Transport Library (fctl)
267836SJohn.Forte@Sun.COM  *
277836SJohn.Forte@Sun.COM  * Function naming conventions:
287836SJohn.Forte@Sun.COM  *		Functions called from ULPs begin with fc_ulp_
297836SJohn.Forte@Sun.COM  *		Functions called from FCAs begin with fc_fca_
307836SJohn.Forte@Sun.COM  *		Internal functions begin with fctl_
317836SJohn.Forte@Sun.COM  *
327836SJohn.Forte@Sun.COM  * Fibre channel packet layout:
3310264SZhong.Wang@Sun.COM  *	  +---------------------+<--------+
3410264SZhong.Wang@Sun.COM  *	  |			|	  |
3510264SZhong.Wang@Sun.COM  *	  | ULP Packet private	|	  |
3610264SZhong.Wang@Sun.COM  *	  |			|	  |
3710264SZhong.Wang@Sun.COM  *	  +---------------------+	  |
3810264SZhong.Wang@Sun.COM  *	  |			|---------+
3910264SZhong.Wang@Sun.COM  *	  |  struct  fc_packet	|---------+
4010264SZhong.Wang@Sun.COM  *	  |			|	  |
4110264SZhong.Wang@Sun.COM  *	  +---------------------+<--------+
4210264SZhong.Wang@Sun.COM  *	  |			|
4310264SZhong.Wang@Sun.COM  *	  | FCA Packet private	|
4410264SZhong.Wang@Sun.COM  *	  |			|
4510264SZhong.Wang@Sun.COM  *	  +---------------------+
467836SJohn.Forte@Sun.COM  *
4710264SZhong.Wang@Sun.COM  * So you  loved  the  ascii  art ?  It's  strongly  desirable	to  cache
487836SJohn.Forte@Sun.COM  * allocate the entire packet in one common  place.  So we define a set a
4910264SZhong.Wang@Sun.COM  * of rules.  In a  contiguous	block of memory,  the top  portion of the
5010264SZhong.Wang@Sun.COM  * block points to ulp packet  private	area, next follows the	fc_packet
517836SJohn.Forte@Sun.COM  * structure used  extensively by all the consumers and what follows this
5210264SZhong.Wang@Sun.COM  * is the FCA packet private.  Note that given a packet	 structure, it is
5310264SZhong.Wang@Sun.COM  * possible  to get to the  ULP	 and  FCA  Packet  private  fields  using
547836SJohn.Forte@Sun.COM  * ulp_private and fca_private fields (which hold pointers) respectively.
557836SJohn.Forte@Sun.COM  *
567836SJohn.Forte@Sun.COM  * It should be noted with a grain of salt that ULP Packet  private  size
577836SJohn.Forte@Sun.COM  * varies  between two different  ULP types, So this poses a challenge to
5810264SZhong.Wang@Sun.COM  * compute the correct	size of the whole block on a per port basis.  The
597836SJohn.Forte@Sun.COM  * transport  layer  doesn't have a problem in dealing with  FCA   packet
607836SJohn.Forte@Sun.COM  * private  sizes as it is the sole  manager of ports  underneath.  Since
617836SJohn.Forte@Sun.COM  * it's not a good idea to cache allocate  different  sizes of memory for
627836SJohn.Forte@Sun.COM  * different ULPs and have the ability to choose from one of these caches
637836SJohn.Forte@Sun.COM  * based on ULP type during every packet  allocation,  the transport some
6410264SZhong.Wang@Sun.COM  * what	 wisely (?)  hands off this job of cache  allocation  to the ULPs
657836SJohn.Forte@Sun.COM  * themselves.
667836SJohn.Forte@Sun.COM  *
677836SJohn.Forte@Sun.COM  * That means FCAs need to make their  packet  private size  known to the
6810264SZhong.Wang@Sun.COM  * transport   to  pass	 it  up	 to  the   ULPs.  This	is  done   during
697836SJohn.Forte@Sun.COM  * fc_fca_attach().  And the transport passes this size up to ULPs during
707836SJohn.Forte@Sun.COM  * fc_ulp_port_attach() of each ULP.
717836SJohn.Forte@Sun.COM  *
7210264SZhong.Wang@Sun.COM  * This	 leaves	 us with  another  possible  question;	How  are  packets
7310264SZhong.Wang@Sun.COM  * allocated for ELS's started by the transport	 itself ?  Well, the port
7410264SZhong.Wang@Sun.COM  * driver  during  attach  time, cache	allocates  on a per port basis to
757836SJohn.Forte@Sun.COM  * handle ELSs too.
767836SJohn.Forte@Sun.COM  */
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM #include <sys/note.h>
797836SJohn.Forte@Sun.COM #include <sys/types.h>
807836SJohn.Forte@Sun.COM #include <sys/varargs.h>
817836SJohn.Forte@Sun.COM #include <sys/param.h>
827836SJohn.Forte@Sun.COM #include <sys/errno.h>
837836SJohn.Forte@Sun.COM #include <sys/uio.h>
847836SJohn.Forte@Sun.COM #include <sys/buf.h>
857836SJohn.Forte@Sun.COM #include <sys/modctl.h>
867836SJohn.Forte@Sun.COM #include <sys/open.h>
877836SJohn.Forte@Sun.COM #include <sys/kmem.h>
887836SJohn.Forte@Sun.COM #include <sys/poll.h>
897836SJohn.Forte@Sun.COM #include <sys/conf.h>
907836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
917836SJohn.Forte@Sun.COM #include <sys/stat.h>
927836SJohn.Forte@Sun.COM #include <sys/ddi.h>
937836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
947836SJohn.Forte@Sun.COM #include <sys/promif.h>
957836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
967836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fc.h>
977836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_ulpif.h>
987836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_fcaif.h>
997836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fctl_private.h>
1007836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_portif.h>
1017836SJohn.Forte@Sun.COM 
1027836SJohn.Forte@Sun.COM /* These are referenced by fp.c!  */
1037836SJohn.Forte@Sun.COM int did_table_size = D_ID_HASH_TABLE_SIZE;
1047836SJohn.Forte@Sun.COM int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
1057836SJohn.Forte@Sun.COM 
10610264SZhong.Wang@Sun.COM static fc_ulp_module_t	*fctl_ulp_modules;
10710264SZhong.Wang@Sun.COM static fc_fca_port_t	*fctl_fca_portlist;
1087836SJohn.Forte@Sun.COM static fc_ulp_list_t	*fctl_ulp_list;
1097836SJohn.Forte@Sun.COM 
1107836SJohn.Forte@Sun.COM static char fctl_greeting[] =
1117836SJohn.Forte@Sun.COM 	"fctl: %s ULP same type (0x%x) as existing module.\n";
1127836SJohn.Forte@Sun.COM 
1137836SJohn.Forte@Sun.COM static char *fctl_undefined = "Undefined";
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM /*
1167836SJohn.Forte@Sun.COM  * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
1177836SJohn.Forte@Sun.COM  */
1187836SJohn.Forte@Sun.COM 
1197836SJohn.Forte@Sun.COM static krwlock_t fctl_ulp_lock;
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM /*
1227836SJohn.Forte@Sun.COM  * The fctl_mod_ports_lock protects the mod_ports element in the
1237836SJohn.Forte@Sun.COM  * fc_ulp_ports_t structure
1247836SJohn.Forte@Sun.COM  */
1257836SJohn.Forte@Sun.COM 
1267836SJohn.Forte@Sun.COM static krwlock_t fctl_mod_ports_lock;
1277836SJohn.Forte@Sun.COM 
1287836SJohn.Forte@Sun.COM /*
1297836SJohn.Forte@Sun.COM  * fctl_port_lock protects the linked list of local port structures
13010264SZhong.Wang@Sun.COM  * (fctl_fca_portlist).	 When walking the list, this lock must be obtained
1317836SJohn.Forte@Sun.COM  * prior to any local port locks.
1327836SJohn.Forte@Sun.COM  */
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM static kmutex_t fctl_port_lock;
1357836SJohn.Forte@Sun.COM static kmutex_t	fctl_ulp_list_mutex;
1367836SJohn.Forte@Sun.COM 
1377836SJohn.Forte@Sun.COM static fctl_nwwn_list_t		*fctl_nwwn_hash_table;
1387836SJohn.Forte@Sun.COM static kmutex_t			fctl_nwwn_hash_mutex;
1397836SJohn.Forte@Sun.COM int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
1407836SJohn.Forte@Sun.COM 
1417836SJohn.Forte@Sun.COM #if	!defined(lint)
1427836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_nwwn_hash_mutex, fctl_nwwn_hash_table))
1437836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(fctl_ulp_list_mutex, fctl_ulp_list))
1447836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_ulp_lock, ulp_module::mod_next))
1457836SJohn.Forte@Sun.COM _NOTE(RWLOCK_PROTECTS_DATA(fctl_mod_ports_lock, ulp_module::mod_ports
1467836SJohn.Forte@Sun.COM     ulp_ports::port_handle))
1477836SJohn.Forte@Sun.COM _NOTE(DATA_READABLE_WITHOUT_LOCK(ulp_module::mod_info))
1487836SJohn.Forte@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
1497836SJohn.Forte@Sun.COM     ulp_ports::port_dstate))
1507836SJohn.Forte@Sun.COM #endif /* lint */
1517836SJohn.Forte@Sun.COM 
15210264SZhong.Wang@Sun.COM #define	FCTL_VERSION		"20090729-1.70"
1537836SJohn.Forte@Sun.COM #define	FCTL_NAME_VERSION	"SunFC Transport v" FCTL_VERSION
1547836SJohn.Forte@Sun.COM 
1557836SJohn.Forte@Sun.COM char *fctl_version = FCTL_NAME_VERSION;
1567836SJohn.Forte@Sun.COM 
1577836SJohn.Forte@Sun.COM extern struct mod_ops mod_miscops;
1587836SJohn.Forte@Sun.COM 
1597836SJohn.Forte@Sun.COM static struct modlmisc modlmisc = {
1607836SJohn.Forte@Sun.COM 	&mod_miscops,			/* type of module */
1617836SJohn.Forte@Sun.COM 	FCTL_NAME_VERSION		/* Module name */
1627836SJohn.Forte@Sun.COM };
1637836SJohn.Forte@Sun.COM 
1647836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
1657836SJohn.Forte@Sun.COM 	MODREV_1, (void *)&modlmisc, NULL
1667836SJohn.Forte@Sun.COM };
1677836SJohn.Forte@Sun.COM 
1687836SJohn.Forte@Sun.COM static struct bus_ops fctl_fca_busops = {
1697836SJohn.Forte@Sun.COM 	BUSO_REV,
1707836SJohn.Forte@Sun.COM 	nullbusmap,			/* bus_map */
1717836SJohn.Forte@Sun.COM 	NULL,				/* bus_get_intrspec */
1727836SJohn.Forte@Sun.COM 	NULL,				/* bus_add_intrspec */
1737836SJohn.Forte@Sun.COM 	NULL,				/* bus_remove_intrspec */
1747836SJohn.Forte@Sun.COM 	i_ddi_map_fault,		/* bus_map_fault */
1757836SJohn.Forte@Sun.COM 	ddi_dma_map,			/* bus_dma_map */
1767836SJohn.Forte@Sun.COM 	ddi_dma_allochdl,		/* bus_dma_allochdl */
1777836SJohn.Forte@Sun.COM 	ddi_dma_freehdl,		/* bus_dma_freehdl */
1787836SJohn.Forte@Sun.COM 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
1797836SJohn.Forte@Sun.COM 	ddi_dma_unbindhdl,		/* bus_unbindhdl */
1807836SJohn.Forte@Sun.COM 	ddi_dma_flush,			/* bus_dma_flush */
1817836SJohn.Forte@Sun.COM 	ddi_dma_win,			/* bus_dma_win */
1827836SJohn.Forte@Sun.COM 	ddi_dma_mctl,			/* bus_dma_ctl */
1837836SJohn.Forte@Sun.COM 	fctl_fca_bus_ctl,		/* bus_ctl */
1847836SJohn.Forte@Sun.COM 	ddi_bus_prop_op,		/* bus_prop_op */
1857836SJohn.Forte@Sun.COM 	NULL,				/* bus_get_eventcookie */
1867836SJohn.Forte@Sun.COM 	NULL,				/* bus_add_eventcall */
1877836SJohn.Forte@Sun.COM 	NULL,				/* bus_remove_event */
1887836SJohn.Forte@Sun.COM 	NULL,				/* bus_post_event */
1897836SJohn.Forte@Sun.COM 	NULL,				/* bus_intr_ctl */
1907836SJohn.Forte@Sun.COM 	NULL,				/* bus_config */
1917836SJohn.Forte@Sun.COM 	NULL,				/* bus_unconfig */
1927836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_init */
1937836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_fini */
1947836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_access_enter */
1957836SJohn.Forte@Sun.COM 	NULL,				/* bus_fm_access_exit */
1967836SJohn.Forte@Sun.COM 	NULL,				/* bus_power */
1977836SJohn.Forte@Sun.COM 	NULL
1987836SJohn.Forte@Sun.COM };
1997836SJohn.Forte@Sun.COM 
2007836SJohn.Forte@Sun.COM struct kmem_cache *fctl_job_cache;
2017836SJohn.Forte@Sun.COM 
2027836SJohn.Forte@Sun.COM static fc_errmap_t fc_errlist [] = {
20310264SZhong.Wang@Sun.COM 	{ FC_FAILURE,		"Operation failed"			},
20410264SZhong.Wang@Sun.COM 	{ FC_SUCCESS,		"Operation success"			},
20510264SZhong.Wang@Sun.COM 	{ FC_CAP_ERROR,		"Capability error"			},
20610264SZhong.Wang@Sun.COM 	{ FC_CAP_FOUND,		"Capability found"			},
20710264SZhong.Wang@Sun.COM 	{ FC_CAP_SETTABLE,	"Capability settable"			},
20810264SZhong.Wang@Sun.COM 	{ FC_UNBOUND,		"Port not bound"			},
20910264SZhong.Wang@Sun.COM 	{ FC_NOMEM,		"No memory"				},
21010264SZhong.Wang@Sun.COM 	{ FC_BADPACKET,		"Bad packet"				},
21110264SZhong.Wang@Sun.COM 	{ FC_OFFLINE,		"Port offline"				},
21210264SZhong.Wang@Sun.COM 	{ FC_OLDPORT,		"Old Port"				},
21310264SZhong.Wang@Sun.COM 	{ FC_NO_MAP,		"No map available"			},
21410264SZhong.Wang@Sun.COM 	{ FC_TRANSPORT_ERROR,	"Transport error"			},
21510264SZhong.Wang@Sun.COM 	{ FC_ELS_FREJECT,	"ELS Frejected"				},
21610264SZhong.Wang@Sun.COM 	{ FC_ELS_PREJECT,	"ELS PRejected"				},
21710264SZhong.Wang@Sun.COM 	{ FC_ELS_BAD,		"Bad ELS request"			},
21810264SZhong.Wang@Sun.COM 	{ FC_ELS_MALFORMED,	"Malformed ELS request"			},
21910264SZhong.Wang@Sun.COM 	{ FC_TOOMANY,		"Too many commands"			},
22010264SZhong.Wang@Sun.COM 	{ FC_UB_BADTOKEN,	"Bad Unsolicited buffer token"		},
22110264SZhong.Wang@Sun.COM 	{ FC_UB_ERROR,		"Unsolicited buffer error"		},
22210264SZhong.Wang@Sun.COM 	{ FC_UB_BUSY,		"Unsolicited buffer busy"		},
22310264SZhong.Wang@Sun.COM 	{ FC_BADULP,		"Bad ULP"				},
22410264SZhong.Wang@Sun.COM 	{ FC_BADTYPE,		"Bad Type"				},
22510264SZhong.Wang@Sun.COM 	{ FC_UNCLAIMED,		"Not Claimed"				},
22610264SZhong.Wang@Sun.COM 	{ FC_ULP_SAMEMODULE,	"Same ULP Module"			},
22710264SZhong.Wang@Sun.COM 	{ FC_ULP_SAMETYPE,	"Same ULP Type"				},
22810264SZhong.Wang@Sun.COM 	{ FC_ABORTED,		"Command Aborted"			},
22910264SZhong.Wang@Sun.COM 	{ FC_ABORT_FAILED,	"Abort Failed"				},
23010264SZhong.Wang@Sun.COM 	{ FC_BADEXCHANGE,	"Bad Exchange"				},
23110264SZhong.Wang@Sun.COM 	{ FC_BADWWN,		"Bad World Wide Name"			},
23210264SZhong.Wang@Sun.COM 	{ FC_BADDEV,		"Bad Device"				},
23310264SZhong.Wang@Sun.COM 	{ FC_BADCMD,		"Bad Command"				},
23410264SZhong.Wang@Sun.COM 	{ FC_BADOBJECT,		"Bad Object"				},
23510264SZhong.Wang@Sun.COM 	{ FC_BADPORT,		"Bad Port"				},
23610264SZhong.Wang@Sun.COM 	{ FC_NOTTHISPORT,	"Not on this Port"			},
23710264SZhong.Wang@Sun.COM 	{ FC_PREJECT,		"Operation Prejected"			},
23810264SZhong.Wang@Sun.COM 	{ FC_FREJECT,		"Operation Frejected"			},
23910264SZhong.Wang@Sun.COM 	{ FC_PBUSY,		"Operation Pbusyed"			},
24010264SZhong.Wang@Sun.COM 	{ FC_FBUSY,		"Operation Fbusyed"			},
24110264SZhong.Wang@Sun.COM 	{ FC_ALREADY,		"Already done"				},
24210264SZhong.Wang@Sun.COM 	{ FC_LOGINREQ,		"PLOGI Required"			},
24310264SZhong.Wang@Sun.COM 	{ FC_RESETFAIL,		"Reset operation failed"		},
24410264SZhong.Wang@Sun.COM 	{ FC_INVALID_REQUEST,	"Invalid Request"			},
24510264SZhong.Wang@Sun.COM 	{ FC_OUTOFBOUNDS,	"Out of Bounds"				},
24610264SZhong.Wang@Sun.COM 	{ FC_TRAN_BUSY,		"Command transport Busy"		},
24710264SZhong.Wang@Sun.COM 	{ FC_STATEC_BUSY,	"State change Busy"			},
2487836SJohn.Forte@Sun.COM 	{ FC_DEVICE_BUSY,	"Port driver is working on this device"	}
2497836SJohn.Forte@Sun.COM };
2507836SJohn.Forte@Sun.COM 
2517836SJohn.Forte@Sun.COM fc_pkt_reason_t remote_stop_reasons [] = {
2527836SJohn.Forte@Sun.COM 	{ FC_REASON_ABTS,	"Abort Sequence"	},
2537836SJohn.Forte@Sun.COM 	{ FC_REASON_ABTX,	"Abort Exchange"	},
2547836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,	NULL			}
2557836SJohn.Forte@Sun.COM };
2567836SJohn.Forte@Sun.COM 
2577836SJohn.Forte@Sun.COM fc_pkt_reason_t general_reasons [] = {
25810264SZhong.Wang@Sun.COM 	{ FC_REASON_HW_ERROR,		"Hardware Error"		},
2597836SJohn.Forte@Sun.COM 	{ FC_REASON_SEQ_TIMEOUT,	"Sequence Timeout"		},
2607836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORTED,		"Aborted"			},
2617836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORT_FAILED,	"Abort Failed"			},
2627836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_CONNECTION,	"No Connection"			},
2637836SJohn.Forte@Sun.COM 	{ FC_REASON_XCHG_DROPPED,	"Exchange Dropped"		},
2647836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_FRAME,	"Illegal Frame"			},
2657836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_LENGTH,	"Illegal Length"		},
2667836SJohn.Forte@Sun.COM 	{ FC_REASON_UNSUPPORTED,	"Unsuported"			},
2677836SJohn.Forte@Sun.COM 	{ FC_REASON_RX_BUF_TIMEOUT,	"Receive Buffer Timeout"	},
2687836SJohn.Forte@Sun.COM 	{ FC_REASON_FCAL_OPN_FAIL,	"FC AL Open Failed"		},
2697836SJohn.Forte@Sun.COM 	{ FC_REASON_OVERRUN,		"Over run"			},
2707836SJohn.Forte@Sun.COM 	{ FC_REASON_QFULL,		"Queue Full"			},
2717836SJohn.Forte@Sun.COM 	{ FC_REASON_ILLEGAL_REQ,	"Illegal Request",		},
2727836SJohn.Forte@Sun.COM 	{ FC_REASON_PKT_BUSY,		"Busy"				},
2737836SJohn.Forte@Sun.COM 	{ FC_REASON_OFFLINE,		"Offline"			},
2747836SJohn.Forte@Sun.COM 	{ FC_REASON_BAD_XID,		"Bad Exchange Id"		},
2757836SJohn.Forte@Sun.COM 	{ FC_REASON_XCHG_BSY,		"Exchange Busy"			},
2767836SJohn.Forte@Sun.COM 	{ FC_REASON_NOMEM,		"No Memory"			},
2777836SJohn.Forte@Sun.COM 	{ FC_REASON_BAD_SID,		"Bad S_ID"			},
2787836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_SEQ_INIT,	"No Sequence Initiative"	},
2797836SJohn.Forte@Sun.COM 	{ FC_REASON_DIAG_BUSY,		"Diagnostic Busy"		},
2807836SJohn.Forte@Sun.COM 	{ FC_REASON_DMA_ERROR,		"DMA Error"			},
2817836SJohn.Forte@Sun.COM 	{ FC_REASON_CRC_ERROR,		"CRC Error"			},
2827836SJohn.Forte@Sun.COM 	{ FC_REASON_ABORT_TIMEOUT,	"Abort Timeout"			},
2837836SJohn.Forte@Sun.COM 	{ FC_REASON_FCA_UNIQUE,		"FCA Unique"			},
2847836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
2857836SJohn.Forte@Sun.COM };
2867836SJohn.Forte@Sun.COM 
2877836SJohn.Forte@Sun.COM fc_pkt_reason_t rjt_reasons [] = {
2887836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_D_ID,	"Invalid D_ID"			},
2897836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_S_ID,	"Invalid S_ID"			},
2907836SJohn.Forte@Sun.COM 	{ FC_REASON_TEMP_UNAVAILABLE,	"Temporarily Unavailable"	},
2917836SJohn.Forte@Sun.COM 	{ FC_REASON_PERM_UNAVAILABLE,	"Permamnently Unavailable"	},
2927836SJohn.Forte@Sun.COM 	{ FC_REASON_CLASS_NOT_SUPP,	"Class Not Supported",		},
2937836SJohn.Forte@Sun.COM 	{ FC_REASON_DELIMTER_USAGE_ERROR,
29410264SZhong.Wang@Sun.COM 	    "Delimeter Usage Error"		},
2957836SJohn.Forte@Sun.COM 	{ FC_REASON_TYPE_NOT_SUPP,	"Type Not Supported"		},
2967836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_LINK_CTRL,	"Invalid Link Control"		},
2977836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_R_CTL,	"Invalid R_CTL"			},
2987836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_F_CTL,	"Invalid F_CTL"			},
2997836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_OX_ID,	"Invalid OX_ID"			},
3007836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_RX_ID,	"Invalid RX_ID"			},
3017836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_SEQ_ID,	"Invalid Sequence ID"		},
3027836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_DF_CTL,	"Invalid DF_CTL"		},
3037836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_SEQ_CNT,	"Invalid Sequence count"	},
3047836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_PARAM,	"Invalid Parameter"		},
3057836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCH_ERROR,		"Exchange Error"		},
3067836SJohn.Forte@Sun.COM 	{ FC_REASON_PROTOCOL_ERROR,	"Protocol Error"		},
3077836SJohn.Forte@Sun.COM 	{ FC_REASON_INCORRECT_LENGTH,	"Incorrect Length"		},
3087836SJohn.Forte@Sun.COM 	{ FC_REASON_UNEXPECTED_ACK,	"Unexpected Ack"		},
30910264SZhong.Wang@Sun.COM 	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset"		},
3107836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGIN_REQUIRED,	"Login Required"		},
3117836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCESSIVE_SEQS,	"Excessive Sequences"
31210264SZhong.Wang@Sun.COM 	    " Attempted"			},
3137836SJohn.Forte@Sun.COM 	{ FC_REASON_EXCH_UNABLE,	"Exchange incapable"		},
3147836SJohn.Forte@Sun.COM 	{ FC_REASON_ESH_NOT_SUPP,	"Expiration Security Header "
31510264SZhong.Wang@Sun.COM 	    "Not Supported"			},
3167836SJohn.Forte@Sun.COM 	{ FC_REASON_NO_FABRIC_PATH,	"No Fabric Path"		},
3177836SJohn.Forte@Sun.COM 	{ FC_REASON_VENDOR_UNIQUE,	"Vendor Unique"			},
3187836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3197836SJohn.Forte@Sun.COM };
3207836SJohn.Forte@Sun.COM 
3217836SJohn.Forte@Sun.COM fc_pkt_reason_t n_port_busy_reasons [] = {
3227836SJohn.Forte@Sun.COM 	{ FC_REASON_PHYSICAL_BUSY,		"Physical Busy"		},
3237836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_RESOURCE_BSY,	"Resource Busy"		},
3247836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_VENDOR_UNIQUE,	"Vendor Unique"		},
3257836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,			NULL			}
3267836SJohn.Forte@Sun.COM };
3277836SJohn.Forte@Sun.COM 
3287836SJohn.Forte@Sun.COM fc_pkt_reason_t f_busy_reasons [] = {
3297836SJohn.Forte@Sun.COM 	{ FC_REASON_FABRIC_BSY,		"Fabric Busy"			},
3307836SJohn.Forte@Sun.COM 	{ FC_REASON_N_PORT_BSY,		"N_Port Busy"			},
3317836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3327836SJohn.Forte@Sun.COM };
3337836SJohn.Forte@Sun.COM 
3347836SJohn.Forte@Sun.COM fc_pkt_reason_t ls_ba_rjt_reasons [] = {
3357836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID_LA_CODE,	"Invalid Link Application Code"	},
3367836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGICAL_ERROR,	"Logical Error"			},
3377836SJohn.Forte@Sun.COM 	{ FC_REASON_LOGICAL_BSY,	"Logical Busy"			},
3387836SJohn.Forte@Sun.COM 	{ FC_REASON_PROTOCOL_ERROR_RJT,	"Protocol Error Reject"		},
3397836SJohn.Forte@Sun.COM 	{ FC_REASON_CMD_UNABLE,		"Unable to Perform Command"	},
3407836SJohn.Forte@Sun.COM 	{ FC_REASON_CMD_UNSUPPORTED,	"Unsupported Command"		},
3417836SJohn.Forte@Sun.COM 	{ FC_REASON_VU_RJT,		"Vendor Unique"			},
3427836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3437836SJohn.Forte@Sun.COM };
3447836SJohn.Forte@Sun.COM 
3457836SJohn.Forte@Sun.COM fc_pkt_reason_t fs_rjt_reasons [] = {
3467836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_CMD,	"Invalid Command"		},
3477836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_VER,	"Invalid Version"		},
3487836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_LOGICAL_ERR,	"Logical Error"			},
3497836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_INVALID_IUSIZE,	"Invalid IU Size"		},
3507836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_LOGICAL_BUSY,	"Logical Busy"			},
3517836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_PROTOCOL_ERR,	"Protocol Error"		},
3527836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_CMD_UNABLE,	"Unable to Perform Command"	},
3537836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_CMD_UNSUPPORTED,	"Unsupported Command"		},
3547836SJohn.Forte@Sun.COM 	{ FC_REASON_FS_VENDOR_UNIQUE,	"Vendor Unique"			},
3557836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3567836SJohn.Forte@Sun.COM };
3577836SJohn.Forte@Sun.COM 
3587836SJohn.Forte@Sun.COM fc_pkt_action_t	n_port_busy_actions [] = {
3597836SJohn.Forte@Sun.COM 	{ FC_ACTION_SEQ_TERM_RETRY,	"Retry terminated Sequence"	},
3607836SJohn.Forte@Sun.COM 	{ FC_ACTION_SEQ_ACTIVE_RETRY,	"Retry Active Sequence"		},
3617836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3627836SJohn.Forte@Sun.COM };
3637836SJohn.Forte@Sun.COM 
3647836SJohn.Forte@Sun.COM fc_pkt_action_t rjt_timeout_actions [] = {
3657836SJohn.Forte@Sun.COM 	{ FC_ACTION_RETRYABLE,		"Retryable"			},
3667836SJohn.Forte@Sun.COM 	{ FC_ACTION_NON_RETRYABLE,	"Non Retryable"			},
3677836SJohn.Forte@Sun.COM 	{ FC_REASON_INVALID,		NULL				}
3687836SJohn.Forte@Sun.COM };
3697836SJohn.Forte@Sun.COM 
3707836SJohn.Forte@Sun.COM fc_pkt_expln_t ba_rjt_explns [] = {
3717836SJohn.Forte@Sun.COM 	{ FC_EXPLN_NONE,		"No Explanation"		},
3727836SJohn.Forte@Sun.COM 	{ FC_EXPLN_INVALID_OX_RX_ID,	"Invalid X_ID"			},
3737836SJohn.Forte@Sun.COM 	{ FC_EXPLN_SEQ_ABORTED,		"Sequence Aborted"		},
3747836SJohn.Forte@Sun.COM 	{ FC_EXPLN_INVALID,		NULL				}
3757836SJohn.Forte@Sun.COM };
3767836SJohn.Forte@Sun.COM 
3777836SJohn.Forte@Sun.COM fc_pkt_error_t fc_pkt_errlist[] = {
3787836SJohn.Forte@Sun.COM 	{
3797836SJohn.Forte@Sun.COM 		FC_PKT_SUCCESS,
3807836SJohn.Forte@Sun.COM 		"Operation Success",
3817836SJohn.Forte@Sun.COM 		NULL,
3827836SJohn.Forte@Sun.COM 		NULL,
3837836SJohn.Forte@Sun.COM 		NULL
3847836SJohn.Forte@Sun.COM 	},
3857836SJohn.Forte@Sun.COM 	{	FC_PKT_REMOTE_STOP,
38610264SZhong.Wang@Sun.COM 	    "Remote Stop",
38710264SZhong.Wang@Sun.COM 	    remote_stop_reasons,
38810264SZhong.Wang@Sun.COM 	    NULL,
38910264SZhong.Wang@Sun.COM 	    NULL
3907836SJohn.Forte@Sun.COM 	},
3917836SJohn.Forte@Sun.COM 	{
3927836SJohn.Forte@Sun.COM 		FC_PKT_LOCAL_RJT,
3937836SJohn.Forte@Sun.COM 		"Local Reject",
3947836SJohn.Forte@Sun.COM 		general_reasons,
3957836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
3967836SJohn.Forte@Sun.COM 		NULL
3977836SJohn.Forte@Sun.COM 	},
3987836SJohn.Forte@Sun.COM 	{
3997836SJohn.Forte@Sun.COM 		FC_PKT_NPORT_RJT,
4007836SJohn.Forte@Sun.COM 		"N_Port Reject",
4017836SJohn.Forte@Sun.COM 		rjt_reasons,
4027836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
4037836SJohn.Forte@Sun.COM 		NULL
4047836SJohn.Forte@Sun.COM 	},
4057836SJohn.Forte@Sun.COM 	{
4067836SJohn.Forte@Sun.COM 		FC_PKT_FABRIC_RJT,
4077836SJohn.Forte@Sun.COM 		"Fabric Reject",
4087836SJohn.Forte@Sun.COM 		rjt_reasons,
4097836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
4107836SJohn.Forte@Sun.COM 		NULL
4117836SJohn.Forte@Sun.COM 	},
4127836SJohn.Forte@Sun.COM 	{
4137836SJohn.Forte@Sun.COM 		FC_PKT_LOCAL_BSY,
4147836SJohn.Forte@Sun.COM 		"Local Busy",
4157836SJohn.Forte@Sun.COM 		general_reasons,
4167836SJohn.Forte@Sun.COM 		NULL,
4177836SJohn.Forte@Sun.COM 		NULL,
4187836SJohn.Forte@Sun.COM 	},
4197836SJohn.Forte@Sun.COM 	{
4207836SJohn.Forte@Sun.COM 		FC_PKT_TRAN_BSY,
4217836SJohn.Forte@Sun.COM 		"Transport Busy",
4227836SJohn.Forte@Sun.COM 		general_reasons,
4237836SJohn.Forte@Sun.COM 		NULL,
4247836SJohn.Forte@Sun.COM 		NULL,
4257836SJohn.Forte@Sun.COM 	},
4267836SJohn.Forte@Sun.COM 	{
4277836SJohn.Forte@Sun.COM 		FC_PKT_NPORT_BSY,
4287836SJohn.Forte@Sun.COM 		"N_Port Busy",
4297836SJohn.Forte@Sun.COM 		n_port_busy_reasons,
4307836SJohn.Forte@Sun.COM 		n_port_busy_actions,
4317836SJohn.Forte@Sun.COM 		NULL
4327836SJohn.Forte@Sun.COM 	},
4337836SJohn.Forte@Sun.COM 	{
4347836SJohn.Forte@Sun.COM 		FC_PKT_FABRIC_BSY,
4357836SJohn.Forte@Sun.COM 		"Fabric Busy",
4367836SJohn.Forte@Sun.COM 		f_busy_reasons,
4377836SJohn.Forte@Sun.COM 		NULL,
4387836SJohn.Forte@Sun.COM 		NULL,
4397836SJohn.Forte@Sun.COM 	},
4407836SJohn.Forte@Sun.COM 	{
4417836SJohn.Forte@Sun.COM 		FC_PKT_LS_RJT,
4427836SJohn.Forte@Sun.COM 		"Link Service Reject",
4437836SJohn.Forte@Sun.COM 		ls_ba_rjt_reasons,
4447836SJohn.Forte@Sun.COM 		NULL,
4457836SJohn.Forte@Sun.COM 		NULL,
4467836SJohn.Forte@Sun.COM 	},
4477836SJohn.Forte@Sun.COM 	{
4487836SJohn.Forte@Sun.COM 		FC_PKT_BA_RJT,
4497836SJohn.Forte@Sun.COM 		"Basic Reject",
4507836SJohn.Forte@Sun.COM 		ls_ba_rjt_reasons,
4517836SJohn.Forte@Sun.COM 		NULL,
4527836SJohn.Forte@Sun.COM 		ba_rjt_explns,
4537836SJohn.Forte@Sun.COM 	},
4547836SJohn.Forte@Sun.COM 	{
4557836SJohn.Forte@Sun.COM 		FC_PKT_TIMEOUT,
4567836SJohn.Forte@Sun.COM 		"Timeout",
4577836SJohn.Forte@Sun.COM 		general_reasons,
4587836SJohn.Forte@Sun.COM 		rjt_timeout_actions,
4597836SJohn.Forte@Sun.COM 		NULL
4607836SJohn.Forte@Sun.COM 	},
4617836SJohn.Forte@Sun.COM 	{
4627836SJohn.Forte@Sun.COM 		FC_PKT_FS_RJT,
4637836SJohn.Forte@Sun.COM 		"Fabric Switch Reject",
4647836SJohn.Forte@Sun.COM 		fs_rjt_reasons,
4657836SJohn.Forte@Sun.COM 		NULL,
4667836SJohn.Forte@Sun.COM 		NULL
4677836SJohn.Forte@Sun.COM 	},
4687836SJohn.Forte@Sun.COM 	{
4697836SJohn.Forte@Sun.COM 		FC_PKT_TRAN_ERROR,
4707836SJohn.Forte@Sun.COM 		"Packet Transport error",
4717836SJohn.Forte@Sun.COM 		general_reasons,
4727836SJohn.Forte@Sun.COM 		NULL,
4737836SJohn.Forte@Sun.COM 		NULL
4747836SJohn.Forte@Sun.COM 	},
4757836SJohn.Forte@Sun.COM 	{
4767836SJohn.Forte@Sun.COM 		FC_PKT_FAILURE,
4777836SJohn.Forte@Sun.COM 		"Packet Failure",
4787836SJohn.Forte@Sun.COM 		general_reasons,
4797836SJohn.Forte@Sun.COM 		NULL,
4807836SJohn.Forte@Sun.COM 		NULL
4817836SJohn.Forte@Sun.COM 	},
4827836SJohn.Forte@Sun.COM 	{
4837836SJohn.Forte@Sun.COM 		FC_PKT_PORT_OFFLINE,
4847836SJohn.Forte@Sun.COM 		"Port Offline",
4857836SJohn.Forte@Sun.COM 		NULL,
4867836SJohn.Forte@Sun.COM 		NULL,
4877836SJohn.Forte@Sun.COM 		NULL
4887836SJohn.Forte@Sun.COM 	},
4897836SJohn.Forte@Sun.COM 	{
4907836SJohn.Forte@Sun.COM 		FC_PKT_ELS_IN_PROGRESS,
4917836SJohn.Forte@Sun.COM 		"ELS is in Progress",
4927836SJohn.Forte@Sun.COM 		NULL,
4937836SJohn.Forte@Sun.COM 		NULL,
4947836SJohn.Forte@Sun.COM 		NULL
4957836SJohn.Forte@Sun.COM 	}
4967836SJohn.Forte@Sun.COM };
4977836SJohn.Forte@Sun.COM 
4987836SJohn.Forte@Sun.COM int
_init()4997836SJohn.Forte@Sun.COM _init()
5007836SJohn.Forte@Sun.COM {
5017836SJohn.Forte@Sun.COM 	int rval;
5027836SJohn.Forte@Sun.COM 
5037836SJohn.Forte@Sun.COM 	rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
5047836SJohn.Forte@Sun.COM 	rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
5057836SJohn.Forte@Sun.COM 	mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
5067836SJohn.Forte@Sun.COM 	mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
5077836SJohn.Forte@Sun.COM 
5087836SJohn.Forte@Sun.COM 	fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
5097836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size, KM_SLEEP);
5107836SJohn.Forte@Sun.COM 
5117836SJohn.Forte@Sun.COM 	fctl_ulp_modules = NULL;
5127836SJohn.Forte@Sun.COM 	fctl_fca_portlist = NULL;
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 	fctl_job_cache = kmem_cache_create("fctl_cache",
5157836SJohn.Forte@Sun.COM 	    sizeof (job_request_t), 8, fctl_cache_constructor,
5167836SJohn.Forte@Sun.COM 	    fctl_cache_destructor, NULL, NULL, NULL, 0);
5177836SJohn.Forte@Sun.COM 
5187836SJohn.Forte@Sun.COM 	if (fctl_job_cache == NULL) {
5197836SJohn.Forte@Sun.COM 		kmem_free(fctl_nwwn_hash_table,
5207836SJohn.Forte@Sun.COM 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
5217836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_nwwn_hash_mutex);
5227836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_port_lock);
5237836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_ulp_lock);
5247836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_mod_ports_lock);
5257836SJohn.Forte@Sun.COM 		return (ENOMEM);
5267836SJohn.Forte@Sun.COM 	}
5277836SJohn.Forte@Sun.COM 
5287836SJohn.Forte@Sun.COM 	if ((rval = mod_install(&modlinkage)) != 0) {
5297836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fctl_job_cache);
5307836SJohn.Forte@Sun.COM 		kmem_free(fctl_nwwn_hash_table,
5317836SJohn.Forte@Sun.COM 		    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
5327836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_nwwn_hash_mutex);
5337836SJohn.Forte@Sun.COM 		mutex_destroy(&fctl_port_lock);
5347836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_ulp_lock);
5357836SJohn.Forte@Sun.COM 		rw_destroy(&fctl_mod_ports_lock);
5367836SJohn.Forte@Sun.COM 	}
5377836SJohn.Forte@Sun.COM 
5387836SJohn.Forte@Sun.COM 	return (rval);
5397836SJohn.Forte@Sun.COM }
5407836SJohn.Forte@Sun.COM 
5417836SJohn.Forte@Sun.COM 
5427836SJohn.Forte@Sun.COM /*
5437836SJohn.Forte@Sun.COM  * The mod_uninstall code doesn't call _fini when
5447836SJohn.Forte@Sun.COM  * there is living dependent module on fctl. So
5457836SJohn.Forte@Sun.COM  * there is no need to be extra careful here ?
5467836SJohn.Forte@Sun.COM  */
5477836SJohn.Forte@Sun.COM int
_fini()5487836SJohn.Forte@Sun.COM _fini()
5497836SJohn.Forte@Sun.COM {
5507836SJohn.Forte@Sun.COM 	int rval;
5517836SJohn.Forte@Sun.COM 
5527836SJohn.Forte@Sun.COM 	if ((rval = mod_remove(&modlinkage)) != 0) {
5537836SJohn.Forte@Sun.COM 		return (rval);
5547836SJohn.Forte@Sun.COM 	}
5557836SJohn.Forte@Sun.COM 
5567836SJohn.Forte@Sun.COM 	kmem_cache_destroy(fctl_job_cache);
5577836SJohn.Forte@Sun.COM 	kmem_free(fctl_nwwn_hash_table,
5587836SJohn.Forte@Sun.COM 	    sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
5597836SJohn.Forte@Sun.COM 	mutex_destroy(&fctl_nwwn_hash_mutex);
5607836SJohn.Forte@Sun.COM 	mutex_destroy(&fctl_port_lock);
5617836SJohn.Forte@Sun.COM 	rw_destroy(&fctl_ulp_lock);
5627836SJohn.Forte@Sun.COM 	rw_destroy(&fctl_mod_ports_lock);
5637836SJohn.Forte@Sun.COM 
5647836SJohn.Forte@Sun.COM 	return (rval);
5657836SJohn.Forte@Sun.COM }
5667836SJohn.Forte@Sun.COM 
5677836SJohn.Forte@Sun.COM 
5687836SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfo_p)5697836SJohn.Forte@Sun.COM _info(struct modinfo *modinfo_p)
5707836SJohn.Forte@Sun.COM {
5717836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfo_p));
5727836SJohn.Forte@Sun.COM }
5737836SJohn.Forte@Sun.COM 
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM /* ARGSUSED */
5767836SJohn.Forte@Sun.COM static int
fctl_cache_constructor(void * buf,void * cdarg,int kmflag)5777836SJohn.Forte@Sun.COM fctl_cache_constructor(void *buf, void *cdarg, int kmflag)
5787836SJohn.Forte@Sun.COM {
5797836SJohn.Forte@Sun.COM 	job_request_t *job = (job_request_t *)buf;
5807836SJohn.Forte@Sun.COM 
5817836SJohn.Forte@Sun.COM 	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
5827836SJohn.Forte@Sun.COM 	sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
5837836SJohn.Forte@Sun.COM 	sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
5847836SJohn.Forte@Sun.COM 
5857836SJohn.Forte@Sun.COM 	return (0);
5867836SJohn.Forte@Sun.COM }
5877836SJohn.Forte@Sun.COM 
5887836SJohn.Forte@Sun.COM 
5897836SJohn.Forte@Sun.COM /* ARGSUSED */
5907836SJohn.Forte@Sun.COM static void
fctl_cache_destructor(void * buf,void * cdarg)5917836SJohn.Forte@Sun.COM fctl_cache_destructor(void *buf, void *cdarg)
5927836SJohn.Forte@Sun.COM {
5937836SJohn.Forte@Sun.COM 	job_request_t *job = (job_request_t *)buf;
5947836SJohn.Forte@Sun.COM 
5957836SJohn.Forte@Sun.COM 	sema_destroy(&job->job_fctl_sema);
5967836SJohn.Forte@Sun.COM 	sema_destroy(&job->job_port_sema);
5977836SJohn.Forte@Sun.COM 	mutex_destroy(&job->job_mutex);
5987836SJohn.Forte@Sun.COM }
5997836SJohn.Forte@Sun.COM 
6007836SJohn.Forte@Sun.COM 
6017836SJohn.Forte@Sun.COM /*
6027836SJohn.Forte@Sun.COM  * fc_ulp_add:
6037836SJohn.Forte@Sun.COM  *		Add a ULP module
6047836SJohn.Forte@Sun.COM  *
6057836SJohn.Forte@Sun.COM  * Return Codes:
6067836SJohn.Forte@Sun.COM  *		FC_ULP_SAMEMODULE
6077836SJohn.Forte@Sun.COM  *		FC_SUCCESS
6087836SJohn.Forte@Sun.COM  *		FC_FAILURE
6097836SJohn.Forte@Sun.COM  *
61010264SZhong.Wang@Sun.COM  *   fc_ulp_add	 prints	 a warning message if there is	already a
6117836SJohn.Forte@Sun.COM  *   similar ULP type  attached and this is unlikely to change as
61210264SZhong.Wang@Sun.COM  *   we trudge along.  Further, this  function	returns a failure
6137836SJohn.Forte@Sun.COM  *   code if the same  module  attempts to add more than once for
6147836SJohn.Forte@Sun.COM  *   the same FC-4 type.
6157836SJohn.Forte@Sun.COM  */
6167836SJohn.Forte@Sun.COM int
fc_ulp_add(fc_ulp_modinfo_t * ulp_info)6177836SJohn.Forte@Sun.COM fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
6187836SJohn.Forte@Sun.COM {
6197836SJohn.Forte@Sun.COM 	fc_ulp_module_t *mod;
6207836SJohn.Forte@Sun.COM 	fc_ulp_module_t *prev;
62110264SZhong.Wang@Sun.COM 	job_request_t	*job;
6227836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*new;
62310264SZhong.Wang@Sun.COM 	fc_fca_port_t	*fca_port;
6247836SJohn.Forte@Sun.COM 	int		ntry = 0;
6257836SJohn.Forte@Sun.COM 
6267836SJohn.Forte@Sun.COM 	ASSERT(ulp_info != NULL);
6277836SJohn.Forte@Sun.COM 
6287836SJohn.Forte@Sun.COM 	/*
6297836SJohn.Forte@Sun.COM 	 * Make sure ulp_rev matches fctl version.
6307836SJohn.Forte@Sun.COM 	 * Whenever non-private data structure or non-static interface changes,
6317836SJohn.Forte@Sun.COM 	 * we should use an increased FCTL_ULP_MODREV_# number here and in all
6327836SJohn.Forte@Sun.COM 	 * ulps to prevent version mismatch.
6337836SJohn.Forte@Sun.COM 	 */
6347836SJohn.Forte@Sun.COM 	if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
6357836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
6367836SJohn.Forte@Sun.COM 		    " ULP %s would not be loaded", ulp_info->ulp_name,
6377836SJohn.Forte@Sun.COM 		    ulp_info->ulp_name);
6387836SJohn.Forte@Sun.COM 		return (FC_BADULP);
6397836SJohn.Forte@Sun.COM 	}
6407836SJohn.Forte@Sun.COM 
6417836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
6427836SJohn.Forte@Sun.COM 	ASSERT(new != NULL);
6437836SJohn.Forte@Sun.COM 
6447836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
6457836SJohn.Forte@Sun.COM 	new->ulp_info = ulp_info;
6467836SJohn.Forte@Sun.COM 	if (fctl_ulp_list != NULL) {
6477836SJohn.Forte@Sun.COM 		new->ulp_next = fctl_ulp_list;
6487836SJohn.Forte@Sun.COM 	}
6497836SJohn.Forte@Sun.COM 	fctl_ulp_list = new;
6507836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
6517836SJohn.Forte@Sun.COM 
6527836SJohn.Forte@Sun.COM 	while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
6537836SJohn.Forte@Sun.COM 		delay(drv_usectohz(1000000));
6547836SJohn.Forte@Sun.COM 		if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
65510264SZhong.Wang@Sun.COM 			fc_ulp_list_t	*list;
65610264SZhong.Wang@Sun.COM 			fc_ulp_list_t	*last;
6577836SJohn.Forte@Sun.COM 			mutex_enter(&fctl_ulp_list_mutex);
6587836SJohn.Forte@Sun.COM 			for (last = NULL, list = fctl_ulp_list; list != NULL;
6597836SJohn.Forte@Sun.COM 			    list = list->ulp_next) {
6607836SJohn.Forte@Sun.COM 				if (list->ulp_info == ulp_info) {
6617836SJohn.Forte@Sun.COM 					break;
6627836SJohn.Forte@Sun.COM 				}
6637836SJohn.Forte@Sun.COM 				last = list;
6647836SJohn.Forte@Sun.COM 			}
6657836SJohn.Forte@Sun.COM 
6667836SJohn.Forte@Sun.COM 			if (list) {
6677836SJohn.Forte@Sun.COM 				if (last) {
6687836SJohn.Forte@Sun.COM 					last->ulp_next = list->ulp_next;
6697836SJohn.Forte@Sun.COM 				} else {
6707836SJohn.Forte@Sun.COM 					fctl_ulp_list = list->ulp_next;
6717836SJohn.Forte@Sun.COM 				}
6727836SJohn.Forte@Sun.COM 				kmem_free(list, sizeof (*list));
6737836SJohn.Forte@Sun.COM 			}
6747836SJohn.Forte@Sun.COM 			mutex_exit(&fctl_ulp_list_mutex);
6757836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "fctl: ULP %s unable to load",
6767836SJohn.Forte@Sun.COM 			    ulp_info->ulp_name);
6777836SJohn.Forte@Sun.COM 			return (FC_FAILURE);
6787836SJohn.Forte@Sun.COM 		}
6797836SJohn.Forte@Sun.COM 	}
6807836SJohn.Forte@Sun.COM 
6817836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
6827836SJohn.Forte@Sun.COM 		ASSERT(mod->mod_info != NULL);
6837836SJohn.Forte@Sun.COM 
6847836SJohn.Forte@Sun.COM 		if (ulp_info == mod->mod_info &&
6857836SJohn.Forte@Sun.COM 		    ulp_info->ulp_type == mod->mod_info->ulp_type) {
6867836SJohn.Forte@Sun.COM 			rw_exit(&fctl_ulp_lock);
6877836SJohn.Forte@Sun.COM 			return (FC_ULP_SAMEMODULE);
6887836SJohn.Forte@Sun.COM 		}
6897836SJohn.Forte@Sun.COM 
6907836SJohn.Forte@Sun.COM 		if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
6917836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
6927836SJohn.Forte@Sun.COM 			    ulp_info->ulp_type);
6937836SJohn.Forte@Sun.COM 		}
6947836SJohn.Forte@Sun.COM 		prev = mod;
6957836SJohn.Forte@Sun.COM 	}
6967836SJohn.Forte@Sun.COM 
6977836SJohn.Forte@Sun.COM 	mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
6987836SJohn.Forte@Sun.COM 	mod->mod_info = ulp_info;
6997836SJohn.Forte@Sun.COM 	mod->mod_next = NULL;
7007836SJohn.Forte@Sun.COM 
7017836SJohn.Forte@Sun.COM 	if (prev) {
7027836SJohn.Forte@Sun.COM 		prev->mod_next = mod;
7037836SJohn.Forte@Sun.COM 	} else {
7047836SJohn.Forte@Sun.COM 		fctl_ulp_modules = mod;
7057836SJohn.Forte@Sun.COM 	}
7067836SJohn.Forte@Sun.COM 
7077836SJohn.Forte@Sun.COM 	/*
7087836SJohn.Forte@Sun.COM 	 * Schedule a job to each port's job_handler
7097836SJohn.Forte@Sun.COM 	 * thread to attach their ports with this ULP.
7107836SJohn.Forte@Sun.COM 	 */
7117836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
7127836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
7137836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
7147836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
7157836SJohn.Forte@Sun.COM 		    NULL, NULL, KM_SLEEP);
7167836SJohn.Forte@Sun.COM 
7177836SJohn.Forte@Sun.COM 		fctl_enque_job(fca_port->port_handle, job);
7187836SJohn.Forte@Sun.COM 	}
7197836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
7207836SJohn.Forte@Sun.COM 
7217836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
7227836SJohn.Forte@Sun.COM 
7237836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
7247836SJohn.Forte@Sun.COM }
7257836SJohn.Forte@Sun.COM 
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM /*
7287836SJohn.Forte@Sun.COM  * fc_ulp_remove
7297836SJohn.Forte@Sun.COM  *	Remove a ULP module
7307836SJohn.Forte@Sun.COM  *
7317836SJohn.Forte@Sun.COM  * A misbehaving ULP may call this routine while I/Os are in progress.
7327836SJohn.Forte@Sun.COM  * Currently there is no mechanism to detect it to fail such a request.
7337836SJohn.Forte@Sun.COM  *
7347836SJohn.Forte@Sun.COM  * Return Codes:
7357836SJohn.Forte@Sun.COM  *		FC_SUCCESS
7367836SJohn.Forte@Sun.COM  *		FC_FAILURE
7377836SJohn.Forte@Sun.COM  */
7387836SJohn.Forte@Sun.COM int
fc_ulp_remove(fc_ulp_modinfo_t * ulp_info)7397836SJohn.Forte@Sun.COM fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
7407836SJohn.Forte@Sun.COM {
7417836SJohn.Forte@Sun.COM 	fc_ulp_module_t *mod;
7427836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*list;
7437836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*last;
7447836SJohn.Forte@Sun.COM 	fc_ulp_module_t *prev;
7457836SJohn.Forte@Sun.COM 
7467836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
7477836SJohn.Forte@Sun.COM 
7487836SJohn.Forte@Sun.COM 	for (last = NULL, list = fctl_ulp_list; list != NULL;
7497836SJohn.Forte@Sun.COM 	    list = list->ulp_next) {
7507836SJohn.Forte@Sun.COM 		if (list->ulp_info == ulp_info) {
7517836SJohn.Forte@Sun.COM 			break;
7527836SJohn.Forte@Sun.COM 		}
7537836SJohn.Forte@Sun.COM 		last = list;
7547836SJohn.Forte@Sun.COM 	}
7557836SJohn.Forte@Sun.COM 
7567836SJohn.Forte@Sun.COM 	if (list) {
7577836SJohn.Forte@Sun.COM 		if (last) {
7587836SJohn.Forte@Sun.COM 			last->ulp_next = list->ulp_next;
7597836SJohn.Forte@Sun.COM 		} else {
7607836SJohn.Forte@Sun.COM 			fctl_ulp_list = list->ulp_next;
7617836SJohn.Forte@Sun.COM 		}
7627836SJohn.Forte@Sun.COM 		kmem_free(list, sizeof (*list));
7637836SJohn.Forte@Sun.COM 	}
7647836SJohn.Forte@Sun.COM 
7657836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
7667836SJohn.Forte@Sun.COM 
7677836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_WRITER);
7687836SJohn.Forte@Sun.COM 
7697836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
7707836SJohn.Forte@Sun.COM 	    mod = mod->mod_next) {
7717836SJohn.Forte@Sun.COM 		if (mod->mod_info == ulp_info) {
7727836SJohn.Forte@Sun.COM 			break;
7737836SJohn.Forte@Sun.COM 		}
7747836SJohn.Forte@Sun.COM 		prev = mod;
7757836SJohn.Forte@Sun.COM 	}
7767836SJohn.Forte@Sun.COM 
7777836SJohn.Forte@Sun.COM 	if (mod) {
7787836SJohn.Forte@Sun.COM 		fc_ulp_ports_t *next;
7797836SJohn.Forte@Sun.COM 
7807836SJohn.Forte@Sun.COM 		if (prev) {
7817836SJohn.Forte@Sun.COM 			prev->mod_next = mod->mod_next;
7827836SJohn.Forte@Sun.COM 		} else {
7837836SJohn.Forte@Sun.COM 			fctl_ulp_modules = mod->mod_next;
7847836SJohn.Forte@Sun.COM 		}
7857836SJohn.Forte@Sun.COM 
7867836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_WRITER);
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 		while ((next = mod->mod_ports) != NULL) {
7897836SJohn.Forte@Sun.COM 			mod->mod_ports = next->port_next;
7907836SJohn.Forte@Sun.COM 			fctl_dealloc_ulp_port(next);
7917836SJohn.Forte@Sun.COM 		}
7927836SJohn.Forte@Sun.COM 
7937836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
7947836SJohn.Forte@Sun.COM 		rw_exit(&fctl_ulp_lock);
7957836SJohn.Forte@Sun.COM 
7967836SJohn.Forte@Sun.COM 		kmem_free(mod, sizeof (*mod));
7977836SJohn.Forte@Sun.COM 
7987836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
7997836SJohn.Forte@Sun.COM 	}
8007836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
8037836SJohn.Forte@Sun.COM }
8047836SJohn.Forte@Sun.COM 
8057836SJohn.Forte@Sun.COM 
8067836SJohn.Forte@Sun.COM /*
8077836SJohn.Forte@Sun.COM  * The callers typically cache allocate the packet, complete the
8087836SJohn.Forte@Sun.COM  * DMA setup for pkt_cmd and pkt_resp fields of the packet and
8097836SJohn.Forte@Sun.COM  * call this function to see if the FCA is interested in doing
8107836SJohn.Forte@Sun.COM  * its own intialization. For example, socal may like to initialize
8117836SJohn.Forte@Sun.COM  * the soc_hdr which is pointed to by the pkt_fca_private field
8127836SJohn.Forte@Sun.COM  * and sitting right below fc_packet_t in memory.
8137836SJohn.Forte@Sun.COM  *
8147836SJohn.Forte@Sun.COM  * The caller is required to ensure that pkt_pd is populated with the
8157836SJohn.Forte@Sun.COM  * handle that it was given when the transport notified it about the
8167836SJohn.Forte@Sun.COM  * device this packet is associated with.  If there is no associated
81710264SZhong.Wang@Sun.COM  * device, pkt_pd must be set to NULL.	A non-NULL pkt_pd will cause an
8187836SJohn.Forte@Sun.COM  * increment of the reference count for said pd.  When the packet is freed,
8197836SJohn.Forte@Sun.COM  * the reference count will be decremented.  This reference count, in
8207836SJohn.Forte@Sun.COM  * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
8217836SJohn.Forte@Sun.COM  * will not wink out of existence while there is a packet outstanding.
8227836SJohn.Forte@Sun.COM  *
8237836SJohn.Forte@Sun.COM  * This function and fca_init_pkt must not perform any operations that
8247836SJohn.Forte@Sun.COM  * would result in a call back to the ULP, as the ULP may be required
8257836SJohn.Forte@Sun.COM  * to hold a mutex across this call to ensure that the pd in question
8267836SJohn.Forte@Sun.COM  * won't go away prior the call to fc_ulp_transport.
8277836SJohn.Forte@Sun.COM  *
8287836SJohn.Forte@Sun.COM  * ULPs are responsible for using the handles they are given during state
8297836SJohn.Forte@Sun.COM  * change callback processing in a manner that ensures consistency.  That
8307836SJohn.Forte@Sun.COM  * is, they must be aware that they could be processing a state change
8317836SJohn.Forte@Sun.COM  * notification that tells them the device associated with a particular
8327836SJohn.Forte@Sun.COM  * handle has gone away at the same time they are being asked to
8337836SJohn.Forte@Sun.COM  * initialize a packet using that handle. ULPs must therefore ensure
8347836SJohn.Forte@Sun.COM  * that their state change processing and packet initialization code
8357836SJohn.Forte@Sun.COM  * paths are sufficiently synchronized to avoid the use of an
8367836SJohn.Forte@Sun.COM  * invalidated handle in any fc_packet_t struct that is passed to the
8377836SJohn.Forte@Sun.COM  * fc_ulp_init_packet() function.
8387836SJohn.Forte@Sun.COM  */
8397836SJohn.Forte@Sun.COM int
fc_ulp_init_packet(opaque_t port_handle,fc_packet_t * pkt,int sleep)8407836SJohn.Forte@Sun.COM fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
8417836SJohn.Forte@Sun.COM {
8427836SJohn.Forte@Sun.COM 	int rval;
8437836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
8447836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
8457836SJohn.Forte@Sun.COM 
8467836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
8477836SJohn.Forte@Sun.COM 
8487836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
8497836SJohn.Forte@Sun.COM 
8507836SJohn.Forte@Sun.COM 	/* Call the FCA driver's fca_init_pkt entry point function. */
8517836SJohn.Forte@Sun.COM 	rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
8527836SJohn.Forte@Sun.COM 
8537836SJohn.Forte@Sun.COM 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
8547836SJohn.Forte@Sun.COM 		/*
8557836SJohn.Forte@Sun.COM 		 * A !NULL pd here must still be a valid
8567836SJohn.Forte@Sun.COM 		 * reference to the fc_remote_port_t.
8577836SJohn.Forte@Sun.COM 		 */
8587836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
8597836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_ref_count >= 0);
8607836SJohn.Forte@Sun.COM 		pd->pd_ref_count++;
8617836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
8627836SJohn.Forte@Sun.COM 	}
8637836SJohn.Forte@Sun.COM 
8647836SJohn.Forte@Sun.COM 	return (rval);
8657836SJohn.Forte@Sun.COM }
8667836SJohn.Forte@Sun.COM 
8677836SJohn.Forte@Sun.COM 
8687836SJohn.Forte@Sun.COM /*
8697836SJohn.Forte@Sun.COM  * This function is called before destroying the cache allocated
8707836SJohn.Forte@Sun.COM  * fc_packet to free up (and uninitialize) any resource specially
8717836SJohn.Forte@Sun.COM  * allocated by the FCA driver during tran_init_pkt().
8727836SJohn.Forte@Sun.COM  *
8737836SJohn.Forte@Sun.COM  * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
8747836SJohn.Forte@Sun.COM  * the pd_ref_count reference count is decremented for the indicated
8757836SJohn.Forte@Sun.COM  * fc_remote_port_t struct.
8767836SJohn.Forte@Sun.COM  */
8777836SJohn.Forte@Sun.COM int
fc_ulp_uninit_packet(opaque_t port_handle,fc_packet_t * pkt)8787836SJohn.Forte@Sun.COM fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
8797836SJohn.Forte@Sun.COM {
8807836SJohn.Forte@Sun.COM 	int rval;
8817836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
8827836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
8837836SJohn.Forte@Sun.COM 
8847836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
8857836SJohn.Forte@Sun.COM 
8867836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
8877836SJohn.Forte@Sun.COM 
8887836SJohn.Forte@Sun.COM 	/* Call the FCA driver's fca_un_init_pkt entry point function */
8897836SJohn.Forte@Sun.COM 	rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM 	if ((rval == FC_SUCCESS) && (pd != NULL)) {
8927836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
8937836SJohn.Forte@Sun.COM 
8947836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_ref_count > 0);
8957836SJohn.Forte@Sun.COM 		pd->pd_ref_count--;
8967836SJohn.Forte@Sun.COM 
8977836SJohn.Forte@Sun.COM 		/*
8987836SJohn.Forte@Sun.COM 		 * If at this point the state of this fc_remote_port_t
8997836SJohn.Forte@Sun.COM 		 * struct is PORT_DEVICE_INVALID, it probably means somebody
9007836SJohn.Forte@Sun.COM 		 * is cleaning up old (e.g. retried) packets. If the
9017836SJohn.Forte@Sun.COM 		 * pd_ref_count has also dropped to zero, it's time to
9027836SJohn.Forte@Sun.COM 		 * deallocate this fc_remote_port_t struct.
9037836SJohn.Forte@Sun.COM 		 */
9047836SJohn.Forte@Sun.COM 		if (pd->pd_state == PORT_DEVICE_INVALID &&
9057836SJohn.Forte@Sun.COM 		    pd->pd_ref_count == 0) {
9067836SJohn.Forte@Sun.COM 			fc_remote_node_t *node = pd->pd_remote_nodep;
9077836SJohn.Forte@Sun.COM 
9087836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
9097836SJohn.Forte@Sun.COM 
9107836SJohn.Forte@Sun.COM 			/*
9117836SJohn.Forte@Sun.COM 			 * Also deallocate the associated fc_remote_node_t
9127836SJohn.Forte@Sun.COM 			 * struct if it has no other associated
9137836SJohn.Forte@Sun.COM 			 * fc_remote_port_t structs.
9147836SJohn.Forte@Sun.COM 			 */
9157836SJohn.Forte@Sun.COM 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
9167836SJohn.Forte@Sun.COM 			    (node != NULL)) {
9177836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
9187836SJohn.Forte@Sun.COM 			}
9197836SJohn.Forte@Sun.COM 			return (rval);
9207836SJohn.Forte@Sun.COM 		}
9217836SJohn.Forte@Sun.COM 
9227836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
9237836SJohn.Forte@Sun.COM 	}
9247836SJohn.Forte@Sun.COM 
9257836SJohn.Forte@Sun.COM 	return (rval);
9267836SJohn.Forte@Sun.COM }
9277836SJohn.Forte@Sun.COM 
9287836SJohn.Forte@Sun.COM 
9297836SJohn.Forte@Sun.COM int
fc_ulp_getportmap(opaque_t port_handle,fc_portmap_t ** map,uint32_t * len,int flag)9307836SJohn.Forte@Sun.COM fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
9317836SJohn.Forte@Sun.COM     int flag)
9327836SJohn.Forte@Sun.COM {
9337836SJohn.Forte@Sun.COM 	int		job_code;
9347836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
9357836SJohn.Forte@Sun.COM 	job_request_t	*job;
9367836SJohn.Forte@Sun.COM 	fc_portmap_t	*tmp_map;
9377836SJohn.Forte@Sun.COM 	uint32_t	tmp_len;
9387836SJohn.Forte@Sun.COM 	fc_portmap_t	*change_list = NULL;
9397836SJohn.Forte@Sun.COM 	uint32_t	listlen = 0;
9407836SJohn.Forte@Sun.COM 
9417836SJohn.Forte@Sun.COM 	port = port_handle;
9427836SJohn.Forte@Sun.COM 
9437836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
9447836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
9457836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
9467836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
9477836SJohn.Forte@Sun.COM 	}
9487836SJohn.Forte@Sun.COM 
9497836SJohn.Forte@Sun.COM 	if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
9507836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
9517836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
9527836SJohn.Forte@Sun.COM 	}
9537836SJohn.Forte@Sun.COM 
9547836SJohn.Forte@Sun.COM 	if (port->fp_dev_count && (port->fp_dev_count ==
9557836SJohn.Forte@Sun.COM 	    port->fp_total_devices)) {
9567836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
9577836SJohn.Forte@Sun.COM 		fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
9587836SJohn.Forte@Sun.COM 		if (listlen > *len) {
9597836SJohn.Forte@Sun.COM 			tmp_map = (fc_portmap_t *)kmem_zalloc(
9607836SJohn.Forte@Sun.COM 			    listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
9617836SJohn.Forte@Sun.COM 			if (tmp_map == NULL) {
9627836SJohn.Forte@Sun.COM 				return (FC_NOMEM);
9637836SJohn.Forte@Sun.COM 			}
9647836SJohn.Forte@Sun.COM 			if (*map) {
9657836SJohn.Forte@Sun.COM 				kmem_free(*map, (*len) * sizeof (fc_portmap_t));
9667836SJohn.Forte@Sun.COM 			}
9677836SJohn.Forte@Sun.COM 			*map = tmp_map;
9687836SJohn.Forte@Sun.COM 		}
9697836SJohn.Forte@Sun.COM 		if (change_list) {
9707836SJohn.Forte@Sun.COM 			bcopy(change_list, *map,
9717836SJohn.Forte@Sun.COM 			    listlen * sizeof (fc_portmap_t));
9727836SJohn.Forte@Sun.COM 			kmem_free(change_list, listlen * sizeof (fc_portmap_t));
9737836SJohn.Forte@Sun.COM 		}
9747836SJohn.Forte@Sun.COM 		*len = listlen;
9757836SJohn.Forte@Sun.COM 	} else {
9767836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
9777836SJohn.Forte@Sun.COM 
9787836SJohn.Forte@Sun.COM 		switch (flag) {
9797836SJohn.Forte@Sun.COM 		case FC_ULP_PLOGI_DONTCARE:
9807836SJohn.Forte@Sun.COM 			job_code = JOB_PORT_GETMAP;
9817836SJohn.Forte@Sun.COM 			break;
9827836SJohn.Forte@Sun.COM 
9837836SJohn.Forte@Sun.COM 		case FC_ULP_PLOGI_PRESERVE:
9847836SJohn.Forte@Sun.COM 			job_code = JOB_PORT_GETMAP_PLOGI_ALL;
9857836SJohn.Forte@Sun.COM 			break;
9867836SJohn.Forte@Sun.COM 
9877836SJohn.Forte@Sun.COM 		default:
9887836SJohn.Forte@Sun.COM 			return (FC_INVALID_REQUEST);
9897836SJohn.Forte@Sun.COM 		}
9907836SJohn.Forte@Sun.COM 		/*
9917836SJohn.Forte@Sun.COM 		 * Submit a job request to the job handler
9927836SJohn.Forte@Sun.COM 		 * thread to get the map and wait
9937836SJohn.Forte@Sun.COM 		 */
9947836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
9957836SJohn.Forte@Sun.COM 		job->job_private = (opaque_t)map;
9967836SJohn.Forte@Sun.COM 		job->job_arg = (opaque_t)len;
9977836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
9987836SJohn.Forte@Sun.COM 
9997836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
10007836SJohn.Forte@Sun.COM 		/*
10017836SJohn.Forte@Sun.COM 		 * The result of the last I/O operation is
10027836SJohn.Forte@Sun.COM 		 * in job_code. We don't care to look at it
10037836SJohn.Forte@Sun.COM 		 * Rather we look at the number of devices
10047836SJohn.Forte@Sun.COM 		 * that are found to fill out the map for
10057836SJohn.Forte@Sun.COM 		 * ULPs.
10067836SJohn.Forte@Sun.COM 		 */
10077836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
10087836SJohn.Forte@Sun.COM 	}
10097836SJohn.Forte@Sun.COM 
10107836SJohn.Forte@Sun.COM 	/*
10117836SJohn.Forte@Sun.COM 	 * If we're here, we're returning a map to the caller, which means
10127836SJohn.Forte@Sun.COM 	 * we'd better make sure every pd in that map has the
10137836SJohn.Forte@Sun.COM 	 * PD_GIVEN_TO_ULPS flag set.
10147836SJohn.Forte@Sun.COM 	 */
10157836SJohn.Forte@Sun.COM 
10167836SJohn.Forte@Sun.COM 	tmp_len = *len;
10177836SJohn.Forte@Sun.COM 	tmp_map = *map;
10187836SJohn.Forte@Sun.COM 
10197836SJohn.Forte@Sun.COM 	while (tmp_len-- != 0) {
10207836SJohn.Forte@Sun.COM 		if (tmp_map->map_state != PORT_DEVICE_INVALID) {
10217836SJohn.Forte@Sun.COM 			fc_remote_port_t *pd =
10227836SJohn.Forte@Sun.COM 			    (fc_remote_port_t *)tmp_map->map_pd;
10237836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
10247836SJohn.Forte@Sun.COM 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
10257836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
10267836SJohn.Forte@Sun.COM 		}
10277836SJohn.Forte@Sun.COM 		tmp_map++;
10287836SJohn.Forte@Sun.COM 	}
10297836SJohn.Forte@Sun.COM 
10307836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
10317836SJohn.Forte@Sun.COM }
10327836SJohn.Forte@Sun.COM 
10337836SJohn.Forte@Sun.COM 
10347836SJohn.Forte@Sun.COM int
fc_ulp_login(opaque_t port_handle,fc_packet_t ** ulp_pkt,uint32_t listlen)10357836SJohn.Forte@Sun.COM fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
10367836SJohn.Forte@Sun.COM {
10377836SJohn.Forte@Sun.COM 	int			rval = FC_SUCCESS;
103810264SZhong.Wang@Sun.COM 	int			job_flags;
10397836SJohn.Forte@Sun.COM 	uint32_t		count;
10407836SJohn.Forte@Sun.COM 	fc_packet_t		**tmp_array;
104110264SZhong.Wang@Sun.COM 	job_request_t		*job;
104210264SZhong.Wang@Sun.COM 	fc_local_port_t		*port = port_handle;
10437836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
10447836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
10457836SJohn.Forte@Sun.COM 
10467836SJohn.Forte@Sun.COM 	/*
10477836SJohn.Forte@Sun.COM 	 * If the port is OFFLINE, or if the port driver is
10487836SJohn.Forte@Sun.COM 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
10497836SJohn.Forte@Sun.COM 	 * PLOGI operations
10507836SJohn.Forte@Sun.COM 	 */
10517836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
10527836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
10537836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
10547836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
10557836SJohn.Forte@Sun.COM 	}
10567836SJohn.Forte@Sun.COM 
10577836SJohn.Forte@Sun.COM 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
10587836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
10597836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
10607836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
10617836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
10627836SJohn.Forte@Sun.COM 	}
10637836SJohn.Forte@Sun.COM 
10647836SJohn.Forte@Sun.COM 	/*
10657836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
10667836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
10677836SJohn.Forte@Sun.COM 	 */
10687836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
10697836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
10707836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
10717836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
10727836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
10737836SJohn.Forte@Sun.COM 	}
10747836SJohn.Forte@Sun.COM 
10757836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
10767836SJohn.Forte@Sun.COM 
10777836SJohn.Forte@Sun.COM 	tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
10787836SJohn.Forte@Sun.COM 	for (count = 0; count < listlen; count++) {
10797836SJohn.Forte@Sun.COM 		tmp_array[count] = ulp_pkt[count];
10807836SJohn.Forte@Sun.COM 	}
10817836SJohn.Forte@Sun.COM 
10827836SJohn.Forte@Sun.COM 	job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
10837836SJohn.Forte@Sun.COM 	    ? 0 : JOB_TYPE_FCTL_ASYNC;
10847836SJohn.Forte@Sun.COM 
10857836SJohn.Forte@Sun.COM #ifdef	DEBUG
10867836SJohn.Forte@Sun.COM 	{
10877836SJohn.Forte@Sun.COM 		int next;
10887836SJohn.Forte@Sun.COM 		int count;
10897836SJohn.Forte@Sun.COM 		int polled;
10907836SJohn.Forte@Sun.COM 
10917836SJohn.Forte@Sun.COM 		polled = ((ulp_pkt[0]->pkt_tran_flags) &
10927836SJohn.Forte@Sun.COM 		    FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
10937836SJohn.Forte@Sun.COM 
10947836SJohn.Forte@Sun.COM 		for (count = 0; count < listlen; count++) {
10957836SJohn.Forte@Sun.COM 			next = ((ulp_pkt[count]->pkt_tran_flags)
10967836SJohn.Forte@Sun.COM 			    & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
10977836SJohn.Forte@Sun.COM 			ASSERT(next == polled);
10987836SJohn.Forte@Sun.COM 		}
10997836SJohn.Forte@Sun.COM 	}
11007836SJohn.Forte@Sun.COM #endif
11017836SJohn.Forte@Sun.COM 
11027836SJohn.Forte@Sun.COM 	job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
11037836SJohn.Forte@Sun.COM 	job->job_ulp_pkts = tmp_array;
11047836SJohn.Forte@Sun.COM 	job->job_ulp_listlen = listlen;
11057836SJohn.Forte@Sun.COM 
11067836SJohn.Forte@Sun.COM 	while (listlen--) {
11077836SJohn.Forte@Sun.COM 		fc_packet_t *pkt;
11087836SJohn.Forte@Sun.COM 
11097836SJohn.Forte@Sun.COM 		pkt = tmp_array[listlen];
11107836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd == NULL) {
11117836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_SUCCESS;
11127836SJohn.Forte@Sun.COM 			continue;
11137836SJohn.Forte@Sun.COM 		}
11147836SJohn.Forte@Sun.COM 
11157836SJohn.Forte@Sun.COM 		mutex_enter(&pkt->pkt_pd->pd_mutex);
11167836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
11177836SJohn.Forte@Sun.COM 		    pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
11187836SJohn.Forte@Sun.COM 			/*
11197836SJohn.Forte@Sun.COM 			 * Set the packet state and let the port
11207836SJohn.Forte@Sun.COM 			 * driver call the completion routine
11217836SJohn.Forte@Sun.COM 			 * from its thread
11227836SJohn.Forte@Sun.COM 			 */
11237836SJohn.Forte@Sun.COM 			mutex_exit(&pkt->pkt_pd->pd_mutex);
11247836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
11257836SJohn.Forte@Sun.COM 			continue;
11267836SJohn.Forte@Sun.COM 		}
11277836SJohn.Forte@Sun.COM 
11287836SJohn.Forte@Sun.COM 		if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
11297836SJohn.Forte@Sun.COM 		    pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
11307836SJohn.Forte@Sun.COM 			mutex_exit(&pkt->pkt_pd->pd_mutex);
11317836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_LOCAL_RJT;
11327836SJohn.Forte@Sun.COM 			continue;
11337836SJohn.Forte@Sun.COM 		}
11347836SJohn.Forte@Sun.COM 		mutex_exit(&pkt->pkt_pd->pd_mutex);
11357836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_SUCCESS;
11367836SJohn.Forte@Sun.COM 	}
11377836SJohn.Forte@Sun.COM 
11387836SJohn.Forte@Sun.COM 	fctl_enque_job(port, job);
11397836SJohn.Forte@Sun.COM 
11407836SJohn.Forte@Sun.COM 	if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
11417836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
11427836SJohn.Forte@Sun.COM 		rval = job->job_result;
11437836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
11447836SJohn.Forte@Sun.COM 	}
11457836SJohn.Forte@Sun.COM 
11467836SJohn.Forte@Sun.COM 	return (rval);
11477836SJohn.Forte@Sun.COM }
11487836SJohn.Forte@Sun.COM 
11497836SJohn.Forte@Sun.COM 
11507836SJohn.Forte@Sun.COM opaque_t
fc_ulp_get_remote_port(opaque_t port_handle,la_wwn_t * pwwn,int * error,int create)11517836SJohn.Forte@Sun.COM fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
11527836SJohn.Forte@Sun.COM     int create)
11537836SJohn.Forte@Sun.COM {
115410264SZhong.Wang@Sun.COM 	fc_local_port_t		*port;
11557836SJohn.Forte@Sun.COM 	job_request_t		*job;
115610264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
11577836SJohn.Forte@Sun.COM 
11587836SJohn.Forte@Sun.COM 	port = port_handle;
11597836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
11607836SJohn.Forte@Sun.COM 
11617836SJohn.Forte@Sun.COM 	if (pd != NULL) {
11627836SJohn.Forte@Sun.COM 		*error = FC_SUCCESS;
11637836SJohn.Forte@Sun.COM 		/*
11647836SJohn.Forte@Sun.COM 		 * A ULP now knows about this pd, so mark it
11657836SJohn.Forte@Sun.COM 		 */
11667836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
11677836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
11687836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
11697836SJohn.Forte@Sun.COM 		return (pd);
11707836SJohn.Forte@Sun.COM 	}
11717836SJohn.Forte@Sun.COM 
11727836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
11737836SJohn.Forte@Sun.COM 	if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
11747836SJohn.Forte@Sun.COM 		uint32_t	d_id;
117510264SZhong.Wang@Sun.COM 		fctl_ns_req_t	*ns_cmd;
11767836SJohn.Forte@Sun.COM 
11777836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
11787836SJohn.Forte@Sun.COM 
11797836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
11807836SJohn.Forte@Sun.COM 
11817836SJohn.Forte@Sun.COM 		if (job == NULL) {
11827836SJohn.Forte@Sun.COM 			*error = FC_NOMEM;
11837836SJohn.Forte@Sun.COM 			return (pd);
11847836SJohn.Forte@Sun.COM 		}
11857836SJohn.Forte@Sun.COM 
11867836SJohn.Forte@Sun.COM 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
11877836SJohn.Forte@Sun.COM 		    sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
11887836SJohn.Forte@Sun.COM 		    0, KM_SLEEP);
11897836SJohn.Forte@Sun.COM 
11907836SJohn.Forte@Sun.COM 		if (ns_cmd == NULL) {
11917836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
11927836SJohn.Forte@Sun.COM 			*error = FC_NOMEM;
11937836SJohn.Forte@Sun.COM 			return (pd);
11947836SJohn.Forte@Sun.COM 		}
11957836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_code = NS_GID_PN;
11967836SJohn.Forte@Sun.COM 		((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
11977836SJohn.Forte@Sun.COM 
11987836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
11997836SJohn.Forte@Sun.COM 		job->job_private = (void *)ns_cmd;
12007836SJohn.Forte@Sun.COM 		job->job_counter = 1;
12017836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
12027836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
12037836SJohn.Forte@Sun.COM 
12047836SJohn.Forte@Sun.COM 		if (job->job_result != FC_SUCCESS) {
12057836SJohn.Forte@Sun.COM 			*error = job->job_result;
12067836SJohn.Forte@Sun.COM 			fctl_free_ns_cmd(ns_cmd);
12077836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
12087836SJohn.Forte@Sun.COM 			return (pd);
12097836SJohn.Forte@Sun.COM 		}
12107836SJohn.Forte@Sun.COM 		d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
12117836SJohn.Forte@Sun.COM 		fctl_free_ns_cmd(ns_cmd);
12127836SJohn.Forte@Sun.COM 
12137836SJohn.Forte@Sun.COM 		ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
12147836SJohn.Forte@Sun.COM 		    sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
12157836SJohn.Forte@Sun.COM 		    KM_SLEEP);
12167836SJohn.Forte@Sun.COM 		ASSERT(ns_cmd != NULL);
12177836SJohn.Forte@Sun.COM 
12187836SJohn.Forte@Sun.COM 		ns_cmd->ns_gan_max = 1;
12197836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_code = NS_GA_NXT;
12207836SJohn.Forte@Sun.COM 		ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
12217836SJohn.Forte@Sun.COM 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
12227836SJohn.Forte@Sun.COM 		((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
12237836SJohn.Forte@Sun.COM 
12247836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
12257836SJohn.Forte@Sun.COM 		job->job_private = (void *)ns_cmd;
12267836SJohn.Forte@Sun.COM 		job->job_counter = 1;
12277836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
12287836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
12297836SJohn.Forte@Sun.COM 
12307836SJohn.Forte@Sun.COM 		fctl_free_ns_cmd(ns_cmd);
12317836SJohn.Forte@Sun.COM 		if (job->job_result != FC_SUCCESS) {
12327836SJohn.Forte@Sun.COM 			*error = job->job_result;
12337836SJohn.Forte@Sun.COM 			fctl_dealloc_job(job);
12347836SJohn.Forte@Sun.COM 			return (pd);
12357836SJohn.Forte@Sun.COM 		}
12367836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
12377836SJohn.Forte@Sun.COM 
12387836SJohn.Forte@Sun.COM 		/*
12397836SJohn.Forte@Sun.COM 		 * Check if the port device is created now.
12407836SJohn.Forte@Sun.COM 		 */
12417836SJohn.Forte@Sun.COM 		pd = fctl_get_remote_port_by_pwwn(port, pwwn);
12427836SJohn.Forte@Sun.COM 
12437836SJohn.Forte@Sun.COM 		if (pd == NULL) {
12447836SJohn.Forte@Sun.COM 			*error = FC_FAILURE;
12457836SJohn.Forte@Sun.COM 		} else {
12467836SJohn.Forte@Sun.COM 			*error = FC_SUCCESS;
12477836SJohn.Forte@Sun.COM 
12487836SJohn.Forte@Sun.COM 			/*
12497836SJohn.Forte@Sun.COM 			 * A ULP now knows about this pd, so mark it
12507836SJohn.Forte@Sun.COM 			 */
12517836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
12527836SJohn.Forte@Sun.COM 			pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
12537836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
12547836SJohn.Forte@Sun.COM 		}
12557836SJohn.Forte@Sun.COM 	} else {
12567836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
12577836SJohn.Forte@Sun.COM 		*error = FC_FAILURE;
12587836SJohn.Forte@Sun.COM 	}
12597836SJohn.Forte@Sun.COM 
12607836SJohn.Forte@Sun.COM 	return (pd);
12617836SJohn.Forte@Sun.COM }
12627836SJohn.Forte@Sun.COM 
12637836SJohn.Forte@Sun.COM 
12647836SJohn.Forte@Sun.COM /*
12657836SJohn.Forte@Sun.COM  * If a NS object exists in the host and query is performed
12667836SJohn.Forte@Sun.COM  * on that object, we should retrieve it from our basket
12677836SJohn.Forte@Sun.COM  * and return it right here, there by saving a request going
12687836SJohn.Forte@Sun.COM  * all the up to the Name Server.
12697836SJohn.Forte@Sun.COM  */
12707836SJohn.Forte@Sun.COM int
fc_ulp_port_ns(opaque_t port_handle,opaque_t pd,fc_ns_cmd_t * ns_req)12717836SJohn.Forte@Sun.COM fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
12727836SJohn.Forte@Sun.COM {
127310264SZhong.Wang@Sun.COM 	int		rval;
12747836SJohn.Forte@Sun.COM 	int		fabric;
12757836SJohn.Forte@Sun.COM 	job_request_t	*job;
12767836SJohn.Forte@Sun.COM 	fctl_ns_req_t	*ns_cmd;
12777836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
12787836SJohn.Forte@Sun.COM 
12797836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
12807836SJohn.Forte@Sun.COM 	fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
12817836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
12827836SJohn.Forte@Sun.COM 
12837836SJohn.Forte@Sun.COM 	/*
12847836SJohn.Forte@Sun.COM 	 * Name server query can't be performed for devices not in Fabric
12857836SJohn.Forte@Sun.COM 	 */
12867836SJohn.Forte@Sun.COM 	if (!fabric && pd) {
12877836SJohn.Forte@Sun.COM 		return (FC_BADOBJECT);
12887836SJohn.Forte@Sun.COM 	}
12897836SJohn.Forte@Sun.COM 
12907836SJohn.Forte@Sun.COM 	if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
12917836SJohn.Forte@Sun.COM 		if (pd == NULL) {
12927836SJohn.Forte@Sun.COM 			rval = fctl_update_host_ns_values(port, ns_req);
12937836SJohn.Forte@Sun.COM 			if (rval != FC_SUCCESS) {
12947836SJohn.Forte@Sun.COM 				return (rval);
12957836SJohn.Forte@Sun.COM 			}
12967836SJohn.Forte@Sun.COM 		} else {
12977836SJohn.Forte@Sun.COM 			/*
12987836SJohn.Forte@Sun.COM 			 * Guess what, FC-GS-2 currently prohibits (not
12997836SJohn.Forte@Sun.COM 			 * in the strongest language though) setting of
13007836SJohn.Forte@Sun.COM 			 * NS object values by other ports. But we might
13017836SJohn.Forte@Sun.COM 			 * get that changed to at least accommodate setting
13027836SJohn.Forte@Sun.COM 			 * symbolic node/port names - But if disks/tapes
13037836SJohn.Forte@Sun.COM 			 * were going to provide a method to set these
13047836SJohn.Forte@Sun.COM 			 * values directly (which in turn might register
13057836SJohn.Forte@Sun.COM 			 * with the NS when they come up; yep, for that
13067836SJohn.Forte@Sun.COM 			 * to happen the disks will have to be very well
13077836SJohn.Forte@Sun.COM 			 * behaved Fabric citizen) we won't need to
13087836SJohn.Forte@Sun.COM 			 * register the symbolic port/node names for
13097836SJohn.Forte@Sun.COM 			 * other ports too (rather send down SCSI commands
13107836SJohn.Forte@Sun.COM 			 * to the devices to set the names)
13117836SJohn.Forte@Sun.COM 			 *
13127836SJohn.Forte@Sun.COM 			 * Be that as it may, let's continue to fail
13137836SJohn.Forte@Sun.COM 			 * registration requests for other ports. period.
13147836SJohn.Forte@Sun.COM 			 */
13157836SJohn.Forte@Sun.COM 			return (FC_BADOBJECT);
13167836SJohn.Forte@Sun.COM 		}
13177836SJohn.Forte@Sun.COM 
13187836SJohn.Forte@Sun.COM 		if (!fabric) {
13197836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
13207836SJohn.Forte@Sun.COM 		}
13217836SJohn.Forte@Sun.COM 	} else if (!fabric) {
13227836SJohn.Forte@Sun.COM 		return (fctl_retrieve_host_ns_values(port, ns_req));
13237836SJohn.Forte@Sun.COM 	}
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 	job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
13267836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
13277836SJohn.Forte@Sun.COM 
13287836SJohn.Forte@Sun.COM 	ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
13297836SJohn.Forte@Sun.COM 	    ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
13307836SJohn.Forte@Sun.COM 	ASSERT(ns_cmd != NULL);
13317836SJohn.Forte@Sun.COM 	ns_cmd->ns_cmd_code = ns_req->ns_cmd;
13327836SJohn.Forte@Sun.COM 	bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
13337836SJohn.Forte@Sun.COM 	    ns_req->ns_req_len);
13347836SJohn.Forte@Sun.COM 
13357836SJohn.Forte@Sun.COM 	job->job_private = (void *)ns_cmd;
13367836SJohn.Forte@Sun.COM 	fctl_enque_job(port, job);
13377836SJohn.Forte@Sun.COM 	fctl_jobwait(job);
13387836SJohn.Forte@Sun.COM 	rval = job->job_result;
13397836SJohn.Forte@Sun.COM 
13407836SJohn.Forte@Sun.COM 	if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
13417836SJohn.Forte@Sun.COM 		bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
13427836SJohn.Forte@Sun.COM 		    ns_cmd->ns_data_len);
13437836SJohn.Forte@Sun.COM 	}
13447836SJohn.Forte@Sun.COM 	bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
13457836SJohn.Forte@Sun.COM 	    sizeof (fc_ct_header_t));
13467836SJohn.Forte@Sun.COM 
13477836SJohn.Forte@Sun.COM 	fctl_free_ns_cmd(ns_cmd);
13487836SJohn.Forte@Sun.COM 	fctl_dealloc_job(job);
13497836SJohn.Forte@Sun.COM 
13507836SJohn.Forte@Sun.COM 	return (rval);
13517836SJohn.Forte@Sun.COM }
13527836SJohn.Forte@Sun.COM 
13537836SJohn.Forte@Sun.COM 
13547836SJohn.Forte@Sun.COM int
fc_ulp_transport(opaque_t port_handle,fc_packet_t * pkt)13557836SJohn.Forte@Sun.COM fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
13567836SJohn.Forte@Sun.COM {
13577836SJohn.Forte@Sun.COM 	int			rval;
135810264SZhong.Wang@Sun.COM 	fc_local_port_t		*port;
13597836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd, *newpd;
13607836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
13617836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
13627836SJohn.Forte@Sun.COM 
13637836SJohn.Forte@Sun.COM 	port = port_handle;
13647836SJohn.Forte@Sun.COM 
13657836SJohn.Forte@Sun.COM 	if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
13667836SJohn.Forte@Sun.COM 		return (port->fp_fca_tran->fca_transport(
13677836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, pkt));
13687836SJohn.Forte@Sun.COM 	}
13697836SJohn.Forte@Sun.COM 
13707836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
13717836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
13727836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
13737836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
13747836SJohn.Forte@Sun.COM 	}
13757836SJohn.Forte@Sun.COM 
13767836SJohn.Forte@Sun.COM 	/* A locus of race conditions */
13777836SJohn.Forte@Sun.COM 	if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
13787836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
13797836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
13807836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
13817836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
13827836SJohn.Forte@Sun.COM 	}
13837836SJohn.Forte@Sun.COM 
13847836SJohn.Forte@Sun.COM 	/*
13857836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
13867836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
13877836SJohn.Forte@Sun.COM 	 */
13887836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
13897836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
13907836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
13917836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
13927836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
13937836SJohn.Forte@Sun.COM 	}
13947836SJohn.Forte@Sun.COM 
13957836SJohn.Forte@Sun.COM 	pd = pkt->pkt_pd;
13967836SJohn.Forte@Sun.COM 	if (pd) {
13977836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
13987836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
13997836SJohn.Forte@Sun.COM 
14007836SJohn.Forte@Sun.COM 			newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
14017836SJohn.Forte@Sun.COM 			    &pd->pd_port_name);
14027836SJohn.Forte@Sun.COM 
14037836SJohn.Forte@Sun.COM 			/*
14047836SJohn.Forte@Sun.COM 			 * The remote port (pd) in the packet is no longer
14057836SJohn.Forte@Sun.COM 			 * usable, as the old pd still exists we can use the
14067836SJohn.Forte@Sun.COM 			 * WWN to check if we have a current pd for the device
14077836SJohn.Forte@Sun.COM 			 * we want. Either way we continue with the old logic
14087836SJohn.Forte@Sun.COM 			 * whether we have a new pd or not, as the new pd
14097836SJohn.Forte@Sun.COM 			 * could be bad, or have become unusable.
14107836SJohn.Forte@Sun.COM 			 */
14117836SJohn.Forte@Sun.COM 			if ((newpd) && (newpd != pd)) {
14127836SJohn.Forte@Sun.COM 
14137836SJohn.Forte@Sun.COM 				/*
14147836SJohn.Forte@Sun.COM 				 * There is a better remote port (pd) to try,
14157836SJohn.Forte@Sun.COM 				 * so we need to fix the reference counts, etc.
14167836SJohn.Forte@Sun.COM 				 */
14177836SJohn.Forte@Sun.COM 				mutex_enter(&newpd->pd_mutex);
14187836SJohn.Forte@Sun.COM 				newpd->pd_ref_count++;
14197836SJohn.Forte@Sun.COM 				pkt->pkt_pd = newpd;
14207836SJohn.Forte@Sun.COM 				mutex_exit(&newpd->pd_mutex);
14217836SJohn.Forte@Sun.COM 
14227836SJohn.Forte@Sun.COM 				mutex_enter(&pd->pd_mutex);
14237836SJohn.Forte@Sun.COM 				pd->pd_ref_count--;
14247836SJohn.Forte@Sun.COM 				if ((pd->pd_state == PORT_DEVICE_INVALID) &&
14257836SJohn.Forte@Sun.COM 				    (pd->pd_ref_count == 0)) {
14267836SJohn.Forte@Sun.COM 					fc_remote_node_t *node =
14277836SJohn.Forte@Sun.COM 					    pd->pd_remote_nodep;
14287836SJohn.Forte@Sun.COM 
14297836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
14307836SJohn.Forte@Sun.COM 					mutex_exit(&port->fp_mutex);
14317836SJohn.Forte@Sun.COM 
14327836SJohn.Forte@Sun.COM 					/*
14337836SJohn.Forte@Sun.COM 					 * This will create another PD hole
14347836SJohn.Forte@Sun.COM 					 * where we have a reference to a pd,
14357836SJohn.Forte@Sun.COM 					 * but someone else could remove it.
14367836SJohn.Forte@Sun.COM 					 */
14377836SJohn.Forte@Sun.COM 					if ((fctl_destroy_remote_port(port, pd)
14387836SJohn.Forte@Sun.COM 					    == 0) && (node != NULL)) {
14397836SJohn.Forte@Sun.COM 						fctl_destroy_remote_node(node);
14407836SJohn.Forte@Sun.COM 					}
14417836SJohn.Forte@Sun.COM 					mutex_enter(&port->fp_mutex);
14427836SJohn.Forte@Sun.COM 				} else {
14437836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
14447836SJohn.Forte@Sun.COM 				}
14457836SJohn.Forte@Sun.COM 				pd = newpd;
14467836SJohn.Forte@Sun.COM 			}
14477836SJohn.Forte@Sun.COM 		}
14487836SJohn.Forte@Sun.COM 
14497836SJohn.Forte@Sun.COM 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
14507836SJohn.Forte@Sun.COM 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
14517836SJohn.Forte@Sun.COM 			    FC_LOGINREQ : FC_BADDEV;
14527836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
14537836SJohn.Forte@Sun.COM 			return (rval);
14547836SJohn.Forte@Sun.COM 		}
14557836SJohn.Forte@Sun.COM 
14567836SJohn.Forte@Sun.COM 		if (pd->pd_flags != PD_IDLE) {
14577836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
14587836SJohn.Forte@Sun.COM 			return (FC_DEVICE_BUSY);
14597836SJohn.Forte@Sun.COM 		}
14607836SJohn.Forte@Sun.COM 
14617836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
14627836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
14637836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
14647836SJohn.Forte@Sun.COM 			return (FC_BADDEV);
14657836SJohn.Forte@Sun.COM 		}
14667836SJohn.Forte@Sun.COM 
14677836SJohn.Forte@Sun.COM 	} else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
14687836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
14697836SJohn.Forte@Sun.COM 		return (FC_BADPACKET);
14707836SJohn.Forte@Sun.COM 	}
14717836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
14727836SJohn.Forte@Sun.COM 
14737836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
14747836SJohn.Forte@Sun.COM }
14757836SJohn.Forte@Sun.COM 
14767836SJohn.Forte@Sun.COM 
14777836SJohn.Forte@Sun.COM int
fc_ulp_issue_els(opaque_t port_handle,fc_packet_t * pkt)14787836SJohn.Forte@Sun.COM fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
14797836SJohn.Forte@Sun.COM {
14807836SJohn.Forte@Sun.COM 	int			rval;
148110264SZhong.Wang@Sun.COM 	fc_local_port_t		*port = port_handle;
14827836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
14837836SJohn.Forte@Sun.COM 	fc_ulp_rscn_info_t	*rscnp =
14847836SJohn.Forte@Sun.COM 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
14857836SJohn.Forte@Sun.COM 
14867836SJohn.Forte@Sun.COM 	/*
14877836SJohn.Forte@Sun.COM 	 * If the port is OFFLINE, or if the port driver is
14887836SJohn.Forte@Sun.COM 	 * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
14897836SJohn.Forte@Sun.COM 	 * ELS operations
14907836SJohn.Forte@Sun.COM 	 */
14917836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
14927836SJohn.Forte@Sun.COM 	if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
14937836SJohn.Forte@Sun.COM 	    (port->fp_soft_state &
14947836SJohn.Forte@Sun.COM 	    (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
14957836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
14967836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
14977836SJohn.Forte@Sun.COM 	}
14987836SJohn.Forte@Sun.COM 
14997836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
15007836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
15017836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
15027836SJohn.Forte@Sun.COM 	}
15037836SJohn.Forte@Sun.COM 
15047836SJohn.Forte@Sun.COM 	/*
15057836SJohn.Forte@Sun.COM 	 * If the rscn count in the packet is not the same as the rscn count
15067836SJohn.Forte@Sun.COM 	 * in the fc_local_port_t, then one or more new RSCNs has occurred.
15077836SJohn.Forte@Sun.COM 	 */
15087836SJohn.Forte@Sun.COM 	if ((rscnp != NULL) &&
15097836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
15107836SJohn.Forte@Sun.COM 	    (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
15117836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
15127836SJohn.Forte@Sun.COM 		return (FC_DEVICE_BUSY_NEW_RSCN);
15137836SJohn.Forte@Sun.COM 	}
15147836SJohn.Forte@Sun.COM 
15157836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
15167836SJohn.Forte@Sun.COM 
15177836SJohn.Forte@Sun.COM 	if ((pd = pkt->pkt_pd) != NULL) {
15187836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
15197836SJohn.Forte@Sun.COM 		if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
15207836SJohn.Forte@Sun.COM 			rval = (pd->pd_state == PORT_DEVICE_VALID) ?
15217836SJohn.Forte@Sun.COM 			    FC_LOGINREQ : FC_BADDEV;
15227836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
15237836SJohn.Forte@Sun.COM 			return (rval);
15247836SJohn.Forte@Sun.COM 		}
15257836SJohn.Forte@Sun.COM 
15267836SJohn.Forte@Sun.COM 		if (pd->pd_flags != PD_IDLE) {
15277836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
15287836SJohn.Forte@Sun.COM 			return (FC_DEVICE_BUSY);
15297836SJohn.Forte@Sun.COM 		}
15307836SJohn.Forte@Sun.COM 		if (pd->pd_type == PORT_DEVICE_OLD ||
15317836SJohn.Forte@Sun.COM 		    pd->pd_state == PORT_DEVICE_INVALID) {
15327836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
15337836SJohn.Forte@Sun.COM 			return (FC_BADDEV);
15347836SJohn.Forte@Sun.COM 		}
15357836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
15367836SJohn.Forte@Sun.COM 	}
15377836SJohn.Forte@Sun.COM 
15387836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
15397836SJohn.Forte@Sun.COM }
15407836SJohn.Forte@Sun.COM 
15417836SJohn.Forte@Sun.COM 
15427836SJohn.Forte@Sun.COM int
fc_ulp_uballoc(opaque_t port_handle,uint32_t * count,uint32_t size,uint32_t type,uint64_t * tokens)15437836SJohn.Forte@Sun.COM fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
15447836SJohn.Forte@Sun.COM     uint32_t type, uint64_t *tokens)
15457836SJohn.Forte@Sun.COM {
15467836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
15477836SJohn.Forte@Sun.COM 
15487836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
15497836SJohn.Forte@Sun.COM 	    tokens, size, count, type));
15507836SJohn.Forte@Sun.COM }
15517836SJohn.Forte@Sun.COM 
15527836SJohn.Forte@Sun.COM 
15537836SJohn.Forte@Sun.COM int
fc_ulp_ubfree(opaque_t port_handle,uint32_t count,uint64_t * tokens)15547836SJohn.Forte@Sun.COM fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
15557836SJohn.Forte@Sun.COM {
15567836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
15577836SJohn.Forte@Sun.COM 
15587836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
15597836SJohn.Forte@Sun.COM 	    count, tokens));
15607836SJohn.Forte@Sun.COM }
15617836SJohn.Forte@Sun.COM 
15627836SJohn.Forte@Sun.COM 
15637836SJohn.Forte@Sun.COM int
fc_ulp_ubrelease(opaque_t port_handle,uint32_t count,uint64_t * tokens)15647836SJohn.Forte@Sun.COM fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
15657836SJohn.Forte@Sun.COM {
15667836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
15677836SJohn.Forte@Sun.COM 
15687836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
15697836SJohn.Forte@Sun.COM 	    count, tokens));
15707836SJohn.Forte@Sun.COM }
15717836SJohn.Forte@Sun.COM 
15727836SJohn.Forte@Sun.COM 
15737836SJohn.Forte@Sun.COM int
fc_ulp_abort(opaque_t port_handle,fc_packet_t * pkt,int flags)15747836SJohn.Forte@Sun.COM fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
15757836SJohn.Forte@Sun.COM {
15767836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
15777836SJohn.Forte@Sun.COM 
15787836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
15797836SJohn.Forte@Sun.COM }
15807836SJohn.Forte@Sun.COM 
15817836SJohn.Forte@Sun.COM 
15827836SJohn.Forte@Sun.COM /*
15837836SJohn.Forte@Sun.COM  * Submit an asynchronous request to the job handler if the sleep
15847836SJohn.Forte@Sun.COM  * flag is set to KM_NOSLEEP, as such calls could have been made
15857836SJohn.Forte@Sun.COM  * in interrupt contexts, and the goal is to avoid busy waiting,
15867836SJohn.Forte@Sun.COM  * blocking on a conditional variable, a semaphore or any of the
15877836SJohn.Forte@Sun.COM  * synchronization primitives. A noticeable draw back with this
15887836SJohn.Forte@Sun.COM  * asynchronous request is that an FC_SUCCESS is returned long
15897836SJohn.Forte@Sun.COM  * before the reset is complete (successful or not).
15907836SJohn.Forte@Sun.COM  */
15917836SJohn.Forte@Sun.COM int
fc_ulp_linkreset(opaque_t port_handle,la_wwn_t * pwwn,int sleep)15927836SJohn.Forte@Sun.COM fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
15937836SJohn.Forte@Sun.COM {
15947836SJohn.Forte@Sun.COM 	int		rval;
15957836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
15967836SJohn.Forte@Sun.COM 	job_request_t	*job;
15977836SJohn.Forte@Sun.COM 
15987836SJohn.Forte@Sun.COM 	port = port_handle;
15997836SJohn.Forte@Sun.COM 	/*
16007836SJohn.Forte@Sun.COM 	 * Many a times, this function is called from interrupt
16017836SJohn.Forte@Sun.COM 	 * contexts and there have been several dead locks and
16027836SJohn.Forte@Sun.COM 	 * hangs - One of the simplest work arounds is to fib
16037836SJohn.Forte@Sun.COM 	 * if a RESET is in progress.
16047836SJohn.Forte@Sun.COM 	 */
16057836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
16067836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
16077836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
16087836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
16097836SJohn.Forte@Sun.COM 	}
16107836SJohn.Forte@Sun.COM 
16117836SJohn.Forte@Sun.COM 	/*
16127836SJohn.Forte@Sun.COM 	 * Ward off this reset if a state change is in progress.
16137836SJohn.Forte@Sun.COM 	 */
16147836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
16157836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
16167836SJohn.Forte@Sun.COM 		return (FC_STATEC_BUSY);
16177836SJohn.Forte@Sun.COM 	}
16187836SJohn.Forte@Sun.COM 	port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
16197836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
16207836SJohn.Forte@Sun.COM 
16217836SJohn.Forte@Sun.COM 	if (fctl_busy_port(port) != 0) {
16227836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
16237836SJohn.Forte@Sun.COM 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
16247836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
16257836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
16267836SJohn.Forte@Sun.COM 	}
16277836SJohn.Forte@Sun.COM 
16287836SJohn.Forte@Sun.COM 	if (sleep == KM_SLEEP) {
16297836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
16307836SJohn.Forte@Sun.COM 		ASSERT(job != NULL);
16317836SJohn.Forte@Sun.COM 
16327836SJohn.Forte@Sun.COM 		job->job_private = (void *)pwwn;
16337836SJohn.Forte@Sun.COM 		job->job_counter = 1;
16347836SJohn.Forte@Sun.COM 		fctl_enque_job(port, job);
16357836SJohn.Forte@Sun.COM 		fctl_jobwait(job);
16367836SJohn.Forte@Sun.COM 
16377836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
16387836SJohn.Forte@Sun.COM 		port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
16397836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
16407836SJohn.Forte@Sun.COM 
16417836SJohn.Forte@Sun.COM 		fctl_idle_port(port);
16427836SJohn.Forte@Sun.COM 
16437836SJohn.Forte@Sun.COM 		rval = job->job_result;
16447836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
16457836SJohn.Forte@Sun.COM 	} else {
16467836SJohn.Forte@Sun.COM 		job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
16477836SJohn.Forte@Sun.COM 		    fctl_link_reset_done, port, sleep);
16487836SJohn.Forte@Sun.COM 		if (job == NULL) {
16497836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
16507836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
16517836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
16527836SJohn.Forte@Sun.COM 			fctl_idle_port(port);
16537836SJohn.Forte@Sun.COM 			return (FC_NOMEM);
16547836SJohn.Forte@Sun.COM 		}
16557836SJohn.Forte@Sun.COM 		job->job_private = (void *)pwwn;
16567836SJohn.Forte@Sun.COM 		job->job_counter = 1;
16577836SJohn.Forte@Sun.COM 		fctl_priority_enque_job(port, job);
16587836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
16597836SJohn.Forte@Sun.COM 	}
16607836SJohn.Forte@Sun.COM 
16617836SJohn.Forte@Sun.COM 	return (rval);
16627836SJohn.Forte@Sun.COM }
16637836SJohn.Forte@Sun.COM 
16647836SJohn.Forte@Sun.COM 
16657836SJohn.Forte@Sun.COM int
fc_ulp_port_reset(opaque_t port_handle,uint32_t cmd)16667836SJohn.Forte@Sun.COM fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
16677836SJohn.Forte@Sun.COM {
16687836SJohn.Forte@Sun.COM 	int		rval = FC_SUCCESS;
16697836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
16707836SJohn.Forte@Sun.COM 
16717836SJohn.Forte@Sun.COM 	switch (cmd) {
16727836SJohn.Forte@Sun.COM 	case FC_RESET_PORT:
16737836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
16747836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_LINK_RESET);
16757836SJohn.Forte@Sun.COM 		break;
16767836SJohn.Forte@Sun.COM 
16777836SJohn.Forte@Sun.COM 	case FC_RESET_ADAPTER:
16787836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
16797836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_RESET);
16807836SJohn.Forte@Sun.COM 		break;
16817836SJohn.Forte@Sun.COM 
16827836SJohn.Forte@Sun.COM 	case FC_RESET_DUMP:
16837836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
16847836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_CORE);
16857836SJohn.Forte@Sun.COM 		break;
16867836SJohn.Forte@Sun.COM 
16877836SJohn.Forte@Sun.COM 	case FC_RESET_CRASH:
16887836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_reset(
16897836SJohn.Forte@Sun.COM 		    port->fp_fca_handle, FC_FCA_RESET_CORE);
16907836SJohn.Forte@Sun.COM 		break;
16917836SJohn.Forte@Sun.COM 
16927836SJohn.Forte@Sun.COM 	default:
16937836SJohn.Forte@Sun.COM 		rval = FC_FAILURE;
16947836SJohn.Forte@Sun.COM 	}
16957836SJohn.Forte@Sun.COM 
16967836SJohn.Forte@Sun.COM 	return (rval);
16977836SJohn.Forte@Sun.COM }
16987836SJohn.Forte@Sun.COM 
16997836SJohn.Forte@Sun.COM 
17007836SJohn.Forte@Sun.COM int
fc_ulp_get_port_login_params(opaque_t port_handle,la_els_logi_t * login_params)17017836SJohn.Forte@Sun.COM fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
17027836SJohn.Forte@Sun.COM {
17037836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
17047836SJohn.Forte@Sun.COM 
17057836SJohn.Forte@Sun.COM 	/* Copy the login parameters */
17067836SJohn.Forte@Sun.COM 	*login_params = port->fp_service_params;
17077836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
17087836SJohn.Forte@Sun.COM }
17097836SJohn.Forte@Sun.COM 
17107836SJohn.Forte@Sun.COM 
17117836SJohn.Forte@Sun.COM int
fc_ulp_get_port_instance(opaque_t port_handle)17127836SJohn.Forte@Sun.COM fc_ulp_get_port_instance(opaque_t port_handle)
17137836SJohn.Forte@Sun.COM {
17147836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
17157836SJohn.Forte@Sun.COM 
17167836SJohn.Forte@Sun.COM 	return (port->fp_instance);
17177836SJohn.Forte@Sun.COM }
17187836SJohn.Forte@Sun.COM 
17197836SJohn.Forte@Sun.COM 
17207836SJohn.Forte@Sun.COM opaque_t
fc_ulp_get_port_handle(int port_instance)17217836SJohn.Forte@Sun.COM fc_ulp_get_port_handle(int port_instance)
17227836SJohn.Forte@Sun.COM {
17237836SJohn.Forte@Sun.COM 	opaque_t	port_handle = NULL;
172410264SZhong.Wang@Sun.COM 	fc_fca_port_t	*cur;
17257836SJohn.Forte@Sun.COM 
17267836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
17277836SJohn.Forte@Sun.COM 	for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
17287836SJohn.Forte@Sun.COM 		if (cur->port_handle->fp_instance == port_instance) {
17297836SJohn.Forte@Sun.COM 			port_handle = (opaque_t)cur->port_handle;
17307836SJohn.Forte@Sun.COM 			break;
17317836SJohn.Forte@Sun.COM 		}
17327836SJohn.Forte@Sun.COM 	}
17337836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
17347836SJohn.Forte@Sun.COM 
17357836SJohn.Forte@Sun.COM 	return (port_handle);
17367836SJohn.Forte@Sun.COM }
17377836SJohn.Forte@Sun.COM 
17387836SJohn.Forte@Sun.COM 
17397836SJohn.Forte@Sun.COM int
fc_ulp_error(int fc_errno,char ** errmsg)17407836SJohn.Forte@Sun.COM fc_ulp_error(int fc_errno, char **errmsg)
17417836SJohn.Forte@Sun.COM {
17427836SJohn.Forte@Sun.COM 	return (fctl_error(fc_errno, errmsg));
17437836SJohn.Forte@Sun.COM }
17447836SJohn.Forte@Sun.COM 
17457836SJohn.Forte@Sun.COM 
17467836SJohn.Forte@Sun.COM int
fc_ulp_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)17477836SJohn.Forte@Sun.COM fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
17487836SJohn.Forte@Sun.COM     char **action, char **expln)
17497836SJohn.Forte@Sun.COM {
17507836SJohn.Forte@Sun.COM 	return (fctl_pkt_error(pkt, state, reason, action, expln));
17517836SJohn.Forte@Sun.COM }
17527836SJohn.Forte@Sun.COM 
17537836SJohn.Forte@Sun.COM 
17547836SJohn.Forte@Sun.COM /*
17557836SJohn.Forte@Sun.COM  * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
17567836SJohn.Forte@Sun.COM  */
17577836SJohn.Forte@Sun.COM int
fc_ulp_is_name_present(caddr_t ulp_name)17587836SJohn.Forte@Sun.COM fc_ulp_is_name_present(caddr_t ulp_name)
17597836SJohn.Forte@Sun.COM {
17607836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
17617836SJohn.Forte@Sun.COM 	fc_ulp_list_t	*list;
17627836SJohn.Forte@Sun.COM 
17637836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_ulp_list_mutex);
17647836SJohn.Forte@Sun.COM 	for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
17657836SJohn.Forte@Sun.COM 		if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
17667836SJohn.Forte@Sun.COM 			rval = FC_SUCCESS;
17677836SJohn.Forte@Sun.COM 			break;
17687836SJohn.Forte@Sun.COM 		}
17697836SJohn.Forte@Sun.COM 	}
17707836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_ulp_list_mutex);
17717836SJohn.Forte@Sun.COM 
17727836SJohn.Forte@Sun.COM 	return (rval);
17737836SJohn.Forte@Sun.COM }
17747836SJohn.Forte@Sun.COM 
17757836SJohn.Forte@Sun.COM 
17767836SJohn.Forte@Sun.COM /*
17777836SJohn.Forte@Sun.COM  * Return port WWN for a port Identifier
17787836SJohn.Forte@Sun.COM  */
17797836SJohn.Forte@Sun.COM int
fc_ulp_get_pwwn_by_did(opaque_t port_handle,fc_portid_t d_id,la_wwn_t * pwwn)17807836SJohn.Forte@Sun.COM fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
17817836SJohn.Forte@Sun.COM {
17827836SJohn.Forte@Sun.COM 	int			rval = FC_FAILURE;
17837836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
17847836SJohn.Forte@Sun.COM 	fc_local_port_t		*port = port_handle;
17857836SJohn.Forte@Sun.COM 
17867836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_did(port, d_id.port_id);
17877836SJohn.Forte@Sun.COM 	if (pd != NULL) {
17887836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
17897836SJohn.Forte@Sun.COM 		*pwwn = pd->pd_port_name;
17907836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
17917836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
17927836SJohn.Forte@Sun.COM 	}
17937836SJohn.Forte@Sun.COM 
17947836SJohn.Forte@Sun.COM 	return (rval);
17957836SJohn.Forte@Sun.COM }
17967836SJohn.Forte@Sun.COM 
17977836SJohn.Forte@Sun.COM 
17987836SJohn.Forte@Sun.COM /*
17997836SJohn.Forte@Sun.COM  * Return a port map for a port WWN
18007836SJohn.Forte@Sun.COM  */
18017836SJohn.Forte@Sun.COM int
fc_ulp_pwwn_to_portmap(opaque_t port_handle,la_wwn_t * bytes,fc_portmap_t * map)18027836SJohn.Forte@Sun.COM fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
18037836SJohn.Forte@Sun.COM {
18047836SJohn.Forte@Sun.COM 	fc_local_port_t		*port = port_handle;
18057836SJohn.Forte@Sun.COM 	fc_remote_node_t	*node;
180610264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
18077836SJohn.Forte@Sun.COM 
18087836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn(port, bytes);
18097836SJohn.Forte@Sun.COM 	if (pd == NULL) {
18107836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
18117836SJohn.Forte@Sun.COM 	}
18127836SJohn.Forte@Sun.COM 
18137836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
18147836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
18157836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
18167836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
18177836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
18187836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
18197836SJohn.Forte@Sun.COM 	map->map_flags = 0;
18207836SJohn.Forte@Sun.COM 
18217836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
18227836SJohn.Forte@Sun.COM 
18237836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
18247836SJohn.Forte@Sun.COM 
18257836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
18267836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
18277836SJohn.Forte@Sun.COM 
18287836SJohn.Forte@Sun.COM 	if (node) {
18297836SJohn.Forte@Sun.COM 		mutex_enter(&node->fd_mutex);
18307836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
18317836SJohn.Forte@Sun.COM 		mutex_exit(&node->fd_mutex);
18327836SJohn.Forte@Sun.COM 	}
18337836SJohn.Forte@Sun.COM 	map->map_pd = pd;
18347836SJohn.Forte@Sun.COM 
18357836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
18367836SJohn.Forte@Sun.COM }
18377836SJohn.Forte@Sun.COM 
18387836SJohn.Forte@Sun.COM 
18397836SJohn.Forte@Sun.COM opaque_t
fc_ulp_get_fca_device(opaque_t port_handle,fc_portid_t d_id)18407836SJohn.Forte@Sun.COM fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
18417836SJohn.Forte@Sun.COM {
18427836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
18437836SJohn.Forte@Sun.COM 
18447836SJohn.Forte@Sun.COM 	if (port->fp_fca_tran->fca_get_device == NULL) {
18457836SJohn.Forte@Sun.COM 		return (NULL);
18467836SJohn.Forte@Sun.COM 	}
18477836SJohn.Forte@Sun.COM 
18487836SJohn.Forte@Sun.COM 	return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
18497836SJohn.Forte@Sun.COM }
18507836SJohn.Forte@Sun.COM 
18517836SJohn.Forte@Sun.COM 
18527836SJohn.Forte@Sun.COM int
fc_ulp_port_notify(opaque_t port_handle,uint32_t cmd)18537836SJohn.Forte@Sun.COM fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
18547836SJohn.Forte@Sun.COM {
18557836SJohn.Forte@Sun.COM 	int		rval = FC_SUCCESS;
18567836SJohn.Forte@Sun.COM 	fc_local_port_t	*port = port_handle;
18577836SJohn.Forte@Sun.COM 
18587836SJohn.Forte@Sun.COM 	if (port->fp_fca_tran->fca_notify) {
18597836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
18607836SJohn.Forte@Sun.COM 		switch (cmd) {
18617836SJohn.Forte@Sun.COM 		case FC_NOTIFY_TARGET_MODE:
18627836SJohn.Forte@Sun.COM 			port->fp_options |= FP_TARGET_MODE;
18637836SJohn.Forte@Sun.COM 			break;
18647836SJohn.Forte@Sun.COM 		case FC_NOTIFY_NO_TARGET_MODE:
18657836SJohn.Forte@Sun.COM 			port->fp_options &= ~FP_TARGET_MODE;
18667836SJohn.Forte@Sun.COM 			break;
18677836SJohn.Forte@Sun.COM 		}
18687836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
18697836SJohn.Forte@Sun.COM 		rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
18707836SJohn.Forte@Sun.COM 	}
18717836SJohn.Forte@Sun.COM 
18727836SJohn.Forte@Sun.COM 	return (rval);
18737836SJohn.Forte@Sun.COM }
18747836SJohn.Forte@Sun.COM 
18757836SJohn.Forte@Sun.COM 
18767836SJohn.Forte@Sun.COM void
fc_ulp_disable_relogin(opaque_t * fc_port,la_wwn_t * pwwn)18777836SJohn.Forte@Sun.COM fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
18787836SJohn.Forte@Sun.COM {
18797836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd =
18807836SJohn.Forte@Sun.COM 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
18817836SJohn.Forte@Sun.COM 
18827836SJohn.Forte@Sun.COM 	if (pd) {
18837836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
18847836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_DISABLE_RELOGIN;
18857836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
18867836SJohn.Forte@Sun.COM 	}
18877836SJohn.Forte@Sun.COM }
18887836SJohn.Forte@Sun.COM 
18897836SJohn.Forte@Sun.COM 
18907836SJohn.Forte@Sun.COM void
fc_ulp_enable_relogin(opaque_t * fc_port,la_wwn_t * pwwn)18917836SJohn.Forte@Sun.COM fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
18927836SJohn.Forte@Sun.COM {
18937836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd =
18947836SJohn.Forte@Sun.COM 	    fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
18957836SJohn.Forte@Sun.COM 
18967836SJohn.Forte@Sun.COM 	if (pd) {
18977836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
18987836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
18997836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
19007836SJohn.Forte@Sun.COM 	}
19017836SJohn.Forte@Sun.COM }
19027836SJohn.Forte@Sun.COM 
19037836SJohn.Forte@Sun.COM 
19047836SJohn.Forte@Sun.COM /*
19057836SJohn.Forte@Sun.COM  * fc_fca_init
190610264SZhong.Wang@Sun.COM  *		Overload the FCA bus_ops vector in its dev_ops with
19077836SJohn.Forte@Sun.COM  *		fctl_fca_busops to handle all the INITchilds for "sf"
19087836SJohn.Forte@Sun.COM  *		in one common place.
19097836SJohn.Forte@Sun.COM  *
19107836SJohn.Forte@Sun.COM  *		Should be called from FCA _init routine.
19117836SJohn.Forte@Sun.COM  */
19127836SJohn.Forte@Sun.COM void
fc_fca_init(struct dev_ops * fca_devops_p)19137836SJohn.Forte@Sun.COM fc_fca_init(struct dev_ops *fca_devops_p)
19147836SJohn.Forte@Sun.COM {
19157836SJohn.Forte@Sun.COM #ifndef	__lock_lint
19167836SJohn.Forte@Sun.COM 	fca_devops_p->devo_bus_ops = &fctl_fca_busops;
19177836SJohn.Forte@Sun.COM #endif	/* __lock_lint */
19187836SJohn.Forte@Sun.COM }
19197836SJohn.Forte@Sun.COM 
19207836SJohn.Forte@Sun.COM 
19217836SJohn.Forte@Sun.COM /*
19227836SJohn.Forte@Sun.COM  * fc_fca_attach
19237836SJohn.Forte@Sun.COM  */
19247836SJohn.Forte@Sun.COM int
fc_fca_attach(dev_info_t * fca_dip,fc_fca_tran_t * tran)19257836SJohn.Forte@Sun.COM fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
19267836SJohn.Forte@Sun.COM {
19277836SJohn.Forte@Sun.COM 	/*
19287836SJohn.Forte@Sun.COM 	 * When we are in a position to offer downward compatibility
19297836SJohn.Forte@Sun.COM 	 * we should change the following check to allow lower revision
19307836SJohn.Forte@Sun.COM 	 * of FCAs; But we aren't there right now.
19317836SJohn.Forte@Sun.COM 	 */
19327836SJohn.Forte@Sun.COM 	if (tran->fca_version != FCTL_FCA_MODREV_5) {
19337836SJohn.Forte@Sun.COM 		const char *name = ddi_driver_name(fca_dip);
19347836SJohn.Forte@Sun.COM 
19357836SJohn.Forte@Sun.COM 		ASSERT(name != NULL);
19367836SJohn.Forte@Sun.COM 
19377836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
19387836SJohn.Forte@Sun.COM 		    " please upgrade %s", name, name);
19397836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
19407836SJohn.Forte@Sun.COM 	}
19417836SJohn.Forte@Sun.COM 
19427836SJohn.Forte@Sun.COM 	ddi_set_driver_private(fca_dip, (caddr_t)tran);
19437836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
19447836SJohn.Forte@Sun.COM }
19457836SJohn.Forte@Sun.COM 
19467836SJohn.Forte@Sun.COM 
19477836SJohn.Forte@Sun.COM /*
19487836SJohn.Forte@Sun.COM  * fc_fca_detach
19497836SJohn.Forte@Sun.COM  */
19507836SJohn.Forte@Sun.COM int
fc_fca_detach(dev_info_t * fca_dip)19517836SJohn.Forte@Sun.COM fc_fca_detach(dev_info_t *fca_dip)
19527836SJohn.Forte@Sun.COM {
19537836SJohn.Forte@Sun.COM 	ddi_set_driver_private(fca_dip, NULL);
19547836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
19557836SJohn.Forte@Sun.COM }
19567836SJohn.Forte@Sun.COM 
19577836SJohn.Forte@Sun.COM 
19587836SJohn.Forte@Sun.COM /*
19597836SJohn.Forte@Sun.COM  * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
19607836SJohn.Forte@Sun.COM  * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
19617836SJohn.Forte@Sun.COM  * Link Service responses such as BA_RJT and Extended Link Service response
19627836SJohn.Forte@Sun.COM  * such as LS_RJT. If the response is a Link_Data Frame or something that
19637836SJohn.Forte@Sun.COM  * this function doesn't understand return FC_FAILURE; Otherwise, fill out
19647836SJohn.Forte@Sun.COM  * various fields (state, action, reason, expln) from the response gotten
19657836SJohn.Forte@Sun.COM  * in the packet and return FC_SUCCESS.
19667836SJohn.Forte@Sun.COM  */
19677836SJohn.Forte@Sun.COM int
fc_fca_update_errors(fc_packet_t * pkt)19687836SJohn.Forte@Sun.COM fc_fca_update_errors(fc_packet_t *pkt)
19697836SJohn.Forte@Sun.COM {
19707836SJohn.Forte@Sun.COM 	int ret = FC_SUCCESS;
19717836SJohn.Forte@Sun.COM 
19727836SJohn.Forte@Sun.COM 	switch (pkt->pkt_resp_fhdr.r_ctl) {
19737836SJohn.Forte@Sun.COM 	case R_CTL_P_RJT: {
19747836SJohn.Forte@Sun.COM 		uint32_t prjt;
19757836SJohn.Forte@Sun.COM 
19767836SJohn.Forte@Sun.COM 		prjt = pkt->pkt_resp_fhdr.ro;
19777836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_NPORT_RJT;
19787836SJohn.Forte@Sun.COM 		pkt->pkt_action = (prjt & 0xFF000000) >> 24;
19797836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (prjt & 0xFF0000) >> 16;
19807836SJohn.Forte@Sun.COM 		break;
19817836SJohn.Forte@Sun.COM 	}
19827836SJohn.Forte@Sun.COM 
19837836SJohn.Forte@Sun.COM 	case R_CTL_F_RJT: {
19847836SJohn.Forte@Sun.COM 		uint32_t frjt;
19857836SJohn.Forte@Sun.COM 
19867836SJohn.Forte@Sun.COM 		frjt = pkt->pkt_resp_fhdr.ro;
19877836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_FABRIC_RJT;
19887836SJohn.Forte@Sun.COM 		pkt->pkt_action = (frjt & 0xFF000000) >> 24;
19897836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (frjt & 0xFF0000) >> 16;
19907836SJohn.Forte@Sun.COM 		break;
19917836SJohn.Forte@Sun.COM 	}
19927836SJohn.Forte@Sun.COM 
19937836SJohn.Forte@Sun.COM 	case R_CTL_P_BSY: {
19947836SJohn.Forte@Sun.COM 		uint32_t pbsy;
19957836SJohn.Forte@Sun.COM 
19967836SJohn.Forte@Sun.COM 		pbsy = pkt->pkt_resp_fhdr.ro;
19977836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_NPORT_BSY;
19987836SJohn.Forte@Sun.COM 		pkt->pkt_action = (pbsy & 0xFF000000) >> 24;
19997836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (pbsy & 0xFF0000) >> 16;
20007836SJohn.Forte@Sun.COM 		break;
20017836SJohn.Forte@Sun.COM 	}
20027836SJohn.Forte@Sun.COM 
20037836SJohn.Forte@Sun.COM 	case R_CTL_F_BSY_LC:
20047836SJohn.Forte@Sun.COM 	case R_CTL_F_BSY_DF: {
20057836SJohn.Forte@Sun.COM 		uchar_t fbsy;
20067836SJohn.Forte@Sun.COM 
20077836SJohn.Forte@Sun.COM 		fbsy = pkt->pkt_resp_fhdr.type;
20087836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_FABRIC_BSY;
20097836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (fbsy & 0xF0) >> 4;
20107836SJohn.Forte@Sun.COM 		break;
20117836SJohn.Forte@Sun.COM 	}
20127836SJohn.Forte@Sun.COM 
20137836SJohn.Forte@Sun.COM 	case R_CTL_LS_BA_RJT: {
20147836SJohn.Forte@Sun.COM 		uint32_t brjt;
20157836SJohn.Forte@Sun.COM 
20167836SJohn.Forte@Sun.COM 		brjt = *(uint32_t *)pkt->pkt_resp;
20177836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_BA_RJT;
20187836SJohn.Forte@Sun.COM 		pkt->pkt_reason = (brjt & 0xFF0000) >> 16;
20197836SJohn.Forte@Sun.COM 		pkt->pkt_expln = (brjt & 0xFF00) >> 8;
20207836SJohn.Forte@Sun.COM 		break;
20217836SJohn.Forte@Sun.COM 	}
20227836SJohn.Forte@Sun.COM 
20237836SJohn.Forte@Sun.COM 	case R_CTL_ELS_RSP: {
20247836SJohn.Forte@Sun.COM 		la_els_rjt_t *lsrjt;
20257836SJohn.Forte@Sun.COM 
20267836SJohn.Forte@Sun.COM 		lsrjt = (la_els_rjt_t *)pkt->pkt_resp;
20277836SJohn.Forte@Sun.COM 		if (lsrjt->ls_code.ls_code == LA_ELS_RJT) {
20287836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_LS_RJT;
20297836SJohn.Forte@Sun.COM 			pkt->pkt_reason = lsrjt->reason;
20307836SJohn.Forte@Sun.COM 			pkt->pkt_action = lsrjt->action;
20317836SJohn.Forte@Sun.COM 			break;
20327836SJohn.Forte@Sun.COM 		}
20337836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
20347836SJohn.Forte@Sun.COM 	}
20357836SJohn.Forte@Sun.COM 
20367836SJohn.Forte@Sun.COM 	default:
20377836SJohn.Forte@Sun.COM 		ret = FC_FAILURE;
20387836SJohn.Forte@Sun.COM 		break;
20397836SJohn.Forte@Sun.COM 	}
20407836SJohn.Forte@Sun.COM 
20417836SJohn.Forte@Sun.COM 	return (ret);
20427836SJohn.Forte@Sun.COM }
20437836SJohn.Forte@Sun.COM 
20447836SJohn.Forte@Sun.COM 
20457836SJohn.Forte@Sun.COM int
fc_fca_error(int fc_errno,char ** errmsg)20467836SJohn.Forte@Sun.COM fc_fca_error(int fc_errno, char **errmsg)
20477836SJohn.Forte@Sun.COM {
20487836SJohn.Forte@Sun.COM 	return (fctl_error(fc_errno, errmsg));
20497836SJohn.Forte@Sun.COM }
20507836SJohn.Forte@Sun.COM 
20517836SJohn.Forte@Sun.COM 
20527836SJohn.Forte@Sun.COM int
fc_fca_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)20537836SJohn.Forte@Sun.COM fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
20547836SJohn.Forte@Sun.COM     char **action, char **expln)
20557836SJohn.Forte@Sun.COM {
20567836SJohn.Forte@Sun.COM 	return (fctl_pkt_error(pkt, state, reason, action, expln));
20577836SJohn.Forte@Sun.COM }
20587836SJohn.Forte@Sun.COM 
20597836SJohn.Forte@Sun.COM 
20607836SJohn.Forte@Sun.COM /*
20617836SJohn.Forte@Sun.COM  * WWN to string goodie. Unpredictable results will happen
20627836SJohn.Forte@Sun.COM  * if enough memory isn't supplied in str argument. If you
20637836SJohn.Forte@Sun.COM  * are wondering how much does this routine need, it is just
20647836SJohn.Forte@Sun.COM  * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
20657836SJohn.Forte@Sun.COM  * argument should have atleast 17 bytes allocated.
20667836SJohn.Forte@Sun.COM  */
20677836SJohn.Forte@Sun.COM void
fc_wwn_to_str(la_wwn_t * wwn,caddr_t str)20687836SJohn.Forte@Sun.COM fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
20697836SJohn.Forte@Sun.COM {
20707836SJohn.Forte@Sun.COM 	int count;
20717836SJohn.Forte@Sun.COM 
20727836SJohn.Forte@Sun.COM 	for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
20737836SJohn.Forte@Sun.COM 		(void) sprintf(str, "%02x", wwn->raw_wwn[count]);
20747836SJohn.Forte@Sun.COM 	}
20757836SJohn.Forte@Sun.COM 	*str = '\0';
20767836SJohn.Forte@Sun.COM }
20777836SJohn.Forte@Sun.COM 
207810264SZhong.Wang@Sun.COM #define	FC_ATOB(x)	(((x) >= '0' && (x) <= '9') ? ((x) - '0') :	\
207910264SZhong.Wang@Sun.COM 			((x) >= 'a' && (x) <= 'f') ?			\
20807836SJohn.Forte@Sun.COM 			((x) - 'a' + 10) : ((x) - 'A' + 10))
20817836SJohn.Forte@Sun.COM 
20827836SJohn.Forte@Sun.COM void
fc_str_to_wwn(caddr_t str,la_wwn_t * wwn)20837836SJohn.Forte@Sun.COM fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
20847836SJohn.Forte@Sun.COM {
20857836SJohn.Forte@Sun.COM 	int count = 0;
20867836SJohn.Forte@Sun.COM 	uchar_t byte;
20877836SJohn.Forte@Sun.COM 
20887836SJohn.Forte@Sun.COM 	while (*str) {
20897836SJohn.Forte@Sun.COM 		byte = FC_ATOB(*str);
20907836SJohn.Forte@Sun.COM 		str++;
20917836SJohn.Forte@Sun.COM 		byte = byte << 4 | FC_ATOB(*str);
20927836SJohn.Forte@Sun.COM 		str++;
20937836SJohn.Forte@Sun.COM 		wwn->raw_wwn[count++] = byte;
20947836SJohn.Forte@Sun.COM 	}
20957836SJohn.Forte@Sun.COM }
20967836SJohn.Forte@Sun.COM 
20977836SJohn.Forte@Sun.COM /*
20987836SJohn.Forte@Sun.COM  * FCA driver's intercepted bus control operations.
20997836SJohn.Forte@Sun.COM  */
21007836SJohn.Forte@Sun.COM static int
fctl_fca_bus_ctl(dev_info_t * fca_dip,dev_info_t * rip,ddi_ctl_enum_t op,void * arg,void * result)21017836SJohn.Forte@Sun.COM fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
210210264SZhong.Wang@Sun.COM     ddi_ctl_enum_t op, void *arg, void *result)
21037836SJohn.Forte@Sun.COM {
21047836SJohn.Forte@Sun.COM 	switch (op) {
21057836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_REPORTDEV:
21067836SJohn.Forte@Sun.COM 		break;
21077836SJohn.Forte@Sun.COM 
21087836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_IOMIN:
21097836SJohn.Forte@Sun.COM 		break;
21107836SJohn.Forte@Sun.COM 
21117836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_INITCHILD:
21127836SJohn.Forte@Sun.COM 		return (fctl_initchild(fca_dip, (dev_info_t *)arg));
21137836SJohn.Forte@Sun.COM 
21147836SJohn.Forte@Sun.COM 	case DDI_CTLOPS_UNINITCHILD:
21157836SJohn.Forte@Sun.COM 		return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
21167836SJohn.Forte@Sun.COM 
21177836SJohn.Forte@Sun.COM 	default:
21187836SJohn.Forte@Sun.COM 		return (ddi_ctlops(fca_dip, rip, op, arg, result));
21197836SJohn.Forte@Sun.COM 	}
21207836SJohn.Forte@Sun.COM 
21217836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
21227836SJohn.Forte@Sun.COM }
21237836SJohn.Forte@Sun.COM 
21247836SJohn.Forte@Sun.COM 
21257836SJohn.Forte@Sun.COM /*
21267836SJohn.Forte@Sun.COM  * FCAs indicate the maximum number of ports supported in their
21277836SJohn.Forte@Sun.COM  * tran structure. Fail the INITCHILD if the child port number
21287836SJohn.Forte@Sun.COM  * is any greater than the maximum number of ports supported
21297836SJohn.Forte@Sun.COM  * by the FCA.
21307836SJohn.Forte@Sun.COM  */
21317836SJohn.Forte@Sun.COM static int
fctl_initchild(dev_info_t * fca_dip,dev_info_t * port_dip)21327836SJohn.Forte@Sun.COM fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
21337836SJohn.Forte@Sun.COM {
213410264SZhong.Wang@Sun.COM 	int		rval;
213510264SZhong.Wang@Sun.COM 	int		port_no;
213610264SZhong.Wang@Sun.COM 	int		port_len;
213710264SZhong.Wang@Sun.COM 	char		name[20];
213810264SZhong.Wang@Sun.COM 	fc_fca_tran_t	*tran;
21397836SJohn.Forte@Sun.COM 	dev_info_t	*dip;
21407836SJohn.Forte@Sun.COM 	int		portprop;
21417836SJohn.Forte@Sun.COM 
21427836SJohn.Forte@Sun.COM 	port_len = sizeof (port_no);
21437836SJohn.Forte@Sun.COM 
21447836SJohn.Forte@Sun.COM 	/* physical port do not has this property */
21457836SJohn.Forte@Sun.COM 	portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
21467836SJohn.Forte@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
21477836SJohn.Forte@Sun.COM 	    "phyport-instance", -1);
21487836SJohn.Forte@Sun.COM 
21497836SJohn.Forte@Sun.COM 	if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
21507836SJohn.Forte@Sun.COM 		/*
21517836SJohn.Forte@Sun.COM 		 * Clear any addr bindings created by fcode interpreter
21527836SJohn.Forte@Sun.COM 		 * in devi_last_addr so that a ndi_devi_find should never
21537836SJohn.Forte@Sun.COM 		 * return this fcode node.
21547836SJohn.Forte@Sun.COM 		 */
21557836SJohn.Forte@Sun.COM 		ddi_set_name_addr(port_dip, NULL);
21567836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
21577836SJohn.Forte@Sun.COM 	}
21587836SJohn.Forte@Sun.COM 
21597836SJohn.Forte@Sun.COM 	rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
21607836SJohn.Forte@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
21617836SJohn.Forte@Sun.COM 	    (caddr_t)&port_no, &port_len);
21627836SJohn.Forte@Sun.COM 
21637836SJohn.Forte@Sun.COM 	if (rval != DDI_SUCCESS) {
21647836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
21657836SJohn.Forte@Sun.COM 	}
21667836SJohn.Forte@Sun.COM 
21677836SJohn.Forte@Sun.COM 	tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
21687836SJohn.Forte@Sun.COM 	ASSERT(tran != NULL);
21697836SJohn.Forte@Sun.COM 
21707836SJohn.Forte@Sun.COM 	(void) sprintf((char *)name, "%x,0", port_no);
21717836SJohn.Forte@Sun.COM 	ddi_set_name_addr(port_dip, name);
21727836SJohn.Forte@Sun.COM 
21737836SJohn.Forte@Sun.COM 	dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
21747836SJohn.Forte@Sun.COM 
21757836SJohn.Forte@Sun.COM 	/*
21767836SJohn.Forte@Sun.COM 	 * Even though we never initialize FCode nodes of fp, such a node
21777836SJohn.Forte@Sun.COM 	 * could still be there after a DR operation. There will only be
21787836SJohn.Forte@Sun.COM 	 * one FCode node, so if this is the one, clear it and issue a
21797836SJohn.Forte@Sun.COM 	 * ndi_devi_find again.
21807836SJohn.Forte@Sun.COM 	 */
21817836SJohn.Forte@Sun.COM 	if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
21827836SJohn.Forte@Sun.COM 		ddi_set_name_addr(dip, NULL);
21837836SJohn.Forte@Sun.COM 		dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
21847836SJohn.Forte@Sun.COM 	}
21857836SJohn.Forte@Sun.COM 
21867836SJohn.Forte@Sun.COM 	if ((portprop == -1) && dip && (dip != port_dip)) {
21877836SJohn.Forte@Sun.COM 		/*
21887836SJohn.Forte@Sun.COM 		 * Here we have a duplicate .conf entry. Clear the addr
21897836SJohn.Forte@Sun.COM 		 * set previously and return failure.
21907836SJohn.Forte@Sun.COM 		 */
21917836SJohn.Forte@Sun.COM 		ddi_set_name_addr(port_dip, NULL);
21927836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
21937836SJohn.Forte@Sun.COM 	}
21947836SJohn.Forte@Sun.COM 
21957836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
21967836SJohn.Forte@Sun.COM }
21977836SJohn.Forte@Sun.COM 
21987836SJohn.Forte@Sun.COM 
21997836SJohn.Forte@Sun.COM /* ARGSUSED */
22007836SJohn.Forte@Sun.COM static int
fctl_uninitchild(dev_info_t * fca_dip,dev_info_t * port_dip)22017836SJohn.Forte@Sun.COM fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
22027836SJohn.Forte@Sun.COM {
22037836SJohn.Forte@Sun.COM 	ddi_set_name_addr(port_dip, NULL);
22047836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
22057836SJohn.Forte@Sun.COM }
22067836SJohn.Forte@Sun.COM 
22077836SJohn.Forte@Sun.COM 
22087836SJohn.Forte@Sun.COM static dev_info_t *
fctl_findchild(dev_info_t * pdip,char * cname,char * caddr)22097836SJohn.Forte@Sun.COM fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
22107836SJohn.Forte@Sun.COM {
22117836SJohn.Forte@Sun.COM 	dev_info_t *dip;
22127836SJohn.Forte@Sun.COM 	char *addr;
22137836SJohn.Forte@Sun.COM 
22147836SJohn.Forte@Sun.COM 	ASSERT(cname != NULL && caddr != NULL);
22157836SJohn.Forte@Sun.COM 	/* ASSERT(DEVI_BUSY_OWNED(pdip)); */
22167836SJohn.Forte@Sun.COM 
22177836SJohn.Forte@Sun.COM 	for (dip = ddi_get_child(pdip); dip != NULL;
22187836SJohn.Forte@Sun.COM 	    dip = ddi_get_next_sibling(dip)) {
221910264SZhong.Wang@Sun.COM 		if (strcmp(cname, ddi_node_name(dip)) != 0) {
22207836SJohn.Forte@Sun.COM 			continue;
222110264SZhong.Wang@Sun.COM 		}
22227836SJohn.Forte@Sun.COM 
22237836SJohn.Forte@Sun.COM 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
22247836SJohn.Forte@Sun.COM 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
22257836SJohn.Forte@Sun.COM 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
22267836SJohn.Forte@Sun.COM 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
22277836SJohn.Forte@Sun.COM 				if (strcmp(caddr, addr) == 0) {
22287836SJohn.Forte@Sun.COM 					ddi_prop_free(addr);
22297836SJohn.Forte@Sun.COM 					return (dip);
22307836SJohn.Forte@Sun.COM 				}
22317836SJohn.Forte@Sun.COM 				ddi_prop_free(addr);
22327836SJohn.Forte@Sun.COM 			}
22337836SJohn.Forte@Sun.COM 		} else {
223410264SZhong.Wang@Sun.COM 			if (strcmp(caddr, addr) == 0) {
22357836SJohn.Forte@Sun.COM 				return (dip);
223610264SZhong.Wang@Sun.COM 			}
22377836SJohn.Forte@Sun.COM 		}
22387836SJohn.Forte@Sun.COM 	}
22397836SJohn.Forte@Sun.COM 
22407836SJohn.Forte@Sun.COM 	return (NULL);
22417836SJohn.Forte@Sun.COM }
22427836SJohn.Forte@Sun.COM 
22437836SJohn.Forte@Sun.COM int
fctl_check_npiv_portindex(dev_info_t * dip,int vindex)22447836SJohn.Forte@Sun.COM fctl_check_npiv_portindex(dev_info_t *dip, int vindex)
22457836SJohn.Forte@Sun.COM {
22467836SJohn.Forte@Sun.COM 	int i, instance;
22477836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
22487836SJohn.Forte@Sun.COM 
22497836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
22507836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
22517836SJohn.Forte@Sun.COM 	if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
22527836SJohn.Forte@Sun.COM 		return (0);
22537836SJohn.Forte@Sun.COM 	}
22547836SJohn.Forte@Sun.COM 
22557836SJohn.Forte@Sun.COM 	i = vindex-1;
22567836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
22577836SJohn.Forte@Sun.COM 	if (port->fp_npiv_portindex[i] == 0) {
22587836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
22597836SJohn.Forte@Sun.COM 		return (vindex);
22607836SJohn.Forte@Sun.COM 	}
22617836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
22627836SJohn.Forte@Sun.COM 	return (0);
22637836SJohn.Forte@Sun.COM }
22647836SJohn.Forte@Sun.COM 
22657836SJohn.Forte@Sun.COM int
fctl_get_npiv_portindex(dev_info_t * dip)22667836SJohn.Forte@Sun.COM fctl_get_npiv_portindex(dev_info_t *dip)
22677836SJohn.Forte@Sun.COM {
22687836SJohn.Forte@Sun.COM 	int i, instance;
22697836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
22707836SJohn.Forte@Sun.COM 
22717836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
22727836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
22737836SJohn.Forte@Sun.COM 	if (!port) {
22747836SJohn.Forte@Sun.COM 		return (0);
22757836SJohn.Forte@Sun.COM 	}
22767836SJohn.Forte@Sun.COM 
22777836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
22787836SJohn.Forte@Sun.COM 	for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
22797836SJohn.Forte@Sun.COM 		if (port->fp_npiv_portindex[i] == 0) {
22807836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
22817836SJohn.Forte@Sun.COM 			return (i+1);
22827836SJohn.Forte@Sun.COM 		}
22837836SJohn.Forte@Sun.COM 	}
22847836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
22857836SJohn.Forte@Sun.COM 	return (0);
22867836SJohn.Forte@Sun.COM }
22877836SJohn.Forte@Sun.COM 
22887836SJohn.Forte@Sun.COM 
22897836SJohn.Forte@Sun.COM void
fctl_set_npiv_portindex(dev_info_t * dip,int index)22907836SJohn.Forte@Sun.COM fctl_set_npiv_portindex(dev_info_t *dip, int index)
22917836SJohn.Forte@Sun.COM {
22927836SJohn.Forte@Sun.COM 	int instance;
22937836SJohn.Forte@Sun.COM 	fc_local_port_t *port;
22947836SJohn.Forte@Sun.COM 
22957836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(dip);
22967836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
22977836SJohn.Forte@Sun.COM 	if (!port) {
22987836SJohn.Forte@Sun.COM 		return;
22997836SJohn.Forte@Sun.COM 	}
23007836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
23017836SJohn.Forte@Sun.COM 	port->fp_npiv_portindex[index - 1] = 1;
23027836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
23037836SJohn.Forte@Sun.COM }
23047836SJohn.Forte@Sun.COM 
23057836SJohn.Forte@Sun.COM 
23067836SJohn.Forte@Sun.COM int
fctl_fca_create_npivport(dev_info_t * parent,dev_info_t * phydip,char * nname,char * pname,uint32_t * vindex)23077836SJohn.Forte@Sun.COM fctl_fca_create_npivport(dev_info_t *parent,
23087836SJohn.Forte@Sun.COM     dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
23097836SJohn.Forte@Sun.COM {
23107836SJohn.Forte@Sun.COM 	int rval = 0, devstrlen;
231110264SZhong.Wang@Sun.COM 	char	*devname, *cname, *caddr, *devstr;
23127836SJohn.Forte@Sun.COM 	dev_info_t	*child = NULL;
23137836SJohn.Forte@Sun.COM 	int		portnum;
23147836SJohn.Forte@Sun.COM 
23157836SJohn.Forte@Sun.COM 	if (*vindex == 0) {
23167836SJohn.Forte@Sun.COM 		portnum = fctl_get_npiv_portindex(phydip);
23177836SJohn.Forte@Sun.COM 		*vindex = portnum;
23187836SJohn.Forte@Sun.COM 	} else {
23197836SJohn.Forte@Sun.COM 		portnum = fctl_check_npiv_portindex(phydip, *vindex);
23207836SJohn.Forte@Sun.COM 	}
23217836SJohn.Forte@Sun.COM 
23227836SJohn.Forte@Sun.COM 	if (portnum == 0) {
23237836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
23247836SJohn.Forte@Sun.COM 		    "Cann't find valid port index, fail to create devnode");
23257836SJohn.Forte@Sun.COM 		return (NDI_FAILURE);
23267836SJohn.Forte@Sun.COM 	}
23277836SJohn.Forte@Sun.COM 
23287836SJohn.Forte@Sun.COM 	devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
23297836SJohn.Forte@Sun.COM 	(void) sprintf(devname, "fp@%x,0", portnum);
23307836SJohn.Forte@Sun.COM 	devstrlen = strlen(devname) + 1;
23317836SJohn.Forte@Sun.COM 	devstr = i_ddi_strdup(devname, KM_SLEEP);
23327836SJohn.Forte@Sun.COM 	i_ddi_parse_name(devstr, &cname, &caddr, NULL);
23337836SJohn.Forte@Sun.COM 
23347836SJohn.Forte@Sun.COM 	if (fctl_findchild(parent, cname, caddr) != NULL) {
23357836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23367836SJohn.Forte@Sun.COM 		goto freememory;
23377836SJohn.Forte@Sun.COM 	}
23387836SJohn.Forte@Sun.COM 
23397836SJohn.Forte@Sun.COM 	ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
23407836SJohn.Forte@Sun.COM 	if (child == NULL) {
23417836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
23427836SJohn.Forte@Sun.COM 		    "fctl_create_npiv_port fail to create new devinfo");
23437836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23447836SJohn.Forte@Sun.COM 		goto freememory;
23457836SJohn.Forte@Sun.COM 	}
23467836SJohn.Forte@Sun.COM 
23477836SJohn.Forte@Sun.COM 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
23487836SJohn.Forte@Sun.COM 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
23497836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
23507836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
23517836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
23527836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23537836SJohn.Forte@Sun.COM 		goto freememory;
23547836SJohn.Forte@Sun.COM 	}
23557836SJohn.Forte@Sun.COM 
23567836SJohn.Forte@Sun.COM 	if (strlen(nname) != 0) {
23577836SJohn.Forte@Sun.COM 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
23587836SJohn.Forte@Sun.COM 		    "node-name", nname) != DDI_PROP_SUCCESS) {
23597836SJohn.Forte@Sun.COM 			(void) ndi_devi_free(child);
23607836SJohn.Forte@Sun.COM 			rval = NDI_FAILURE;
23617836SJohn.Forte@Sun.COM 			goto freememory;
23627836SJohn.Forte@Sun.COM 		}
23637836SJohn.Forte@Sun.COM 	}
23647836SJohn.Forte@Sun.COM 
23657836SJohn.Forte@Sun.COM 	if (strlen(pname) != 0) {
23667836SJohn.Forte@Sun.COM 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
23677836SJohn.Forte@Sun.COM 		    "port-name", pname) != DDI_PROP_SUCCESS) {
23687836SJohn.Forte@Sun.COM 			(void) ndi_devi_free(child);
23697836SJohn.Forte@Sun.COM 			rval = NDI_FAILURE;
23707836SJohn.Forte@Sun.COM 			goto freememory;
23717836SJohn.Forte@Sun.COM 		}
23727836SJohn.Forte@Sun.COM 	}
23737836SJohn.Forte@Sun.COM 
23747836SJohn.Forte@Sun.COM 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
23757836SJohn.Forte@Sun.COM 	    "port", portnum) != DDI_PROP_SUCCESS) {
23767836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
23777836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
23787836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
23797836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23807836SJohn.Forte@Sun.COM 		goto freememory;
23817836SJohn.Forte@Sun.COM 	}
23827836SJohn.Forte@Sun.COM 
23837836SJohn.Forte@Sun.COM 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
23847836SJohn.Forte@Sun.COM 	    "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
23857836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
23867836SJohn.Forte@Sun.COM 		    "fp%d: prop_update phyport-instance %s@%s failed",
23877836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname, caddr);
23887836SJohn.Forte@Sun.COM 		(void) ndi_devi_free(child);
23897836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23907836SJohn.Forte@Sun.COM 		goto freememory;
23917836SJohn.Forte@Sun.COM 	}
23927836SJohn.Forte@Sun.COM 
23937836SJohn.Forte@Sun.COM 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
23947836SJohn.Forte@Sun.COM 	if (rval != NDI_SUCCESS) {
23957836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "fp%d: online_driver %s failed",
23967836SJohn.Forte@Sun.COM 		    ddi_get_instance(parent), cname);
23977836SJohn.Forte@Sun.COM 		rval = NDI_FAILURE;
23987836SJohn.Forte@Sun.COM 		goto freememory;
23997836SJohn.Forte@Sun.COM 	}
24007836SJohn.Forte@Sun.COM 
24017836SJohn.Forte@Sun.COM 	fctl_set_npiv_portindex(phydip, portnum);
24027836SJohn.Forte@Sun.COM freememory:
24037836SJohn.Forte@Sun.COM 	kmem_free(devstr, devstrlen);
24047836SJohn.Forte@Sun.COM 	kmem_free(devname, MAXNAMELEN);
24057836SJohn.Forte@Sun.COM 
24067836SJohn.Forte@Sun.COM 	return (rval);
24077836SJohn.Forte@Sun.COM }
24087836SJohn.Forte@Sun.COM 
24097836SJohn.Forte@Sun.COM 
24107836SJohn.Forte@Sun.COM void
fctl_add_port(fc_local_port_t * port)24117836SJohn.Forte@Sun.COM fctl_add_port(fc_local_port_t *port)
24127836SJohn.Forte@Sun.COM {
24137836SJohn.Forte@Sun.COM 	fc_fca_port_t *new;
24147836SJohn.Forte@Sun.COM 
24157836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), KM_SLEEP);
24167836SJohn.Forte@Sun.COM 
24177836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
24187836SJohn.Forte@Sun.COM 	new->port_handle = port;
24197836SJohn.Forte@Sun.COM 	new->port_next = fctl_fca_portlist;
24207836SJohn.Forte@Sun.COM 	fctl_fca_portlist = new;
24217836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
24227836SJohn.Forte@Sun.COM }
24237836SJohn.Forte@Sun.COM 
24247836SJohn.Forte@Sun.COM 
24257836SJohn.Forte@Sun.COM void
fctl_remove_port(fc_local_port_t * port)24267836SJohn.Forte@Sun.COM fctl_remove_port(fc_local_port_t *port)
24277836SJohn.Forte@Sun.COM {
242810264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
242910264SZhong.Wang@Sun.COM 	fc_fca_port_t		*prev;
243010264SZhong.Wang@Sun.COM 	fc_fca_port_t		*list;
24317836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
24327836SJohn.Forte@Sun.COM 
24337836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_WRITER);
24347836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
24357836SJohn.Forte@Sun.COM 
24367836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
24377836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
24387836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
24397836SJohn.Forte@Sun.COM 			continue;
24407836SJohn.Forte@Sun.COM 		}
24417836SJohn.Forte@Sun.COM 
24427836SJohn.Forte@Sun.COM #ifndef	__lock_lint
24437836SJohn.Forte@Sun.COM 		ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
24447836SJohn.Forte@Sun.COM #endif /* __lock_lint */
24457836SJohn.Forte@Sun.COM 
24467836SJohn.Forte@Sun.COM 		(void) fctl_remove_ulp_port(mod, port);
24477836SJohn.Forte@Sun.COM 	}
24487836SJohn.Forte@Sun.COM 
24497836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
24507836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
24517836SJohn.Forte@Sun.COM 
24527836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
24537836SJohn.Forte@Sun.COM 
24547836SJohn.Forte@Sun.COM 	list = fctl_fca_portlist;
24557836SJohn.Forte@Sun.COM 	prev = NULL;
24567836SJohn.Forte@Sun.COM 	while (list != NULL) {
24577836SJohn.Forte@Sun.COM 		if (list->port_handle == port) {
24587836SJohn.Forte@Sun.COM 			if (prev == NULL) {
24597836SJohn.Forte@Sun.COM 				fctl_fca_portlist = list->port_next;
24607836SJohn.Forte@Sun.COM 			} else {
24617836SJohn.Forte@Sun.COM 				prev->port_next = list->port_next;
24627836SJohn.Forte@Sun.COM 			}
24637836SJohn.Forte@Sun.COM 			kmem_free(list, sizeof (*list));
24647836SJohn.Forte@Sun.COM 			break;
24657836SJohn.Forte@Sun.COM 		}
24667836SJohn.Forte@Sun.COM 		prev = list;
24677836SJohn.Forte@Sun.COM 		list = list->port_next;
24687836SJohn.Forte@Sun.COM 	}
24697836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
24707836SJohn.Forte@Sun.COM }
24717836SJohn.Forte@Sun.COM 
24727836SJohn.Forte@Sun.COM 
24737836SJohn.Forte@Sun.COM void
fctl_attach_ulps(fc_local_port_t * port,fc_attach_cmd_t cmd,struct modlinkage * linkage)24747836SJohn.Forte@Sun.COM fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
24757836SJohn.Forte@Sun.COM     struct modlinkage *linkage)
24767836SJohn.Forte@Sun.COM {
24777836SJohn.Forte@Sun.COM 	int			rval;
24787836SJohn.Forte@Sun.COM 	uint32_t		s_id;
24797836SJohn.Forte@Sun.COM 	uint32_t		state;
248010264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
248110264SZhong.Wang@Sun.COM 	fc_ulp_port_info_t	info;
24827836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
24837836SJohn.Forte@Sun.COM 
24847836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
24857836SJohn.Forte@Sun.COM 
24867836SJohn.Forte@Sun.COM 	info.port_linkage = linkage;
24877836SJohn.Forte@Sun.COM 	info.port_dip = port->fp_port_dip;
24887836SJohn.Forte@Sun.COM 	info.port_handle = (opaque_t)port;
24897836SJohn.Forte@Sun.COM 	info.port_dma_behavior = port->fp_dma_behavior;
24907836SJohn.Forte@Sun.COM 	info.port_fcp_dma = port->fp_fcp_dma;
24917836SJohn.Forte@Sun.COM 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
24927836SJohn.Forte@Sun.COM 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
24937836SJohn.Forte@Sun.COM 	info.port_reset_action = port->fp_reset_action;
24947836SJohn.Forte@Sun.COM 
24957836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
24967836SJohn.Forte@Sun.COM 
24977836SJohn.Forte@Sun.COM 	/*
24987836SJohn.Forte@Sun.COM 	 * It is still possible that another thread could have gotten
24997836SJohn.Forte@Sun.COM 	 * into the detach process before we got here.
25007836SJohn.Forte@Sun.COM 	 */
25017836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
25027836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
25037836SJohn.Forte@Sun.COM 		return;
25047836SJohn.Forte@Sun.COM 	}
25057836SJohn.Forte@Sun.COM 
25067836SJohn.Forte@Sun.COM 	s_id = port->fp_port_id.port_id;
25077836SJohn.Forte@Sun.COM 	if (port->fp_statec_busy) {
25087836SJohn.Forte@Sun.COM 		info.port_state = port->fp_bind_state;
25097836SJohn.Forte@Sun.COM 	} else {
25107836SJohn.Forte@Sun.COM 		info.port_state = port->fp_state;
25117836SJohn.Forte@Sun.COM 	}
25127836SJohn.Forte@Sun.COM 
25137836SJohn.Forte@Sun.COM 	switch (state = FC_PORT_STATE_MASK(info.port_state)) {
25147836SJohn.Forte@Sun.COM 	case FC_STATE_LOOP:
25157836SJohn.Forte@Sun.COM 	case FC_STATE_NAMESERVICE:
25167836SJohn.Forte@Sun.COM 		info.port_state &= ~state;
25177836SJohn.Forte@Sun.COM 		info.port_state |= FC_STATE_ONLINE;
25187836SJohn.Forte@Sun.COM 		break;
25197836SJohn.Forte@Sun.COM 
25207836SJohn.Forte@Sun.COM 	default:
25217836SJohn.Forte@Sun.COM 		break;
25227836SJohn.Forte@Sun.COM 	}
25237836SJohn.Forte@Sun.COM 	ASSERT((info.port_state & FC_STATE_LOOP) == 0);
25247836SJohn.Forte@Sun.COM 
25257836SJohn.Forte@Sun.COM 	info.port_flags = port->fp_topology;
25267836SJohn.Forte@Sun.COM 	info.port_pwwn = port->fp_service_params.nport_ww_name;
25277836SJohn.Forte@Sun.COM 	info.port_nwwn = port->fp_service_params.node_ww_name;
25287836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
25297836SJohn.Forte@Sun.COM 
25307836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
25317836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
25327836SJohn.Forte@Sun.COM 
25337836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
253410264SZhong.Wang@Sun.COM 		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
253510264SZhong.Wang@Sun.COM 		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
253610264SZhong.Wang@Sun.COM 			/*
253710264SZhong.Wang@Sun.COM 			 * We don't support IP over FC on FCOE HBA
253810264SZhong.Wang@Sun.COM 			 */
253910264SZhong.Wang@Sun.COM 			continue;
254010264SZhong.Wang@Sun.COM 		}
254110264SZhong.Wang@Sun.COM 
25427836SJohn.Forte@Sun.COM 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
25437836SJohn.Forte@Sun.COM 			ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
25447836SJohn.Forte@Sun.COM 			ASSERT(ulp_port != NULL);
25457836SJohn.Forte@Sun.COM 
25467836SJohn.Forte@Sun.COM 			mutex_enter(&ulp_port->port_mutex);
254710264SZhong.Wang@Sun.COM 			ulp_port->port_statec = ((info.port_state &
25487836SJohn.Forte@Sun.COM 			    FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
254910264SZhong.Wang@Sun.COM 			    FC_ULP_STATEC_OFFLINE);
25507836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
25517836SJohn.Forte@Sun.COM 		}
25527836SJohn.Forte@Sun.COM 	}
25537836SJohn.Forte@Sun.COM 
25547836SJohn.Forte@Sun.COM 	rw_downgrade(&fctl_mod_ports_lock);
25557836SJohn.Forte@Sun.COM 
25567836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
255710264SZhong.Wang@Sun.COM 		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
255810264SZhong.Wang@Sun.COM 		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
255910264SZhong.Wang@Sun.COM 			/*
256010264SZhong.Wang@Sun.COM 			 * We don't support IP over FC on FCOE HBA
256110264SZhong.Wang@Sun.COM 			 */
256210264SZhong.Wang@Sun.COM 			continue;
256310264SZhong.Wang@Sun.COM 		}
256410264SZhong.Wang@Sun.COM 
25657836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
25667836SJohn.Forte@Sun.COM 		ASSERT(ulp_port != NULL);
25677836SJohn.Forte@Sun.COM 
25687836SJohn.Forte@Sun.COM 		if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
25697836SJohn.Forte@Sun.COM 			continue;
25707836SJohn.Forte@Sun.COM 		}
25717836SJohn.Forte@Sun.COM 
25727836SJohn.Forte@Sun.COM 		fctl_init_dma_attr(port, mod, &info);
25737836SJohn.Forte@Sun.COM 
25747836SJohn.Forte@Sun.COM 		rval = mod->mod_info->ulp_port_attach(
25757836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, &info, cmd, s_id);
25767836SJohn.Forte@Sun.COM 
25777836SJohn.Forte@Sun.COM 		fctl_post_attach(mod, ulp_port, cmd, rval);
25787836SJohn.Forte@Sun.COM 
25797836SJohn.Forte@Sun.COM 		if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
25807836SJohn.Forte@Sun.COM 		    strcmp(mod->mod_info->ulp_name, "fcp") == 0) {
25817836SJohn.Forte@Sun.COM 			ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
25827836SJohn.Forte@Sun.COM 		}
25837836SJohn.Forte@Sun.COM 	}
25847836SJohn.Forte@Sun.COM 
25857836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
25867836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
25877836SJohn.Forte@Sun.COM }
25887836SJohn.Forte@Sun.COM 
25897836SJohn.Forte@Sun.COM 
25907836SJohn.Forte@Sun.COM static int
fctl_pre_attach(fc_ulp_ports_t * ulp_port,fc_attach_cmd_t cmd)25917836SJohn.Forte@Sun.COM fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
25927836SJohn.Forte@Sun.COM {
25937836SJohn.Forte@Sun.COM 	int rval = FC_SUCCESS;
25947836SJohn.Forte@Sun.COM 
25957836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
25967836SJohn.Forte@Sun.COM 
25977836SJohn.Forte@Sun.COM 	switch (cmd) {
25987836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH:
25997836SJohn.Forte@Sun.COM 		if (ulp_port->port_dstate & ULP_PORT_ATTACH) {
26007836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
26017836SJohn.Forte@Sun.COM 		}
26027836SJohn.Forte@Sun.COM 		break;
26037836SJohn.Forte@Sun.COM 
26047836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
26057836SJohn.Forte@Sun.COM 		ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
26067836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
26077836SJohn.Forte@Sun.COM 		    !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) {
26087836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
26097836SJohn.Forte@Sun.COM 		}
26107836SJohn.Forte@Sun.COM 		break;
26117836SJohn.Forte@Sun.COM 
26127836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
26137836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
26147836SJohn.Forte@Sun.COM 		    !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
26157836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
26167836SJohn.Forte@Sun.COM 		}
26177836SJohn.Forte@Sun.COM 		break;
26187836SJohn.Forte@Sun.COM 	}
26197836SJohn.Forte@Sun.COM 
26207836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
26217836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_BUSY;
26227836SJohn.Forte@Sun.COM 	}
26237836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
26247836SJohn.Forte@Sun.COM 
26257836SJohn.Forte@Sun.COM 	return (rval);
26267836SJohn.Forte@Sun.COM }
26277836SJohn.Forte@Sun.COM 
26287836SJohn.Forte@Sun.COM 
26297836SJohn.Forte@Sun.COM static void
fctl_post_attach(fc_ulp_module_t * mod,fc_ulp_ports_t * ulp_port,fc_attach_cmd_t cmd,int rval)26307836SJohn.Forte@Sun.COM fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
26317836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, int rval)
26327836SJohn.Forte@Sun.COM {
26337836SJohn.Forte@Sun.COM 	int	be_chatty;
26347836SJohn.Forte@Sun.COM 
26357836SJohn.Forte@Sun.COM 	ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
26367836SJohn.Forte@Sun.COM 	    cmd == FC_CMD_POWER_UP);
26377836SJohn.Forte@Sun.COM 
26387836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
26397836SJohn.Forte@Sun.COM 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
26407836SJohn.Forte@Sun.COM 
26417836SJohn.Forte@Sun.COM 	be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1;
26427836SJohn.Forte@Sun.COM 
26437836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
26447836SJohn.Forte@Sun.COM 		caddr_t		op;
26457836SJohn.Forte@Sun.COM 		fc_local_port_t *port = ulp_port->port_handle;
26467836SJohn.Forte@Sun.COM 
26477836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
26487836SJohn.Forte@Sun.COM 
26497836SJohn.Forte@Sun.COM 		switch (cmd) {
26507836SJohn.Forte@Sun.COM 		case FC_CMD_ATTACH:
26517836SJohn.Forte@Sun.COM 			op = "attach";
26527836SJohn.Forte@Sun.COM 			break;
26537836SJohn.Forte@Sun.COM 
26547836SJohn.Forte@Sun.COM 		case FC_CMD_RESUME:
26557836SJohn.Forte@Sun.COM 			op = "resume";
26567836SJohn.Forte@Sun.COM 			break;
26577836SJohn.Forte@Sun.COM 
26587836SJohn.Forte@Sun.COM 		case FC_CMD_POWER_UP:
26597836SJohn.Forte@Sun.COM 			op = "power up";
26607836SJohn.Forte@Sun.COM 			break;
26617836SJohn.Forte@Sun.COM 		}
26627836SJohn.Forte@Sun.COM 
26637836SJohn.Forte@Sun.COM 		if (be_chatty) {
26647836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
26657836SJohn.Forte@Sun.COM 			    port->fp_instance, op, mod->mod_info->ulp_name);
26667836SJohn.Forte@Sun.COM 		}
26677836SJohn.Forte@Sun.COM 
26687836SJohn.Forte@Sun.COM 		return;
26697836SJohn.Forte@Sun.COM 	}
26707836SJohn.Forte@Sun.COM 
26717836SJohn.Forte@Sun.COM 	switch (cmd) {
26727836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH:
26737836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_ATTACH;
26747836SJohn.Forte@Sun.COM 		break;
26757836SJohn.Forte@Sun.COM 
26767836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
26777836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_SUSPEND;
26787836SJohn.Forte@Sun.COM 		break;
26797836SJohn.Forte@Sun.COM 
26807836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
26817836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN;
26827836SJohn.Forte@Sun.COM 		break;
26837836SJohn.Forte@Sun.COM 	}
26847836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
26857836SJohn.Forte@Sun.COM }
26867836SJohn.Forte@Sun.COM 
26877836SJohn.Forte@Sun.COM 
26887836SJohn.Forte@Sun.COM int
fctl_detach_ulps(fc_local_port_t * port,fc_detach_cmd_t cmd,struct modlinkage * linkage)26897836SJohn.Forte@Sun.COM fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
26907836SJohn.Forte@Sun.COM     struct modlinkage *linkage)
26917836SJohn.Forte@Sun.COM {
26927836SJohn.Forte@Sun.COM 	int			rval = FC_SUCCESS;
269310264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
269410264SZhong.Wang@Sun.COM 	fc_ulp_port_info_t	info;
26957836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
26967836SJohn.Forte@Sun.COM 
26977836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
26987836SJohn.Forte@Sun.COM 
26997836SJohn.Forte@Sun.COM 	info.port_linkage = linkage;
27007836SJohn.Forte@Sun.COM 	info.port_dip = port->fp_port_dip;
27017836SJohn.Forte@Sun.COM 	info.port_handle = (opaque_t)port;
27027836SJohn.Forte@Sun.COM 	info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
27037836SJohn.Forte@Sun.COM 	info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
27047836SJohn.Forte@Sun.COM 
27057836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
27067836SJohn.Forte@Sun.COM 	rw_enter(&fctl_mod_ports_lock, RW_READER);
27077836SJohn.Forte@Sun.COM 
27087836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
27097836SJohn.Forte@Sun.COM 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
27107836SJohn.Forte@Sun.COM 			continue;
27117836SJohn.Forte@Sun.COM 		}
27127836SJohn.Forte@Sun.COM 
27137836SJohn.Forte@Sun.COM 		if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
27147836SJohn.Forte@Sun.COM 			continue;
27157836SJohn.Forte@Sun.COM 		}
27167836SJohn.Forte@Sun.COM 
27177836SJohn.Forte@Sun.COM 		fctl_init_dma_attr(port, mod, &info);
27187836SJohn.Forte@Sun.COM 
27197836SJohn.Forte@Sun.COM 		rval = mod->mod_info->ulp_port_detach(
27207836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, &info, cmd);
27217836SJohn.Forte@Sun.COM 
27227836SJohn.Forte@Sun.COM 		fctl_post_detach(mod, ulp_port, cmd, rval);
27237836SJohn.Forte@Sun.COM 
27247836SJohn.Forte@Sun.COM 		if (rval != FC_SUCCESS) {
27257836SJohn.Forte@Sun.COM 			break;
27267836SJohn.Forte@Sun.COM 		}
27277836SJohn.Forte@Sun.COM 
27287836SJohn.Forte@Sun.COM 		if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
27297836SJohn.Forte@Sun.COM 		    "fcp") == 0) {
27307836SJohn.Forte@Sun.COM 			ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
27317836SJohn.Forte@Sun.COM 		}
27327836SJohn.Forte@Sun.COM 
27337836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
27347836SJohn.Forte@Sun.COM 		ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE;
27357836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
27367836SJohn.Forte@Sun.COM 	}
27377836SJohn.Forte@Sun.COM 
27387836SJohn.Forte@Sun.COM 	rw_exit(&fctl_mod_ports_lock);
27397836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
27407836SJohn.Forte@Sun.COM 
27417836SJohn.Forte@Sun.COM 	return (rval);
27427836SJohn.Forte@Sun.COM }
27437836SJohn.Forte@Sun.COM 
27447836SJohn.Forte@Sun.COM static	void
fctl_init_dma_attr(fc_local_port_t * port,fc_ulp_module_t * mod,fc_ulp_port_info_t * info)27457836SJohn.Forte@Sun.COM fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
274610264SZhong.Wang@Sun.COM     fc_ulp_port_info_t	*info)
27477836SJohn.Forte@Sun.COM {
27487836SJohn.Forte@Sun.COM 
274910264SZhong.Wang@Sun.COM 	if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
275010264SZhong.Wang@Sun.COM 	    (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
275110264SZhong.Wang@Sun.COM 		info->port_cmd_dma_attr =
275210264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcp_cmd_attr;
275310264SZhong.Wang@Sun.COM 		info->port_data_dma_attr =
275410264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcp_data_attr;
275510264SZhong.Wang@Sun.COM 		info->port_resp_dma_attr =
275610264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcp_rsp_attr;
275710264SZhong.Wang@Sun.COM 	} else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
275810264SZhong.Wang@Sun.COM 		info->port_cmd_dma_attr =
275910264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
276010264SZhong.Wang@Sun.COM 		info->port_data_dma_attr =
276110264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_attr;
276210264SZhong.Wang@Sun.COM 		info->port_resp_dma_attr =
276310264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
276410264SZhong.Wang@Sun.COM 	} else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
276510264SZhong.Wang@Sun.COM 		info->port_cmd_dma_attr =
276610264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcip_cmd_attr;
276710264SZhong.Wang@Sun.COM 		info->port_data_dma_attr =
276810264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_attr;
276910264SZhong.Wang@Sun.COM 		info->port_resp_dma_attr =
277010264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_fcip_rsp_attr;
277110264SZhong.Wang@Sun.COM 	} else {
277210264SZhong.Wang@Sun.COM 		info->port_cmd_dma_attr = info->port_data_dma_attr =
277310264SZhong.Wang@Sun.COM 		    info->port_resp_dma_attr =
277410264SZhong.Wang@Sun.COM 		    port->fp_fca_tran->fca_dma_attr; /* default */
277510264SZhong.Wang@Sun.COM 	}
27767836SJohn.Forte@Sun.COM }
27777836SJohn.Forte@Sun.COM 
27787836SJohn.Forte@Sun.COM static int
fctl_pre_detach(fc_ulp_ports_t * ulp_port,fc_detach_cmd_t cmd)27797836SJohn.Forte@Sun.COM fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
27807836SJohn.Forte@Sun.COM {
27817836SJohn.Forte@Sun.COM 	int rval = FC_SUCCESS;
27827836SJohn.Forte@Sun.COM 
27837836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
27847836SJohn.Forte@Sun.COM 
27857836SJohn.Forte@Sun.COM 	switch (cmd) {
27867836SJohn.Forte@Sun.COM 	case FC_CMD_DETACH:
27877836SJohn.Forte@Sun.COM 		if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
27887836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
27897836SJohn.Forte@Sun.COM 		}
27907836SJohn.Forte@Sun.COM 		break;
27917836SJohn.Forte@Sun.COM 
27927836SJohn.Forte@Sun.COM 	case FC_CMD_SUSPEND:
27937836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
27947836SJohn.Forte@Sun.COM 		    ulp_port->port_dstate & ULP_PORT_SUSPEND) {
27957836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
27967836SJohn.Forte@Sun.COM 		}
27977836SJohn.Forte@Sun.COM 		break;
27987836SJohn.Forte@Sun.COM 
27997836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_DOWN:
28007836SJohn.Forte@Sun.COM 		if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
28017836SJohn.Forte@Sun.COM 		    ulp_port->port_dstate & ULP_PORT_POWER_DOWN) {
28027836SJohn.Forte@Sun.COM 			rval = FC_FAILURE;
28037836SJohn.Forte@Sun.COM 		}
28047836SJohn.Forte@Sun.COM 		break;
28057836SJohn.Forte@Sun.COM 	}
28067836SJohn.Forte@Sun.COM 
28077836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
28087836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_BUSY;
28097836SJohn.Forte@Sun.COM 	}
28107836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
28117836SJohn.Forte@Sun.COM 
28127836SJohn.Forte@Sun.COM 	return (rval);
28137836SJohn.Forte@Sun.COM }
28147836SJohn.Forte@Sun.COM 
28157836SJohn.Forte@Sun.COM 
28167836SJohn.Forte@Sun.COM static void
fctl_post_detach(fc_ulp_module_t * mod,fc_ulp_ports_t * ulp_port,fc_detach_cmd_t cmd,int rval)28177836SJohn.Forte@Sun.COM fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
28187836SJohn.Forte@Sun.COM     fc_detach_cmd_t cmd, int rval)
28197836SJohn.Forte@Sun.COM {
28207836SJohn.Forte@Sun.COM 	ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
28217836SJohn.Forte@Sun.COM 	    cmd == FC_CMD_POWER_DOWN);
28227836SJohn.Forte@Sun.COM 
28237836SJohn.Forte@Sun.COM 	mutex_enter(&ulp_port->port_mutex);
28247836SJohn.Forte@Sun.COM 	ulp_port->port_dstate &= ~ULP_PORT_BUSY;
28257836SJohn.Forte@Sun.COM 
28267836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS) {
28277836SJohn.Forte@Sun.COM 		caddr_t		op;
28287836SJohn.Forte@Sun.COM 		fc_local_port_t *port = ulp_port->port_handle;
28297836SJohn.Forte@Sun.COM 
28307836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
28317836SJohn.Forte@Sun.COM 
28327836SJohn.Forte@Sun.COM 		switch (cmd) {
28337836SJohn.Forte@Sun.COM 		case FC_CMD_DETACH:
28347836SJohn.Forte@Sun.COM 			op = "detach";
28357836SJohn.Forte@Sun.COM 			break;
28367836SJohn.Forte@Sun.COM 
28377836SJohn.Forte@Sun.COM 		case FC_CMD_SUSPEND:
28387836SJohn.Forte@Sun.COM 			op = "suspend";
28397836SJohn.Forte@Sun.COM 			break;
28407836SJohn.Forte@Sun.COM 
28417836SJohn.Forte@Sun.COM 		case FC_CMD_POWER_DOWN:
28427836SJohn.Forte@Sun.COM 			op = "power down";
28437836SJohn.Forte@Sun.COM 			break;
28447836SJohn.Forte@Sun.COM 		}
28457836SJohn.Forte@Sun.COM 
28467836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
28477836SJohn.Forte@Sun.COM 		    port->fp_instance, op, mod->mod_info->ulp_name);
28487836SJohn.Forte@Sun.COM 
28497836SJohn.Forte@Sun.COM 		return;
28507836SJohn.Forte@Sun.COM 	}
28517836SJohn.Forte@Sun.COM 
28527836SJohn.Forte@Sun.COM 	switch (cmd) {
28537836SJohn.Forte@Sun.COM 	case FC_CMD_DETACH:
28547836SJohn.Forte@Sun.COM 		ulp_port->port_dstate &= ~ULP_PORT_ATTACH;
28557836SJohn.Forte@Sun.COM 		break;
28567836SJohn.Forte@Sun.COM 
28577836SJohn.Forte@Sun.COM 	case FC_CMD_SUSPEND:
28587836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_SUSPEND;
28597836SJohn.Forte@Sun.COM 		break;
28607836SJohn.Forte@Sun.COM 
28617836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_DOWN:
28627836SJohn.Forte@Sun.COM 		ulp_port->port_dstate |= ULP_PORT_POWER_DOWN;
28637836SJohn.Forte@Sun.COM 		break;
28647836SJohn.Forte@Sun.COM 	}
28657836SJohn.Forte@Sun.COM 	mutex_exit(&ulp_port->port_mutex);
28667836SJohn.Forte@Sun.COM }
28677836SJohn.Forte@Sun.COM 
28687836SJohn.Forte@Sun.COM 
28697836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
fctl_add_ulp_port(fc_ulp_module_t * ulp_module,fc_local_port_t * port_handle,int sleep)28707836SJohn.Forte@Sun.COM fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
28717836SJohn.Forte@Sun.COM     int sleep)
28727836SJohn.Forte@Sun.COM {
28737836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *last;
28747836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
28757836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *new;
28767836SJohn.Forte@Sun.COM 
28777836SJohn.Forte@Sun.COM 	ASSERT(RW_READ_HELD(&fctl_ulp_lock));
28787836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
28797836SJohn.Forte@Sun.COM 
28807836SJohn.Forte@Sun.COM 	last = NULL;
28817836SJohn.Forte@Sun.COM 	next = ulp_module->mod_ports;
28827836SJohn.Forte@Sun.COM 
28837836SJohn.Forte@Sun.COM 	while (next != NULL) {
28847836SJohn.Forte@Sun.COM 		last = next;
28857836SJohn.Forte@Sun.COM 		next = next->port_next;
28867836SJohn.Forte@Sun.COM 	}
28877836SJohn.Forte@Sun.COM 
28887836SJohn.Forte@Sun.COM 	new = fctl_alloc_ulp_port(sleep);
28897836SJohn.Forte@Sun.COM 	if (new == NULL) {
28907836SJohn.Forte@Sun.COM 		return (new);
28917836SJohn.Forte@Sun.COM 	}
28927836SJohn.Forte@Sun.COM 
28937836SJohn.Forte@Sun.COM 	new->port_handle = port_handle;
28947836SJohn.Forte@Sun.COM 	if (last == NULL) {
28957836SJohn.Forte@Sun.COM 		ulp_module->mod_ports = new;
28967836SJohn.Forte@Sun.COM 	} else {
28977836SJohn.Forte@Sun.COM 		last->port_next = new;
28987836SJohn.Forte@Sun.COM 	}
28997836SJohn.Forte@Sun.COM 
29007836SJohn.Forte@Sun.COM 	return (new);
29017836SJohn.Forte@Sun.COM }
29027836SJohn.Forte@Sun.COM 
29037836SJohn.Forte@Sun.COM 
29047836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
fctl_alloc_ulp_port(int sleep)29057836SJohn.Forte@Sun.COM fctl_alloc_ulp_port(int sleep)
29067836SJohn.Forte@Sun.COM {
29077836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *new;
29087836SJohn.Forte@Sun.COM 
29097836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), sleep);
29107836SJohn.Forte@Sun.COM 	if (new == NULL) {
29117836SJohn.Forte@Sun.COM 		return (new);
29127836SJohn.Forte@Sun.COM 	}
29137836SJohn.Forte@Sun.COM 	mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
29147836SJohn.Forte@Sun.COM 
29157836SJohn.Forte@Sun.COM 	return (new);
29167836SJohn.Forte@Sun.COM }
29177836SJohn.Forte@Sun.COM 
29187836SJohn.Forte@Sun.COM 
29197836SJohn.Forte@Sun.COM static int
fctl_remove_ulp_port(struct ulp_module * ulp_module,fc_local_port_t * port_handle)29207836SJohn.Forte@Sun.COM fctl_remove_ulp_port(struct ulp_module *ulp_module,
29217836SJohn.Forte@Sun.COM     fc_local_port_t *port_handle)
29227836SJohn.Forte@Sun.COM {
29237836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *last;
29247836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
29257836SJohn.Forte@Sun.COM 
29267836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_ulp_lock));
29277836SJohn.Forte@Sun.COM 	ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
29287836SJohn.Forte@Sun.COM 
29297836SJohn.Forte@Sun.COM 	last = NULL;
29307836SJohn.Forte@Sun.COM 	next = ulp_module->mod_ports;
29317836SJohn.Forte@Sun.COM 
29327836SJohn.Forte@Sun.COM 	while (next != NULL) {
29337836SJohn.Forte@Sun.COM 		if (next->port_handle == port_handle) {
29347836SJohn.Forte@Sun.COM 			if (next->port_dstate & ULP_PORT_ATTACH) {
29357836SJohn.Forte@Sun.COM 				return (FC_FAILURE);
29367836SJohn.Forte@Sun.COM 			}
29377836SJohn.Forte@Sun.COM 			break;
29387836SJohn.Forte@Sun.COM 		}
29397836SJohn.Forte@Sun.COM 		last = next;
29407836SJohn.Forte@Sun.COM 		next = next->port_next;
29417836SJohn.Forte@Sun.COM 	}
29427836SJohn.Forte@Sun.COM 
29437836SJohn.Forte@Sun.COM 	if (next != NULL) {
29447836SJohn.Forte@Sun.COM 		ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
29457836SJohn.Forte@Sun.COM 
29467836SJohn.Forte@Sun.COM 		if (last == NULL) {
29477836SJohn.Forte@Sun.COM 			ulp_module->mod_ports = next->port_next;
29487836SJohn.Forte@Sun.COM 		} else {
29497836SJohn.Forte@Sun.COM 			last->port_next = next->port_next;
29507836SJohn.Forte@Sun.COM 		}
29517836SJohn.Forte@Sun.COM 		fctl_dealloc_ulp_port(next);
29527836SJohn.Forte@Sun.COM 
29537836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
29547836SJohn.Forte@Sun.COM 	} else {
29557836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
29567836SJohn.Forte@Sun.COM 	}
29577836SJohn.Forte@Sun.COM }
29587836SJohn.Forte@Sun.COM 
29597836SJohn.Forte@Sun.COM 
29607836SJohn.Forte@Sun.COM static void
fctl_dealloc_ulp_port(fc_ulp_ports_t * next)29617836SJohn.Forte@Sun.COM fctl_dealloc_ulp_port(fc_ulp_ports_t *next)
29627836SJohn.Forte@Sun.COM {
29637836SJohn.Forte@Sun.COM 	mutex_destroy(&next->port_mutex);
29647836SJohn.Forte@Sun.COM 	kmem_free(next, sizeof (*next));
29657836SJohn.Forte@Sun.COM }
29667836SJohn.Forte@Sun.COM 
29677836SJohn.Forte@Sun.COM 
29687836SJohn.Forte@Sun.COM static fc_ulp_ports_t *
fctl_get_ulp_port(struct ulp_module * ulp_module,fc_local_port_t * port_handle)29697836SJohn.Forte@Sun.COM fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
29707836SJohn.Forte@Sun.COM {
29717836SJohn.Forte@Sun.COM 	fc_ulp_ports_t *next;
29727836SJohn.Forte@Sun.COM 
29737836SJohn.Forte@Sun.COM 	ASSERT(RW_LOCK_HELD(&fctl_ulp_lock));
29747836SJohn.Forte@Sun.COM 	ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock));
29757836SJohn.Forte@Sun.COM 
29767836SJohn.Forte@Sun.COM 	for (next = ulp_module->mod_ports; next != NULL;
29777836SJohn.Forte@Sun.COM 	    next = next->port_next) {
29787836SJohn.Forte@Sun.COM 		if (next->port_handle == port_handle) {
29797836SJohn.Forte@Sun.COM 			return (next);
29807836SJohn.Forte@Sun.COM 		}
29817836SJohn.Forte@Sun.COM 	}
29827836SJohn.Forte@Sun.COM 
29837836SJohn.Forte@Sun.COM 	return (NULL);
29847836SJohn.Forte@Sun.COM }
29857836SJohn.Forte@Sun.COM 
29867836SJohn.Forte@Sun.COM 
29877836SJohn.Forte@Sun.COM /*
29887836SJohn.Forte@Sun.COM  * Pass state change notfications on to registered ULPs.
29897836SJohn.Forte@Sun.COM  *
29907836SJohn.Forte@Sun.COM  * Can issue wakeups to client callers who might be waiting for completions
29917836SJohn.Forte@Sun.COM  * on other threads.
29927836SJohn.Forte@Sun.COM  *
29937836SJohn.Forte@Sun.COM  * Caution: will silently deallocate any fc_remote_port_t and/or
29947836SJohn.Forte@Sun.COM  * fc_remote_node_t structs it finds that are not in use.
29957836SJohn.Forte@Sun.COM  */
29967836SJohn.Forte@Sun.COM void
fctl_ulp_statec_cb(void * arg)29977836SJohn.Forte@Sun.COM fctl_ulp_statec_cb(void *arg)
29987836SJohn.Forte@Sun.COM {
29997836SJohn.Forte@Sun.COM 	uint32_t		s_id;
30007836SJohn.Forte@Sun.COM 	uint32_t		new_state;
30017836SJohn.Forte@Sun.COM 	fc_local_port_t		*port;
30027836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
300310264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
300410264SZhong.Wang@Sun.COM 	fc_port_clist_t		*clist = (fc_port_clist_t *)arg;
30057836SJohn.Forte@Sun.COM 
30067836SJohn.Forte@Sun.COM 	ASSERT(clist != NULL);
30077836SJohn.Forte@Sun.COM 
30087836SJohn.Forte@Sun.COM 	port = clist->clist_port;
30097836SJohn.Forte@Sun.COM 
30107836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
30117836SJohn.Forte@Sun.COM 	s_id = port->fp_port_id.port_id;
30127836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
30137836SJohn.Forte@Sun.COM 
30147836SJohn.Forte@Sun.COM 	switch (clist->clist_state) {
30157836SJohn.Forte@Sun.COM 	case FC_STATE_ONLINE:
30167836SJohn.Forte@Sun.COM 		new_state = FC_ULP_STATEC_ONLINE;
30177836SJohn.Forte@Sun.COM 		break;
30187836SJohn.Forte@Sun.COM 
30197836SJohn.Forte@Sun.COM 	case FC_STATE_OFFLINE:
30207836SJohn.Forte@Sun.COM 		if (clist->clist_len) {
30217836SJohn.Forte@Sun.COM 			new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT;
30227836SJohn.Forte@Sun.COM 		} else {
30237836SJohn.Forte@Sun.COM 			new_state = FC_ULP_STATEC_OFFLINE;
30247836SJohn.Forte@Sun.COM 		}
30257836SJohn.Forte@Sun.COM 		break;
30267836SJohn.Forte@Sun.COM 
30277836SJohn.Forte@Sun.COM 	default:
30287836SJohn.Forte@Sun.COM 		new_state = FC_ULP_STATEC_DONT_CARE;
30297836SJohn.Forte@Sun.COM 		break;
30307836SJohn.Forte@Sun.COM 	}
30317836SJohn.Forte@Sun.COM 
30327836SJohn.Forte@Sun.COM #ifdef	DEBUG
30337836SJohn.Forte@Sun.COM 	/*
30347836SJohn.Forte@Sun.COM 	 * sanity check for presence of OLD devices in the hash lists
30357836SJohn.Forte@Sun.COM 	 */
30367836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
303710264SZhong.Wang@Sun.COM 		int			count;
30387836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd;
30397836SJohn.Forte@Sun.COM 
30407836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
30417836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len; count++) {
30427836SJohn.Forte@Sun.COM 			if (clist->clist_map[count].map_state ==
30437836SJohn.Forte@Sun.COM 			    PORT_DEVICE_INVALID) {
304410264SZhong.Wang@Sun.COM 				la_wwn_t	pwwn;
304510264SZhong.Wang@Sun.COM 				fc_portid_t	d_id;
30467836SJohn.Forte@Sun.COM 
30477836SJohn.Forte@Sun.COM 				pd = clist->clist_map[count].map_pd;
30487836SJohn.Forte@Sun.COM 				if (pd != NULL) {
30497836SJohn.Forte@Sun.COM 					mutex_enter(&pd->pd_mutex);
30507836SJohn.Forte@Sun.COM 					pwwn = pd->pd_port_name;
30517836SJohn.Forte@Sun.COM 					d_id = pd->pd_port_id;
30527836SJohn.Forte@Sun.COM 					mutex_exit(&pd->pd_mutex);
30537836SJohn.Forte@Sun.COM 
30547836SJohn.Forte@Sun.COM 					pd = fctl_get_remote_port_by_pwwn(port,
30557836SJohn.Forte@Sun.COM 					    &pwwn);
30567836SJohn.Forte@Sun.COM 
30577836SJohn.Forte@Sun.COM 					ASSERT(pd != clist->clist_map[count].
30587836SJohn.Forte@Sun.COM 					    map_pd);
30597836SJohn.Forte@Sun.COM 
30607836SJohn.Forte@Sun.COM 					pd = fctl_get_remote_port_by_did(port,
30617836SJohn.Forte@Sun.COM 					    d_id.port_id);
30627836SJohn.Forte@Sun.COM 					ASSERT(pd != clist->clist_map[count].
30637836SJohn.Forte@Sun.COM 					    map_pd);
30647836SJohn.Forte@Sun.COM 				}
30657836SJohn.Forte@Sun.COM 			}
30667836SJohn.Forte@Sun.COM 		}
30677836SJohn.Forte@Sun.COM 	}
30687836SJohn.Forte@Sun.COM #endif
30697836SJohn.Forte@Sun.COM 
30707836SJohn.Forte@Sun.COM 	/*
30717836SJohn.Forte@Sun.COM 	 * Check for duplicate map entries
30727836SJohn.Forte@Sun.COM 	 */
30737836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
307410264SZhong.Wang@Sun.COM 		int			count;
30757836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd1, *pd2;
30767836SJohn.Forte@Sun.COM 
30777836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
30787836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len-1; count++) {
30797836SJohn.Forte@Sun.COM 			int count2;
30807836SJohn.Forte@Sun.COM 
30817836SJohn.Forte@Sun.COM 			pd1 = clist->clist_map[count].map_pd;
30827836SJohn.Forte@Sun.COM 			if (pd1 == NULL) {
30837836SJohn.Forte@Sun.COM 				continue;
30847836SJohn.Forte@Sun.COM 			}
30857836SJohn.Forte@Sun.COM 
30867836SJohn.Forte@Sun.COM 			for (count2 = count+1;
30877836SJohn.Forte@Sun.COM 			    count2 < clist->clist_len;
30887836SJohn.Forte@Sun.COM 			    count2++) {
30897836SJohn.Forte@Sun.COM 
30907836SJohn.Forte@Sun.COM 				pd2 = clist->clist_map[count2].map_pd;
30917836SJohn.Forte@Sun.COM 				if (pd2 == NULL) {
30927836SJohn.Forte@Sun.COM 					continue;
30937836SJohn.Forte@Sun.COM 				}
30947836SJohn.Forte@Sun.COM 
30957836SJohn.Forte@Sun.COM 				if (pd1 == pd2) {
30967836SJohn.Forte@Sun.COM 					clist->clist_map[count].map_flags |=
30977836SJohn.Forte@Sun.COM 					    PORT_DEVICE_DUPLICATE_MAP_ENTRY;
30987836SJohn.Forte@Sun.COM 					break;
30997836SJohn.Forte@Sun.COM 				}
31007836SJohn.Forte@Sun.COM 			}
31017836SJohn.Forte@Sun.COM 		}
31027836SJohn.Forte@Sun.COM 	}
31037836SJohn.Forte@Sun.COM 
31047836SJohn.Forte@Sun.COM 
31057836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
31067836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
31077836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
31087836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
31097836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
31107836SJohn.Forte@Sun.COM 
31117836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
31127836SJohn.Forte@Sun.COM 			continue;
31137836SJohn.Forte@Sun.COM 		}
31147836SJohn.Forte@Sun.COM 
31157836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
31167836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
31177836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
31187836SJohn.Forte@Sun.COM 			continue;
31197836SJohn.Forte@Sun.COM 		}
31207836SJohn.Forte@Sun.COM 
31217836SJohn.Forte@Sun.COM 		switch (ulp_port->port_statec) {
31227836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_DONT_CARE:
31237836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec != new_state) {
31247836SJohn.Forte@Sun.COM 				ulp_port->port_statec = new_state;
31257836SJohn.Forte@Sun.COM 			}
31267836SJohn.Forte@Sun.COM 			break;
31277836SJohn.Forte@Sun.COM 
31287836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_ONLINE:
31297836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_OFFLINE:
31307836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec == new_state) {
31317836SJohn.Forte@Sun.COM 				mutex_exit(&ulp_port->port_mutex);
31327836SJohn.Forte@Sun.COM 				continue;
31337836SJohn.Forte@Sun.COM 			}
31347836SJohn.Forte@Sun.COM 			ulp_port->port_statec = new_state;
31357836SJohn.Forte@Sun.COM 			break;
31367836SJohn.Forte@Sun.COM 
31377836SJohn.Forte@Sun.COM 		case FC_ULP_STATEC_OFFLINE_TIMEOUT:
31387836SJohn.Forte@Sun.COM 			if (ulp_port->port_statec == new_state ||
31397836SJohn.Forte@Sun.COM 			    new_state == FC_ULP_STATEC_OFFLINE) {
31407836SJohn.Forte@Sun.COM 				mutex_exit(&ulp_port->port_mutex);
31417836SJohn.Forte@Sun.COM 				continue;
31427836SJohn.Forte@Sun.COM 			}
31437836SJohn.Forte@Sun.COM 			ulp_port->port_statec = new_state;
31447836SJohn.Forte@Sun.COM 			break;
31457836SJohn.Forte@Sun.COM 
31467836SJohn.Forte@Sun.COM 		default:
31477836SJohn.Forte@Sun.COM 			ASSERT(0);
31487836SJohn.Forte@Sun.COM 			break;
31497836SJohn.Forte@Sun.COM 		}
31507836SJohn.Forte@Sun.COM 
31517836SJohn.Forte@Sun.COM 		mod->mod_info->ulp_statec_callback(
31527836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, (opaque_t)port,
31537836SJohn.Forte@Sun.COM 		    clist->clist_state, clist->clist_flags,
31547836SJohn.Forte@Sun.COM 		    clist->clist_map, clist->clist_len, s_id);
31557836SJohn.Forte@Sun.COM 
31567836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
31577836SJohn.Forte@Sun.COM 	}
31587836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
31597836SJohn.Forte@Sun.COM 
31607836SJohn.Forte@Sun.COM 	if (clist->clist_size) {
316110264SZhong.Wang@Sun.COM 		int			count;
31627836SJohn.Forte@Sun.COM 		fc_remote_node_t	*node;
31637836SJohn.Forte@Sun.COM 		fc_remote_port_t	*pd;
31647836SJohn.Forte@Sun.COM 
31657836SJohn.Forte@Sun.COM 		ASSERT(clist->clist_map != NULL);
31667836SJohn.Forte@Sun.COM 		for (count = 0; count < clist->clist_len; count++) {
31677836SJohn.Forte@Sun.COM 
31687836SJohn.Forte@Sun.COM 			if ((pd = clist->clist_map[count].map_pd) == NULL) {
31697836SJohn.Forte@Sun.COM 				continue;
31707836SJohn.Forte@Sun.COM 			}
31717836SJohn.Forte@Sun.COM 
31727836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
31737836SJohn.Forte@Sun.COM 
31747836SJohn.Forte@Sun.COM 			pd->pd_ref_count--;
31757836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
31767836SJohn.Forte@Sun.COM 
31777836SJohn.Forte@Sun.COM 			if (clist->clist_map[count].map_state !=
31787836SJohn.Forte@Sun.COM 			    PORT_DEVICE_INVALID) {
31797836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
31807836SJohn.Forte@Sun.COM 				continue;
31817836SJohn.Forte@Sun.COM 			}
31827836SJohn.Forte@Sun.COM 
31837836SJohn.Forte@Sun.COM 			node = pd->pd_remote_nodep;
31847836SJohn.Forte@Sun.COM 			pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS;
31857836SJohn.Forte@Sun.COM 
31867836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
31877836SJohn.Forte@Sun.COM 
31887836SJohn.Forte@Sun.COM 			/*
31897836SJohn.Forte@Sun.COM 			 * This fc_remote_port_t is no longer referenced
31907836SJohn.Forte@Sun.COM 			 * by any ULPs. Deallocate it if its pd_ref_count
31917836SJohn.Forte@Sun.COM 			 * has reached zero.
31927836SJohn.Forte@Sun.COM 			 */
31937836SJohn.Forte@Sun.COM 			if ((fctl_destroy_remote_port(port, pd) == 0) &&
31947836SJohn.Forte@Sun.COM 			    (node != NULL)) {
31957836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
31967836SJohn.Forte@Sun.COM 			}
31977836SJohn.Forte@Sun.COM 		}
31987836SJohn.Forte@Sun.COM 
31997836SJohn.Forte@Sun.COM 		kmem_free(clist->clist_map,
32007836SJohn.Forte@Sun.COM 		    sizeof (*(clist->clist_map)) * clist->clist_size);
32017836SJohn.Forte@Sun.COM 	}
32027836SJohn.Forte@Sun.COM 
32037836SJohn.Forte@Sun.COM 	if (clist->clist_wait) {
32047836SJohn.Forte@Sun.COM 		mutex_enter(&clist->clist_mutex);
32057836SJohn.Forte@Sun.COM 		clist->clist_wait = 0;
32067836SJohn.Forte@Sun.COM 		cv_signal(&clist->clist_cv);
32077836SJohn.Forte@Sun.COM 		mutex_exit(&clist->clist_mutex);
32087836SJohn.Forte@Sun.COM 	} else {
32097836SJohn.Forte@Sun.COM 		kmem_free(clist, sizeof (*clist));
32107836SJohn.Forte@Sun.COM 	}
32117836SJohn.Forte@Sun.COM }
32127836SJohn.Forte@Sun.COM 
32137836SJohn.Forte@Sun.COM 
32147836SJohn.Forte@Sun.COM /*
32157836SJohn.Forte@Sun.COM  * Allocate an fc_remote_node_t struct to represent a remote node for the
321610264SZhong.Wang@Sun.COM  * given nwwn.	This will also add the nwwn to the global nwwn table.
32177836SJohn.Forte@Sun.COM  *
32187836SJohn.Forte@Sun.COM  * Returns a pointer to the newly-allocated struct.  Returns NULL if
32197836SJohn.Forte@Sun.COM  * the kmem_zalloc fails or if the enlist_wwn attempt fails.
32207836SJohn.Forte@Sun.COM  */
32217836SJohn.Forte@Sun.COM fc_remote_node_t *
fctl_create_remote_node(la_wwn_t * nwwn,int sleep)32227836SJohn.Forte@Sun.COM fctl_create_remote_node(la_wwn_t *nwwn, int sleep)
32237836SJohn.Forte@Sun.COM {
32247836SJohn.Forte@Sun.COM 	fc_remote_node_t *rnodep;
32257836SJohn.Forte@Sun.COM 
32267836SJohn.Forte@Sun.COM 	if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
32277836SJohn.Forte@Sun.COM 		return (NULL);
32287836SJohn.Forte@Sun.COM 	}
32297836SJohn.Forte@Sun.COM 
32307836SJohn.Forte@Sun.COM 	mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
32317836SJohn.Forte@Sun.COM 
32327836SJohn.Forte@Sun.COM 	rnodep->fd_node_name = *nwwn;
32337836SJohn.Forte@Sun.COM 	rnodep->fd_flags = FC_REMOTE_NODE_VALID;
32347836SJohn.Forte@Sun.COM 	rnodep->fd_numports = 1;
32357836SJohn.Forte@Sun.COM 
32367836SJohn.Forte@Sun.COM 	if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
32377836SJohn.Forte@Sun.COM 		mutex_destroy(&rnodep->fd_mutex);
32387836SJohn.Forte@Sun.COM 		kmem_free(rnodep, sizeof (*rnodep));
32397836SJohn.Forte@Sun.COM 		return (NULL);
32407836SJohn.Forte@Sun.COM 	}
32417836SJohn.Forte@Sun.COM 
32427836SJohn.Forte@Sun.COM 	return (rnodep);
32437836SJohn.Forte@Sun.COM }
32447836SJohn.Forte@Sun.COM 
32457836SJohn.Forte@Sun.COM /*
32467836SJohn.Forte@Sun.COM  * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
32477836SJohn.Forte@Sun.COM  * Silently skips the deconstruct/free if there are any fc_remote_port_t
32487836SJohn.Forte@Sun.COM  * (remote port device) structs still referenced by the given
32497836SJohn.Forte@Sun.COM  * fc_remote_node_t struct.
32507836SJohn.Forte@Sun.COM  */
32517836SJohn.Forte@Sun.COM void
fctl_destroy_remote_node(fc_remote_node_t * rnodep)32527836SJohn.Forte@Sun.COM fctl_destroy_remote_node(fc_remote_node_t *rnodep)
32537836SJohn.Forte@Sun.COM {
32547836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
32557836SJohn.Forte@Sun.COM 
32567836SJohn.Forte@Sun.COM 	/*
32577836SJohn.Forte@Sun.COM 	 * Look at the count and linked list of of remote ports
32587836SJohn.Forte@Sun.COM 	 * (fc_remote_port_t structs); bail if these indicate that
32597836SJohn.Forte@Sun.COM 	 * given fc_remote_node_t may be in use.
32607836SJohn.Forte@Sun.COM 	 */
32617836SJohn.Forte@Sun.COM 	if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
32627836SJohn.Forte@Sun.COM 		mutex_exit(&rnodep->fd_mutex);
32637836SJohn.Forte@Sun.COM 		return;
32647836SJohn.Forte@Sun.COM 	}
32657836SJohn.Forte@Sun.COM 
32667836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
32677836SJohn.Forte@Sun.COM 
32687836SJohn.Forte@Sun.COM 	mutex_destroy(&rnodep->fd_mutex);
32697836SJohn.Forte@Sun.COM 	kmem_free(rnodep, sizeof (*rnodep));
32707836SJohn.Forte@Sun.COM }
32717836SJohn.Forte@Sun.COM 
32727836SJohn.Forte@Sun.COM 
32737836SJohn.Forte@Sun.COM /*
32747836SJohn.Forte@Sun.COM  * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
32757836SJohn.Forte@Sun.COM  * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
32767836SJohn.Forte@Sun.COM  * This only fails if the kmem_zalloc fails.  This does not check for a
32777836SJohn.Forte@Sun.COM  * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
32787836SJohn.Forte@Sun.COM  * This is only called from fctl_create_remote_node().
32797836SJohn.Forte@Sun.COM  */
32807836SJohn.Forte@Sun.COM int
fctl_enlist_nwwn_table(fc_remote_node_t * rnodep,int sleep)32817836SJohn.Forte@Sun.COM fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
32827836SJohn.Forte@Sun.COM {
328310264SZhong.Wang@Sun.COM 	int			index;
328410264SZhong.Wang@Sun.COM 	fctl_nwwn_elem_t	*new;
328510264SZhong.Wang@Sun.COM 	fctl_nwwn_list_t	*head;
32867836SJohn.Forte@Sun.COM 
32877836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
32887836SJohn.Forte@Sun.COM 
32897836SJohn.Forte@Sun.COM 	if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
32907836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
32917836SJohn.Forte@Sun.COM 	}
32927836SJohn.Forte@Sun.COM 
32937836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
32947836SJohn.Forte@Sun.COM 	new->fne_nodep = rnodep;
32957836SJohn.Forte@Sun.COM 
32967836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
32977836SJohn.Forte@Sun.COM 	ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
32987836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
32997836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
33007836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
33017836SJohn.Forte@Sun.COM 
33027836SJohn.Forte@Sun.COM 	head = &fctl_nwwn_hash_table[index];
33037836SJohn.Forte@Sun.COM 
33047836SJohn.Forte@Sun.COM 	/* Link it in at the head of the hash list */
33057836SJohn.Forte@Sun.COM 	new->fne_nextp = head->fnl_headp;
33067836SJohn.Forte@Sun.COM 	head->fnl_headp = new;
33077836SJohn.Forte@Sun.COM 
33087836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
33097836SJohn.Forte@Sun.COM 
33107836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
33117836SJohn.Forte@Sun.COM }
33127836SJohn.Forte@Sun.COM 
33137836SJohn.Forte@Sun.COM 
33147836SJohn.Forte@Sun.COM /*
33157836SJohn.Forte@Sun.COM  * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
33167836SJohn.Forte@Sun.COM  * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
33177836SJohn.Forte@Sun.COM  */
33187836SJohn.Forte@Sun.COM void
fctl_delist_nwwn_table(fc_remote_node_t * rnodep)33197836SJohn.Forte@Sun.COM fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
33207836SJohn.Forte@Sun.COM {
332110264SZhong.Wang@Sun.COM 	int			index;
332210264SZhong.Wang@Sun.COM 	fctl_nwwn_list_t	*head;
332310264SZhong.Wang@Sun.COM 	fctl_nwwn_elem_t	*elem;
332410264SZhong.Wang@Sun.COM 	fctl_nwwn_elem_t	*prev;
33257836SJohn.Forte@Sun.COM 
33267836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
33277836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
33287836SJohn.Forte@Sun.COM 
33297836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
33307836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
33317836SJohn.Forte@Sun.COM 
33327836SJohn.Forte@Sun.COM 	head = &fctl_nwwn_hash_table[index];
33337836SJohn.Forte@Sun.COM 	elem = head->fnl_headp;
33347836SJohn.Forte@Sun.COM 	prev = NULL;
33357836SJohn.Forte@Sun.COM 
33367836SJohn.Forte@Sun.COM 	while (elem != NULL) {
33377836SJohn.Forte@Sun.COM 		if (elem->fne_nodep == rnodep) {
33387836SJohn.Forte@Sun.COM 			/*
33397836SJohn.Forte@Sun.COM 			 * Found it -- unlink it from the list & decrement
33407836SJohn.Forte@Sun.COM 			 * the count for the hash chain.
33417836SJohn.Forte@Sun.COM 			 */
33427836SJohn.Forte@Sun.COM 			if (prev == NULL) {
33437836SJohn.Forte@Sun.COM 				head->fnl_headp = elem->fne_nextp;
33447836SJohn.Forte@Sun.COM 			} else {
33457836SJohn.Forte@Sun.COM 				prev->fne_nextp = elem->fne_nextp;
33467836SJohn.Forte@Sun.COM 			}
33477836SJohn.Forte@Sun.COM 			break;
33487836SJohn.Forte@Sun.COM 		}
33497836SJohn.Forte@Sun.COM 		prev = elem;
33507836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
33517836SJohn.Forte@Sun.COM 	}
33527836SJohn.Forte@Sun.COM 
33537836SJohn.Forte@Sun.COM 	if (elem != NULL) {
33547836SJohn.Forte@Sun.COM 		kmem_free(elem, sizeof (*elem));
33557836SJohn.Forte@Sun.COM 	}
33567836SJohn.Forte@Sun.COM }
33577836SJohn.Forte@Sun.COM 
33587836SJohn.Forte@Sun.COM 
33597836SJohn.Forte@Sun.COM /*
33607836SJohn.Forte@Sun.COM  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
33617836SJohn.Forte@Sun.COM  * Looks in the global fctl_nwwn_hash_table[]. Identical to the
33627836SJohn.Forte@Sun.COM  * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
33637836SJohn.Forte@Sun.COM  * the fc_count reference count in the f_device_t before returning.
33647836SJohn.Forte@Sun.COM  *
33657836SJohn.Forte@Sun.COM  * This function is called by: fctl_create_remote_port_t().
33667836SJohn.Forte@Sun.COM  *
33677836SJohn.Forte@Sun.COM  * OLD COMMENT:
33687836SJohn.Forte@Sun.COM  * Note: The calling thread needs to make sure it isn't holding any device
33697836SJohn.Forte@Sun.COM  * mutex (more so the fc_remote_node_t that could potentially have this wwn).
33707836SJohn.Forte@Sun.COM  */
33717836SJohn.Forte@Sun.COM fc_remote_node_t *
fctl_get_remote_node_by_nwwn(la_wwn_t * node_wwn)33727836SJohn.Forte@Sun.COM fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
33737836SJohn.Forte@Sun.COM {
337410264SZhong.Wang@Sun.COM 	int			index;
337510264SZhong.Wang@Sun.COM 	fctl_nwwn_elem_t	*elem;
33767836SJohn.Forte@Sun.COM 	fc_remote_node_t	*next;
337710264SZhong.Wang@Sun.COM 	fc_remote_node_t	*rnodep = NULL;
33787836SJohn.Forte@Sun.COM 
33797836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
33807836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
33817836SJohn.Forte@Sun.COM 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
33827836SJohn.Forte@Sun.COM 
33837836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
33847836SJohn.Forte@Sun.COM 	elem = fctl_nwwn_hash_table[index].fnl_headp;
33857836SJohn.Forte@Sun.COM 	while (elem != NULL) {
33867836SJohn.Forte@Sun.COM 		next = elem->fne_nodep;
33877836SJohn.Forte@Sun.COM 		if (next != NULL) {
33887836SJohn.Forte@Sun.COM 			mutex_enter(&next->fd_mutex);
33897836SJohn.Forte@Sun.COM 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
33907836SJohn.Forte@Sun.COM 				rnodep = next;
33917836SJohn.Forte@Sun.COM 				mutex_exit(&next->fd_mutex);
33927836SJohn.Forte@Sun.COM 				break;
33937836SJohn.Forte@Sun.COM 			}
33947836SJohn.Forte@Sun.COM 			mutex_exit(&next->fd_mutex);
33957836SJohn.Forte@Sun.COM 		}
33967836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
33977836SJohn.Forte@Sun.COM 	}
33987836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
33997836SJohn.Forte@Sun.COM 
34007836SJohn.Forte@Sun.COM 	return (rnodep);
34017836SJohn.Forte@Sun.COM }
34027836SJohn.Forte@Sun.COM 
34037836SJohn.Forte@Sun.COM 
34047836SJohn.Forte@Sun.COM /*
34057836SJohn.Forte@Sun.COM  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
34067836SJohn.Forte@Sun.COM  * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
34077836SJohn.Forte@Sun.COM  * reference count in the f_device_t before returning.
34087836SJohn.Forte@Sun.COM  *
34097836SJohn.Forte@Sun.COM  * This function is only called by fctl_create_remote_port_t().
34107836SJohn.Forte@Sun.COM  */
34117836SJohn.Forte@Sun.COM fc_remote_node_t *
fctl_lock_remote_node_by_nwwn(la_wwn_t * node_wwn)34127836SJohn.Forte@Sun.COM fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
34137836SJohn.Forte@Sun.COM {
341410264SZhong.Wang@Sun.COM 	int			index;
341510264SZhong.Wang@Sun.COM 	fctl_nwwn_elem_t	*elem;
34167836SJohn.Forte@Sun.COM 	fc_remote_node_t	*next;
341710264SZhong.Wang@Sun.COM 	fc_remote_node_t	*rnodep = NULL;
34187836SJohn.Forte@Sun.COM 
34197836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
34207836SJohn.Forte@Sun.COM 	    fctl_nwwn_table_size);
34217836SJohn.Forte@Sun.COM 	ASSERT(index >= 0 && index < fctl_nwwn_table_size);
34227836SJohn.Forte@Sun.COM 
34237836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
34247836SJohn.Forte@Sun.COM 	elem = fctl_nwwn_hash_table[index].fnl_headp;
34257836SJohn.Forte@Sun.COM 	while (elem != NULL) {
34267836SJohn.Forte@Sun.COM 		next = elem->fne_nodep;
34277836SJohn.Forte@Sun.COM 		if (next != NULL) {
34287836SJohn.Forte@Sun.COM 			mutex_enter(&next->fd_mutex);
34297836SJohn.Forte@Sun.COM 			if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
34307836SJohn.Forte@Sun.COM 				rnodep = next;
34317836SJohn.Forte@Sun.COM 				rnodep->fd_numports++;
34327836SJohn.Forte@Sun.COM 				mutex_exit(&next->fd_mutex);
34337836SJohn.Forte@Sun.COM 				break;
34347836SJohn.Forte@Sun.COM 			}
34357836SJohn.Forte@Sun.COM 			mutex_exit(&next->fd_mutex);
34367836SJohn.Forte@Sun.COM 		}
34377836SJohn.Forte@Sun.COM 		elem = elem->fne_nextp;
34387836SJohn.Forte@Sun.COM 	}
34397836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
34407836SJohn.Forte@Sun.COM 
34417836SJohn.Forte@Sun.COM 	return (rnodep);
34427836SJohn.Forte@Sun.COM }
34437836SJohn.Forte@Sun.COM 
34447836SJohn.Forte@Sun.COM 
34457836SJohn.Forte@Sun.COM /*
34467836SJohn.Forte@Sun.COM  * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
344710264SZhong.Wang@Sun.COM  * the newly allocated struct.	Only fails if the kmem_zalloc() fails.
34487836SJohn.Forte@Sun.COM  */
34497836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_alloc_remote_port(fc_local_port_t * port,la_wwn_t * port_wwn,uint32_t d_id,uchar_t recepient,int sleep)34507836SJohn.Forte@Sun.COM fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
34517836SJohn.Forte@Sun.COM     uint32_t d_id, uchar_t recepient, int sleep)
34527836SJohn.Forte@Sun.COM {
34537836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd;
34547836SJohn.Forte@Sun.COM 
34557836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
34567836SJohn.Forte@Sun.COM 	ASSERT(FC_IS_REAL_DEVICE(d_id));
34577836SJohn.Forte@Sun.COM 
34587836SJohn.Forte@Sun.COM 	if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
34597836SJohn.Forte@Sun.COM 		return (NULL);
34607836SJohn.Forte@Sun.COM 	}
34617836SJohn.Forte@Sun.COM 	fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
34627836SJohn.Forte@Sun.COM 	    FC_LOGO_TOLERANCE_TIME_LIMIT);
34637836SJohn.Forte@Sun.COM 
34647836SJohn.Forte@Sun.COM 	mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
34657836SJohn.Forte@Sun.COM 
34667836SJohn.Forte@Sun.COM 	pd->pd_port_id.port_id = d_id;
34677836SJohn.Forte@Sun.COM 	pd->pd_port_name = *port_wwn;
34687836SJohn.Forte@Sun.COM 	pd->pd_port = port;
34697836SJohn.Forte@Sun.COM 	pd->pd_state = PORT_DEVICE_VALID;
34707836SJohn.Forte@Sun.COM 	pd->pd_type = PORT_DEVICE_NEW;
34717836SJohn.Forte@Sun.COM 	pd->pd_recepient = recepient;
34727836SJohn.Forte@Sun.COM 
34737836SJohn.Forte@Sun.COM 	return (pd);
34747836SJohn.Forte@Sun.COM }
34757836SJohn.Forte@Sun.COM 
34767836SJohn.Forte@Sun.COM 
34777836SJohn.Forte@Sun.COM /*
34787836SJohn.Forte@Sun.COM  * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
34797836SJohn.Forte@Sun.COM  */
34807836SJohn.Forte@Sun.COM void
fctl_dealloc_remote_port(fc_remote_port_t * pd)34817836SJohn.Forte@Sun.COM fctl_dealloc_remote_port(fc_remote_port_t *pd)
34827836SJohn.Forte@Sun.COM {
34837836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
34847836SJohn.Forte@Sun.COM 
34857836SJohn.Forte@Sun.COM 	fctl_tc_destructor(&pd->pd_logo_tc);
34867836SJohn.Forte@Sun.COM 	mutex_destroy(&pd->pd_mutex);
34877836SJohn.Forte@Sun.COM 	kmem_free(pd, sizeof (*pd));
34887836SJohn.Forte@Sun.COM }
34897836SJohn.Forte@Sun.COM 
34907836SJohn.Forte@Sun.COM /*
34917836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t onto the linked list of remote port
34927836SJohn.Forte@Sun.COM  * devices associated with the given fc_remote_node_t. Does NOT add the
34937836SJohn.Forte@Sun.COM  * fc_remote_port_t to the list if already exists on the list.
34947836SJohn.Forte@Sun.COM  */
34957836SJohn.Forte@Sun.COM void
fctl_link_remote_port_to_remote_node(fc_remote_node_t * rnodep,fc_remote_port_t * pd)34967836SJohn.Forte@Sun.COM fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
34977836SJohn.Forte@Sun.COM     fc_remote_port_t *pd)
34987836SJohn.Forte@Sun.COM {
34997836SJohn.Forte@Sun.COM 	fc_remote_port_t *last;
35007836SJohn.Forte@Sun.COM 	fc_remote_port_t *ports;
35017836SJohn.Forte@Sun.COM 
35027836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
35037836SJohn.Forte@Sun.COM 
35047836SJohn.Forte@Sun.COM 	last = NULL;
35057836SJohn.Forte@Sun.COM 	for (ports = rnodep->fd_portlistp; ports != NULL;
35067836SJohn.Forte@Sun.COM 	    ports = ports->pd_port_next) {
35077836SJohn.Forte@Sun.COM 		if (ports == pd) {
35087836SJohn.Forte@Sun.COM 			/*
35097836SJohn.Forte@Sun.COM 			 * The given fc_remote_port_t is already on the linked
35107836SJohn.Forte@Sun.COM 			 * list chain for the given remote node, so bail now.
35117836SJohn.Forte@Sun.COM 			 */
35127836SJohn.Forte@Sun.COM 			mutex_exit(&rnodep->fd_mutex);
35137836SJohn.Forte@Sun.COM 			return;
35147836SJohn.Forte@Sun.COM 		}
35157836SJohn.Forte@Sun.COM 		last = ports;
35167836SJohn.Forte@Sun.COM 	}
35177836SJohn.Forte@Sun.COM 
35187836SJohn.Forte@Sun.COM 	/* Add the fc_remote_port_t to the tail of the linked list */
35197836SJohn.Forte@Sun.COM 	if (last != NULL) {
35207836SJohn.Forte@Sun.COM 		last->pd_port_next = pd;
35217836SJohn.Forte@Sun.COM 	} else {
35227836SJohn.Forte@Sun.COM 		rnodep->fd_portlistp = pd;
35237836SJohn.Forte@Sun.COM 	}
35247836SJohn.Forte@Sun.COM 	pd->pd_port_next = NULL;
35257836SJohn.Forte@Sun.COM 
35267836SJohn.Forte@Sun.COM 	/*
35277836SJohn.Forte@Sun.COM 	 * Link the fc_remote_port_t back to the associated fc_remote_node_t.
35287836SJohn.Forte@Sun.COM 	 */
35297836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
35307836SJohn.Forte@Sun.COM 	pd->pd_remote_nodep = rnodep;
35317836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
35327836SJohn.Forte@Sun.COM 
35337836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
35347836SJohn.Forte@Sun.COM }
35357836SJohn.Forte@Sun.COM 
35367836SJohn.Forte@Sun.COM 
35377836SJohn.Forte@Sun.COM /*
35387836SJohn.Forte@Sun.COM  * Remove the specified fc_remote_port_t from the linked list of remote ports
35397836SJohn.Forte@Sun.COM  * for the given fc_remote_node_t.
35407836SJohn.Forte@Sun.COM  *
35417836SJohn.Forte@Sun.COM  * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
35427836SJohn.Forte@Sun.COM  * list of the fc_remote_node_t.
35437836SJohn.Forte@Sun.COM  *
35447836SJohn.Forte@Sun.COM  * The fd_numports on the given fc_remote_node_t is decremented, and if
35457836SJohn.Forte@Sun.COM  * it hits zero then this function also removes the fc_remote_node_t from the
35467836SJohn.Forte@Sun.COM  * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
35477836SJohn.Forte@Sun.COM  * are removed from the fctl_nwwn_hash_table[].
35487836SJohn.Forte@Sun.COM  */
35497836SJohn.Forte@Sun.COM int
fctl_unlink_remote_port_from_remote_node(fc_remote_node_t * rnodep,fc_remote_port_t * pd)35507836SJohn.Forte@Sun.COM fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
35517836SJohn.Forte@Sun.COM     fc_remote_port_t *pd)
35527836SJohn.Forte@Sun.COM {
35537836SJohn.Forte@Sun.COM 	int			rcount = 0;
355410264SZhong.Wang@Sun.COM 	fc_remote_port_t	*last;
355510264SZhong.Wang@Sun.COM 	fc_remote_port_t	*ports;
35567836SJohn.Forte@Sun.COM 
35577836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
35587836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
35597836SJohn.Forte@Sun.COM 
35607836SJohn.Forte@Sun.COM 	last = NULL;
35617836SJohn.Forte@Sun.COM 
35627836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_nwwn_hash_mutex);
35637836SJohn.Forte@Sun.COM 
35647836SJohn.Forte@Sun.COM 	mutex_enter(&rnodep->fd_mutex);
35657836SJohn.Forte@Sun.COM 
35667836SJohn.Forte@Sun.COM 	/*
35677836SJohn.Forte@Sun.COM 	 * Go thru the linked list of fc_remote_port_t structs for the given
35687836SJohn.Forte@Sun.COM 	 * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
35697836SJohn.Forte@Sun.COM 	 */
35707836SJohn.Forte@Sun.COM 	ports = rnodep->fd_portlistp;
35717836SJohn.Forte@Sun.COM 	while (ports != NULL) {
35727836SJohn.Forte@Sun.COM 		if (ports == pd) {
35737836SJohn.Forte@Sun.COM 			break;	/* Found the requested fc_remote_port_t */
35747836SJohn.Forte@Sun.COM 		}
35757836SJohn.Forte@Sun.COM 		last = ports;
35767836SJohn.Forte@Sun.COM 		ports = ports->pd_port_next;
35777836SJohn.Forte@Sun.COM 	}
35787836SJohn.Forte@Sun.COM 
35797836SJohn.Forte@Sun.COM 	if (ports) {
35807836SJohn.Forte@Sun.COM 		rcount = --rnodep->fd_numports;
35817836SJohn.Forte@Sun.COM 		if (rcount == 0) {
35827836SJohn.Forte@Sun.COM 			/* Note: this is only ever called from here */
35837836SJohn.Forte@Sun.COM 			fctl_delist_nwwn_table(rnodep);
35847836SJohn.Forte@Sun.COM 		}
35857836SJohn.Forte@Sun.COM 		if (last) {
35867836SJohn.Forte@Sun.COM 			last->pd_port_next = pd->pd_port_next;
35877836SJohn.Forte@Sun.COM 		} else {
35887836SJohn.Forte@Sun.COM 			rnodep->fd_portlistp = pd->pd_port_next;
35897836SJohn.Forte@Sun.COM 		}
35907836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
35917836SJohn.Forte@Sun.COM 		pd->pd_remote_nodep = NULL;
35927836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
35937836SJohn.Forte@Sun.COM 	}
35947836SJohn.Forte@Sun.COM 
35957836SJohn.Forte@Sun.COM 	pd->pd_port_next = NULL;
35967836SJohn.Forte@Sun.COM 
35977836SJohn.Forte@Sun.COM 	mutex_exit(&rnodep->fd_mutex);
35987836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_nwwn_hash_mutex);
35997836SJohn.Forte@Sun.COM 
36007836SJohn.Forte@Sun.COM 	return (rcount);
36017836SJohn.Forte@Sun.COM }
36027836SJohn.Forte@Sun.COM 
36037836SJohn.Forte@Sun.COM 
36047836SJohn.Forte@Sun.COM /*
36057836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t struct to the d_id table in the given
36067836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
36077836SJohn.Forte@Sun.COM  * fc_remote_port_t.
36087836SJohn.Forte@Sun.COM  *
36097836SJohn.Forte@Sun.COM  * No memory allocs are required, so this never fails, but it does use the
36107836SJohn.Forte@Sun.COM  * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
36117836SJohn.Forte@Sun.COM  * (There does not seem to be a way to tell the caller that a duplicate
36127836SJohn.Forte@Sun.COM  * exists.)
36137836SJohn.Forte@Sun.COM  */
36147836SJohn.Forte@Sun.COM void
fctl_enlist_did_table(fc_local_port_t * port,fc_remote_port_t * pd)36157836SJohn.Forte@Sun.COM fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
36167836SJohn.Forte@Sun.COM {
36177836SJohn.Forte@Sun.COM 	struct d_id_hash *head;
36187836SJohn.Forte@Sun.COM 
36197836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
36207836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
36217836SJohn.Forte@Sun.COM 
36227836SJohn.Forte@Sun.COM 	if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
36237836SJohn.Forte@Sun.COM 		return;
36247836SJohn.Forte@Sun.COM 	}
36257836SJohn.Forte@Sun.COM 
36267836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id,
36277836SJohn.Forte@Sun.COM 	    did_table_size)];
36287836SJohn.Forte@Sun.COM 
36297836SJohn.Forte@Sun.COM #ifdef	DEBUG
36307836SJohn.Forte@Sun.COM 	{
36317836SJohn.Forte@Sun.COM 		int			index;
363210264SZhong.Wang@Sun.COM 		fc_remote_port_t	*tmp_pd;
36337836SJohn.Forte@Sun.COM 		struct d_id_hash	*tmp_head;
36347836SJohn.Forte@Sun.COM 
36357836SJohn.Forte@Sun.COM 		/*
36367836SJohn.Forte@Sun.COM 		 * Search down in each bucket for a duplicate pd
36377836SJohn.Forte@Sun.COM 		 * Also search for duplicate D_IDs
36387836SJohn.Forte@Sun.COM 		 * This DEBUG code will force an ASSERT if a duplicate
36397836SJohn.Forte@Sun.COM 		 * is ever found.
36407836SJohn.Forte@Sun.COM 		 */
36417836SJohn.Forte@Sun.COM 		for (index = 0; index < did_table_size; index++) {
36427836SJohn.Forte@Sun.COM 			tmp_head = &port->fp_did_table[index];
36437836SJohn.Forte@Sun.COM 
36447836SJohn.Forte@Sun.COM 			tmp_pd = tmp_head->d_id_head;
36457836SJohn.Forte@Sun.COM 			while (tmp_pd != NULL) {
36467836SJohn.Forte@Sun.COM 				ASSERT(tmp_pd != pd);
36477836SJohn.Forte@Sun.COM 
36487836SJohn.Forte@Sun.COM 				if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
36497836SJohn.Forte@Sun.COM 				    tmp_pd->pd_type != PORT_DEVICE_OLD) {
36507836SJohn.Forte@Sun.COM 					ASSERT(tmp_pd->pd_port_id.port_id !=
36517836SJohn.Forte@Sun.COM 					    pd->pd_port_id.port_id);
36527836SJohn.Forte@Sun.COM 				}
36537836SJohn.Forte@Sun.COM 
36547836SJohn.Forte@Sun.COM 				tmp_pd = tmp_pd->pd_did_hnext;
36557836SJohn.Forte@Sun.COM 			}
36567836SJohn.Forte@Sun.COM 		}
36577836SJohn.Forte@Sun.COM 	}
36587836SJohn.Forte@Sun.COM 
36597836SJohn.Forte@Sun.COM 	bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack));
36607836SJohn.Forte@Sun.COM 	pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH);
36617836SJohn.Forte@Sun.COM #endif
36627836SJohn.Forte@Sun.COM 
36637836SJohn.Forte@Sun.COM 	pd->pd_did_hnext = head->d_id_head;
36647836SJohn.Forte@Sun.COM 	head->d_id_head = pd;
36657836SJohn.Forte@Sun.COM 
36667836SJohn.Forte@Sun.COM 	pd->pd_aux_flags |= PD_IN_DID_QUEUE;
36677836SJohn.Forte@Sun.COM 	head->d_id_count++;
36687836SJohn.Forte@Sun.COM }
36697836SJohn.Forte@Sun.COM 
36707836SJohn.Forte@Sun.COM 
36717836SJohn.Forte@Sun.COM /*
36727836SJohn.Forte@Sun.COM  * Remove the given fc_remote_port_t struct from the d_id table in the given
36737836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
36747836SJohn.Forte@Sun.COM  * fc_remote_port_t.
36757836SJohn.Forte@Sun.COM  *
36767836SJohn.Forte@Sun.COM  * Does nothing if the requested fc_remote_port_t was not found.
36777836SJohn.Forte@Sun.COM  */
36787836SJohn.Forte@Sun.COM void
fctl_delist_did_table(fc_local_port_t * port,fc_remote_port_t * pd)36797836SJohn.Forte@Sun.COM fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
36807836SJohn.Forte@Sun.COM {
36817836SJohn.Forte@Sun.COM 	uint32_t		d_id;
368210264SZhong.Wang@Sun.COM 	struct d_id_hash	*head;
368310264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd_next;
368410264SZhong.Wang@Sun.COM 	fc_remote_port_t	*last;
36857836SJohn.Forte@Sun.COM 
36867836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
36877836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
36887836SJohn.Forte@Sun.COM 
36897836SJohn.Forte@Sun.COM 	d_id = pd->pd_port_id.port_id;
36907836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
36917836SJohn.Forte@Sun.COM 
36927836SJohn.Forte@Sun.COM 	pd_next = head->d_id_head;
36937836SJohn.Forte@Sun.COM 	last = NULL;
36947836SJohn.Forte@Sun.COM 	while (pd_next != NULL) {
36957836SJohn.Forte@Sun.COM 		if (pd == pd_next) {
36967836SJohn.Forte@Sun.COM 			break;	/* Found the given fc_remote_port_t */
36977836SJohn.Forte@Sun.COM 		}
36987836SJohn.Forte@Sun.COM 		last = pd_next;
36997836SJohn.Forte@Sun.COM 		pd_next = pd_next->pd_did_hnext;
37007836SJohn.Forte@Sun.COM 	}
37017836SJohn.Forte@Sun.COM 
37027836SJohn.Forte@Sun.COM 	if (pd_next) {
37037836SJohn.Forte@Sun.COM 		/*
37047836SJohn.Forte@Sun.COM 		 * Found the given fc_remote_port_t; now remove it from the
37057836SJohn.Forte@Sun.COM 		 * d_id list.
37067836SJohn.Forte@Sun.COM 		 */
37077836SJohn.Forte@Sun.COM 		head->d_id_count--;
37087836SJohn.Forte@Sun.COM 		if (last == NULL) {
37097836SJohn.Forte@Sun.COM 			head->d_id_head = pd->pd_did_hnext;
37107836SJohn.Forte@Sun.COM 		} else {
37117836SJohn.Forte@Sun.COM 			last->pd_did_hnext = pd->pd_did_hnext;
37127836SJohn.Forte@Sun.COM 		}
37137836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
37147836SJohn.Forte@Sun.COM 		pd->pd_did_hnext = NULL;
37157836SJohn.Forte@Sun.COM 	}
37167836SJohn.Forte@Sun.COM }
37177836SJohn.Forte@Sun.COM 
37187836SJohn.Forte@Sun.COM 
37197836SJohn.Forte@Sun.COM /*
37207836SJohn.Forte@Sun.COM  * Add the given fc_remote_port_t struct to the pwwn table in the given
37217836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
37227836SJohn.Forte@Sun.COM  * in the fc_remote_port_t.
37237836SJohn.Forte@Sun.COM  *
37247836SJohn.Forte@Sun.COM  * No memory allocs are required, so this never fails.
37257836SJohn.Forte@Sun.COM  */
37267836SJohn.Forte@Sun.COM void
fctl_enlist_pwwn_table(fc_local_port_t * port,fc_remote_port_t * pd)37277836SJohn.Forte@Sun.COM fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
37287836SJohn.Forte@Sun.COM {
37297836SJohn.Forte@Sun.COM 	int index;
37307836SJohn.Forte@Sun.COM 	struct pwwn_hash *head;
37317836SJohn.Forte@Sun.COM 
37327836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
37337836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
37347836SJohn.Forte@Sun.COM 
37357836SJohn.Forte@Sun.COM 	ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE);
37367836SJohn.Forte@Sun.COM 
37377836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn),
37387836SJohn.Forte@Sun.COM 	    pwwn_table_size);
37397836SJohn.Forte@Sun.COM 
37407836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
37417836SJohn.Forte@Sun.COM 
37427836SJohn.Forte@Sun.COM #ifdef	DEBUG
37437836SJohn.Forte@Sun.COM 	{
37447836SJohn.Forte@Sun.COM 		int			index;
374510264SZhong.Wang@Sun.COM 		fc_remote_port_t	*tmp_pd;
37467836SJohn.Forte@Sun.COM 		struct pwwn_hash	*tmp_head;
37477836SJohn.Forte@Sun.COM 
37487836SJohn.Forte@Sun.COM 		/*
37497836SJohn.Forte@Sun.COM 		 * Search down in each bucket for a duplicate pd
37507836SJohn.Forte@Sun.COM 		 * Search also for a duplicate WWN
37517836SJohn.Forte@Sun.COM 		 * Throw an ASSERT if any duplicate is found.
37527836SJohn.Forte@Sun.COM 		 */
37537836SJohn.Forte@Sun.COM 		for (index = 0; index < pwwn_table_size; index++) {
37547836SJohn.Forte@Sun.COM 			tmp_head = &port->fp_pwwn_table[index];
37557836SJohn.Forte@Sun.COM 
37567836SJohn.Forte@Sun.COM 			tmp_pd = tmp_head->pwwn_head;
37577836SJohn.Forte@Sun.COM 			while (tmp_pd != NULL) {
37587836SJohn.Forte@Sun.COM 				ASSERT(tmp_pd != pd);
37597836SJohn.Forte@Sun.COM 
37607836SJohn.Forte@Sun.COM 				if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
37617836SJohn.Forte@Sun.COM 				    tmp_pd->pd_type != PORT_DEVICE_OLD) {
37627836SJohn.Forte@Sun.COM 					ASSERT(fctl_wwn_cmp(
37637836SJohn.Forte@Sun.COM 					    &tmp_pd->pd_port_name,
37647836SJohn.Forte@Sun.COM 					    &pd->pd_port_name) != 0);
37657836SJohn.Forte@Sun.COM 				}
37667836SJohn.Forte@Sun.COM 
37677836SJohn.Forte@Sun.COM 				tmp_pd = tmp_pd->pd_wwn_hnext;
37687836SJohn.Forte@Sun.COM 			}
37697836SJohn.Forte@Sun.COM 		}
37707836SJohn.Forte@Sun.COM 	}
37717836SJohn.Forte@Sun.COM 
37727836SJohn.Forte@Sun.COM 	bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack));
37737836SJohn.Forte@Sun.COM 	pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH);
37747836SJohn.Forte@Sun.COM #endif /* DEBUG */
37757836SJohn.Forte@Sun.COM 
37767836SJohn.Forte@Sun.COM 	pd->pd_wwn_hnext = head->pwwn_head;
37777836SJohn.Forte@Sun.COM 	head->pwwn_head = pd;
37787836SJohn.Forte@Sun.COM 
37797836SJohn.Forte@Sun.COM 	head->pwwn_count++;
37807836SJohn.Forte@Sun.COM 	/*
37817836SJohn.Forte@Sun.COM 	 * Make sure we tie fp_dev_count to the size of the
37827836SJohn.Forte@Sun.COM 	 * pwwn_table
37837836SJohn.Forte@Sun.COM 	 */
37847836SJohn.Forte@Sun.COM 	port->fp_dev_count++;
37857836SJohn.Forte@Sun.COM }
37867836SJohn.Forte@Sun.COM 
37877836SJohn.Forte@Sun.COM 
37887836SJohn.Forte@Sun.COM /*
37897836SJohn.Forte@Sun.COM  * Remove the given fc_remote_port_t struct from the pwwn table in the given
37907836SJohn.Forte@Sun.COM  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
37917836SJohn.Forte@Sun.COM  * in the fc_remote_port_t.
37927836SJohn.Forte@Sun.COM  *
37937836SJohn.Forte@Sun.COM  * Does nothing if the requested fc_remote_port_t was not found.
37947836SJohn.Forte@Sun.COM  */
37957836SJohn.Forte@Sun.COM void
fctl_delist_pwwn_table(fc_local_port_t * port,fc_remote_port_t * pd)37967836SJohn.Forte@Sun.COM fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
37977836SJohn.Forte@Sun.COM {
37987836SJohn.Forte@Sun.COM 	int			index;
37997836SJohn.Forte@Sun.COM 	la_wwn_t		pwwn;
380010264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
380110264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd_next;
380210264SZhong.Wang@Sun.COM 	fc_remote_port_t	*last;
38037836SJohn.Forte@Sun.COM 
38047836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
38057836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
38067836SJohn.Forte@Sun.COM 
38077836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
38087836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size);
38097836SJohn.Forte@Sun.COM 
38107836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
38117836SJohn.Forte@Sun.COM 
38127836SJohn.Forte@Sun.COM 	last = NULL;
38137836SJohn.Forte@Sun.COM 	pd_next = head->pwwn_head;
38147836SJohn.Forte@Sun.COM 	while (pd_next != NULL) {
38157836SJohn.Forte@Sun.COM 		if (pd_next == pd) {
38167836SJohn.Forte@Sun.COM 			break;	/* Found the given fc_remote_port_t */
38177836SJohn.Forte@Sun.COM 		}
38187836SJohn.Forte@Sun.COM 		last = pd_next;
38197836SJohn.Forte@Sun.COM 		pd_next = pd_next->pd_wwn_hnext;
38207836SJohn.Forte@Sun.COM 	}
38217836SJohn.Forte@Sun.COM 
38227836SJohn.Forte@Sun.COM 	if (pd_next) {
38237836SJohn.Forte@Sun.COM 		/*
38247836SJohn.Forte@Sun.COM 		 * Found the given fc_remote_port_t; now remove it from the
38257836SJohn.Forte@Sun.COM 		 * pwwn list.
38267836SJohn.Forte@Sun.COM 		 */
38277836SJohn.Forte@Sun.COM 		head->pwwn_count--;
38287836SJohn.Forte@Sun.COM 		/*
38297836SJohn.Forte@Sun.COM 		 * Make sure we tie fp_dev_count to the size of the
38307836SJohn.Forte@Sun.COM 		 * pwwn_table
38317836SJohn.Forte@Sun.COM 		 */
38327836SJohn.Forte@Sun.COM 		port->fp_dev_count--;
38337836SJohn.Forte@Sun.COM 		if (last == NULL) {
38347836SJohn.Forte@Sun.COM 			head->pwwn_head = pd->pd_wwn_hnext;
38357836SJohn.Forte@Sun.COM 		} else {
38367836SJohn.Forte@Sun.COM 			last->pd_wwn_hnext = pd->pd_wwn_hnext;
38377836SJohn.Forte@Sun.COM 		}
38387836SJohn.Forte@Sun.COM 		pd->pd_wwn_hnext = NULL;
38397836SJohn.Forte@Sun.COM 	}
38407836SJohn.Forte@Sun.COM }
38417836SJohn.Forte@Sun.COM 
38427836SJohn.Forte@Sun.COM 
38437836SJohn.Forte@Sun.COM /*
38447836SJohn.Forte@Sun.COM  * Looks in the d_id table of the specified fc_local_port_t for the
38457836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon
38467836SJohn.Forte@Sun.COM  * the given d_id.
38477836SJohn.Forte@Sun.COM  * Returns a pointer to the fc_remote_port_t struct, but does not update any
38487836SJohn.Forte@Sun.COM  * reference counts or otherwise indicate that the fc_remote_port_t is in
38497836SJohn.Forte@Sun.COM  * use.
38507836SJohn.Forte@Sun.COM  */
38517836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_get_remote_port_by_did(fc_local_port_t * port,uint32_t d_id)38527836SJohn.Forte@Sun.COM fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
38537836SJohn.Forte@Sun.COM {
385410264SZhong.Wang@Sun.COM 	struct d_id_hash	*head;
385510264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
38567836SJohn.Forte@Sun.COM 
38577836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
38587836SJohn.Forte@Sun.COM 
38597836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
38607836SJohn.Forte@Sun.COM 
38617836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
38627836SJohn.Forte@Sun.COM 
38637836SJohn.Forte@Sun.COM 	pd = head->d_id_head;
38647836SJohn.Forte@Sun.COM 	while (pd != NULL) {
38657836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
38667836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id == d_id) {
38677836SJohn.Forte@Sun.COM 			/* Match found -- break out of the loop */
38687836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
38697836SJohn.Forte@Sun.COM 			break;
38707836SJohn.Forte@Sun.COM 		}
38717836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
38727836SJohn.Forte@Sun.COM 		pd = pd->pd_did_hnext;
38737836SJohn.Forte@Sun.COM 	}
38747836SJohn.Forte@Sun.COM 
38757836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
38767836SJohn.Forte@Sun.COM 
38777836SJohn.Forte@Sun.COM 	return (pd);
38787836SJohn.Forte@Sun.COM }
38797836SJohn.Forte@Sun.COM 
38807836SJohn.Forte@Sun.COM 
38817836SJohn.Forte@Sun.COM #ifndef	__lock_lint		/* uncomment when there is a consumer */
38827836SJohn.Forte@Sun.COM 
38837836SJohn.Forte@Sun.COM void
fc_ulp_hold_remote_port(opaque_t port_handle)38847836SJohn.Forte@Sun.COM fc_ulp_hold_remote_port(opaque_t port_handle)
38857836SJohn.Forte@Sun.COM {
38867836SJohn.Forte@Sun.COM 	fc_remote_port_t *pd = port_handle;
38877836SJohn.Forte@Sun.COM 
38887836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
38897836SJohn.Forte@Sun.COM 	pd->pd_ref_count++;
38907836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
38917836SJohn.Forte@Sun.COM }
38927836SJohn.Forte@Sun.COM 
38937836SJohn.Forte@Sun.COM /*
38947836SJohn.Forte@Sun.COM  * Looks in the d_id table of the specified fc_local_port_t for the
38957836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon
38967836SJohn.Forte@Sun.COM  * the given d_id. Returns a pointer to the fc_remote_port_t struct.
38977836SJohn.Forte@Sun.COM  *
38987836SJohn.Forte@Sun.COM  * Increments pd_ref_count in the fc_remote_port_t if the
38997836SJohn.Forte@Sun.COM  * fc_remote_port_t is found at the given d_id.
39007836SJohn.Forte@Sun.COM  *
39017836SJohn.Forte@Sun.COM  * The fc_remote_port_t is ignored (treated as non-existent) if either
39027836SJohn.Forte@Sun.COM  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
39037836SJohn.Forte@Sun.COM  */
39047836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_hold_remote_port_by_did(fc_local_port_t * port,uint32_t d_id)39057836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
39067836SJohn.Forte@Sun.COM {
390710264SZhong.Wang@Sun.COM 	struct d_id_hash	*head;
390810264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
39097836SJohn.Forte@Sun.COM 
39107836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
39117836SJohn.Forte@Sun.COM 
39127836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
39137836SJohn.Forte@Sun.COM 
39147836SJohn.Forte@Sun.COM 	head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
39157836SJohn.Forte@Sun.COM 
39167836SJohn.Forte@Sun.COM 	pd = head->d_id_head;
39177836SJohn.Forte@Sun.COM 	while (pd != NULL) {
39187836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
39197836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
39207836SJohn.Forte@Sun.COM 		    PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
39217836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
39227836SJohn.Forte@Sun.COM 			pd->pd_ref_count++;
39237836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
39247836SJohn.Forte@Sun.COM 			break;
39257836SJohn.Forte@Sun.COM 		}
39267836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
39277836SJohn.Forte@Sun.COM 		pd = pd->pd_did_hnext;
39287836SJohn.Forte@Sun.COM 	}
39297836SJohn.Forte@Sun.COM 
39307836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
39317836SJohn.Forte@Sun.COM 
39327836SJohn.Forte@Sun.COM 	return (pd);
39337836SJohn.Forte@Sun.COM }
39347836SJohn.Forte@Sun.COM 
39357836SJohn.Forte@Sun.COM #endif /* __lock_lint */
39367836SJohn.Forte@Sun.COM 
39377836SJohn.Forte@Sun.COM /*
39387836SJohn.Forte@Sun.COM  * Looks in the pwwn table of the specified fc_local_port_t for the
39397836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given pwwn.  Hashes based upon the
39407836SJohn.Forte@Sun.COM  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
39417836SJohn.Forte@Sun.COM  * but does not update any reference counts or otherwise indicate that
39427836SJohn.Forte@Sun.COM  * the fc_remote_port_t is in use.
39437836SJohn.Forte@Sun.COM  */
39447836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_get_remote_port_by_pwwn(fc_local_port_t * port,la_wwn_t * pwwn)39457836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
39467836SJohn.Forte@Sun.COM {
39477836SJohn.Forte@Sun.COM 	int			index;
394810264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
394910264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
39507836SJohn.Forte@Sun.COM 
39517836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
39527836SJohn.Forte@Sun.COM 
39537836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
39547836SJohn.Forte@Sun.COM 
39557836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
39567836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
39577836SJohn.Forte@Sun.COM 
39587836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
39597836SJohn.Forte@Sun.COM 	while (pd != NULL) {
39607836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
39617836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
39627836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
39637836SJohn.Forte@Sun.COM 			break;
39647836SJohn.Forte@Sun.COM 		}
39657836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
39667836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
39677836SJohn.Forte@Sun.COM 	}
39687836SJohn.Forte@Sun.COM 
39697836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
39707836SJohn.Forte@Sun.COM 
39717836SJohn.Forte@Sun.COM 	return (pd);
39727836SJohn.Forte@Sun.COM }
39737836SJohn.Forte@Sun.COM 
39747836SJohn.Forte@Sun.COM 
39757836SJohn.Forte@Sun.COM /*
39767836SJohn.Forte@Sun.COM  * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
39777836SJohn.Forte@Sun.COM  * the caller already hold the fp_mutex in the fc_local_port_t struct.
39787836SJohn.Forte@Sun.COM  */
39797836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t * port,la_wwn_t * pwwn)39807836SJohn.Forte@Sun.COM fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
39817836SJohn.Forte@Sun.COM {
39827836SJohn.Forte@Sun.COM 	int			index;
398310264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
398410264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
39857836SJohn.Forte@Sun.COM 
39867836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
39877836SJohn.Forte@Sun.COM 
39887836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
39897836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
39907836SJohn.Forte@Sun.COM 
39917836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
39927836SJohn.Forte@Sun.COM 	while (pd != NULL) {
39937836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
39947836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
39957836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
39967836SJohn.Forte@Sun.COM 			break;
39977836SJohn.Forte@Sun.COM 		}
39987836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
39997836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
40007836SJohn.Forte@Sun.COM 	}
40017836SJohn.Forte@Sun.COM 
40027836SJohn.Forte@Sun.COM 	return (pd);
40037836SJohn.Forte@Sun.COM }
40047836SJohn.Forte@Sun.COM 
40057836SJohn.Forte@Sun.COM 
40067836SJohn.Forte@Sun.COM /*
40077836SJohn.Forte@Sun.COM  * Looks in the pwwn table of the specified fc_local_port_t for the
40087836SJohn.Forte@Sun.COM  * fc_remote_port_t that matches the given d_id.  Hashes based upon the
40097836SJohn.Forte@Sun.COM  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
40107836SJohn.Forte@Sun.COM  *
40117836SJohn.Forte@Sun.COM  * Increments pd_ref_count in the fc_remote_port_t if the
40127836SJohn.Forte@Sun.COM  * fc_remote_port_t is found at the given pwwn.
40137836SJohn.Forte@Sun.COM  *
40147836SJohn.Forte@Sun.COM  * The fc_remote_port_t is ignored (treated as non-existent) if either
40157836SJohn.Forte@Sun.COM  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
40167836SJohn.Forte@Sun.COM  */
40177836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_hold_remote_port_by_pwwn(fc_local_port_t * port,la_wwn_t * pwwn)40187836SJohn.Forte@Sun.COM fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
40197836SJohn.Forte@Sun.COM {
40207836SJohn.Forte@Sun.COM 	int			index;
402110264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
402210264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
40237836SJohn.Forte@Sun.COM 
40247836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
40257836SJohn.Forte@Sun.COM 
40267836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
40277836SJohn.Forte@Sun.COM 
40287836SJohn.Forte@Sun.COM 	index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
40297836SJohn.Forte@Sun.COM 	head = &port->fp_pwwn_table[index];
40307836SJohn.Forte@Sun.COM 
40317836SJohn.Forte@Sun.COM 	pd = head->pwwn_head;
40327836SJohn.Forte@Sun.COM 	while (pd != NULL) {
40337836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
40347836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 &&
40357836SJohn.Forte@Sun.COM 		    pd->pd_state != PORT_DEVICE_INVALID &&
40367836SJohn.Forte@Sun.COM 		    pd->pd_type != PORT_DEVICE_OLD) {
40377836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_ref_count >= 0);
40387836SJohn.Forte@Sun.COM 			pd->pd_ref_count++;
40397836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
40407836SJohn.Forte@Sun.COM 			break;
40417836SJohn.Forte@Sun.COM 		}
40427836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
40437836SJohn.Forte@Sun.COM 		pd = pd->pd_wwn_hnext;
40447836SJohn.Forte@Sun.COM 	}
40457836SJohn.Forte@Sun.COM 
40467836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
40477836SJohn.Forte@Sun.COM 
40487836SJohn.Forte@Sun.COM 	return (pd);
40497836SJohn.Forte@Sun.COM }
40507836SJohn.Forte@Sun.COM 
40517836SJohn.Forte@Sun.COM 
40527836SJohn.Forte@Sun.COM /*
40537836SJohn.Forte@Sun.COM  * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
40547836SJohn.Forte@Sun.COM  * struct.
40557836SJohn.Forte@Sun.COM  *
40567836SJohn.Forte@Sun.COM  * If pd_ref_count reaches zero, then this function will see if the
40577836SJohn.Forte@Sun.COM  * fc_remote_port_t has been marked for deallocation. If so (and also if there
40587836SJohn.Forte@Sun.COM  * are no other potential operations in progress, as indicated by the
40597836SJohn.Forte@Sun.COM  * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
40607836SJohn.Forte@Sun.COM  * fctl_destroy_remote_port_t() is called to deconstruct/free the given
40617836SJohn.Forte@Sun.COM  * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
406210264SZhong.Wang@Sun.COM  * on the associated fc_local_port_t).	If the associated fc_remote_node_t is no
40637836SJohn.Forte@Sun.COM  * longer in use, then it too is deconstructed/freed.
40647836SJohn.Forte@Sun.COM  */
40657836SJohn.Forte@Sun.COM void
fctl_release_remote_port(fc_remote_port_t * pd)40667836SJohn.Forte@Sun.COM fctl_release_remote_port(fc_remote_port_t *pd)
40677836SJohn.Forte@Sun.COM {
40687836SJohn.Forte@Sun.COM 	int			remove = 0;
406910264SZhong.Wang@Sun.COM 	fc_remote_node_t	*node;
407010264SZhong.Wang@Sun.COM 	fc_local_port_t		*port;
40717836SJohn.Forte@Sun.COM 
40727836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
40737836SJohn.Forte@Sun.COM 	port = pd->pd_port;
40747836SJohn.Forte@Sun.COM 
40757836SJohn.Forte@Sun.COM 	ASSERT(pd->pd_ref_count > 0);
40767836SJohn.Forte@Sun.COM 	pd->pd_ref_count--;
40777836SJohn.Forte@Sun.COM 	if (pd->pd_ref_count == 0 &&
40787836SJohn.Forte@Sun.COM 	    (pd->pd_aux_flags & PD_NEEDS_REMOVAL) &&
40797836SJohn.Forte@Sun.COM 	    (pd->pd_flags != PD_ELS_IN_PROGRESS) &&
40807836SJohn.Forte@Sun.COM 	    (pd->pd_flags != PD_ELS_MARK)) {
40817836SJohn.Forte@Sun.COM 		remove = 1;
40827836SJohn.Forte@Sun.COM 		pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL;
40837836SJohn.Forte@Sun.COM 	}
40847836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
40857836SJohn.Forte@Sun.COM 	ASSERT(node != NULL);
40867836SJohn.Forte@Sun.COM 
40877836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
40887836SJohn.Forte@Sun.COM 
40897836SJohn.Forte@Sun.COM 	if (remove) {
40907836SJohn.Forte@Sun.COM 		/*
40917836SJohn.Forte@Sun.COM 		 * The fc_remote_port_t struct has to go away now, so call the
40927836SJohn.Forte@Sun.COM 		 * cleanup function to get it off the various lists and remove
40937836SJohn.Forte@Sun.COM 		 * references to it in any other associated structs.
40947836SJohn.Forte@Sun.COM 		 */
40957836SJohn.Forte@Sun.COM 		if (fctl_destroy_remote_port(port, pd) == 0) {
40967836SJohn.Forte@Sun.COM 			/*
40977836SJohn.Forte@Sun.COM 			 * No more fc_remote_port_t references found in the
40987836SJohn.Forte@Sun.COM 			 * associated fc_remote_node_t, so deallocate the
40997836SJohn.Forte@Sun.COM 			 * fc_remote_node_t (if it even exists).
41007836SJohn.Forte@Sun.COM 			 */
41017836SJohn.Forte@Sun.COM 			if (node) {
41027836SJohn.Forte@Sun.COM 				fctl_destroy_remote_node(node);
41037836SJohn.Forte@Sun.COM 			}
41047836SJohn.Forte@Sun.COM 		}
41057836SJohn.Forte@Sun.COM 	}
41067836SJohn.Forte@Sun.COM }
41077836SJohn.Forte@Sun.COM 
41087836SJohn.Forte@Sun.COM 
41097836SJohn.Forte@Sun.COM void
fctl_fillout_map(fc_local_port_t * port,fc_portmap_t ** map,uint32_t * len,int whole_map,int justcopy,int orphan)41107836SJohn.Forte@Sun.COM fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
41117836SJohn.Forte@Sun.COM     int whole_map, int justcopy, int orphan)
41127836SJohn.Forte@Sun.COM {
41137836SJohn.Forte@Sun.COM 	int			index;
41147836SJohn.Forte@Sun.COM 	int			listlen;
41157836SJohn.Forte@Sun.COM 	int			full_list;
41167836SJohn.Forte@Sun.COM 	int			initiator;
41177836SJohn.Forte@Sun.COM 	uint32_t		topology;
411810264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
411910264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
412010264SZhong.Wang@Sun.COM 	fc_remote_port_t	*old_pd;
41217836SJohn.Forte@Sun.COM 	fc_remote_port_t	*last_pd;
41227836SJohn.Forte@Sun.COM 	fc_portmap_t		*listptr;
41237836SJohn.Forte@Sun.COM 
41247836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
41257836SJohn.Forte@Sun.COM 
41267836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
41277836SJohn.Forte@Sun.COM 
41287836SJohn.Forte@Sun.COM 	topology = port->fp_topology;
41297836SJohn.Forte@Sun.COM 
41307836SJohn.Forte@Sun.COM 	if (orphan) {
41317836SJohn.Forte@Sun.COM 		ASSERT(!FC_IS_TOP_SWITCH(topology));
41327836SJohn.Forte@Sun.COM 	}
41337836SJohn.Forte@Sun.COM 
41347836SJohn.Forte@Sun.COM 	for (full_list = listlen = index = 0;
41357836SJohn.Forte@Sun.COM 	    index < pwwn_table_size; index++) {
41367836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
41377836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
41387836SJohn.Forte@Sun.COM 		while (pd != NULL) {
41397836SJohn.Forte@Sun.COM 			full_list++;
41407836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
41417836SJohn.Forte@Sun.COM 			if (pd->pd_type != PORT_DEVICE_NOCHANGE) {
41427836SJohn.Forte@Sun.COM 				listlen++;
41437836SJohn.Forte@Sun.COM 			}
41447836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
41457836SJohn.Forte@Sun.COM 			pd = pd->pd_wwn_hnext;
41467836SJohn.Forte@Sun.COM 		}
41477836SJohn.Forte@Sun.COM 	}
41487836SJohn.Forte@Sun.COM 
41497836SJohn.Forte@Sun.COM 	if (whole_map == 0) {
41507836SJohn.Forte@Sun.COM 		if (listlen == 0 && *len == 0) {
41517836SJohn.Forte@Sun.COM 			*map = NULL;
41527836SJohn.Forte@Sun.COM 			*len = listlen;
41537836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
41547836SJohn.Forte@Sun.COM 			return;
41557836SJohn.Forte@Sun.COM 		}
41567836SJohn.Forte@Sun.COM 	} else {
41577836SJohn.Forte@Sun.COM 		if (full_list == 0 && *len == 0) {
41587836SJohn.Forte@Sun.COM 			*map = NULL;
41597836SJohn.Forte@Sun.COM 			*len = full_list;
41607836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
41617836SJohn.Forte@Sun.COM 			return;
41627836SJohn.Forte@Sun.COM 		}
41637836SJohn.Forte@Sun.COM 	}
41647836SJohn.Forte@Sun.COM 
41657836SJohn.Forte@Sun.COM 	if (*len == 0) {
41667836SJohn.Forte@Sun.COM 		ASSERT(*map == NULL);
41677836SJohn.Forte@Sun.COM 		if (whole_map == 0) {
41687836SJohn.Forte@Sun.COM 			listptr = *map = kmem_zalloc(
41697836SJohn.Forte@Sun.COM 			    sizeof (*listptr) * listlen, KM_SLEEP);
41707836SJohn.Forte@Sun.COM 			*len = listlen;
41717836SJohn.Forte@Sun.COM 		} else {
41727836SJohn.Forte@Sun.COM 			listptr = *map = kmem_zalloc(
41737836SJohn.Forte@Sun.COM 			    sizeof (*listptr) * full_list, KM_SLEEP);
41747836SJohn.Forte@Sun.COM 			*len = full_list;
41757836SJohn.Forte@Sun.COM 		}
41767836SJohn.Forte@Sun.COM 	} else {
41777836SJohn.Forte@Sun.COM 		/*
41787836SJohn.Forte@Sun.COM 		 * By design this routine mandates the callers to
41797836SJohn.Forte@Sun.COM 		 * ask for a whole map when they specify the length
41807836SJohn.Forte@Sun.COM 		 * and the listptr.
41817836SJohn.Forte@Sun.COM 		 */
41827836SJohn.Forte@Sun.COM 		ASSERT(whole_map == 1);
41837836SJohn.Forte@Sun.COM 		if (*len < full_list) {
41847836SJohn.Forte@Sun.COM 			*len = full_list;
41857836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
41867836SJohn.Forte@Sun.COM 			return;
41877836SJohn.Forte@Sun.COM 		}
41887836SJohn.Forte@Sun.COM 		listptr = *map;
41897836SJohn.Forte@Sun.COM 		*len = full_list;
41907836SJohn.Forte@Sun.COM 	}
41917836SJohn.Forte@Sun.COM 
41927836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
41937836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
41947836SJohn.Forte@Sun.COM 		last_pd = NULL;
41957836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
41967836SJohn.Forte@Sun.COM 		while (pd != NULL) {
41977836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
41987836SJohn.Forte@Sun.COM 			if ((whole_map == 0 &&
41997836SJohn.Forte@Sun.COM 			    pd->pd_type == PORT_DEVICE_NOCHANGE) ||
42007836SJohn.Forte@Sun.COM 			    pd->pd_state == PORT_DEVICE_INVALID) {
42017836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
42027836SJohn.Forte@Sun.COM 				last_pd = pd;
42037836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
42047836SJohn.Forte@Sun.COM 				continue;
42057836SJohn.Forte@Sun.COM 			}
42067836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
42077836SJohn.Forte@Sun.COM 
42087836SJohn.Forte@Sun.COM 			fctl_copy_portmap(listptr, pd);
42097836SJohn.Forte@Sun.COM 
42107836SJohn.Forte@Sun.COM 			if (justcopy) {
42117836SJohn.Forte@Sun.COM 				last_pd = pd;
42127836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
42137836SJohn.Forte@Sun.COM 				listptr++;
42147836SJohn.Forte@Sun.COM 				continue;
42157836SJohn.Forte@Sun.COM 			}
42167836SJohn.Forte@Sun.COM 
42177836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
42187836SJohn.Forte@Sun.COM 			ASSERT(pd->pd_state != PORT_DEVICE_INVALID);
42197836SJohn.Forte@Sun.COM 			if (pd->pd_type == PORT_DEVICE_OLD) {
42207836SJohn.Forte@Sun.COM 				listptr->map_pd = pd;
42217836SJohn.Forte@Sun.COM 				listptr->map_state = pd->pd_state =
42227836SJohn.Forte@Sun.COM 				    PORT_DEVICE_INVALID;
42237836SJohn.Forte@Sun.COM 				/*
42247836SJohn.Forte@Sun.COM 				 * Remove this from the PWWN hash table.
42257836SJohn.Forte@Sun.COM 				 */
42267836SJohn.Forte@Sun.COM 				old_pd = pd;
42277836SJohn.Forte@Sun.COM 				pd = old_pd->pd_wwn_hnext;
42287836SJohn.Forte@Sun.COM 
42297836SJohn.Forte@Sun.COM 				if (last_pd == NULL) {
42307836SJohn.Forte@Sun.COM 					ASSERT(old_pd == head->pwwn_head);
42317836SJohn.Forte@Sun.COM 
42327836SJohn.Forte@Sun.COM 					head->pwwn_head = pd;
42337836SJohn.Forte@Sun.COM 				} else {
42347836SJohn.Forte@Sun.COM 					last_pd->pd_wwn_hnext = pd;
42357836SJohn.Forte@Sun.COM 				}
42367836SJohn.Forte@Sun.COM 				head->pwwn_count--;
42377836SJohn.Forte@Sun.COM 				/*
42387836SJohn.Forte@Sun.COM 				 * Make sure we tie fp_dev_count to the size
42397836SJohn.Forte@Sun.COM 				 * of the pwwn_table
42407836SJohn.Forte@Sun.COM 				 */
42417836SJohn.Forte@Sun.COM 				port->fp_dev_count--;
42427836SJohn.Forte@Sun.COM 				old_pd->pd_wwn_hnext = NULL;
42437836SJohn.Forte@Sun.COM 
42447836SJohn.Forte@Sun.COM 				if (port->fp_topology == FC_TOP_PRIVATE_LOOP &&
42457836SJohn.Forte@Sun.COM 				    port->fp_statec_busy && !orphan) {
42467836SJohn.Forte@Sun.COM 					fctl_check_alpa_list(port, old_pd);
42477836SJohn.Forte@Sun.COM 				}
42487836SJohn.Forte@Sun.COM 
42497836SJohn.Forte@Sun.COM 				/*
42507836SJohn.Forte@Sun.COM 				 * Remove if the port device has stealthily
42517836SJohn.Forte@Sun.COM 				 * present in the D_ID hash table
42527836SJohn.Forte@Sun.COM 				 */
42537836SJohn.Forte@Sun.COM 				fctl_delist_did_table(port, old_pd);
42547836SJohn.Forte@Sun.COM 
42557836SJohn.Forte@Sun.COM 				ASSERT(old_pd->pd_remote_nodep != NULL);
42567836SJohn.Forte@Sun.COM 
42577836SJohn.Forte@Sun.COM 				initiator = (old_pd->pd_recepient ==
42587836SJohn.Forte@Sun.COM 				    PD_PLOGI_INITIATOR) ? 1 : 0;
42597836SJohn.Forte@Sun.COM 
42607836SJohn.Forte@Sun.COM 				mutex_exit(&old_pd->pd_mutex);
42617836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
42627836SJohn.Forte@Sun.COM 
42637836SJohn.Forte@Sun.COM 				if (orphan) {
42647836SJohn.Forte@Sun.COM 					fctl_print_if_not_orphan(port, old_pd);
42657836SJohn.Forte@Sun.COM 
42667836SJohn.Forte@Sun.COM 					(void) fctl_add_orphan(port, old_pd,
42677836SJohn.Forte@Sun.COM 					    KM_NOSLEEP);
42687836SJohn.Forte@Sun.COM 				}
42697836SJohn.Forte@Sun.COM 
42707836SJohn.Forte@Sun.COM 				if (FC_IS_TOP_SWITCH(topology) && initiator) {
42717836SJohn.Forte@Sun.COM 					(void) fctl_add_orphan(port, old_pd,
42727836SJohn.Forte@Sun.COM 					    KM_NOSLEEP);
42737836SJohn.Forte@Sun.COM 				}
42747836SJohn.Forte@Sun.COM 				mutex_enter(&port->fp_mutex);
42757836SJohn.Forte@Sun.COM 			} else {
42767836SJohn.Forte@Sun.COM 				listptr->map_pd = pd;
42777836SJohn.Forte@Sun.COM 				pd->pd_type = PORT_DEVICE_NOCHANGE;
42787836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
42797836SJohn.Forte@Sun.COM 				last_pd = pd;
42807836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
42817836SJohn.Forte@Sun.COM 			}
42827836SJohn.Forte@Sun.COM 			listptr++;
42837836SJohn.Forte@Sun.COM 		}
42847836SJohn.Forte@Sun.COM 	}
42857836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
42867836SJohn.Forte@Sun.COM }
42877836SJohn.Forte@Sun.COM 
42887836SJohn.Forte@Sun.COM 
42897836SJohn.Forte@Sun.COM job_request_t *
fctl_alloc_job(int job_code,int job_flags,void (* comp)(opaque_t,uchar_t),opaque_t arg,int sleep)42907836SJohn.Forte@Sun.COM fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
42917836SJohn.Forte@Sun.COM     opaque_t arg, int sleep)
42927836SJohn.Forte@Sun.COM {
42937836SJohn.Forte@Sun.COM 	job_request_t *job;
42947836SJohn.Forte@Sun.COM 
42957836SJohn.Forte@Sun.COM 	job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
42967836SJohn.Forte@Sun.COM 	if (job != NULL) {
42977836SJohn.Forte@Sun.COM 		job->job_result = FC_SUCCESS;
42987836SJohn.Forte@Sun.COM 		job->job_code = job_code;
42997836SJohn.Forte@Sun.COM 		job->job_flags = job_flags;
43007836SJohn.Forte@Sun.COM 		job->job_cb_arg = arg;
43017836SJohn.Forte@Sun.COM 		job->job_comp = comp;
43027836SJohn.Forte@Sun.COM 		job->job_private = NULL;
43037836SJohn.Forte@Sun.COM 		job->job_ulp_pkts = NULL;
43047836SJohn.Forte@Sun.COM 		job->job_ulp_listlen = 0;
43057836SJohn.Forte@Sun.COM #ifndef __lock_lint
43067836SJohn.Forte@Sun.COM 		job->job_counter = 0;
43077836SJohn.Forte@Sun.COM 		job->job_next = NULL;
43087836SJohn.Forte@Sun.COM #endif /* __lock_lint */
43097836SJohn.Forte@Sun.COM 	}
43107836SJohn.Forte@Sun.COM 
43117836SJohn.Forte@Sun.COM 	return (job);
43127836SJohn.Forte@Sun.COM }
43137836SJohn.Forte@Sun.COM 
43147836SJohn.Forte@Sun.COM 
43157836SJohn.Forte@Sun.COM void
fctl_dealloc_job(job_request_t * job)43167836SJohn.Forte@Sun.COM fctl_dealloc_job(job_request_t *job)
43177836SJohn.Forte@Sun.COM {
43187836SJohn.Forte@Sun.COM 	kmem_cache_free(fctl_job_cache, (void *)job);
43197836SJohn.Forte@Sun.COM }
43207836SJohn.Forte@Sun.COM 
43217836SJohn.Forte@Sun.COM 
43227836SJohn.Forte@Sun.COM void
fctl_enque_job(fc_local_port_t * port,job_request_t * job)43237836SJohn.Forte@Sun.COM fctl_enque_job(fc_local_port_t *port, job_request_t *job)
43247836SJohn.Forte@Sun.COM {
43257836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
43267836SJohn.Forte@Sun.COM 
43277836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
43287836SJohn.Forte@Sun.COM 
43297836SJohn.Forte@Sun.COM 	if (port->fp_job_tail == NULL) {
43307836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_head == NULL);
43317836SJohn.Forte@Sun.COM 		port->fp_job_head = port->fp_job_tail = job;
43327836SJohn.Forte@Sun.COM 	} else {
43337836SJohn.Forte@Sun.COM 		port->fp_job_tail->job_next = job;
43347836SJohn.Forte@Sun.COM 		port->fp_job_tail = job;
43357836SJohn.Forte@Sun.COM 	}
43367836SJohn.Forte@Sun.COM 	job->job_next = NULL;
43377836SJohn.Forte@Sun.COM 
43387836SJohn.Forte@Sun.COM 	cv_signal(&port->fp_cv);
43397836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
43407836SJohn.Forte@Sun.COM }
43417836SJohn.Forte@Sun.COM 
43427836SJohn.Forte@Sun.COM 
43437836SJohn.Forte@Sun.COM job_request_t *
fctl_deque_job(fc_local_port_t * port)43447836SJohn.Forte@Sun.COM fctl_deque_job(fc_local_port_t *port)
43457836SJohn.Forte@Sun.COM {
43467836SJohn.Forte@Sun.COM 	job_request_t *job;
43477836SJohn.Forte@Sun.COM 
43487836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
43497836SJohn.Forte@Sun.COM 
43507836SJohn.Forte@Sun.COM 	if (port->fp_job_head == NULL) {
43517836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_tail == NULL);
43527836SJohn.Forte@Sun.COM 		job = NULL;
43537836SJohn.Forte@Sun.COM 	} else {
43547836SJohn.Forte@Sun.COM 		job = port->fp_job_head;
43557836SJohn.Forte@Sun.COM 		if (job->job_next == NULL) {
43567836SJohn.Forte@Sun.COM 			ASSERT(job == port->fp_job_tail);
43577836SJohn.Forte@Sun.COM 			port->fp_job_tail = NULL;
43587836SJohn.Forte@Sun.COM 		}
43597836SJohn.Forte@Sun.COM 		port->fp_job_head = job->job_next;
43607836SJohn.Forte@Sun.COM 	}
43617836SJohn.Forte@Sun.COM 
43627836SJohn.Forte@Sun.COM 	return (job);
43637836SJohn.Forte@Sun.COM }
43647836SJohn.Forte@Sun.COM 
43657836SJohn.Forte@Sun.COM 
43667836SJohn.Forte@Sun.COM void
fctl_priority_enque_job(fc_local_port_t * port,job_request_t * job)43677836SJohn.Forte@Sun.COM fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job)
43687836SJohn.Forte@Sun.COM {
43697836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
43707836SJohn.Forte@Sun.COM 
43717836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
43727836SJohn.Forte@Sun.COM 	if (port->fp_job_tail == NULL) {
43737836SJohn.Forte@Sun.COM 		ASSERT(port->fp_job_head == NULL);
43747836SJohn.Forte@Sun.COM 		port->fp_job_head = port->fp_job_tail = job;
43757836SJohn.Forte@Sun.COM 		job->job_next = NULL;
43767836SJohn.Forte@Sun.COM 	} else {
43777836SJohn.Forte@Sun.COM 		job->job_next = port->fp_job_head;
43787836SJohn.Forte@Sun.COM 		port->fp_job_head = job;
43797836SJohn.Forte@Sun.COM 	}
43807836SJohn.Forte@Sun.COM 	cv_signal(&port->fp_cv);
43817836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
43827836SJohn.Forte@Sun.COM }
43837836SJohn.Forte@Sun.COM 
43847836SJohn.Forte@Sun.COM 
43857836SJohn.Forte@Sun.COM void
fctl_jobwait(job_request_t * job)43867836SJohn.Forte@Sun.COM fctl_jobwait(job_request_t *job)
43877836SJohn.Forte@Sun.COM {
43887836SJohn.Forte@Sun.COM 	ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC));
43897836SJohn.Forte@Sun.COM 	sema_p(&job->job_fctl_sema);
43907836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&job->job_mutex));
43917836SJohn.Forte@Sun.COM }
43927836SJohn.Forte@Sun.COM 
43937836SJohn.Forte@Sun.COM 
43947836SJohn.Forte@Sun.COM void
fctl_jobdone(job_request_t * job)43957836SJohn.Forte@Sun.COM fctl_jobdone(job_request_t *job)
43967836SJohn.Forte@Sun.COM {
43977836SJohn.Forte@Sun.COM 	if (job->job_flags & JOB_TYPE_FCTL_ASYNC) {
43987836SJohn.Forte@Sun.COM 		if (job->job_comp) {
43997836SJohn.Forte@Sun.COM 			job->job_comp(job->job_cb_arg, job->job_result);
44007836SJohn.Forte@Sun.COM 		}
44017836SJohn.Forte@Sun.COM 		fctl_dealloc_job(job);
44027836SJohn.Forte@Sun.COM 	} else {
44037836SJohn.Forte@Sun.COM 		sema_v(&job->job_fctl_sema);
44047836SJohn.Forte@Sun.COM 	}
44057836SJohn.Forte@Sun.COM }
44067836SJohn.Forte@Sun.COM 
44077836SJohn.Forte@Sun.COM 
44087836SJohn.Forte@Sun.COM /*
440910264SZhong.Wang@Sun.COM  * Compare two WWNs.
441010264SZhong.Wang@Sun.COM  * The NAA can't be omitted for comparison.
44117836SJohn.Forte@Sun.COM  *
44127836SJohn.Forte@Sun.COM  * Return Values:
44137836SJohn.Forte@Sun.COM  *   if src == dst return  0
44147836SJohn.Forte@Sun.COM  *   if src > dst  return  1
44157836SJohn.Forte@Sun.COM  *   if src < dst  return -1
44167836SJohn.Forte@Sun.COM  */
44177836SJohn.Forte@Sun.COM int
fctl_wwn_cmp(la_wwn_t * src,la_wwn_t * dst)44187836SJohn.Forte@Sun.COM fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
44197836SJohn.Forte@Sun.COM {
442010264SZhong.Wang@Sun.COM 	uint8_t *l, *r;
442110264SZhong.Wang@Sun.COM 	int i;
442210264SZhong.Wang@Sun.COM 	uint64_t wl, wr;
442310264SZhong.Wang@Sun.COM 
442410264SZhong.Wang@Sun.COM 	l = (uint8_t *)src;
442510264SZhong.Wang@Sun.COM 	r = (uint8_t *)dst;
442610264SZhong.Wang@Sun.COM 
442710264SZhong.Wang@Sun.COM 	for (i = 0, wl = 0; i < 8; i++) {
442810264SZhong.Wang@Sun.COM 		wl <<= 8;
442910264SZhong.Wang@Sun.COM 		wl |= l[i];
443010264SZhong.Wang@Sun.COM 	}
443110264SZhong.Wang@Sun.COM 	for (i = 0, wr = 0; i < 8; i++) {
443210264SZhong.Wang@Sun.COM 		wr <<= 8;
443310264SZhong.Wang@Sun.COM 		wr |= r[i];
443410264SZhong.Wang@Sun.COM 	}
443510264SZhong.Wang@Sun.COM 
443610264SZhong.Wang@Sun.COM 	if (wl > wr) {
443710264SZhong.Wang@Sun.COM 		return (1);
443810264SZhong.Wang@Sun.COM 	} else if (wl == wr) {
443910264SZhong.Wang@Sun.COM 		return (0);
444010264SZhong.Wang@Sun.COM 	} else {
444110264SZhong.Wang@Sun.COM 		return (-1);
444210264SZhong.Wang@Sun.COM 	}
44437836SJohn.Forte@Sun.COM }
44447836SJohn.Forte@Sun.COM 
44457836SJohn.Forte@Sun.COM 
44467836SJohn.Forte@Sun.COM /*
44477836SJohn.Forte@Sun.COM  * ASCII to Integer goodie with support for base 16, 10, 2 and 8
44487836SJohn.Forte@Sun.COM  */
44497836SJohn.Forte@Sun.COM int
fctl_atoi(char * s,int base)44507836SJohn.Forte@Sun.COM fctl_atoi(char *s, int base)
44517836SJohn.Forte@Sun.COM {
44527836SJohn.Forte@Sun.COM 	int val;
44537836SJohn.Forte@Sun.COM 	int ch;
44547836SJohn.Forte@Sun.COM 
44557836SJohn.Forte@Sun.COM 	for (val = 0; *s != '\0'; s++) {
44567836SJohn.Forte@Sun.COM 		switch (base) {
44577836SJohn.Forte@Sun.COM 		case 16:
44587836SJohn.Forte@Sun.COM 			if (*s >= '0' && *s <= '9') {
44597836SJohn.Forte@Sun.COM 				ch = *s - '0';
44607836SJohn.Forte@Sun.COM 			} else if (*s >= 'a' && *s <= 'f') {
44617836SJohn.Forte@Sun.COM 				ch = *s - 'a' + 10;
44627836SJohn.Forte@Sun.COM 			} else if (*s >= 'A' && *s <= 'F') {
44637836SJohn.Forte@Sun.COM 				ch = *s - 'A' + 10;
44647836SJohn.Forte@Sun.COM 			} else {
44657836SJohn.Forte@Sun.COM 				return (-1);
44667836SJohn.Forte@Sun.COM 			}
44677836SJohn.Forte@Sun.COM 			break;
44687836SJohn.Forte@Sun.COM 
44697836SJohn.Forte@Sun.COM 		case 10:
44707836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '9') {
44717836SJohn.Forte@Sun.COM 				return (-1);
44727836SJohn.Forte@Sun.COM 			}
44737836SJohn.Forte@Sun.COM 			ch = *s - '0';
44747836SJohn.Forte@Sun.COM 			break;
44757836SJohn.Forte@Sun.COM 
44767836SJohn.Forte@Sun.COM 		case 2:
44777836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '1') {
44787836SJohn.Forte@Sun.COM 				return (-1);
44797836SJohn.Forte@Sun.COM 			}
44807836SJohn.Forte@Sun.COM 			ch = *s - '0';
44817836SJohn.Forte@Sun.COM 			break;
44827836SJohn.Forte@Sun.COM 
44837836SJohn.Forte@Sun.COM 		case 8:
44847836SJohn.Forte@Sun.COM 			if (*s < '0' || *s > '7') {
44857836SJohn.Forte@Sun.COM 				return (-1);
44867836SJohn.Forte@Sun.COM 			}
44877836SJohn.Forte@Sun.COM 			ch = *s - '0';
44887836SJohn.Forte@Sun.COM 			break;
44897836SJohn.Forte@Sun.COM 
44907836SJohn.Forte@Sun.COM 		default:
44917836SJohn.Forte@Sun.COM 			return (-1);
44927836SJohn.Forte@Sun.COM 		}
44937836SJohn.Forte@Sun.COM 		val = (val * base) + ch;
44947836SJohn.Forte@Sun.COM 	}
44957836SJohn.Forte@Sun.COM 	return (val);
44967836SJohn.Forte@Sun.COM }
44977836SJohn.Forte@Sun.COM 
44987836SJohn.Forte@Sun.COM 
44997836SJohn.Forte@Sun.COM /*
45007836SJohn.Forte@Sun.COM  * Create the fc_remote_port_t struct for the given port_wwn and d_id.
45017836SJohn.Forte@Sun.COM  *
45027836SJohn.Forte@Sun.COM  * If the struct already exists (and is "valid"), then use it. Before using
45037836SJohn.Forte@Sun.COM  * it, the code below also checks: (a) if the d_id has changed, and (b) if
45047836SJohn.Forte@Sun.COM  * the device is maked as PORT_DEVICE_OLD.
45057836SJohn.Forte@Sun.COM  *
45067836SJohn.Forte@Sun.COM  * If no fc_remote_node_t struct exists for the given node_wwn, then that
45077836SJohn.Forte@Sun.COM  * struct is also created (and linked with the fc_remote_port_t).
45087836SJohn.Forte@Sun.COM  *
45097836SJohn.Forte@Sun.COM  * The given fc_local_port_t struct is updated with the info on the new
45107836SJohn.Forte@Sun.COM  * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
45117836SJohn.Forte@Sun.COM  * The global node_hash_table[] is updated (if necessary).
45127836SJohn.Forte@Sun.COM  */
45137836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_create_remote_port(fc_local_port_t * port,la_wwn_t * node_wwn,la_wwn_t * port_wwn,uint32_t d_id,uchar_t recepient,int sleep)45147836SJohn.Forte@Sun.COM fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
45157836SJohn.Forte@Sun.COM     la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep)
45167836SJohn.Forte@Sun.COM {
45177836SJohn.Forte@Sun.COM 	int			invalid = 0;
45187836SJohn.Forte@Sun.COM 	fc_remote_node_t	*rnodep;
451910264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
45207836SJohn.Forte@Sun.COM 
45217836SJohn.Forte@Sun.COM 	rnodep = fctl_get_remote_node_by_nwwn(node_wwn);
45227836SJohn.Forte@Sun.COM 	if (rnodep) {
45237836SJohn.Forte@Sun.COM 		/*
45247836SJohn.Forte@Sun.COM 		 * We found an fc_remote_node_t for the remote node -- see if
45257836SJohn.Forte@Sun.COM 		 * anyone has marked it as going away or gone.
45267836SJohn.Forte@Sun.COM 		 */
45277836SJohn.Forte@Sun.COM 		mutex_enter(&rnodep->fd_mutex);
45287836SJohn.Forte@Sun.COM 		invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0;
45297836SJohn.Forte@Sun.COM 		mutex_exit(&rnodep->fd_mutex);
45307836SJohn.Forte@Sun.COM 	}
45317836SJohn.Forte@Sun.COM 	if (rnodep == NULL || invalid) {
45327836SJohn.Forte@Sun.COM 		/*
45337836SJohn.Forte@Sun.COM 		 * No valid remote node struct found -- create it.
45347836SJohn.Forte@Sun.COM 		 * Note: this is the only place that this func is called.
45357836SJohn.Forte@Sun.COM 		 */
45367836SJohn.Forte@Sun.COM 		rnodep = fctl_create_remote_node(node_wwn, sleep);
45377836SJohn.Forte@Sun.COM 		if (rnodep == NULL) {
45387836SJohn.Forte@Sun.COM 			return (NULL);
45397836SJohn.Forte@Sun.COM 		}
45407836SJohn.Forte@Sun.COM 	}
45417836SJohn.Forte@Sun.COM 
45427836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
45437836SJohn.Forte@Sun.COM 
45447836SJohn.Forte@Sun.COM 	/*
45457836SJohn.Forte@Sun.COM 	 * See if there already is an fc_remote_port_t struct in existence
454610264SZhong.Wang@Sun.COM 	 * on the specified fc_local_port_t for the given pwwn.	 If so, then
45477836SJohn.Forte@Sun.COM 	 * grab a reference to it. The 'held' here just means that fp_mutex
45487836SJohn.Forte@Sun.COM 	 * is held by the caller -- no reference counts are updated.
45497836SJohn.Forte@Sun.COM 	 */
45507836SJohn.Forte@Sun.COM 	pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn);
45517836SJohn.Forte@Sun.COM 	if (pd) {
45527836SJohn.Forte@Sun.COM 		/*
45537836SJohn.Forte@Sun.COM 		 * An fc_remote_port_t struct was found -- see if anyone has
45547836SJohn.Forte@Sun.COM 		 * marked it as "invalid", which means that it is in the
45557836SJohn.Forte@Sun.COM 		 * process of going away & we don't want to use it.
45567836SJohn.Forte@Sun.COM 		 */
45577836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
45587836SJohn.Forte@Sun.COM 		invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0;
45597836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
45607836SJohn.Forte@Sun.COM 	}
45617836SJohn.Forte@Sun.COM 
45627836SJohn.Forte@Sun.COM 	if (pd == NULL || invalid) {
45637836SJohn.Forte@Sun.COM 		/*
45647836SJohn.Forte@Sun.COM 		 * No fc_remote_port_t was found (or the existing one is
45657836SJohn.Forte@Sun.COM 		 * marked as "invalid".) Allocate a new one and use that.
45667836SJohn.Forte@Sun.COM 		 * This call will also update the d_id and pwwn hash tables
45677836SJohn.Forte@Sun.COM 		 * in the given fc_local_port_t struct with the newly allocated
45687836SJohn.Forte@Sun.COM 		 * fc_remote_port_t.
45697836SJohn.Forte@Sun.COM 		 */
45707836SJohn.Forte@Sun.COM 		if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id,
45717836SJohn.Forte@Sun.COM 		    recepient, sleep)) == NULL) {
45727836SJohn.Forte@Sun.COM 			/* Just give up if the allocation fails. */
45737836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
45747836SJohn.Forte@Sun.COM 			fctl_destroy_remote_node(rnodep);
45757836SJohn.Forte@Sun.COM 			return (pd);
45767836SJohn.Forte@Sun.COM 		}
45777836SJohn.Forte@Sun.COM 
45787836SJohn.Forte@Sun.COM 		/*
45797836SJohn.Forte@Sun.COM 		 * Add the new fc_remote_port_t struct to the d_id and pwwn
45807836SJohn.Forte@Sun.COM 		 * hash tables on the associated fc_local_port_t struct.
45817836SJohn.Forte@Sun.COM 		 */
45827836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
45837836SJohn.Forte@Sun.COM 		pd->pd_remote_nodep = rnodep;
45847836SJohn.Forte@Sun.COM 		fctl_enlist_did_table(port, pd);
45857836SJohn.Forte@Sun.COM 		fctl_enlist_pwwn_table(port, pd);
45867836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
45877836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
45887836SJohn.Forte@Sun.COM 
45897836SJohn.Forte@Sun.COM 		/*
45907836SJohn.Forte@Sun.COM 		 * Retrieve a pointer to the fc_remote_node_t (i.e., remote
45917836SJohn.Forte@Sun.COM 		 * node) specified by the given node_wwn.  This looks in the
45927836SJohn.Forte@Sun.COM 		 * global fctl_nwwn_hash_table[]. The fd_numports reference
45937836SJohn.Forte@Sun.COM 		 * count in the fc_remote_node_t struct is incremented.
45947836SJohn.Forte@Sun.COM 		 */
45957836SJohn.Forte@Sun.COM 		rnodep = fctl_lock_remote_node_by_nwwn(node_wwn);
45967836SJohn.Forte@Sun.COM 
45977836SJohn.Forte@Sun.COM 	} else {
45987836SJohn.Forte@Sun.COM 		/*
45997836SJohn.Forte@Sun.COM 		 * An existing and valid fc_remote_port_t struct already
46007836SJohn.Forte@Sun.COM 		 * exists on the fc_local_port_t for the given pwwn.
46017836SJohn.Forte@Sun.COM 		 */
46027836SJohn.Forte@Sun.COM 
46037836SJohn.Forte@Sun.COM 		mutex_enter(&pd->pd_mutex);
46047836SJohn.Forte@Sun.COM 		ASSERT(pd->pd_remote_nodep != NULL);
46057836SJohn.Forte@Sun.COM 
46067836SJohn.Forte@Sun.COM 		if (pd->pd_port_id.port_id != d_id) {
46077836SJohn.Forte@Sun.COM 			/*
46087836SJohn.Forte@Sun.COM 			 * A very unlikely occurance in a well
46097836SJohn.Forte@Sun.COM 			 * behaved environment.
46107836SJohn.Forte@Sun.COM 			 */
46117836SJohn.Forte@Sun.COM 
46127836SJohn.Forte@Sun.COM 			/*
46137836SJohn.Forte@Sun.COM 			 * The existing fc_remote_port_t has a different
46147836SJohn.Forte@Sun.COM 			 * d_id than what we were given. This code will
46157836SJohn.Forte@Sun.COM 			 * update the existing one with the one that was
46167836SJohn.Forte@Sun.COM 			 * just given.
46177836SJohn.Forte@Sun.COM 			 */
46187836SJohn.Forte@Sun.COM 			char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1];
46197836SJohn.Forte@Sun.COM 			uint32_t old_id;
46207836SJohn.Forte@Sun.COM 
46217836SJohn.Forte@Sun.COM 			fc_wwn_to_str(port_wwn, string);
46227836SJohn.Forte@Sun.COM 
46237836SJohn.Forte@Sun.COM 			old_id = pd->pd_port_id.port_id;
46247836SJohn.Forte@Sun.COM 
46257836SJohn.Forte@Sun.COM 			fctl_delist_did_table(port, pd);
46267836SJohn.Forte@Sun.COM 
46277836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device"
46287836SJohn.Forte@Sun.COM 			    " with PWWN %s changed. New D_ID = %x,"
46297836SJohn.Forte@Sun.COM 			    " OLD D_ID = %x", port->fp_instance, string,
46307836SJohn.Forte@Sun.COM 			    d_id, old_id);
46317836SJohn.Forte@Sun.COM 
46327836SJohn.Forte@Sun.COM 			pd->pd_port_id.port_id = d_id;
46337836SJohn.Forte@Sun.COM 
46347836SJohn.Forte@Sun.COM 			/*
46357836SJohn.Forte@Sun.COM 			 * Looks like we have to presume here that the
46367836SJohn.Forte@Sun.COM 			 * remote port could be something entirely different
46377836SJohn.Forte@Sun.COM 			 * from what was previously existing & valid at this
46387836SJohn.Forte@Sun.COM 			 * pwwn.
46397836SJohn.Forte@Sun.COM 			 */
46407836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_CHANGED;
46417836SJohn.Forte@Sun.COM 
46427836SJohn.Forte@Sun.COM 			/* Record (update) the new d_id for the remote port */
46437836SJohn.Forte@Sun.COM 			fctl_enlist_did_table(port, pd);
46447836SJohn.Forte@Sun.COM 
46457836SJohn.Forte@Sun.COM 		} else if (pd->pd_type == PORT_DEVICE_OLD) {
46467836SJohn.Forte@Sun.COM 			/*
46477836SJohn.Forte@Sun.COM 			 * OK at least the old & new d_id's match. So for
46487836SJohn.Forte@Sun.COM 			 * PORT_DEVICE_OLD, this assumes that the remote
46497836SJohn.Forte@Sun.COM 			 * port had disappeared but now has come back.
46507836SJohn.Forte@Sun.COM 			 * Update the pd_type and pd_state to put the
46517836SJohn.Forte@Sun.COM 			 * remote port back into service.
46527836SJohn.Forte@Sun.COM 			 */
46537836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_NOCHANGE;
46547836SJohn.Forte@Sun.COM 			pd->pd_state = PORT_DEVICE_VALID;
46557836SJohn.Forte@Sun.COM 
46567836SJohn.Forte@Sun.COM 			fctl_enlist_did_table(port, pd);
46577836SJohn.Forte@Sun.COM 
46587836SJohn.Forte@Sun.COM 		} else {
46597836SJohn.Forte@Sun.COM 			/*
46607836SJohn.Forte@Sun.COM 			 * OK the old & new d_id's match, and the remote
46617836SJohn.Forte@Sun.COM 			 * port struct is not marked as PORT_DEVICE_OLD, so
46627836SJohn.Forte@Sun.COM 			 * presume that it's still the same device and is
466310264SZhong.Wang@Sun.COM 			 * still in good shape.	 Also this presumes that we
46647836SJohn.Forte@Sun.COM 			 * do not need to update d_id or pwwn hash tables.
46657836SJohn.Forte@Sun.COM 			 */
46667836SJohn.Forte@Sun.COM 			/* sanitize device values */
46677836SJohn.Forte@Sun.COM 			pd->pd_type = PORT_DEVICE_NOCHANGE;
46687836SJohn.Forte@Sun.COM 			pd->pd_state = PORT_DEVICE_VALID;
46697836SJohn.Forte@Sun.COM 		}
46707836SJohn.Forte@Sun.COM 
46717836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
46727836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
46737836SJohn.Forte@Sun.COM 
46747836SJohn.Forte@Sun.COM 		if (rnodep != pd->pd_remote_nodep) {
46757836SJohn.Forte@Sun.COM 			if ((rnodep != NULL) &&
46767836SJohn.Forte@Sun.COM 			    (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name,
46777836SJohn.Forte@Sun.COM 			    node_wwn) != 0)) {
46787836SJohn.Forte@Sun.COM 				/*
46797836SJohn.Forte@Sun.COM 				 * Rut-roh, there is an fc_remote_node_t remote
46807836SJohn.Forte@Sun.COM 				 * node struct for the given node_wwn, but the
46817836SJohn.Forte@Sun.COM 				 * fc_remote_port_t remote port struct doesn't
46827836SJohn.Forte@Sun.COM 				 * know about it.  This just prints a warning
46837836SJohn.Forte@Sun.COM 				 * message & fails the fc_remote_port_t
46847836SJohn.Forte@Sun.COM 				 * allocation (possible leak here?).
46857836SJohn.Forte@Sun.COM 				 */
46867836SJohn.Forte@Sun.COM 				char	ww1_name[17];
46877836SJohn.Forte@Sun.COM 				char	ww2_name[17];
46887836SJohn.Forte@Sun.COM 
46897836SJohn.Forte@Sun.COM 				fc_wwn_to_str(
46907836SJohn.Forte@Sun.COM 				    &pd->pd_remote_nodep->fd_node_name,
46917836SJohn.Forte@Sun.COM 				    ww1_name);
46927836SJohn.Forte@Sun.COM 				fc_wwn_to_str(node_wwn, ww2_name);
46937836SJohn.Forte@Sun.COM 
46947836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: "
46957836SJohn.Forte@Sun.COM 				    "Expected %s Got %s", port->fp_instance,
46967836SJohn.Forte@Sun.COM 				    ww1_name, ww2_name);
46977836SJohn.Forte@Sun.COM 			}
46987836SJohn.Forte@Sun.COM 
46997836SJohn.Forte@Sun.COM 			return (NULL);
47007836SJohn.Forte@Sun.COM 		}
47017836SJohn.Forte@Sun.COM 	}
47027836SJohn.Forte@Sun.COM 
47037836SJohn.Forte@Sun.COM 	/*
470410264SZhong.Wang@Sun.COM 	 * Add	the fc_remote_port_t onto the linked list of remote port
47057836SJohn.Forte@Sun.COM 	 * devices associated with the given fc_remote_node_t (remote node).
47067836SJohn.Forte@Sun.COM 	 */
47077836SJohn.Forte@Sun.COM 	fctl_link_remote_port_to_remote_node(rnodep, pd);
47087836SJohn.Forte@Sun.COM 
47097836SJohn.Forte@Sun.COM 	return (pd);
47107836SJohn.Forte@Sun.COM }
47117836SJohn.Forte@Sun.COM 
47127836SJohn.Forte@Sun.COM 
47137836SJohn.Forte@Sun.COM /*
47147836SJohn.Forte@Sun.COM  * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
47157836SJohn.Forte@Sun.COM  * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
47167836SJohn.Forte@Sun.COM  * references to the fc_remote_port_t from the d_id and pwwn tables in the
47177836SJohn.Forte@Sun.COM  * given fc_local_port_t.  Deallocates the given fc_remote_port_t.
47187836SJohn.Forte@Sun.COM  *
47197836SJohn.Forte@Sun.COM  * Returns a count of the number of remaining fc_remote_port_t structs
47207836SJohn.Forte@Sun.COM  * associated with the fc_remote_node_t struct.
47217836SJohn.Forte@Sun.COM  *
47227836SJohn.Forte@Sun.COM  * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
47237836SJohn.Forte@Sun.COM  * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
47247836SJohn.Forte@Sun.COM  * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
472510264SZhong.Wang@Sun.COM  * the cleanup.	 The function then also returns '1'
47267836SJohn.Forte@Sun.COM  * instead of the actual number of remaining fc_remote_port_t structs
47277836SJohn.Forte@Sun.COM  *
47287836SJohn.Forte@Sun.COM  * If there are no more remote ports on the remote node, return 0.
47297836SJohn.Forte@Sun.COM  * Otherwise, return non-zero.
47307836SJohn.Forte@Sun.COM  */
47317836SJohn.Forte@Sun.COM int
fctl_destroy_remote_port(fc_local_port_t * port,fc_remote_port_t * pd)47327836SJohn.Forte@Sun.COM fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
47337836SJohn.Forte@Sun.COM {
473410264SZhong.Wang@Sun.COM 	fc_remote_node_t	*rnodep;
47357836SJohn.Forte@Sun.COM 	int			rcount = 0;
47367836SJohn.Forte@Sun.COM 
47377836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
47387836SJohn.Forte@Sun.COM 
47397836SJohn.Forte@Sun.COM 	/*
47407836SJohn.Forte@Sun.COM 	 * If pd_ref_count > 0, we can't pull the rug out from any
47417836SJohn.Forte@Sun.COM 	 * current users of this fc_remote_port_t.  We'll mark it as old
47427836SJohn.Forte@Sun.COM 	 * and in need of removal.  The same goes for any fc_remote_port_t
47437836SJohn.Forte@Sun.COM 	 * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
47447836SJohn.Forte@Sun.COM 	 * have not yet been notified that the handle is no longer valid
47457836SJohn.Forte@Sun.COM 	 * (i.e., PD_GIVEN_TO_ULPS is set).
47467836SJohn.Forte@Sun.COM 	 */
47477836SJohn.Forte@Sun.COM 	if ((pd->pd_ref_count > 0) ||
47487836SJohn.Forte@Sun.COM 	    (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) {
47497836SJohn.Forte@Sun.COM 		pd->pd_aux_flags |= PD_NEEDS_REMOVAL;
47507836SJohn.Forte@Sun.COM 		pd->pd_type = PORT_DEVICE_OLD;
47517836SJohn.Forte@Sun.COM 		mutex_exit(&pd->pd_mutex);
47527836SJohn.Forte@Sun.COM 		return (1);
47537836SJohn.Forte@Sun.COM 	}
47547836SJohn.Forte@Sun.COM 
47557836SJohn.Forte@Sun.COM 	pd->pd_type = PORT_DEVICE_OLD;
47567836SJohn.Forte@Sun.COM 
47577836SJohn.Forte@Sun.COM 	rnodep = pd->pd_remote_nodep;
47587836SJohn.Forte@Sun.COM 
47597836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
47607836SJohn.Forte@Sun.COM 
47617836SJohn.Forte@Sun.COM 	if (rnodep != NULL) {
47627836SJohn.Forte@Sun.COM 		/*
47637836SJohn.Forte@Sun.COM 		 * Remove the fc_remote_port_t from the linked list of remote
47647836SJohn.Forte@Sun.COM 		 * ports for the given fc_remote_node_t. This is only called
47657836SJohn.Forte@Sun.COM 		 * here and in fctl_destroy_all_remote_ports().
47667836SJohn.Forte@Sun.COM 		 */
47677836SJohn.Forte@Sun.COM 		rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd);
47687836SJohn.Forte@Sun.COM 	}
47697836SJohn.Forte@Sun.COM 
47707836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
47717836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
47727836SJohn.Forte@Sun.COM 
47737836SJohn.Forte@Sun.COM 	fctl_delist_did_table(port, pd);
47747836SJohn.Forte@Sun.COM 	fctl_delist_pwwn_table(port, pd);
47757836SJohn.Forte@Sun.COM 
47767836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
47777836SJohn.Forte@Sun.COM 
47787836SJohn.Forte@Sun.COM 	/*
47797836SJohn.Forte@Sun.COM 	 * Deconstruct & free the fc_remote_port_t. This is only called
47807836SJohn.Forte@Sun.COM 	 * here and in fctl_destroy_all_remote_ports().
47817836SJohn.Forte@Sun.COM 	 */
47827836SJohn.Forte@Sun.COM 	fctl_dealloc_remote_port(pd);
47837836SJohn.Forte@Sun.COM 
47847836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
47857836SJohn.Forte@Sun.COM 
47867836SJohn.Forte@Sun.COM 	return (rcount);
47877836SJohn.Forte@Sun.COM }
47887836SJohn.Forte@Sun.COM 
47897836SJohn.Forte@Sun.COM 
47907836SJohn.Forte@Sun.COM /*
47917836SJohn.Forte@Sun.COM  * This goes thru the d_id table on the given fc_local_port_t.
47927836SJohn.Forte@Sun.COM  * For each fc_remote_port_t found, this will:
47937836SJohn.Forte@Sun.COM  *
47947836SJohn.Forte@Sun.COM  *  - Remove the fc_remote_port_t from the linked list of remote ports for
479510264SZhong.Wang@Sun.COM  *    the associated fc_remote_node_t.	If the linked list goes empty, then this
47967836SJohn.Forte@Sun.COM  *    tries to deconstruct & free the fc_remote_node_t (that also removes the
47977836SJohn.Forte@Sun.COM  *    fc_remote_node_t from the global fctl_nwwn_hash_table[]).
47987836SJohn.Forte@Sun.COM  *
47997836SJohn.Forte@Sun.COM  *  - Remove the fc_remote_port_t from the pwwn list on the given
48007836SJohn.Forte@Sun.COM  *    fc_local_port_t.
48017836SJohn.Forte@Sun.COM  *
48027836SJohn.Forte@Sun.COM  *  - Deconstruct and free the fc_remote_port_t.
48037836SJohn.Forte@Sun.COM  *
48047836SJohn.Forte@Sun.COM  *  - Removes the link to the fc_remote_port_t in the d_id table. Note, this
48057836SJohn.Forte@Sun.COM  *    does not appear to correctle decrement the d_id_count tho.
48067836SJohn.Forte@Sun.COM  */
48077836SJohn.Forte@Sun.COM void
fctl_destroy_all_remote_ports(fc_local_port_t * port)48087836SJohn.Forte@Sun.COM fctl_destroy_all_remote_ports(fc_local_port_t *port)
48097836SJohn.Forte@Sun.COM {
48107836SJohn.Forte@Sun.COM 	int			index;
48117836SJohn.Forte@Sun.COM 	fc_remote_port_t	*pd;
48127836SJohn.Forte@Sun.COM 	fc_remote_node_t	*rnodep;
481310264SZhong.Wang@Sun.COM 	struct d_id_hash	*head;
48147836SJohn.Forte@Sun.COM 
48157836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
48167836SJohn.Forte@Sun.COM 
48177836SJohn.Forte@Sun.COM 	for (index = 0; index < did_table_size; index++) {
48187836SJohn.Forte@Sun.COM 
48197836SJohn.Forte@Sun.COM 		head = &port->fp_did_table[index];
48207836SJohn.Forte@Sun.COM 
48217836SJohn.Forte@Sun.COM 		while (head->d_id_head != NULL) {
48227836SJohn.Forte@Sun.COM 			pd = head->d_id_head;
48237836SJohn.Forte@Sun.COM 
48247836SJohn.Forte@Sun.COM 			/*
48257836SJohn.Forte@Sun.COM 			 * See if this remote port (fc_remote_port_t) has a
48267836SJohn.Forte@Sun.COM 			 * reference to a remote node (fc_remote_node_t) in its
48277836SJohn.Forte@Sun.COM 			 * pd->pd_remote_nodep pointer.
48287836SJohn.Forte@Sun.COM 			 */
48297836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
48307836SJohn.Forte@Sun.COM 			rnodep = pd->pd_remote_nodep;
48317836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
48327836SJohn.Forte@Sun.COM 
48337836SJohn.Forte@Sun.COM 			if (rnodep != NULL) {
48347836SJohn.Forte@Sun.COM 				/*
48357836SJohn.Forte@Sun.COM 				 * An fc_remote_node_t reference exists. Remove
48367836SJohn.Forte@Sun.COM 				 * the fc_remote_port_t from the linked list of
48377836SJohn.Forte@Sun.COM 				 * remote ports for fc_remote_node_t.
48387836SJohn.Forte@Sun.COM 				 */
48397836SJohn.Forte@Sun.COM 				if (fctl_unlink_remote_port_from_remote_node(
48407836SJohn.Forte@Sun.COM 				    rnodep, pd) == 0) {
48417836SJohn.Forte@Sun.COM 					/*
48427836SJohn.Forte@Sun.COM 					 * The fd_numports reference count
48437836SJohn.Forte@Sun.COM 					 * in the fc_remote_node_t has come
48447836SJohn.Forte@Sun.COM 					 * back as zero, so we can free the
48457836SJohn.Forte@Sun.COM 					 * fc_remote_node_t. This also means
48467836SJohn.Forte@Sun.COM 					 * that the fc_remote_node_t was
48477836SJohn.Forte@Sun.COM 					 * removed from the
48487836SJohn.Forte@Sun.COM 					 * fctl_nwwn_hash_table[].
48497836SJohn.Forte@Sun.COM 					 *
48507836SJohn.Forte@Sun.COM 					 * This will silently skip the
48517836SJohn.Forte@Sun.COM 					 * kmem_free() if either the
48527836SJohn.Forte@Sun.COM 					 * fd_numports is nonzero or
48537836SJohn.Forte@Sun.COM 					 * the fd_port is not NULL in
48547836SJohn.Forte@Sun.COM 					 * the fc_remote_node_t.
48557836SJohn.Forte@Sun.COM 					 */
48567836SJohn.Forte@Sun.COM 					fctl_destroy_remote_node(rnodep);
48577836SJohn.Forte@Sun.COM 				}
48587836SJohn.Forte@Sun.COM 			}
48597836SJohn.Forte@Sun.COM 
48607836SJohn.Forte@Sun.COM 			/*
48617836SJohn.Forte@Sun.COM 			 * Clean up the entry in the fc_local_port_t's pwwn
48627836SJohn.Forte@Sun.COM 			 * table for the given fc_remote_port_t (i.e., the pd).
48637836SJohn.Forte@Sun.COM 			 */
48647836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
48657836SJohn.Forte@Sun.COM 			fctl_delist_pwwn_table(port, pd);
48667836SJohn.Forte@Sun.COM 			pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
48677836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
48687836SJohn.Forte@Sun.COM 
48697836SJohn.Forte@Sun.COM 			/*
48707836SJohn.Forte@Sun.COM 			 * Remove the current entry from the d_id list.
48717836SJohn.Forte@Sun.COM 			 */
48727836SJohn.Forte@Sun.COM 			head->d_id_head = pd->pd_did_hnext;
48737836SJohn.Forte@Sun.COM 
48747836SJohn.Forte@Sun.COM 			/*
48757836SJohn.Forte@Sun.COM 			 * Deconstruct & free the fc_remote_port_t (pd)
48767836SJohn.Forte@Sun.COM 			 * Note: this is only called here and in
48777836SJohn.Forte@Sun.COM 			 * fctl_destroy_remote_port_t().
48787836SJohn.Forte@Sun.COM 			 */
48797836SJohn.Forte@Sun.COM 			fctl_dealloc_remote_port(pd);
48807836SJohn.Forte@Sun.COM 		}
48817836SJohn.Forte@Sun.COM 	}
48827836SJohn.Forte@Sun.COM 
48837836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
48847836SJohn.Forte@Sun.COM }
48857836SJohn.Forte@Sun.COM 
48867836SJohn.Forte@Sun.COM 
48877836SJohn.Forte@Sun.COM int
fctl_is_wwn_zero(la_wwn_t * wwn)48887836SJohn.Forte@Sun.COM fctl_is_wwn_zero(la_wwn_t *wwn)
48897836SJohn.Forte@Sun.COM {
48907836SJohn.Forte@Sun.COM 	int count;
48917836SJohn.Forte@Sun.COM 
48927836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (la_wwn_t); count++) {
48937836SJohn.Forte@Sun.COM 		if (wwn->raw_wwn[count] != 0) {
48947836SJohn.Forte@Sun.COM 			return (FC_FAILURE);
48957836SJohn.Forte@Sun.COM 		}
48967836SJohn.Forte@Sun.COM 	}
48977836SJohn.Forte@Sun.COM 
48987836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
48997836SJohn.Forte@Sun.COM }
49007836SJohn.Forte@Sun.COM 
49017836SJohn.Forte@Sun.COM 
49027836SJohn.Forte@Sun.COM void
fctl_ulp_unsol_cb(fc_local_port_t * port,fc_unsol_buf_t * buf,uchar_t type)49037836SJohn.Forte@Sun.COM fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
49047836SJohn.Forte@Sun.COM {
49057836SJohn.Forte@Sun.COM 	int			data_cb;
49067836SJohn.Forte@Sun.COM 	int			check_type;
49077836SJohn.Forte@Sun.COM 	int			rval;
49087836SJohn.Forte@Sun.COM 	uint32_t		claimed;
490910264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
49107836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
49117836SJohn.Forte@Sun.COM 
49127836SJohn.Forte@Sun.COM 	claimed = 0;
49137836SJohn.Forte@Sun.COM 	check_type = 1;
49147836SJohn.Forte@Sun.COM 
49157836SJohn.Forte@Sun.COM 	switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) {
49167836SJohn.Forte@Sun.COM 	case R_CTL_DEVICE_DATA:
49177836SJohn.Forte@Sun.COM 		data_cb = 1;
49187836SJohn.Forte@Sun.COM 		break;
49197836SJohn.Forte@Sun.COM 
49207836SJohn.Forte@Sun.COM 	case R_CTL_EXTENDED_SVC:
49217836SJohn.Forte@Sun.COM 		check_type = 0;
49227836SJohn.Forte@Sun.COM 		/* FALLTHROUGH */
49237836SJohn.Forte@Sun.COM 
49247836SJohn.Forte@Sun.COM 	case R_CTL_FC4_SVC:
49257836SJohn.Forte@Sun.COM 		data_cb = 0;
49267836SJohn.Forte@Sun.COM 		break;
49277836SJohn.Forte@Sun.COM 
49287836SJohn.Forte@Sun.COM 	default:
49297836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
49307836SJohn.Forte@Sun.COM 		ASSERT(port->fp_active_ubs > 0);
49317836SJohn.Forte@Sun.COM 		if (--(port->fp_active_ubs) == 0) {
49327836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
49337836SJohn.Forte@Sun.COM 		}
49347836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
49357836SJohn.Forte@Sun.COM 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
49367836SJohn.Forte@Sun.COM 		    1, &buf->ub_token);
49377836SJohn.Forte@Sun.COM 		return;
49387836SJohn.Forte@Sun.COM 	}
49397836SJohn.Forte@Sun.COM 
49407836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
49417836SJohn.Forte@Sun.COM 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
49427836SJohn.Forte@Sun.COM 		if (check_type && mod->mod_info->ulp_type != type) {
49437836SJohn.Forte@Sun.COM 			continue;
49447836SJohn.Forte@Sun.COM 		}
49457836SJohn.Forte@Sun.COM 
49467836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
49477836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
49487836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
49497836SJohn.Forte@Sun.COM 
49507836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
49517836SJohn.Forte@Sun.COM 			continue;
49527836SJohn.Forte@Sun.COM 		}
49537836SJohn.Forte@Sun.COM 
49547836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
49557836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
49567836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
49577836SJohn.Forte@Sun.COM 			continue;
49587836SJohn.Forte@Sun.COM 		}
49597836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
49607836SJohn.Forte@Sun.COM 
49617836SJohn.Forte@Sun.COM 		if (data_cb == 1) {
49627836SJohn.Forte@Sun.COM 			rval = mod->mod_info->ulp_data_callback(
49637836SJohn.Forte@Sun.COM 			    mod->mod_info->ulp_handle,
49647836SJohn.Forte@Sun.COM 			    (opaque_t)port, buf, claimed);
49657836SJohn.Forte@Sun.COM 		} else {
49667836SJohn.Forte@Sun.COM 			rval = mod->mod_info->ulp_els_callback(
49677836SJohn.Forte@Sun.COM 			    mod->mod_info->ulp_handle,
49687836SJohn.Forte@Sun.COM 			    (opaque_t)port, buf, claimed);
49697836SJohn.Forte@Sun.COM 		}
49707836SJohn.Forte@Sun.COM 
49717836SJohn.Forte@Sun.COM 		if (rval == FC_SUCCESS && claimed == 0) {
49727836SJohn.Forte@Sun.COM 			claimed = 1;
49737836SJohn.Forte@Sun.COM 		}
49747836SJohn.Forte@Sun.COM 	}
49757836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
49767836SJohn.Forte@Sun.COM 
49777836SJohn.Forte@Sun.COM 	if (claimed == 0) {
49787836SJohn.Forte@Sun.COM 		/*
49797836SJohn.Forte@Sun.COM 		 * We should actually RJT since nobody claimed it.
49807836SJohn.Forte@Sun.COM 		 */
49817836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
49827836SJohn.Forte@Sun.COM 		ASSERT(port->fp_active_ubs > 0);
49837836SJohn.Forte@Sun.COM 		if (--(port->fp_active_ubs) == 0) {
49847836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
49857836SJohn.Forte@Sun.COM 		}
49867836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
49877836SJohn.Forte@Sun.COM 		port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
49887836SJohn.Forte@Sun.COM 		    1, &buf->ub_token);
49897836SJohn.Forte@Sun.COM 
49907836SJohn.Forte@Sun.COM 	} else {
49917836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
49927836SJohn.Forte@Sun.COM 		if (--port->fp_active_ubs == 0) {
49937836SJohn.Forte@Sun.COM 			port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
49947836SJohn.Forte@Sun.COM 		}
49957836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
49967836SJohn.Forte@Sun.COM 	}
49977836SJohn.Forte@Sun.COM }
49987836SJohn.Forte@Sun.COM 
49997836SJohn.Forte@Sun.COM 
50007836SJohn.Forte@Sun.COM /*
50017836SJohn.Forte@Sun.COM  * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
50027836SJohn.Forte@Sun.COM  *
50037836SJohn.Forte@Sun.COM  * With all these mutexes held, we should make sure this function does not eat
50047836SJohn.Forte@Sun.COM  * up much time.
50057836SJohn.Forte@Sun.COM  */
50067836SJohn.Forte@Sun.COM void
fctl_copy_portmap_held(fc_portmap_t * map,fc_remote_port_t * pd)50077836SJohn.Forte@Sun.COM fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd)
50087836SJohn.Forte@Sun.COM {
50097836SJohn.Forte@Sun.COM 	fc_remote_node_t *node;
50107836SJohn.Forte@Sun.COM 
50117836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
50127836SJohn.Forte@Sun.COM 
50137836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
50147836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
50157836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
50167836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
50177836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
50187836SJohn.Forte@Sun.COM 	map->map_flags = 0;
50197836SJohn.Forte@Sun.COM 
50207836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
50217836SJohn.Forte@Sun.COM 
50227836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
50237836SJohn.Forte@Sun.COM 
50247836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
50257836SJohn.Forte@Sun.COM 
50267836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&node->fd_mutex));
50277836SJohn.Forte@Sun.COM 
50287836SJohn.Forte@Sun.COM 	if (node) {
50297836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
50307836SJohn.Forte@Sun.COM 	}
50317836SJohn.Forte@Sun.COM 	map->map_pd = pd;
50327836SJohn.Forte@Sun.COM }
50337836SJohn.Forte@Sun.COM 
50347836SJohn.Forte@Sun.COM void
fctl_copy_portmap(fc_portmap_t * map,fc_remote_port_t * pd)50357836SJohn.Forte@Sun.COM fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
50367836SJohn.Forte@Sun.COM {
50377836SJohn.Forte@Sun.COM 	fc_remote_node_t *node;
50387836SJohn.Forte@Sun.COM 
50397836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
50407836SJohn.Forte@Sun.COM 
50417836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
50427836SJohn.Forte@Sun.COM 	map->map_pwwn = pd->pd_port_name;
50437836SJohn.Forte@Sun.COM 	map->map_did = pd->pd_port_id;
50447836SJohn.Forte@Sun.COM 	map->map_hard_addr = pd->pd_hard_addr;
50457836SJohn.Forte@Sun.COM 	map->map_state = pd->pd_state;
50467836SJohn.Forte@Sun.COM 	map->map_type = pd->pd_type;
50477836SJohn.Forte@Sun.COM 	map->map_flags = 0;
50487836SJohn.Forte@Sun.COM 
50497836SJohn.Forte@Sun.COM 	ASSERT(map->map_type <= PORT_DEVICE_DELETE);
50507836SJohn.Forte@Sun.COM 
50517836SJohn.Forte@Sun.COM 	bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
50527836SJohn.Forte@Sun.COM 
50537836SJohn.Forte@Sun.COM 	node = pd->pd_remote_nodep;
50547836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
50557836SJohn.Forte@Sun.COM 
50567836SJohn.Forte@Sun.COM 	if (node) {
50577836SJohn.Forte@Sun.COM 		mutex_enter(&node->fd_mutex);
50587836SJohn.Forte@Sun.COM 		map->map_nwwn = node->fd_node_name;
50597836SJohn.Forte@Sun.COM 		mutex_exit(&node->fd_mutex);
50607836SJohn.Forte@Sun.COM 	}
50617836SJohn.Forte@Sun.COM 	map->map_pd = pd;
50627836SJohn.Forte@Sun.COM }
50637836SJohn.Forte@Sun.COM 
50647836SJohn.Forte@Sun.COM 
50657836SJohn.Forte@Sun.COM static int
fctl_update_host_ns_values(fc_local_port_t * port,fc_ns_cmd_t * ns_req)50667836SJohn.Forte@Sun.COM fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
50677836SJohn.Forte@Sun.COM {
506810264SZhong.Wang@Sun.COM 	int	rval = FC_SUCCESS;
50697836SJohn.Forte@Sun.COM 
50707836SJohn.Forte@Sun.COM 	switch (ns_req->ns_cmd) {
50717836SJohn.Forte@Sun.COM 	case NS_RFT_ID: {
50727836SJohn.Forte@Sun.COM 		int		count;
50737836SJohn.Forte@Sun.COM 		uint32_t	*src;
50747836SJohn.Forte@Sun.COM 		uint32_t	*dst;
507510264SZhong.Wang@Sun.COM 		ns_rfc_type_t	*rfc;
50767836SJohn.Forte@Sun.COM 
50777836SJohn.Forte@Sun.COM 		rfc = (ns_rfc_type_t *)ns_req->ns_req_payload;
50787836SJohn.Forte@Sun.COM 
50797836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
50807836SJohn.Forte@Sun.COM 		src = (uint32_t *)port->fp_fc4_types;
50817836SJohn.Forte@Sun.COM 		dst = (uint32_t *)rfc->rfc_types;
50827836SJohn.Forte@Sun.COM 
50837836SJohn.Forte@Sun.COM 		for (count = 0; count < 8; count++) {
50847836SJohn.Forte@Sun.COM 			*src++ |= *dst++;
50857836SJohn.Forte@Sun.COM 		}
50867836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
50877836SJohn.Forte@Sun.COM 
50887836SJohn.Forte@Sun.COM 		break;
50897836SJohn.Forte@Sun.COM 	}
50907836SJohn.Forte@Sun.COM 
50917836SJohn.Forte@Sun.COM 	case NS_RSPN_ID: {
50927836SJohn.Forte@Sun.COM 		ns_spn_t *spn;
50937836SJohn.Forte@Sun.COM 
50947836SJohn.Forte@Sun.COM 		spn = (ns_spn_t *)ns_req->ns_req_payload;
50957836SJohn.Forte@Sun.COM 
50967836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
50977836SJohn.Forte@Sun.COM 		port->fp_sym_port_namelen = spn->spn_len;
50987836SJohn.Forte@Sun.COM 		if (spn->spn_len) {
50997836SJohn.Forte@Sun.COM 			bcopy((caddr_t)spn + sizeof (ns_spn_t),
51007836SJohn.Forte@Sun.COM 			    port->fp_sym_port_name, spn->spn_len);
51017836SJohn.Forte@Sun.COM 		}
51027836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51037836SJohn.Forte@Sun.COM 
51047836SJohn.Forte@Sun.COM 		break;
51057836SJohn.Forte@Sun.COM 	}
51067836SJohn.Forte@Sun.COM 
51077836SJohn.Forte@Sun.COM 	case NS_RSNN_NN: {
51087836SJohn.Forte@Sun.COM 		ns_snn_t *snn;
51097836SJohn.Forte@Sun.COM 
51107836SJohn.Forte@Sun.COM 		snn = (ns_snn_t *)ns_req->ns_req_payload;
51117836SJohn.Forte@Sun.COM 
51127836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51137836SJohn.Forte@Sun.COM 		port->fp_sym_node_namelen = snn->snn_len;
51147836SJohn.Forte@Sun.COM 		if (snn->snn_len) {
51157836SJohn.Forte@Sun.COM 			bcopy((caddr_t)snn + sizeof (ns_snn_t),
51167836SJohn.Forte@Sun.COM 			    port->fp_sym_node_name, snn->snn_len);
51177836SJohn.Forte@Sun.COM 		}
51187836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51197836SJohn.Forte@Sun.COM 
51207836SJohn.Forte@Sun.COM 		break;
51217836SJohn.Forte@Sun.COM 	}
51227836SJohn.Forte@Sun.COM 
51237836SJohn.Forte@Sun.COM 	case NS_RIP_NN: {
51247836SJohn.Forte@Sun.COM 		ns_rip_t *rip;
51257836SJohn.Forte@Sun.COM 
51267836SJohn.Forte@Sun.COM 		rip = (ns_rip_t *)ns_req->ns_req_payload;
51277836SJohn.Forte@Sun.COM 
51287836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51297836SJohn.Forte@Sun.COM 		bcopy(rip->rip_ip_addr, port->fp_ip_addr,
51307836SJohn.Forte@Sun.COM 		    sizeof (rip->rip_ip_addr));
51317836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51327836SJohn.Forte@Sun.COM 
51337836SJohn.Forte@Sun.COM 		break;
51347836SJohn.Forte@Sun.COM 	}
51357836SJohn.Forte@Sun.COM 
51367836SJohn.Forte@Sun.COM 	case NS_RIPA_NN: {
51377836SJohn.Forte@Sun.COM 		ns_ipa_t *ipa;
51387836SJohn.Forte@Sun.COM 
51397836SJohn.Forte@Sun.COM 		ipa = (ns_ipa_t *)ns_req->ns_req_payload;
51407836SJohn.Forte@Sun.COM 
51417836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51427836SJohn.Forte@Sun.COM 		bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value));
51437836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51447836SJohn.Forte@Sun.COM 
51457836SJohn.Forte@Sun.COM 		break;
51467836SJohn.Forte@Sun.COM 	}
51477836SJohn.Forte@Sun.COM 
51487836SJohn.Forte@Sun.COM 	default:
51497836SJohn.Forte@Sun.COM 		rval = FC_BADOBJECT;
51507836SJohn.Forte@Sun.COM 		break;
51517836SJohn.Forte@Sun.COM 	}
51527836SJohn.Forte@Sun.COM 
51537836SJohn.Forte@Sun.COM 	return (rval);
51547836SJohn.Forte@Sun.COM }
51557836SJohn.Forte@Sun.COM 
51567836SJohn.Forte@Sun.COM 
51577836SJohn.Forte@Sun.COM static int
fctl_retrieve_host_ns_values(fc_local_port_t * port,fc_ns_cmd_t * ns_req)51587836SJohn.Forte@Sun.COM fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
51597836SJohn.Forte@Sun.COM {
516010264SZhong.Wang@Sun.COM 	int	rval = FC_SUCCESS;
51617836SJohn.Forte@Sun.COM 
51627836SJohn.Forte@Sun.COM 	switch (ns_req->ns_cmd) {
51637836SJohn.Forte@Sun.COM 	case NS_GFT_ID: {
51647836SJohn.Forte@Sun.COM 		ns_rfc_type_t *rfc;
51657836SJohn.Forte@Sun.COM 
51667836SJohn.Forte@Sun.COM 		rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload;
51677836SJohn.Forte@Sun.COM 
51687836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51697836SJohn.Forte@Sun.COM 		bcopy(port->fp_fc4_types, rfc->rfc_types,
51707836SJohn.Forte@Sun.COM 		    sizeof (rfc->rfc_types));
51717836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51727836SJohn.Forte@Sun.COM 		break;
51737836SJohn.Forte@Sun.COM 	}
51747836SJohn.Forte@Sun.COM 
51757836SJohn.Forte@Sun.COM 	case NS_GSPN_ID: {
51767836SJohn.Forte@Sun.COM 		ns_spn_t *spn;
51777836SJohn.Forte@Sun.COM 
51787836SJohn.Forte@Sun.COM 		spn = (ns_spn_t *)ns_req->ns_resp_payload;
51797836SJohn.Forte@Sun.COM 
51807836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51817836SJohn.Forte@Sun.COM 		spn->spn_len = port->fp_sym_port_namelen;
51827836SJohn.Forte@Sun.COM 		if (spn->spn_len) {
51837836SJohn.Forte@Sun.COM 			bcopy(port->fp_sym_port_name, (caddr_t)spn +
51847836SJohn.Forte@Sun.COM 			    sizeof (ns_spn_t), spn->spn_len);
51857836SJohn.Forte@Sun.COM 		}
51867836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
51877836SJohn.Forte@Sun.COM 
51887836SJohn.Forte@Sun.COM 		break;
51897836SJohn.Forte@Sun.COM 	}
51907836SJohn.Forte@Sun.COM 
51917836SJohn.Forte@Sun.COM 	case NS_GSNN_NN: {
51927836SJohn.Forte@Sun.COM 		ns_snn_t *snn;
51937836SJohn.Forte@Sun.COM 
51947836SJohn.Forte@Sun.COM 		snn = (ns_snn_t *)ns_req->ns_resp_payload;
51957836SJohn.Forte@Sun.COM 
51967836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
51977836SJohn.Forte@Sun.COM 		snn->snn_len = port->fp_sym_node_namelen;
51987836SJohn.Forte@Sun.COM 		if (snn->snn_len) {
51997836SJohn.Forte@Sun.COM 			bcopy(port->fp_sym_node_name, (caddr_t)snn +
52007836SJohn.Forte@Sun.COM 			    sizeof (ns_snn_t), snn->snn_len);
52017836SJohn.Forte@Sun.COM 		}
52027836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
52037836SJohn.Forte@Sun.COM 
52047836SJohn.Forte@Sun.COM 		break;
52057836SJohn.Forte@Sun.COM 	}
52067836SJohn.Forte@Sun.COM 
52077836SJohn.Forte@Sun.COM 	case NS_GIP_NN: {
52087836SJohn.Forte@Sun.COM 		ns_rip_t *rip;
52097836SJohn.Forte@Sun.COM 
52107836SJohn.Forte@Sun.COM 		rip = (ns_rip_t *)ns_req->ns_resp_payload;
52117836SJohn.Forte@Sun.COM 
52127836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
52137836SJohn.Forte@Sun.COM 		bcopy(port->fp_ip_addr, rip->rip_ip_addr,
52147836SJohn.Forte@Sun.COM 		    sizeof (rip->rip_ip_addr));
52157836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
52167836SJohn.Forte@Sun.COM 
52177836SJohn.Forte@Sun.COM 		break;
52187836SJohn.Forte@Sun.COM 	}
52197836SJohn.Forte@Sun.COM 
52207836SJohn.Forte@Sun.COM 	case NS_GIPA_NN: {
52217836SJohn.Forte@Sun.COM 		ns_ipa_t *ipa;
52227836SJohn.Forte@Sun.COM 
52237836SJohn.Forte@Sun.COM 		ipa = (ns_ipa_t *)ns_req->ns_resp_payload;
52247836SJohn.Forte@Sun.COM 
52257836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
52267836SJohn.Forte@Sun.COM 		bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value));
52277836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
52287836SJohn.Forte@Sun.COM 
52297836SJohn.Forte@Sun.COM 		break;
52307836SJohn.Forte@Sun.COM 	}
52317836SJohn.Forte@Sun.COM 
52327836SJohn.Forte@Sun.COM 	default:
52337836SJohn.Forte@Sun.COM 		rval = FC_BADOBJECT;
52347836SJohn.Forte@Sun.COM 		break;
52357836SJohn.Forte@Sun.COM 	}
52367836SJohn.Forte@Sun.COM 
52377836SJohn.Forte@Sun.COM 	return (rval);
52387836SJohn.Forte@Sun.COM }
52397836SJohn.Forte@Sun.COM 
52407836SJohn.Forte@Sun.COM 
52417836SJohn.Forte@Sun.COM fctl_ns_req_t *
fctl_alloc_ns_cmd(uint32_t cmd_len,uint32_t resp_len,uint32_t data_len,uint32_t ns_flags,int sleep)52427836SJohn.Forte@Sun.COM fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len,
52437836SJohn.Forte@Sun.COM     uint32_t ns_flags, int sleep)
52447836SJohn.Forte@Sun.COM {
52457836SJohn.Forte@Sun.COM 	fctl_ns_req_t *ns_cmd;
52467836SJohn.Forte@Sun.COM 
52477836SJohn.Forte@Sun.COM 	ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep);
52487836SJohn.Forte@Sun.COM 	if (ns_cmd == NULL) {
52497836SJohn.Forte@Sun.COM 		return (NULL);
52507836SJohn.Forte@Sun.COM 	}
52517836SJohn.Forte@Sun.COM 
52527836SJohn.Forte@Sun.COM 	if (cmd_len) {
52537836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep);
52547836SJohn.Forte@Sun.COM 		if (ns_cmd->ns_cmd_buf == NULL) {
52557836SJohn.Forte@Sun.COM 			kmem_free(ns_cmd, sizeof (*ns_cmd));
52567836SJohn.Forte@Sun.COM 			return (NULL);
52577836SJohn.Forte@Sun.COM 		}
52587836SJohn.Forte@Sun.COM 		ns_cmd->ns_cmd_size = cmd_len;
52597836SJohn.Forte@Sun.COM 	}
52607836SJohn.Forte@Sun.COM 
52617836SJohn.Forte@Sun.COM 	ns_cmd->ns_resp_size = resp_len;
52627836SJohn.Forte@Sun.COM 
52637836SJohn.Forte@Sun.COM 	if (data_len) {
52647836SJohn.Forte@Sun.COM 		ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep);
52657836SJohn.Forte@Sun.COM 		if (ns_cmd->ns_data_buf == NULL) {
52667836SJohn.Forte@Sun.COM 			if (ns_cmd->ns_cmd_buf && cmd_len) {
52677836SJohn.Forte@Sun.COM 				kmem_free(ns_cmd->ns_cmd_buf, cmd_len);
52687836SJohn.Forte@Sun.COM 			}
52697836SJohn.Forte@Sun.COM 			kmem_free(ns_cmd, sizeof (*ns_cmd));
52707836SJohn.Forte@Sun.COM 			return (NULL);
52717836SJohn.Forte@Sun.COM 		}
52727836SJohn.Forte@Sun.COM 		ns_cmd->ns_data_len = data_len;
52737836SJohn.Forte@Sun.COM 	}
52747836SJohn.Forte@Sun.COM 	ns_cmd->ns_flags = ns_flags;
52757836SJohn.Forte@Sun.COM 
52767836SJohn.Forte@Sun.COM 	return (ns_cmd);
52777836SJohn.Forte@Sun.COM }
52787836SJohn.Forte@Sun.COM 
52797836SJohn.Forte@Sun.COM 
52807836SJohn.Forte@Sun.COM void
fctl_free_ns_cmd(fctl_ns_req_t * ns_cmd)52817836SJohn.Forte@Sun.COM fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd)
52827836SJohn.Forte@Sun.COM {
52837836SJohn.Forte@Sun.COM 	if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) {
52847836SJohn.Forte@Sun.COM 		kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size);
52857836SJohn.Forte@Sun.COM 	}
52867836SJohn.Forte@Sun.COM 	if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) {
52877836SJohn.Forte@Sun.COM 		kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len);
52887836SJohn.Forte@Sun.COM 	}
52897836SJohn.Forte@Sun.COM 	kmem_free(ns_cmd, sizeof (*ns_cmd));
52907836SJohn.Forte@Sun.COM }
52917836SJohn.Forte@Sun.COM 
52927836SJohn.Forte@Sun.COM 
52937836SJohn.Forte@Sun.COM int
fctl_ulp_port_ioctl(fc_local_port_t * port,dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)52947836SJohn.Forte@Sun.COM fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
52957836SJohn.Forte@Sun.COM     intptr_t data, int mode, cred_t *credp, int *rval)
52967836SJohn.Forte@Sun.COM {
52977836SJohn.Forte@Sun.COM 	int			ret;
52987836SJohn.Forte@Sun.COM 	int			save;
529910264SZhong.Wang@Sun.COM 	uint32_t		claimed;
530010264SZhong.Wang@Sun.COM 	fc_ulp_module_t		*mod;
53017836SJohn.Forte@Sun.COM 	fc_ulp_ports_t		*ulp_port;
53027836SJohn.Forte@Sun.COM 
53037836SJohn.Forte@Sun.COM 	save = *rval;
53047836SJohn.Forte@Sun.COM 	*rval = ENOTTY;
53057836SJohn.Forte@Sun.COM 
53067836SJohn.Forte@Sun.COM 	rw_enter(&fctl_ulp_lock, RW_READER);
53077836SJohn.Forte@Sun.COM 	for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
53087836SJohn.Forte@Sun.COM 		rw_enter(&fctl_mod_ports_lock, RW_READER);
53097836SJohn.Forte@Sun.COM 		ulp_port = fctl_get_ulp_port(mod, port);
53107836SJohn.Forte@Sun.COM 		rw_exit(&fctl_mod_ports_lock);
53117836SJohn.Forte@Sun.COM 
53127836SJohn.Forte@Sun.COM 		if (ulp_port == NULL) {
53137836SJohn.Forte@Sun.COM 			continue;
53147836SJohn.Forte@Sun.COM 		}
53157836SJohn.Forte@Sun.COM 
53167836SJohn.Forte@Sun.COM 		mutex_enter(&ulp_port->port_mutex);
53177836SJohn.Forte@Sun.COM 		if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) ||
53187836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_port_ioctl == NULL) {
53197836SJohn.Forte@Sun.COM 			mutex_exit(&ulp_port->port_mutex);
53207836SJohn.Forte@Sun.COM 			continue;
53217836SJohn.Forte@Sun.COM 		}
53227836SJohn.Forte@Sun.COM 		mutex_exit(&ulp_port->port_mutex);
53237836SJohn.Forte@Sun.COM 
53247836SJohn.Forte@Sun.COM 		ret = mod->mod_info->ulp_port_ioctl(
53257836SJohn.Forte@Sun.COM 		    mod->mod_info->ulp_handle, (opaque_t)port,
53267836SJohn.Forte@Sun.COM 		    dev, cmd, data, mode, credp, rval, claimed);
53277836SJohn.Forte@Sun.COM 
53287836SJohn.Forte@Sun.COM 		if (ret == FC_SUCCESS && claimed == 0) {
53297836SJohn.Forte@Sun.COM 			claimed = 1;
53307836SJohn.Forte@Sun.COM 		}
53317836SJohn.Forte@Sun.COM 	}
53327836SJohn.Forte@Sun.COM 	rw_exit(&fctl_ulp_lock);
53337836SJohn.Forte@Sun.COM 
53347836SJohn.Forte@Sun.COM 	ret = *rval;
53357836SJohn.Forte@Sun.COM 	*rval = save;
53367836SJohn.Forte@Sun.COM 
53377836SJohn.Forte@Sun.COM 	return (ret);
53387836SJohn.Forte@Sun.COM }
53397836SJohn.Forte@Sun.COM 
53407836SJohn.Forte@Sun.COM /*
53417836SJohn.Forte@Sun.COM  * raise power if necessary, and set the port busy
53427836SJohn.Forte@Sun.COM  *
53437836SJohn.Forte@Sun.COM  * this may cause power to be raised, so no power related locks should
53447836SJohn.Forte@Sun.COM  * be held
53457836SJohn.Forte@Sun.COM  */
53467836SJohn.Forte@Sun.COM int
fc_ulp_busy_port(opaque_t port_handle)53477836SJohn.Forte@Sun.COM fc_ulp_busy_port(opaque_t port_handle)
53487836SJohn.Forte@Sun.COM {
53497836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
53507836SJohn.Forte@Sun.COM 
53517836SJohn.Forte@Sun.COM 	return (fctl_busy_port(port));
53527836SJohn.Forte@Sun.COM }
53537836SJohn.Forte@Sun.COM 
53547836SJohn.Forte@Sun.COM void
fc_ulp_idle_port(opaque_t port_handle)53557836SJohn.Forte@Sun.COM fc_ulp_idle_port(opaque_t port_handle)
53567836SJohn.Forte@Sun.COM {
53577836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
53587836SJohn.Forte@Sun.COM 	fctl_idle_port(port);
53597836SJohn.Forte@Sun.COM }
53607836SJohn.Forte@Sun.COM 
53617836SJohn.Forte@Sun.COM void
fc_ulp_copy_portmap(fc_portmap_t * map,opaque_t pd)53627836SJohn.Forte@Sun.COM fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd)
53637836SJohn.Forte@Sun.COM {
53647836SJohn.Forte@Sun.COM 	fctl_copy_portmap(map, (fc_remote_port_t *)pd);
53657836SJohn.Forte@Sun.COM }
53667836SJohn.Forte@Sun.COM 
53677836SJohn.Forte@Sun.COM 
53687836SJohn.Forte@Sun.COM int
fc_ulp_get_npiv_port_num(opaque_t port_handle)53697836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_num(opaque_t port_handle)
53707836SJohn.Forte@Sun.COM {
53717836SJohn.Forte@Sun.COM 	int portsnum = 0;
53727836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
53737836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
53747836SJohn.Forte@Sun.COM 
53757836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
53767836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
53777836SJohn.Forte@Sun.COM 	if (!tmpport) {
53787836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
53797836SJohn.Forte@Sun.COM 		return (portsnum);
53807836SJohn.Forte@Sun.COM 	}
53817836SJohn.Forte@Sun.COM 	while (tmpport != port) {
53827836SJohn.Forte@Sun.COM 		portsnum ++;
53837836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
53847836SJohn.Forte@Sun.COM 	}
53857836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
53867836SJohn.Forte@Sun.COM 	return (portsnum);
53877836SJohn.Forte@Sun.COM }
53887836SJohn.Forte@Sun.COM 
53897836SJohn.Forte@Sun.COM fc_local_port_t *
fc_get_npiv_port(fc_local_port_t * phyport,la_wwn_t * pwwn)53907836SJohn.Forte@Sun.COM fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn)
53917836SJohn.Forte@Sun.COM {
53927836SJohn.Forte@Sun.COM 	fc_fca_port_t	*fca_port;
53937836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = phyport;
53947836SJohn.Forte@Sun.COM 
53957836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
53967836SJohn.Forte@Sun.COM 
53977836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
53987836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
53997836SJohn.Forte@Sun.COM 		tmpPort = fca_port->port_handle;
54007836SJohn.Forte@Sun.COM 		if (tmpPort == NULL) {
54017836SJohn.Forte@Sun.COM 			continue;
54027836SJohn.Forte@Sun.COM 		}
54037836SJohn.Forte@Sun.COM 		mutex_enter(&tmpPort->fp_mutex);
54047836SJohn.Forte@Sun.COM 		if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn,
54057836SJohn.Forte@Sun.COM 		    pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) {
54067836SJohn.Forte@Sun.COM 			mutex_exit(&tmpPort->fp_mutex);
54077836SJohn.Forte@Sun.COM 			mutex_exit(&fctl_port_lock);
54087836SJohn.Forte@Sun.COM 			return (tmpPort);
54097836SJohn.Forte@Sun.COM 		}
54107836SJohn.Forte@Sun.COM 		mutex_exit(&tmpPort->fp_mutex);
54117836SJohn.Forte@Sun.COM 	}
54127836SJohn.Forte@Sun.COM 
54137836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
54147836SJohn.Forte@Sun.COM 
54157836SJohn.Forte@Sun.COM 	return (NULL);
54167836SJohn.Forte@Sun.COM }
54177836SJohn.Forte@Sun.COM 
54187836SJohn.Forte@Sun.COM int
fc_ulp_get_npiv_port_list(opaque_t port_handle,char * pathList)54197836SJohn.Forte@Sun.COM fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList)
54207836SJohn.Forte@Sun.COM {
54217836SJohn.Forte@Sun.COM 	int portsnum = 0;
54227836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
54237836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
54247836SJohn.Forte@Sun.COM 
54257836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
54267836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
54277836SJohn.Forte@Sun.COM 	if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
54287836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
54297836SJohn.Forte@Sun.COM 		return (portsnum);
54307836SJohn.Forte@Sun.COM 	}
54317836SJohn.Forte@Sun.COM 
54327836SJohn.Forte@Sun.COM 	while (tmpport != port) {
54337836SJohn.Forte@Sun.COM 		(void) ddi_pathname(tmpport->fp_port_dip,
54347836SJohn.Forte@Sun.COM 		    &pathList[MAXPATHLEN * portsnum]);
54357836SJohn.Forte@Sun.COM 		portsnum ++;
54367836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
54377836SJohn.Forte@Sun.COM 	}
54387836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
54397836SJohn.Forte@Sun.COM 
54407836SJohn.Forte@Sun.COM 	return (portsnum);
54417836SJohn.Forte@Sun.COM }
54427836SJohn.Forte@Sun.COM 
54437836SJohn.Forte@Sun.COM 
54447836SJohn.Forte@Sun.COM fc_local_port_t *
fc_delete_npiv_port(fc_local_port_t * port,la_wwn_t * pwwn)54457836SJohn.Forte@Sun.COM fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
54467836SJohn.Forte@Sun.COM {
54477836SJohn.Forte@Sun.COM 	fc_local_port_t *tmpport;
54487836SJohn.Forte@Sun.COM 
54497836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
54507836SJohn.Forte@Sun.COM 	tmpport = port->fp_port_next;
54517836SJohn.Forte@Sun.COM 	if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
54527836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
54537836SJohn.Forte@Sun.COM 		return (NULL);
54547836SJohn.Forte@Sun.COM 	}
54557836SJohn.Forte@Sun.COM 
54567836SJohn.Forte@Sun.COM 	while (tmpport != port) {
54577836SJohn.Forte@Sun.COM 		if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn,
54587836SJohn.Forte@Sun.COM 		    pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) &&
54597836SJohn.Forte@Sun.COM 		    (tmpport->fp_npiv_state == 0)) {
54607836SJohn.Forte@Sun.COM 			tmpport->fp_npiv_state = FC_NPIV_DELETING;
54617836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
54627836SJohn.Forte@Sun.COM 			return (tmpport);
54637836SJohn.Forte@Sun.COM 		}
54647836SJohn.Forte@Sun.COM 		tmpport = tmpport->fp_port_next;
54657836SJohn.Forte@Sun.COM 	}
54667836SJohn.Forte@Sun.COM 
54677836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
54687836SJohn.Forte@Sun.COM 	return (NULL);
54697836SJohn.Forte@Sun.COM }
54707836SJohn.Forte@Sun.COM 
54717836SJohn.Forte@Sun.COM /*
54727836SJohn.Forte@Sun.COM  * Get the list of Adapters.  On multi-ported adapters,
54737836SJohn.Forte@Sun.COM  * only ONE port on the adapter will be returned.
54747836SJohn.Forte@Sun.COM  * pathList should be (count * MAXPATHLEN) long.
54757836SJohn.Forte@Sun.COM  * The return value will be set to the number of
547610264SZhong.Wang@Sun.COM  * HBAs that were found on the system.	If the value
54777836SJohn.Forte@Sun.COM  * is greater than count, the routine should be retried
54787836SJohn.Forte@Sun.COM  * with a larger buffer.
54797836SJohn.Forte@Sun.COM  */
54807836SJohn.Forte@Sun.COM int
fc_ulp_get_adapter_paths(char * pathList,int count)54817836SJohn.Forte@Sun.COM fc_ulp_get_adapter_paths(char *pathList, int count)
54827836SJohn.Forte@Sun.COM {
548310264SZhong.Wang@Sun.COM 	fc_fca_port_t	*fca_port;
54847836SJohn.Forte@Sun.COM 	int		in = 0, out = 0, check, skip, maxPorts = 0;
54857836SJohn.Forte@Sun.COM 	fc_local_port_t		**portList;
54867836SJohn.Forte@Sun.COM 	fc_local_port_t		*new_port, *stored_port;
54877836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*new_fru, *stored_fru;
54887836SJohn.Forte@Sun.COM 
54897836SJohn.Forte@Sun.COM 	ASSERT(pathList != NULL);
54907836SJohn.Forte@Sun.COM 
54917836SJohn.Forte@Sun.COM 	/* First figure out how many ports we have */
54927836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
54937836SJohn.Forte@Sun.COM 
54947836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
54957836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
54967836SJohn.Forte@Sun.COM 		maxPorts ++;
54977836SJohn.Forte@Sun.COM 	}
54987836SJohn.Forte@Sun.COM 
54997836SJohn.Forte@Sun.COM 	/* Now allocate a buffer to store all the pointers for comparisons */
55007836SJohn.Forte@Sun.COM 	portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP);
55017836SJohn.Forte@Sun.COM 
55027836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
55037836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
55047836SJohn.Forte@Sun.COM 		skip = 0;
55057836SJohn.Forte@Sun.COM 
55067836SJohn.Forte@Sun.COM 		/* Lock the new port for subsequent comparisons */
55077836SJohn.Forte@Sun.COM 		new_port = fca_port->port_handle;
55087836SJohn.Forte@Sun.COM 		mutex_enter(&new_port->fp_mutex);
55097836SJohn.Forte@Sun.COM 		new_fru = &new_port->fp_hba_port_attrs.hba_fru_details;
55107836SJohn.Forte@Sun.COM 
55117836SJohn.Forte@Sun.COM 		/* Filter out secondary ports from the list */
55127836SJohn.Forte@Sun.COM 		for (check = 0; check < out; check++) {
551310264SZhong.Wang@Sun.COM 			if (portList[check] == NULL) {
551410264SZhong.Wang@Sun.COM 				continue;
551510264SZhong.Wang@Sun.COM 			}
551610264SZhong.Wang@Sun.COM 			/* Guard against duplicates (should never happen) */
551710264SZhong.Wang@Sun.COM 			if (portList[check] == fca_port->port_handle) {
551810264SZhong.Wang@Sun.COM 				/* Same port */
551910264SZhong.Wang@Sun.COM 				skip = 1;
552010264SZhong.Wang@Sun.COM 				break;
552110264SZhong.Wang@Sun.COM 			}
552210264SZhong.Wang@Sun.COM 
552310264SZhong.Wang@Sun.COM 			/* Lock the already stored port for comparison */
552410264SZhong.Wang@Sun.COM 			stored_port = portList[check];
552510264SZhong.Wang@Sun.COM 			mutex_enter(&stored_port->fp_mutex);
552610264SZhong.Wang@Sun.COM 			stored_fru =
552710264SZhong.Wang@Sun.COM 			    &stored_port->fp_hba_port_attrs.hba_fru_details;
552810264SZhong.Wang@Sun.COM 
552910264SZhong.Wang@Sun.COM 			/* Are these ports on the same HBA? */
553010264SZhong.Wang@Sun.COM 			if (new_fru->high == stored_fru->high &&
553110264SZhong.Wang@Sun.COM 			    new_fru->low == stored_fru->low) {
553210264SZhong.Wang@Sun.COM 				/* Now double check driver */
553310264SZhong.Wang@Sun.COM 				if (strncmp(
553410264SZhong.Wang@Sun.COM 				    new_port->fp_hba_port_attrs.driver_name,
553510264SZhong.Wang@Sun.COM 				    stored_port->fp_hba_port_attrs.driver_name,
553610264SZhong.Wang@Sun.COM 				    FCHBA_DRIVER_NAME_LEN) == 0) {
553710264SZhong.Wang@Sun.COM 					/* we don't need to grow the list */
553810264SZhong.Wang@Sun.COM 					skip = 1;
553910264SZhong.Wang@Sun.COM 					/* looking at a lower port index? */
554010264SZhong.Wang@Sun.COM 					if (new_fru->port_index <
554110264SZhong.Wang@Sun.COM 					    stored_fru->port_index) {
554210264SZhong.Wang@Sun.COM 						/* Replace the port in list */
554310264SZhong.Wang@Sun.COM 						mutex_exit(
554410264SZhong.Wang@Sun.COM 						    &stored_port->fp_mutex);
554510264SZhong.Wang@Sun.COM 						if (new_port->fp_npiv_type ==
554610264SZhong.Wang@Sun.COM 						    FC_NPIV_PORT) {
554710264SZhong.Wang@Sun.COM 							break;
554810264SZhong.Wang@Sun.COM 						}
554910264SZhong.Wang@Sun.COM 						portList[check] = new_port;
555010264SZhong.Wang@Sun.COM 						break;
555110264SZhong.Wang@Sun.COM 					} /* Else, just skip this port */
55527836SJohn.Forte@Sun.COM 				}
555310264SZhong.Wang@Sun.COM 			}
555410264SZhong.Wang@Sun.COM 
555510264SZhong.Wang@Sun.COM 			mutex_exit(&stored_port->fp_mutex);
555610264SZhong.Wang@Sun.COM 		}
555710264SZhong.Wang@Sun.COM 		mutex_exit(&new_port->fp_mutex);
555810264SZhong.Wang@Sun.COM 
555910264SZhong.Wang@Sun.COM 		if (!skip) {
556010264SZhong.Wang@Sun.COM 			/*
556110264SZhong.Wang@Sun.COM 			 * Either this is the first port for this HBA, or
556210264SZhong.Wang@Sun.COM 			 * it's a secondary port and we haven't stored the
556310264SZhong.Wang@Sun.COM 			 * primary/first port for that HBA.  In the latter case,
556410264SZhong.Wang@Sun.COM 			 * will just filter it out as we proceed to loop.
556510264SZhong.Wang@Sun.COM 			 */
556610264SZhong.Wang@Sun.COM 			if (fca_port->port_handle->fp_npiv_type ==
556710264SZhong.Wang@Sun.COM 			    FC_NPIV_PORT) {
556810264SZhong.Wang@Sun.COM 				continue;
556910264SZhong.Wang@Sun.COM 			} else {
557010264SZhong.Wang@Sun.COM 				portList[out++] = fca_port->port_handle;
557110264SZhong.Wang@Sun.COM 			}
557210264SZhong.Wang@Sun.COM 		}
55737836SJohn.Forte@Sun.COM 	}
55747836SJohn.Forte@Sun.COM 
55757836SJohn.Forte@Sun.COM 	if (out <= count) {
557610264SZhong.Wang@Sun.COM 		for (in = 0; in < out; in++) {
557710264SZhong.Wang@Sun.COM 			(void) ddi_pathname(portList[in]->fp_port_dip,
557810264SZhong.Wang@Sun.COM 			    &pathList[MAXPATHLEN * in]);
557910264SZhong.Wang@Sun.COM 		}
55807836SJohn.Forte@Sun.COM 	}
55817836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
55827836SJohn.Forte@Sun.COM 	kmem_free(portList, sizeof (*portList) * maxPorts);
55837836SJohn.Forte@Sun.COM 	return (out);
55847836SJohn.Forte@Sun.COM }
55857836SJohn.Forte@Sun.COM 
55867836SJohn.Forte@Sun.COM uint32_t
fc_ulp_get_rscn_count(opaque_t port_handle)55877836SJohn.Forte@Sun.COM fc_ulp_get_rscn_count(opaque_t port_handle)
55887836SJohn.Forte@Sun.COM {
55897836SJohn.Forte@Sun.COM 	uint32_t	count;
55907836SJohn.Forte@Sun.COM 	fc_local_port_t	*port;
55917836SJohn.Forte@Sun.COM 
55927836SJohn.Forte@Sun.COM 	port = (fc_local_port_t *)port_handle;
55937836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
55947836SJohn.Forte@Sun.COM 	count = port->fp_rscn_count;
55957836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
55967836SJohn.Forte@Sun.COM 
55977836SJohn.Forte@Sun.COM 	return (count);
55987836SJohn.Forte@Sun.COM }
55997836SJohn.Forte@Sun.COM 
56007836SJohn.Forte@Sun.COM 
56017836SJohn.Forte@Sun.COM /*
56027836SJohn.Forte@Sun.COM  * This function is a very similar to fctl_add_orphan except that it expects
56037836SJohn.Forte@Sun.COM  * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
56047836SJohn.Forte@Sun.COM  *
56057836SJohn.Forte@Sun.COM  * Note that there is a lock hierarchy here (fp_mutex should be held first) but
56067836SJohn.Forte@Sun.COM  * since this function could be called with a different pd's pd_mutex held, we
56077836SJohn.Forte@Sun.COM  * should take care not to release fp_mutex in this function.
56087836SJohn.Forte@Sun.COM  */
56097836SJohn.Forte@Sun.COM int
fctl_add_orphan_held(fc_local_port_t * port,fc_remote_port_t * pd)56107836SJohn.Forte@Sun.COM fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
56117836SJohn.Forte@Sun.COM {
56127836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
56137836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
561410264SZhong.Wang@Sun.COM 	fc_orphan_t	*orp;
56157836SJohn.Forte@Sun.COM 	fc_orphan_t	*orphan;
56167836SJohn.Forte@Sun.COM 
56177836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
56187836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
56197836SJohn.Forte@Sun.COM 
56207836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
56217836SJohn.Forte@Sun.COM 
56227836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
56237836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
56247836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
56257836SJohn.Forte@Sun.COM 		}
56267836SJohn.Forte@Sun.COM 	}
56277836SJohn.Forte@Sun.COM 
56287836SJohn.Forte@Sun.COM 	orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP);
56297836SJohn.Forte@Sun.COM 	if (orphan) {
56307836SJohn.Forte@Sun.COM 		orphan->orp_pwwn = pwwn;
56317836SJohn.Forte@Sun.COM 		orphan->orp_tstamp = ddi_get_lbolt();
56327836SJohn.Forte@Sun.COM 
56337836SJohn.Forte@Sun.COM 		if (port->fp_orphan_list) {
56347836SJohn.Forte@Sun.COM 			ASSERT(port->fp_orphan_count > 0);
56357836SJohn.Forte@Sun.COM 			orphan->orp_next = port->fp_orphan_list;
56367836SJohn.Forte@Sun.COM 		}
56377836SJohn.Forte@Sun.COM 		port->fp_orphan_list = orphan;
56387836SJohn.Forte@Sun.COM 		port->fp_orphan_count++;
56397836SJohn.Forte@Sun.COM 
56407836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
56417836SJohn.Forte@Sun.COM 	}
56427836SJohn.Forte@Sun.COM 
56437836SJohn.Forte@Sun.COM 	return (rval);
56447836SJohn.Forte@Sun.COM }
56457836SJohn.Forte@Sun.COM 
56467836SJohn.Forte@Sun.COM int
fctl_add_orphan(fc_local_port_t * port,fc_remote_port_t * pd,int sleep)56477836SJohn.Forte@Sun.COM fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
56487836SJohn.Forte@Sun.COM {
56497836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
56507836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
565110264SZhong.Wang@Sun.COM 	fc_orphan_t	*orp;
56527836SJohn.Forte@Sun.COM 	fc_orphan_t	*orphan;
56537836SJohn.Forte@Sun.COM 
56547836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
56557836SJohn.Forte@Sun.COM 
56567836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
56577836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
56587836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
56597836SJohn.Forte@Sun.COM 
56607836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
56617836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
56627836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
56637836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
56647836SJohn.Forte@Sun.COM 		}
56657836SJohn.Forte@Sun.COM 	}
56667836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
56677836SJohn.Forte@Sun.COM 
56687836SJohn.Forte@Sun.COM 	orphan = kmem_zalloc(sizeof (*orphan), sleep);
56697836SJohn.Forte@Sun.COM 	if (orphan != NULL) {
56707836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
56717836SJohn.Forte@Sun.COM 
56727836SJohn.Forte@Sun.COM 		orphan->orp_pwwn = pwwn;
56737836SJohn.Forte@Sun.COM 		orphan->orp_tstamp = ddi_get_lbolt();
56747836SJohn.Forte@Sun.COM 
56757836SJohn.Forte@Sun.COM 		if (port->fp_orphan_list) {
56767836SJohn.Forte@Sun.COM 			ASSERT(port->fp_orphan_count > 0);
56777836SJohn.Forte@Sun.COM 			orphan->orp_next = port->fp_orphan_list;
56787836SJohn.Forte@Sun.COM 		}
56797836SJohn.Forte@Sun.COM 		port->fp_orphan_list = orphan;
56807836SJohn.Forte@Sun.COM 		port->fp_orphan_count++;
56817836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
56827836SJohn.Forte@Sun.COM 
56837836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
56847836SJohn.Forte@Sun.COM 	}
56857836SJohn.Forte@Sun.COM 
56867836SJohn.Forte@Sun.COM 	return (rval);
56877836SJohn.Forte@Sun.COM }
56887836SJohn.Forte@Sun.COM 
56897836SJohn.Forte@Sun.COM 
56907836SJohn.Forte@Sun.COM int
fctl_remove_if_orphan(fc_local_port_t * port,la_wwn_t * pwwn)56917836SJohn.Forte@Sun.COM fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
56927836SJohn.Forte@Sun.COM {
56937836SJohn.Forte@Sun.COM 	int		rval = FC_FAILURE;
56947836SJohn.Forte@Sun.COM 	fc_orphan_t	*prev = NULL;
569510264SZhong.Wang@Sun.COM 	fc_orphan_t	*orp;
56967836SJohn.Forte@Sun.COM 
56977836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
56987836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
56997836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) {
57007836SJohn.Forte@Sun.COM 			if (prev) {
57017836SJohn.Forte@Sun.COM 				prev->orp_next = orp->orp_next;
57027836SJohn.Forte@Sun.COM 			} else {
57037836SJohn.Forte@Sun.COM 				ASSERT(port->fp_orphan_list == orp);
57047836SJohn.Forte@Sun.COM 				port->fp_orphan_list = orp->orp_next;
57057836SJohn.Forte@Sun.COM 			}
57067836SJohn.Forte@Sun.COM 			port->fp_orphan_count--;
57077836SJohn.Forte@Sun.COM 			rval = FC_SUCCESS;
57087836SJohn.Forte@Sun.COM 			break;
57097836SJohn.Forte@Sun.COM 		}
57107836SJohn.Forte@Sun.COM 		prev = orp;
57117836SJohn.Forte@Sun.COM 	}
57127836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
57137836SJohn.Forte@Sun.COM 
57147836SJohn.Forte@Sun.COM 	if (rval == FC_SUCCESS) {
57157836SJohn.Forte@Sun.COM 		kmem_free(orp, sizeof (*orp));
57167836SJohn.Forte@Sun.COM 	}
57177836SJohn.Forte@Sun.COM 
57187836SJohn.Forte@Sun.COM 	return (rval);
57197836SJohn.Forte@Sun.COM }
57207836SJohn.Forte@Sun.COM 
57217836SJohn.Forte@Sun.COM 
57227836SJohn.Forte@Sun.COM static void
fctl_print_if_not_orphan(fc_local_port_t * port,fc_remote_port_t * pd)57237836SJohn.Forte@Sun.COM fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
57247836SJohn.Forte@Sun.COM {
572510264SZhong.Wang@Sun.COM 	char		ww_name[17];
572610264SZhong.Wang@Sun.COM 	la_wwn_t	pwwn;
572710264SZhong.Wang@Sun.COM 	fc_orphan_t	*orp;
57287836SJohn.Forte@Sun.COM 
57297836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
57307836SJohn.Forte@Sun.COM 
57317836SJohn.Forte@Sun.COM 	mutex_enter(&pd->pd_mutex);
57327836SJohn.Forte@Sun.COM 	pwwn = pd->pd_port_name;
57337836SJohn.Forte@Sun.COM 	mutex_exit(&pd->pd_mutex);
57347836SJohn.Forte@Sun.COM 
57357836SJohn.Forte@Sun.COM 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
57367836SJohn.Forte@Sun.COM 		if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
57377836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
57387836SJohn.Forte@Sun.COM 			return;
57397836SJohn.Forte@Sun.COM 		}
57407836SJohn.Forte@Sun.COM 	}
57417836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
57427836SJohn.Forte@Sun.COM 
57437836SJohn.Forte@Sun.COM 	fc_wwn_to_str(&pwwn, ww_name);
57447836SJohn.Forte@Sun.COM 
57457836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
57467836SJohn.Forte@Sun.COM 	    " disappeared from fabric", port->fp_instance,
57477836SJohn.Forte@Sun.COM 	    pd->pd_port_id.port_id, ww_name);
57487836SJohn.Forte@Sun.COM }
57497836SJohn.Forte@Sun.COM 
57507836SJohn.Forte@Sun.COM 
57517836SJohn.Forte@Sun.COM /* ARGSUSED */
57527836SJohn.Forte@Sun.COM static void
fctl_link_reset_done(opaque_t port_handle,uchar_t result)57537836SJohn.Forte@Sun.COM fctl_link_reset_done(opaque_t port_handle, uchar_t result)
57547836SJohn.Forte@Sun.COM {
57557836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
57567836SJohn.Forte@Sun.COM 
57577836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
57587836SJohn.Forte@Sun.COM 	port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
57597836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
57607836SJohn.Forte@Sun.COM 
57617836SJohn.Forte@Sun.COM 	fctl_idle_port(port);
57627836SJohn.Forte@Sun.COM }
57637836SJohn.Forte@Sun.COM 
57647836SJohn.Forte@Sun.COM 
57657836SJohn.Forte@Sun.COM static int
fctl_error(int fc_errno,char ** errmsg)57667836SJohn.Forte@Sun.COM fctl_error(int fc_errno, char **errmsg)
57677836SJohn.Forte@Sun.COM {
57687836SJohn.Forte@Sun.COM 	int count;
57697836SJohn.Forte@Sun.COM 
57707836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fc_errlist) /
57717836SJohn.Forte@Sun.COM 	    sizeof (fc_errlist[0]); count++) {
57727836SJohn.Forte@Sun.COM 		if (fc_errlist[count].fc_errno == fc_errno) {
57737836SJohn.Forte@Sun.COM 			*errmsg = fc_errlist[count].fc_errname;
57747836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
57757836SJohn.Forte@Sun.COM 		}
57767836SJohn.Forte@Sun.COM 	}
57777836SJohn.Forte@Sun.COM 	*errmsg = fctl_undefined;
57787836SJohn.Forte@Sun.COM 
57797836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
57807836SJohn.Forte@Sun.COM }
57817836SJohn.Forte@Sun.COM 
57827836SJohn.Forte@Sun.COM 
57837836SJohn.Forte@Sun.COM /*
57847836SJohn.Forte@Sun.COM  * Return number of successful translations.
57857836SJohn.Forte@Sun.COM  *	Anybody with some userland programming experience would have
57867836SJohn.Forte@Sun.COM  *	figured it by now that the return value exactly resembles that
57877836SJohn.Forte@Sun.COM  *	of scanf(3c). This function returns a count of successful
57887836SJohn.Forte@Sun.COM  *	translations. It could range from 0 (no match for state, reason,
57897836SJohn.Forte@Sun.COM  *	action, expln) to 4 (successful matches for all state, reason,
57907836SJohn.Forte@Sun.COM  *	action, expln) and where translation isn't successful into a
57917836SJohn.Forte@Sun.COM  *	friendlier message the relevent field is set to "Undefined"
57927836SJohn.Forte@Sun.COM  */
57937836SJohn.Forte@Sun.COM static int
fctl_pkt_error(fc_packet_t * pkt,char ** state,char ** reason,char ** action,char ** expln)57947836SJohn.Forte@Sun.COM fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
57957836SJohn.Forte@Sun.COM     char **action, char **expln)
57967836SJohn.Forte@Sun.COM {
57977836SJohn.Forte@Sun.COM 	int		ret;
579810264SZhong.Wang@Sun.COM 	int		len;
57997836SJohn.Forte@Sun.COM 	int		index;
58007836SJohn.Forte@Sun.COM 	fc_pkt_error_t	*error;
58017836SJohn.Forte@Sun.COM 	fc_pkt_reason_t	*reason_b;	/* Base pointer */
58027836SJohn.Forte@Sun.COM 	fc_pkt_action_t	*action_b;	/* Base pointer */
58037836SJohn.Forte@Sun.COM 	fc_pkt_expln_t	*expln_b;	/* Base pointer */
58047836SJohn.Forte@Sun.COM 
58057836SJohn.Forte@Sun.COM 	ret = 0;
58067836SJohn.Forte@Sun.COM 	*state = *reason = *action = *expln = fctl_undefined;
58077836SJohn.Forte@Sun.COM 
58087836SJohn.Forte@Sun.COM 	len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0];
58097836SJohn.Forte@Sun.COM 	for (index = 0; index < len; index++) {
58107836SJohn.Forte@Sun.COM 		error = fc_pkt_errlist + index;
58117836SJohn.Forte@Sun.COM 		if (pkt->pkt_state == error->pkt_state) {
58127836SJohn.Forte@Sun.COM 			*state = error->pkt_msg;
58137836SJohn.Forte@Sun.COM 			ret++;
58147836SJohn.Forte@Sun.COM 
58157836SJohn.Forte@Sun.COM 			reason_b = error->pkt_reason;
58167836SJohn.Forte@Sun.COM 			action_b = error->pkt_action;
58177836SJohn.Forte@Sun.COM 			expln_b = error->pkt_expln;
58187836SJohn.Forte@Sun.COM 
58197836SJohn.Forte@Sun.COM 			while (reason_b != NULL &&
58207836SJohn.Forte@Sun.COM 			    reason_b->reason_val != FC_REASON_INVALID) {
58217836SJohn.Forte@Sun.COM 				if (reason_b->reason_val == pkt->pkt_reason) {
58227836SJohn.Forte@Sun.COM 					*reason = reason_b->reason_msg;
58237836SJohn.Forte@Sun.COM 					ret++;
58247836SJohn.Forte@Sun.COM 					break;
58257836SJohn.Forte@Sun.COM 				}
58267836SJohn.Forte@Sun.COM 				reason_b++;
58277836SJohn.Forte@Sun.COM 			}
58287836SJohn.Forte@Sun.COM 
58297836SJohn.Forte@Sun.COM 			while (action_b != NULL &&
58307836SJohn.Forte@Sun.COM 			    action_b->action_val != FC_ACTION_INVALID) {
58317836SJohn.Forte@Sun.COM 				if (action_b->action_val == pkt->pkt_action) {
58327836SJohn.Forte@Sun.COM 					*action = action_b->action_msg;
58337836SJohn.Forte@Sun.COM 					ret++;
58347836SJohn.Forte@Sun.COM 					break;
58357836SJohn.Forte@Sun.COM 				}
58367836SJohn.Forte@Sun.COM 				action_b++;
58377836SJohn.Forte@Sun.COM 			}
58387836SJohn.Forte@Sun.COM 
58397836SJohn.Forte@Sun.COM 			while (expln_b != NULL &&
58407836SJohn.Forte@Sun.COM 			    expln_b->expln_val != FC_EXPLN_INVALID) {
58417836SJohn.Forte@Sun.COM 				if (expln_b->expln_val == pkt->pkt_expln) {
58427836SJohn.Forte@Sun.COM 					*expln = expln_b->expln_msg;
58437836SJohn.Forte@Sun.COM 					ret++;
58447836SJohn.Forte@Sun.COM 					break;
58457836SJohn.Forte@Sun.COM 				}
58467836SJohn.Forte@Sun.COM 				expln_b++;
58477836SJohn.Forte@Sun.COM 			}
58487836SJohn.Forte@Sun.COM 			break;
58497836SJohn.Forte@Sun.COM 		}
58507836SJohn.Forte@Sun.COM 	}
58517836SJohn.Forte@Sun.COM 
58527836SJohn.Forte@Sun.COM 	return (ret);
58537836SJohn.Forte@Sun.COM }
58547836SJohn.Forte@Sun.COM 
58557836SJohn.Forte@Sun.COM 
58567836SJohn.Forte@Sun.COM /*
58577836SJohn.Forte@Sun.COM  * Remove all port devices that are marked OLD, remove
58587836SJohn.Forte@Sun.COM  * corresponding node devices (fc_remote_node_t)
58597836SJohn.Forte@Sun.COM  */
58607836SJohn.Forte@Sun.COM void
fctl_remove_oldies(fc_local_port_t * port)58617836SJohn.Forte@Sun.COM fctl_remove_oldies(fc_local_port_t *port)
58627836SJohn.Forte@Sun.COM {
58637836SJohn.Forte@Sun.COM 	int			index;
58647836SJohn.Forte@Sun.COM 	int			initiator;
58657836SJohn.Forte@Sun.COM 	fc_remote_node_t	*node;
586610264SZhong.Wang@Sun.COM 	struct pwwn_hash	*head;
586710264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
586810264SZhong.Wang@Sun.COM 	fc_remote_port_t	*old_pd;
58697836SJohn.Forte@Sun.COM 	fc_remote_port_t	*last_pd;
58707836SJohn.Forte@Sun.COM 
58717836SJohn.Forte@Sun.COM 	/*
58727836SJohn.Forte@Sun.COM 	 * Nuke all OLD devices
58737836SJohn.Forte@Sun.COM 	 */
58747836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
58757836SJohn.Forte@Sun.COM 
58767836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
58777836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
58787836SJohn.Forte@Sun.COM 		last_pd = NULL;
58797836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
58807836SJohn.Forte@Sun.COM 
58817836SJohn.Forte@Sun.COM 		while (pd != NULL) {
58827836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
58837836SJohn.Forte@Sun.COM 			if (pd->pd_type != PORT_DEVICE_OLD) {
58847836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
58857836SJohn.Forte@Sun.COM 				last_pd = pd;
58867836SJohn.Forte@Sun.COM 				pd = pd->pd_wwn_hnext;
58877836SJohn.Forte@Sun.COM 				continue;
58887836SJohn.Forte@Sun.COM 			}
58897836SJohn.Forte@Sun.COM 
58907836SJohn.Forte@Sun.COM 			/*
58917836SJohn.Forte@Sun.COM 			 * Remove this from the PWWN hash table
58927836SJohn.Forte@Sun.COM 			 */
58937836SJohn.Forte@Sun.COM 			old_pd = pd;
58947836SJohn.Forte@Sun.COM 			pd = old_pd->pd_wwn_hnext;
58957836SJohn.Forte@Sun.COM 
58967836SJohn.Forte@Sun.COM 			if (last_pd == NULL) {
58977836SJohn.Forte@Sun.COM 				ASSERT(old_pd == head->pwwn_head);
58987836SJohn.Forte@Sun.COM 				head->pwwn_head = pd;
58997836SJohn.Forte@Sun.COM 			} else {
59007836SJohn.Forte@Sun.COM 				last_pd->pd_wwn_hnext = pd;
59017836SJohn.Forte@Sun.COM 			}
59027836SJohn.Forte@Sun.COM 			head->pwwn_count--;
59037836SJohn.Forte@Sun.COM 			/*
59047836SJohn.Forte@Sun.COM 			 * Make sure we tie fp_dev_count to the size of the
59057836SJohn.Forte@Sun.COM 			 * pwwn_table
59067836SJohn.Forte@Sun.COM 			 */
59077836SJohn.Forte@Sun.COM 			port->fp_dev_count--;
59087836SJohn.Forte@Sun.COM 			old_pd->pd_wwn_hnext = NULL;
59097836SJohn.Forte@Sun.COM 
59107836SJohn.Forte@Sun.COM 			fctl_delist_did_table(port, old_pd);
59117836SJohn.Forte@Sun.COM 			node = old_pd->pd_remote_nodep;
59127836SJohn.Forte@Sun.COM 			ASSERT(node != NULL);
59137836SJohn.Forte@Sun.COM 
59147836SJohn.Forte@Sun.COM 			initiator = (old_pd->pd_recepient ==
59157836SJohn.Forte@Sun.COM 			    PD_PLOGI_INITIATOR) ? 1 : 0;
59167836SJohn.Forte@Sun.COM 
59177836SJohn.Forte@Sun.COM 			mutex_exit(&old_pd->pd_mutex);
59187836SJohn.Forte@Sun.COM 
59197836SJohn.Forte@Sun.COM 			if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) {
59207836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
59217836SJohn.Forte@Sun.COM 
59227836SJohn.Forte@Sun.COM 				(void) fctl_add_orphan(port, old_pd,
59237836SJohn.Forte@Sun.COM 				    KM_NOSLEEP);
59247836SJohn.Forte@Sun.COM 			} else {
59257836SJohn.Forte@Sun.COM 				mutex_exit(&port->fp_mutex);
59267836SJohn.Forte@Sun.COM 			}
59277836SJohn.Forte@Sun.COM 
59287836SJohn.Forte@Sun.COM 			if (fctl_destroy_remote_port(port, old_pd) == 0) {
59297836SJohn.Forte@Sun.COM 				if (node) {
59307836SJohn.Forte@Sun.COM 					fctl_destroy_remote_node(node);
59317836SJohn.Forte@Sun.COM 				}
59327836SJohn.Forte@Sun.COM 			}
59337836SJohn.Forte@Sun.COM 
59347836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
59357836SJohn.Forte@Sun.COM 		}
59367836SJohn.Forte@Sun.COM 	}
59377836SJohn.Forte@Sun.COM 
59387836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
59397836SJohn.Forte@Sun.COM }
59407836SJohn.Forte@Sun.COM 
59417836SJohn.Forte@Sun.COM 
59427836SJohn.Forte@Sun.COM static void
fctl_check_alpa_list(fc_local_port_t * port,fc_remote_port_t * pd)59437836SJohn.Forte@Sun.COM fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd)
59447836SJohn.Forte@Sun.COM {
59457836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
59467836SJohn.Forte@Sun.COM 	ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
59477836SJohn.Forte@Sun.COM 
59487836SJohn.Forte@Sun.COM 	if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) {
59497836SJohn.Forte@Sun.COM 		return;
59507836SJohn.Forte@Sun.COM 	}
59517836SJohn.Forte@Sun.COM 
59527836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
59537836SJohn.Forte@Sun.COM 	    port->fp_instance, pd->pd_port_id.port_id);
59547836SJohn.Forte@Sun.COM }
59557836SJohn.Forte@Sun.COM 
59567836SJohn.Forte@Sun.COM 
59577836SJohn.Forte@Sun.COM static int
fctl_is_alpa_present(fc_local_port_t * port,uchar_t alpa)59587836SJohn.Forte@Sun.COM fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa)
59597836SJohn.Forte@Sun.COM {
59607836SJohn.Forte@Sun.COM 	int index;
59617836SJohn.Forte@Sun.COM 
59627836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
59637836SJohn.Forte@Sun.COM 	ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
59647836SJohn.Forte@Sun.COM 
59657836SJohn.Forte@Sun.COM 	for (index = 0; index < port->fp_lilp_map.lilp_length; index++) {
59667836SJohn.Forte@Sun.COM 		if (port->fp_lilp_map.lilp_alpalist[index] == alpa) {
59677836SJohn.Forte@Sun.COM 			return (FC_SUCCESS);
59687836SJohn.Forte@Sun.COM 		}
59697836SJohn.Forte@Sun.COM 	}
59707836SJohn.Forte@Sun.COM 
59717836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
59727836SJohn.Forte@Sun.COM }
59737836SJohn.Forte@Sun.COM 
59747836SJohn.Forte@Sun.COM 
59757836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_lookup_pd_by_did(fc_local_port_t * port,uint32_t d_id)59767836SJohn.Forte@Sun.COM fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
59777836SJohn.Forte@Sun.COM {
59787836SJohn.Forte@Sun.COM 	int			index;
59797836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
598010264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
59817836SJohn.Forte@Sun.COM 
59827836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
59837836SJohn.Forte@Sun.COM 
59847836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
59857836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
59867836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
59877836SJohn.Forte@Sun.COM 
59887836SJohn.Forte@Sun.COM 		while (pd != NULL) {
59897836SJohn.Forte@Sun.COM 			mutex_enter(&pd->pd_mutex);
59907836SJohn.Forte@Sun.COM 			if (pd->pd_port_id.port_id == d_id) {
59917836SJohn.Forte@Sun.COM 				mutex_exit(&pd->pd_mutex);
59927836SJohn.Forte@Sun.COM 				return (pd);
59937836SJohn.Forte@Sun.COM 			}
59947836SJohn.Forte@Sun.COM 			mutex_exit(&pd->pd_mutex);
59957836SJohn.Forte@Sun.COM 			pd = pd->pd_wwn_hnext;
59967836SJohn.Forte@Sun.COM 		}
59977836SJohn.Forte@Sun.COM 	}
59987836SJohn.Forte@Sun.COM 
59997836SJohn.Forte@Sun.COM 	return (pd);
60007836SJohn.Forte@Sun.COM }
60017836SJohn.Forte@Sun.COM 
60027836SJohn.Forte@Sun.COM 
60037836SJohn.Forte@Sun.COM /*
60047836SJohn.Forte@Sun.COM  * trace debugging
60057836SJohn.Forte@Sun.COM  */
60067836SJohn.Forte@Sun.COM void
fc_trace_debug(fc_trace_logq_t * logq,caddr_t name,int dflag,int dlevel,int errno,const char * fmt,...)60077836SJohn.Forte@Sun.COM fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
60087836SJohn.Forte@Sun.COM     int errno, const char *fmt, ...)
60097836SJohn.Forte@Sun.COM {
601010264SZhong.Wang@Sun.COM 	char	buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
60117836SJohn.Forte@Sun.COM 	char	*bufptr = buf;
60127836SJohn.Forte@Sun.COM 	va_list	ap;
60137836SJohn.Forte@Sun.COM 	int	cnt = 0;
60147836SJohn.Forte@Sun.COM 
60157836SJohn.Forte@Sun.COM 	if ((dlevel & dflag) == 0) {
60167836SJohn.Forte@Sun.COM 		return;
60177836SJohn.Forte@Sun.COM 	}
60187836SJohn.Forte@Sun.COM 
60197836SJohn.Forte@Sun.COM 	if (name) {
60207836SJohn.Forte@Sun.COM 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
602110264SZhong.Wang@Sun.COM 		    logq->il_id++, name);
60227836SJohn.Forte@Sun.COM 	} else {
60237836SJohn.Forte@Sun.COM 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
602410264SZhong.Wang@Sun.COM 		    logq->il_id++);
60257836SJohn.Forte@Sun.COM 	}
60267836SJohn.Forte@Sun.COM 
60277836SJohn.Forte@Sun.COM 	if (cnt < FC_MAX_TRACE_BUF_LEN) {
60287836SJohn.Forte@Sun.COM 		va_start(ap, fmt);
60297836SJohn.Forte@Sun.COM 		cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
603010264SZhong.Wang@Sun.COM 		    fmt, ap);
60317836SJohn.Forte@Sun.COM 		va_end(ap);
60327836SJohn.Forte@Sun.COM 	}
60337836SJohn.Forte@Sun.COM 
60347836SJohn.Forte@Sun.COM 	if (cnt > FC_MAX_TRACE_BUF_LEN) {
60357836SJohn.Forte@Sun.COM 		cnt = FC_MAX_TRACE_BUF_LEN;
60367836SJohn.Forte@Sun.COM 	}
60377836SJohn.Forte@Sun.COM 	if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) {
60387836SJohn.Forte@Sun.COM 		cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
603910264SZhong.Wang@Sun.COM 		    "error=0x%x\n", errno);
60407836SJohn.Forte@Sun.COM 	}
60417836SJohn.Forte@Sun.COM 	(void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
60427836SJohn.Forte@Sun.COM 
60437836SJohn.Forte@Sun.COM 	if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) {
60447836SJohn.Forte@Sun.COM 		fc_trace_logmsg(logq, buf, dlevel);
60457836SJohn.Forte@Sun.COM 	}
60467836SJohn.Forte@Sun.COM 
60477836SJohn.Forte@Sun.COM 	/*
60487836SJohn.Forte@Sun.COM 	 * We do not want to print the log numbers that appear as
60497836SJohn.Forte@Sun.COM 	 * random numbers at the console and messages files, to
60507836SJohn.Forte@Sun.COM 	 * the user.
60517836SJohn.Forte@Sun.COM 	 */
60527836SJohn.Forte@Sun.COM 	if ((bufptr = strchr(buf, '>')) == NULL) {
60537836SJohn.Forte@Sun.COM 		/*
60547836SJohn.Forte@Sun.COM 		 * We would have added the a string with "=>" above and so,
60557836SJohn.Forte@Sun.COM 		 * ideally, we should not get here at all. But, if we do,
60567836SJohn.Forte@Sun.COM 		 * we'll just use the full buf.
60577836SJohn.Forte@Sun.COM 		 */
60587836SJohn.Forte@Sun.COM 		bufptr = buf;
60597836SJohn.Forte@Sun.COM 	} else {
60607836SJohn.Forte@Sun.COM 		bufptr++;
60617836SJohn.Forte@Sun.COM 	}
60627836SJohn.Forte@Sun.COM 
60637836SJohn.Forte@Sun.COM 	switch (dlevel & FC_TRACE_LOG_MASK) {
60647836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_CONSOLE:
60657836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "%s", bufptr);
60667836SJohn.Forte@Sun.COM 		break;
60677836SJohn.Forte@Sun.COM 
60687836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_CONSOLE_MSG:
60697836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "%s", bufptr);
60707836SJohn.Forte@Sun.COM 		break;
60717836SJohn.Forte@Sun.COM 
60727836SJohn.Forte@Sun.COM 	case FC_TRACE_LOG_MSG:
60737836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "!%s", bufptr);
60747836SJohn.Forte@Sun.COM 		break;
60757836SJohn.Forte@Sun.COM 
60767836SJohn.Forte@Sun.COM 	default:
60777836SJohn.Forte@Sun.COM 		break;
60787836SJohn.Forte@Sun.COM 	}
60797836SJohn.Forte@Sun.COM }
60807836SJohn.Forte@Sun.COM 
60817836SJohn.Forte@Sun.COM 
60827836SJohn.Forte@Sun.COM /*
60837836SJohn.Forte@Sun.COM  * This function can block
60847836SJohn.Forte@Sun.COM  */
60857836SJohn.Forte@Sun.COM fc_trace_logq_t *
fc_trace_alloc_logq(int maxsize)60867836SJohn.Forte@Sun.COM fc_trace_alloc_logq(int maxsize)
60877836SJohn.Forte@Sun.COM {
60887836SJohn.Forte@Sun.COM 	fc_trace_logq_t *logq;
60897836SJohn.Forte@Sun.COM 
60907836SJohn.Forte@Sun.COM 	logq = kmem_zalloc(sizeof (*logq), KM_SLEEP);
60917836SJohn.Forte@Sun.COM 
60927836SJohn.Forte@Sun.COM 	mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL);
60937836SJohn.Forte@Sun.COM 	logq->il_hiwat = maxsize;
60947836SJohn.Forte@Sun.COM 	logq->il_flags |= FC_TRACE_LOGQ_V2;
60957836SJohn.Forte@Sun.COM 
60967836SJohn.Forte@Sun.COM 	return (logq);
60977836SJohn.Forte@Sun.COM }
60987836SJohn.Forte@Sun.COM 
60997836SJohn.Forte@Sun.COM 
61007836SJohn.Forte@Sun.COM void
fc_trace_free_logq(fc_trace_logq_t * logq)61017836SJohn.Forte@Sun.COM fc_trace_free_logq(fc_trace_logq_t *logq)
61027836SJohn.Forte@Sun.COM {
61037836SJohn.Forte@Sun.COM 	mutex_enter(&logq->il_lock);
61047836SJohn.Forte@Sun.COM 	while (logq->il_msgh) {
61057836SJohn.Forte@Sun.COM 		fc_trace_freemsg(logq);
61067836SJohn.Forte@Sun.COM 	}
61077836SJohn.Forte@Sun.COM 	mutex_exit(&logq->il_lock);
61087836SJohn.Forte@Sun.COM 
61097836SJohn.Forte@Sun.COM 	mutex_destroy(&logq->il_lock);
61107836SJohn.Forte@Sun.COM 	kmem_free(logq, sizeof (*logq));
61117836SJohn.Forte@Sun.COM }
61127836SJohn.Forte@Sun.COM 
61137836SJohn.Forte@Sun.COM 
61147836SJohn.Forte@Sun.COM /* ARGSUSED */
61157836SJohn.Forte@Sun.COM void
fc_trace_logmsg(fc_trace_logq_t * logq,caddr_t buf,int level)61167836SJohn.Forte@Sun.COM fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level)
61177836SJohn.Forte@Sun.COM {
61187836SJohn.Forte@Sun.COM 	int		qfull = 0;
61197836SJohn.Forte@Sun.COM 	fc_trace_dmsg_t	*dmsg;
61207836SJohn.Forte@Sun.COM 
61217836SJohn.Forte@Sun.COM 	dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP);
61227836SJohn.Forte@Sun.COM 	if (dmsg == NULL) {
61237836SJohn.Forte@Sun.COM 		mutex_enter(&logq->il_lock);
61247836SJohn.Forte@Sun.COM 		logq->il_afail++;
61257836SJohn.Forte@Sun.COM 		mutex_exit(&logq->il_lock);
61267836SJohn.Forte@Sun.COM 
61277836SJohn.Forte@Sun.COM 		return;
61287836SJohn.Forte@Sun.COM 	}
61297836SJohn.Forte@Sun.COM 
61307836SJohn.Forte@Sun.COM 	gethrestime(&dmsg->id_time);
61317836SJohn.Forte@Sun.COM 
61327836SJohn.Forte@Sun.COM 	dmsg->id_size = strlen(buf) + 1;
61337836SJohn.Forte@Sun.COM 	dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP);
61347836SJohn.Forte@Sun.COM 	if (dmsg->id_buf == NULL) {
61357836SJohn.Forte@Sun.COM 		kmem_free(dmsg, sizeof (*dmsg));
61367836SJohn.Forte@Sun.COM 
61377836SJohn.Forte@Sun.COM 		mutex_enter(&logq->il_lock);
61387836SJohn.Forte@Sun.COM 		logq->il_afail++;
61397836SJohn.Forte@Sun.COM 		mutex_exit(&logq->il_lock);
61407836SJohn.Forte@Sun.COM 
61417836SJohn.Forte@Sun.COM 		return;
61427836SJohn.Forte@Sun.COM 	}
61437836SJohn.Forte@Sun.COM 	bcopy(buf, dmsg->id_buf, strlen(buf));
61447836SJohn.Forte@Sun.COM 	dmsg->id_buf[strlen(buf)] = '\0';
61457836SJohn.Forte@Sun.COM 
61467836SJohn.Forte@Sun.COM 	mutex_enter(&logq->il_lock);
61477836SJohn.Forte@Sun.COM 
61487836SJohn.Forte@Sun.COM 	logq->il_size += dmsg->id_size;
61497836SJohn.Forte@Sun.COM 	if (logq->il_size >= logq->il_hiwat) {
61507836SJohn.Forte@Sun.COM 		qfull = 1;
61517836SJohn.Forte@Sun.COM 	}
61527836SJohn.Forte@Sun.COM 
61537836SJohn.Forte@Sun.COM 	if (qfull) {
61547836SJohn.Forte@Sun.COM 		fc_trace_freemsg(logq);
61557836SJohn.Forte@Sun.COM 	}
61567836SJohn.Forte@Sun.COM 
61577836SJohn.Forte@Sun.COM 	dmsg->id_next = NULL;
61587836SJohn.Forte@Sun.COM 	if (logq->il_msgt) {
61597836SJohn.Forte@Sun.COM 		logq->il_msgt->id_next = dmsg;
61607836SJohn.Forte@Sun.COM 	} else {
61617836SJohn.Forte@Sun.COM 		ASSERT(logq->il_msgh == NULL);
61627836SJohn.Forte@Sun.COM 		logq->il_msgh = dmsg;
61637836SJohn.Forte@Sun.COM 	}
61647836SJohn.Forte@Sun.COM 	logq->il_msgt = dmsg;
61657836SJohn.Forte@Sun.COM 
61667836SJohn.Forte@Sun.COM 	mutex_exit(&logq->il_lock);
61677836SJohn.Forte@Sun.COM }
61687836SJohn.Forte@Sun.COM 
61697836SJohn.Forte@Sun.COM 
61707836SJohn.Forte@Sun.COM static void
fc_trace_freemsg(fc_trace_logq_t * logq)61717836SJohn.Forte@Sun.COM fc_trace_freemsg(fc_trace_logq_t *logq)
61727836SJohn.Forte@Sun.COM {
61737836SJohn.Forte@Sun.COM 	fc_trace_dmsg_t	*dmsg;
61747836SJohn.Forte@Sun.COM 
61757836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&logq->il_lock));
61767836SJohn.Forte@Sun.COM 
61777836SJohn.Forte@Sun.COM 	if ((dmsg = logq->il_msgh) != NULL) {
61787836SJohn.Forte@Sun.COM 		logq->il_msgh = dmsg->id_next;
61797836SJohn.Forte@Sun.COM 		if (logq->il_msgh == NULL) {
61807836SJohn.Forte@Sun.COM 			logq->il_msgt = NULL;
61817836SJohn.Forte@Sun.COM 		}
61827836SJohn.Forte@Sun.COM 
61837836SJohn.Forte@Sun.COM 		logq->il_size -= dmsg->id_size;
61847836SJohn.Forte@Sun.COM 		kmem_free(dmsg->id_buf, dmsg->id_size);
61857836SJohn.Forte@Sun.COM 		kmem_free(dmsg, sizeof (*dmsg));
61867836SJohn.Forte@Sun.COM 	} else {
61877836SJohn.Forte@Sun.COM 		ASSERT(logq->il_msgt == NULL);
61887836SJohn.Forte@Sun.COM 	}
61897836SJohn.Forte@Sun.COM }
61907836SJohn.Forte@Sun.COM 
61917836SJohn.Forte@Sun.COM /*
61927836SJohn.Forte@Sun.COM  * Used by T11 FC-HBA to fetch discovered ports by index.
61937836SJohn.Forte@Sun.COM  * Returns NULL if the index isn't valid.
61947836SJohn.Forte@Sun.COM  */
61957836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_lookup_pd_by_index(fc_local_port_t * port,uint32_t index)61967836SJohn.Forte@Sun.COM fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
61977836SJohn.Forte@Sun.COM {
61987836SJohn.Forte@Sun.COM 	int			outer;
61997836SJohn.Forte@Sun.COM 	int			match = 0;
62007836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
620110264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
62027836SJohn.Forte@Sun.COM 
62037836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
62047836SJohn.Forte@Sun.COM 
62057836SJohn.Forte@Sun.COM 	for (outer = 0;
620610264SZhong.Wang@Sun.COM 	    outer < pwwn_table_size && match <= index;
620710264SZhong.Wang@Sun.COM 	    outer++) {
620810264SZhong.Wang@Sun.COM 		head = &port->fp_pwwn_table[outer];
620910264SZhong.Wang@Sun.COM 		pd = head->pwwn_head;
62107836SJohn.Forte@Sun.COM 		if (pd != NULL) match ++;
621110264SZhong.Wang@Sun.COM 
621210264SZhong.Wang@Sun.COM 		while (pd != NULL && match <= index) {
621310264SZhong.Wang@Sun.COM 			pd = pd->pd_wwn_hnext;
621410264SZhong.Wang@Sun.COM 			if (pd != NULL) match ++;
621510264SZhong.Wang@Sun.COM 		}
62167836SJohn.Forte@Sun.COM 	}
62177836SJohn.Forte@Sun.COM 
62187836SJohn.Forte@Sun.COM 	return (pd);
62197836SJohn.Forte@Sun.COM }
62207836SJohn.Forte@Sun.COM 
62217836SJohn.Forte@Sun.COM /*
62227836SJohn.Forte@Sun.COM  * Search for a matching Node or Port WWN in the discovered port list
62237836SJohn.Forte@Sun.COM  */
62247836SJohn.Forte@Sun.COM fc_remote_port_t *
fctl_lookup_pd_by_wwn(fc_local_port_t * port,la_wwn_t wwn)62257836SJohn.Forte@Sun.COM fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
62267836SJohn.Forte@Sun.COM {
62277836SJohn.Forte@Sun.COM 	int			index;
62287836SJohn.Forte@Sun.COM 	struct pwwn_hash	*head;
622910264SZhong.Wang@Sun.COM 	fc_remote_port_t	*pd;
62307836SJohn.Forte@Sun.COM 
62317836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&port->fp_mutex));
62327836SJohn.Forte@Sun.COM 
62337836SJohn.Forte@Sun.COM 	for (index = 0; index < pwwn_table_size; index++) {
62347836SJohn.Forte@Sun.COM 		head = &port->fp_pwwn_table[index];
62357836SJohn.Forte@Sun.COM 		pd = head->pwwn_head;
62367836SJohn.Forte@Sun.COM 
623710264SZhong.Wang@Sun.COM 		while (pd != NULL) {
623810264SZhong.Wang@Sun.COM 			mutex_enter(&pd->pd_mutex);
623910264SZhong.Wang@Sun.COM 			if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
624010264SZhong.Wang@Sun.COM 			    sizeof (la_wwn_t)) == 0) {
624110264SZhong.Wang@Sun.COM 				mutex_exit(&pd->pd_mutex);
624210264SZhong.Wang@Sun.COM 				return (pd);
624310264SZhong.Wang@Sun.COM 			}
624410264SZhong.Wang@Sun.COM 			if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn,
624510264SZhong.Wang@Sun.COM 			    wwn.raw_wwn, sizeof (la_wwn_t)) == 0) {
624610264SZhong.Wang@Sun.COM 				mutex_exit(&pd->pd_mutex);
624710264SZhong.Wang@Sun.COM 				return (pd);
624810264SZhong.Wang@Sun.COM 			}
624910264SZhong.Wang@Sun.COM 			mutex_exit(&pd->pd_mutex);
625010264SZhong.Wang@Sun.COM 			pd = pd->pd_wwn_hnext;
625110264SZhong.Wang@Sun.COM 		}
62527836SJohn.Forte@Sun.COM 	}
62537836SJohn.Forte@Sun.COM 	/* No match */
62547836SJohn.Forte@Sun.COM 	return (NULL);
62557836SJohn.Forte@Sun.COM }
62567836SJohn.Forte@Sun.COM 
62577836SJohn.Forte@Sun.COM 
62587836SJohn.Forte@Sun.COM /*
62597836SJohn.Forte@Sun.COM  * Count the number of ports on this adapter.
62607836SJohn.Forte@Sun.COM  * This routine will walk the port list and count up the number of adapters
62617836SJohn.Forte@Sun.COM  * with matching fp_hba_port_attrs.hba_fru_details.high and
62627836SJohn.Forte@Sun.COM  * fp_hba_port_attrs.hba_fru_details.low.
62637836SJohn.Forte@Sun.COM  *
62647836SJohn.Forte@Sun.COM  * port->fp_mutex must not be held.
62657836SJohn.Forte@Sun.COM  */
62667836SJohn.Forte@Sun.COM int
fctl_count_fru_ports(fc_local_port_t * port,int npivflag)62677836SJohn.Forte@Sun.COM fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
62687836SJohn.Forte@Sun.COM {
62697836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*fru;
627010264SZhong.Wang@Sun.COM 	fc_fca_port_t	*fca_port;
62717836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = NULL;
62727836SJohn.Forte@Sun.COM 	uint32_t	count = 1;
62737836SJohn.Forte@Sun.COM 
62747836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
62757836SJohn.Forte@Sun.COM 
62767836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
62777836SJohn.Forte@Sun.COM 	fru = &port->fp_hba_port_attrs.hba_fru_details;
62787836SJohn.Forte@Sun.COM 
62797836SJohn.Forte@Sun.COM 	/* Detect FCA drivers that don't support linking HBA ports */
62807836SJohn.Forte@Sun.COM 	if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
62817836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
62827836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
62837836SJohn.Forte@Sun.COM 		return (1);
62847836SJohn.Forte@Sun.COM 	}
62857836SJohn.Forte@Sun.COM 
62867836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
62877836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
628810264SZhong.Wang@Sun.COM 		tmpPort = fca_port->port_handle;
628910264SZhong.Wang@Sun.COM 		if (tmpPort == port) {
629010264SZhong.Wang@Sun.COM 			continue;
629110264SZhong.Wang@Sun.COM 		}
629210264SZhong.Wang@Sun.COM 		mutex_enter(&tmpPort->fp_mutex);
62937836SJohn.Forte@Sun.COM 
62947836SJohn.Forte@Sun.COM 		/*
62957836SJohn.Forte@Sun.COM 		 * If an FCA driver returns unique fru->high and fru->low for
62967836SJohn.Forte@Sun.COM 		 * ports on the same card, there is no way for the transport
62977836SJohn.Forte@Sun.COM 		 * layer to determine that the two ports on the same FRU. So,
62987836SJohn.Forte@Sun.COM 		 * the discovery of the ports on a same FRU  is limited to what
62997836SJohn.Forte@Sun.COM 		 * the FCA driver can report back.
63007836SJohn.Forte@Sun.COM 		 */
63017836SJohn.Forte@Sun.COM 		if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
63027836SJohn.Forte@Sun.COM 		    fru->high &&
63037836SJohn.Forte@Sun.COM 		    tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
63047836SJohn.Forte@Sun.COM 		    fru->low) {
63057836SJohn.Forte@Sun.COM 			/* Now double check driver */
63067836SJohn.Forte@Sun.COM 			if (strncmp(port->fp_hba_port_attrs.driver_name,
63077836SJohn.Forte@Sun.COM 			    tmpPort->fp_hba_port_attrs.driver_name,
63087836SJohn.Forte@Sun.COM 			    FCHBA_DRIVER_NAME_LEN) == 0) {
63097836SJohn.Forte@Sun.COM 				if (!npivflag ||
63107836SJohn.Forte@Sun.COM 				    (tmpPort->fp_npiv_type != FC_NPIV_PORT)) {
63117836SJohn.Forte@Sun.COM 					count++;
63127836SJohn.Forte@Sun.COM 				}
63137836SJohn.Forte@Sun.COM 			} /* Else, different FCA driver */
63147836SJohn.Forte@Sun.COM 		} /* Else not the same HBA FRU */
63157836SJohn.Forte@Sun.COM 		mutex_exit(&tmpPort->fp_mutex);
63167836SJohn.Forte@Sun.COM 	}
63177836SJohn.Forte@Sun.COM 
63187836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
63197836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
63207836SJohn.Forte@Sun.COM 
63217836SJohn.Forte@Sun.COM 	return (count);
63227836SJohn.Forte@Sun.COM }
63237836SJohn.Forte@Sun.COM 
63247836SJohn.Forte@Sun.COM fc_fca_port_t *
fctl_local_port_list_add(fc_fca_port_t * list,fc_local_port_t * port)63257836SJohn.Forte@Sun.COM fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port)
63267836SJohn.Forte@Sun.COM {
63277836SJohn.Forte@Sun.COM 	fc_fca_port_t *tmp = list, *newentry = NULL;
63287836SJohn.Forte@Sun.COM 
63297836SJohn.Forte@Sun.COM 	newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP);
63307836SJohn.Forte@Sun.COM 	if (newentry == NULL) {
63317836SJohn.Forte@Sun.COM 		return (list);
63327836SJohn.Forte@Sun.COM 	}
63337836SJohn.Forte@Sun.COM 	newentry->port_handle = port;
63347836SJohn.Forte@Sun.COM 
63357836SJohn.Forte@Sun.COM 	if (tmp == NULL) {
63367836SJohn.Forte@Sun.COM 		return (newentry);
63377836SJohn.Forte@Sun.COM 	}
63387836SJohn.Forte@Sun.COM 	while (tmp->port_next != NULL)	tmp = tmp->port_next;
63397836SJohn.Forte@Sun.COM 	tmp->port_next = newentry;
63407836SJohn.Forte@Sun.COM 
63417836SJohn.Forte@Sun.COM 	return (list);
63427836SJohn.Forte@Sun.COM }
63437836SJohn.Forte@Sun.COM 
63447836SJohn.Forte@Sun.COM void
fctl_local_port_list_free(fc_fca_port_t * list)63457836SJohn.Forte@Sun.COM fctl_local_port_list_free(fc_fca_port_t *list)
63467836SJohn.Forte@Sun.COM {
63477836SJohn.Forte@Sun.COM 	fc_fca_port_t *tmp = list, *nextentry;
63487836SJohn.Forte@Sun.COM 
63497836SJohn.Forte@Sun.COM 	if (tmp == NULL) {
63507836SJohn.Forte@Sun.COM 		return;
63517836SJohn.Forte@Sun.COM 	}
63527836SJohn.Forte@Sun.COM 
63537836SJohn.Forte@Sun.COM 	while (tmp != NULL) {
63547836SJohn.Forte@Sun.COM 		nextentry = tmp->port_next;
63557836SJohn.Forte@Sun.COM 		kmem_free(tmp, sizeof (*tmp));
63567836SJohn.Forte@Sun.COM 		tmp = nextentry;
63577836SJohn.Forte@Sun.COM 	}
63587836SJohn.Forte@Sun.COM }
63597836SJohn.Forte@Sun.COM 
63607836SJohn.Forte@Sun.COM /*
63617836SJohn.Forte@Sun.COM  * Fetch another port on the HBA FRU based on index.
63627836SJohn.Forte@Sun.COM  * Returns NULL if index not found.
63637836SJohn.Forte@Sun.COM  *
63647836SJohn.Forte@Sun.COM  * port->fp_mutex must not be held.
63657836SJohn.Forte@Sun.COM  */
63667836SJohn.Forte@Sun.COM fc_local_port_t *
fctl_get_adapter_port_by_index(fc_local_port_t * port,uint32_t port_index)63677836SJohn.Forte@Sun.COM fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
63687836SJohn.Forte@Sun.COM {
63697836SJohn.Forte@Sun.COM 	fca_hba_fru_details_t	*fru;
637010264SZhong.Wang@Sun.COM 	fc_fca_port_t	*fca_port;
63717836SJohn.Forte@Sun.COM 	fc_local_port_t	*tmpPort = NULL;
63727836SJohn.Forte@Sun.COM 	fc_fca_port_t	*list = NULL, *tmpEntry;
63737836SJohn.Forte@Sun.COM 	fc_local_port_t		*phyPort, *virPort = NULL;
63747836SJohn.Forte@Sun.COM 	int	index, phyPortNum = 0;
63757836SJohn.Forte@Sun.COM 
63767836SJohn.Forte@Sun.COM 	mutex_enter(&fctl_port_lock);
63777836SJohn.Forte@Sun.COM 
63787836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
63797836SJohn.Forte@Sun.COM 	fru = &port->fp_hba_port_attrs.hba_fru_details;
63807836SJohn.Forte@Sun.COM 
63817836SJohn.Forte@Sun.COM 	/* Are we looking for this port? */
63827836SJohn.Forte@Sun.COM 	if (fru->port_index == port_index) {
63837836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
63847836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
63857836SJohn.Forte@Sun.COM 		return (port);
63867836SJohn.Forte@Sun.COM 	}
63877836SJohn.Forte@Sun.COM 
63887836SJohn.Forte@Sun.COM 	/* Detect FCA drivers that don't support linking HBA ports */
63897836SJohn.Forte@Sun.COM 	if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
63907836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
63917836SJohn.Forte@Sun.COM 		mutex_exit(&fctl_port_lock);
63927836SJohn.Forte@Sun.COM 		return (NULL);
63937836SJohn.Forte@Sun.COM 	}
63947836SJohn.Forte@Sun.COM 
63957836SJohn.Forte@Sun.COM 	list = fctl_local_port_list_add(list, port);
63967836SJohn.Forte@Sun.COM 	phyPortNum++;
63977836SJohn.Forte@Sun.COM 	/* Loop through all known ports */
63987836SJohn.Forte@Sun.COM 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
63997836SJohn.Forte@Sun.COM 	    fca_port = fca_port->port_next) {
640010264SZhong.Wang@Sun.COM 		tmpPort = fca_port->port_handle;
640110264SZhong.Wang@Sun.COM 		if (tmpPort == port) {
640210264SZhong.Wang@Sun.COM 			/* Skip the port that was passed in as the argument */
640310264SZhong.Wang@Sun.COM 			continue;
640410264SZhong.Wang@Sun.COM 		}
640510264SZhong.Wang@Sun.COM 		mutex_enter(&tmpPort->fp_mutex);
640610264SZhong.Wang@Sun.COM 
640710264SZhong.Wang@Sun.COM 		/* See if this port is on the same HBA FRU (fast check) */
640810264SZhong.Wang@Sun.COM 		if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
64097836SJohn.Forte@Sun.COM 		    fru->high &&
64107836SJohn.Forte@Sun.COM 		    tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
64117836SJohn.Forte@Sun.COM 		    fru->low) {
641210264SZhong.Wang@Sun.COM 			/* Now double check driver (slower check) */
641310264SZhong.Wang@Sun.COM 			if (strncmp(port->fp_hba_port_attrs.driver_name,
641410264SZhong.Wang@Sun.COM 			    tmpPort->fp_hba_port_attrs.driver_name,
641510264SZhong.Wang@Sun.COM 			    FCHBA_DRIVER_NAME_LEN) == 0) {
641610264SZhong.Wang@Sun.COM 
641710264SZhong.Wang@Sun.COM 				fru =
641810264SZhong.Wang@Sun.COM 				    &tmpPort->fp_hba_port_attrs.hba_fru_details;
641910264SZhong.Wang@Sun.COM 				/* Check for the matching port_index */
642010264SZhong.Wang@Sun.COM 				if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
642110264SZhong.Wang@Sun.COM 				    (fru->port_index == port_index)) {
642210264SZhong.Wang@Sun.COM 					/* Found it! */
642310264SZhong.Wang@Sun.COM 					mutex_exit(&tmpPort->fp_mutex);
642410264SZhong.Wang@Sun.COM 					mutex_exit(&port->fp_mutex);
642510264SZhong.Wang@Sun.COM 					mutex_exit(&fctl_port_lock);
642610264SZhong.Wang@Sun.COM 					fctl_local_port_list_free(list);
642710264SZhong.Wang@Sun.COM 					return (tmpPort);
642810264SZhong.Wang@Sun.COM 				}
642910264SZhong.Wang@Sun.COM 				if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
643010264SZhong.Wang@Sun.COM 					(void) fctl_local_port_list_add(list,
643110264SZhong.Wang@Sun.COM 					    tmpPort);
643210264SZhong.Wang@Sun.COM 					phyPortNum++;
643310264SZhong.Wang@Sun.COM 				}
643410264SZhong.Wang@Sun.COM 			} /* Else, different FCA driver */
643510264SZhong.Wang@Sun.COM 		} /* Else not the same HBA FRU */
643610264SZhong.Wang@Sun.COM 		mutex_exit(&tmpPort->fp_mutex);
64377836SJohn.Forte@Sun.COM 
64387836SJohn.Forte@Sun.COM 	}
64397836SJohn.Forte@Sun.COM 
64407836SJohn.Forte@Sun.COM 	/* scan all physical port on same chip to find virtual port */
64417836SJohn.Forte@Sun.COM 	tmpEntry = list;
64427836SJohn.Forte@Sun.COM 	index = phyPortNum - 1;
64437836SJohn.Forte@Sun.COM 	virPort = NULL;
64447836SJohn.Forte@Sun.COM 	while (index < port_index) {
64457836SJohn.Forte@Sun.COM 		if (tmpEntry == NULL) {
64467836SJohn.Forte@Sun.COM 			break;
64477836SJohn.Forte@Sun.COM 		}
64487836SJohn.Forte@Sun.COM 		if (virPort == NULL) {
64497836SJohn.Forte@Sun.COM 			phyPort = tmpEntry->port_handle;
64507836SJohn.Forte@Sun.COM 			virPort = phyPort->fp_port_next;
64517836SJohn.Forte@Sun.COM 			if (virPort == NULL) {
64527836SJohn.Forte@Sun.COM 				tmpEntry = tmpEntry->port_next;
64537836SJohn.Forte@Sun.COM 				continue;
64547836SJohn.Forte@Sun.COM 			}
64557836SJohn.Forte@Sun.COM 		} else {
64567836SJohn.Forte@Sun.COM 			virPort = virPort->fp_port_next;
64577836SJohn.Forte@Sun.COM 		}
64587836SJohn.Forte@Sun.COM 		if (virPort == phyPort) {
64597836SJohn.Forte@Sun.COM 			tmpEntry = tmpEntry->port_next;
64607836SJohn.Forte@Sun.COM 			virPort = NULL;
64617836SJohn.Forte@Sun.COM 		} else {
64627836SJohn.Forte@Sun.COM 			index++;
64637836SJohn.Forte@Sun.COM 		}
64647836SJohn.Forte@Sun.COM 	}
64657836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
64667836SJohn.Forte@Sun.COM 	mutex_exit(&fctl_port_lock);
64677836SJohn.Forte@Sun.COM 
64687836SJohn.Forte@Sun.COM 	fctl_local_port_list_free(list);
64697836SJohn.Forte@Sun.COM 	if (virPort) {
64707836SJohn.Forte@Sun.COM 		return (virPort);
64717836SJohn.Forte@Sun.COM 	}
64727836SJohn.Forte@Sun.COM 	return (NULL);
64737836SJohn.Forte@Sun.COM }
64747836SJohn.Forte@Sun.COM 
64757836SJohn.Forte@Sun.COM int
fctl_busy_port(fc_local_port_t * port)64767836SJohn.Forte@Sun.COM fctl_busy_port(fc_local_port_t *port)
64777836SJohn.Forte@Sun.COM {
64787836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
64797836SJohn.Forte@Sun.COM 
64807836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
64817836SJohn.Forte@Sun.COM 	if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
64827836SJohn.Forte@Sun.COM 		/*
64837836SJohn.Forte@Sun.COM 		 * If fctl_busy_port() is called before we've registered our
64847836SJohn.Forte@Sun.COM 		 * PM components, we return success. We need to be aware of
64857836SJohn.Forte@Sun.COM 		 * this because the caller will eventually call fctl_idle_port.
64867836SJohn.Forte@Sun.COM 		 * This wouldn't be a problem except that if we have
64877836SJohn.Forte@Sun.COM 		 * registered our PM components in the meantime, we will
64887836SJohn.Forte@Sun.COM 		 * then be idling a component that was never busied.  PM
648910264SZhong.Wang@Sun.COM 		 * will be very unhappy if we do this.	Thus, we keep
64907836SJohn.Forte@Sun.COM 		 * track of this with port->fp_pm_busy_nocomp.
64917836SJohn.Forte@Sun.COM 		 */
64927836SJohn.Forte@Sun.COM 		port->fp_pm_busy_nocomp++;
64937836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
64947836SJohn.Forte@Sun.COM 		return (0);
64957836SJohn.Forte@Sun.COM 	}
64967836SJohn.Forte@Sun.COM 	port->fp_pm_busy++;
64977836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
64987836SJohn.Forte@Sun.COM 
64997836SJohn.Forte@Sun.COM 	if (pm_busy_component(port->fp_port_dip,
65007836SJohn.Forte@Sun.COM 	    FP_PM_COMPONENT) != DDI_SUCCESS) {
65017836SJohn.Forte@Sun.COM 		mutex_enter(&port->fp_mutex);
65027836SJohn.Forte@Sun.COM 		port->fp_pm_busy--;
65037836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
65047836SJohn.Forte@Sun.COM 		return (ENXIO);
65057836SJohn.Forte@Sun.COM 	}
65067836SJohn.Forte@Sun.COM 
65077836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
65087836SJohn.Forte@Sun.COM 	if (port->fp_pm_level == FP_PM_PORT_DOWN) {
65097836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
65107836SJohn.Forte@Sun.COM 		if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT,
65117836SJohn.Forte@Sun.COM 		    FP_PM_PORT_UP) != DDI_SUCCESS) {
65127836SJohn.Forte@Sun.COM 
65137836SJohn.Forte@Sun.COM 			mutex_enter(&port->fp_mutex);
65147836SJohn.Forte@Sun.COM 			port->fp_pm_busy--;
65157836SJohn.Forte@Sun.COM 			mutex_exit(&port->fp_mutex);
65167836SJohn.Forte@Sun.COM 
65177836SJohn.Forte@Sun.COM 			(void) pm_idle_component(port->fp_port_dip,
65187836SJohn.Forte@Sun.COM 			    FP_PM_COMPONENT);
65197836SJohn.Forte@Sun.COM 			return (EIO);
65207836SJohn.Forte@Sun.COM 		}
65217836SJohn.Forte@Sun.COM 		return (0);
65227836SJohn.Forte@Sun.COM 	}
65237836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
65247836SJohn.Forte@Sun.COM 	return (0);
65257836SJohn.Forte@Sun.COM }
65267836SJohn.Forte@Sun.COM 
65277836SJohn.Forte@Sun.COM void
fctl_idle_port(fc_local_port_t * port)65287836SJohn.Forte@Sun.COM fctl_idle_port(fc_local_port_t *port)
65297836SJohn.Forte@Sun.COM {
65307836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
65317836SJohn.Forte@Sun.COM 
65327836SJohn.Forte@Sun.COM 	mutex_enter(&port->fp_mutex);
65337836SJohn.Forte@Sun.COM 
65347836SJohn.Forte@Sun.COM 	/*
65357836SJohn.Forte@Sun.COM 	 * If port->fp_pm_busy_nocomp is > 0, that means somebody had
65367836SJohn.Forte@Sun.COM 	 * called fctl_busy_port prior to us registering our PM components.
65377836SJohn.Forte@Sun.COM 	 * In that case, we just decrement fp_pm_busy_nocomp and return.
65387836SJohn.Forte@Sun.COM 	 */
65397836SJohn.Forte@Sun.COM 
65407836SJohn.Forte@Sun.COM 	if (port->fp_pm_busy_nocomp > 0) {
65417836SJohn.Forte@Sun.COM 		port->fp_pm_busy_nocomp--;
65427836SJohn.Forte@Sun.COM 		mutex_exit(&port->fp_mutex);
65437836SJohn.Forte@Sun.COM 		return;
65447836SJohn.Forte@Sun.COM 	}
65457836SJohn.Forte@Sun.COM 
65467836SJohn.Forte@Sun.COM 	port->fp_pm_busy--;
65477836SJohn.Forte@Sun.COM 	mutex_exit(&port->fp_mutex);
65487836SJohn.Forte@Sun.COM 
65497836SJohn.Forte@Sun.COM 	(void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT);
65507836SJohn.Forte@Sun.COM }
65517836SJohn.Forte@Sun.COM 
65527836SJohn.Forte@Sun.COM /*
65537836SJohn.Forte@Sun.COM  *     Function: fctl_tc_timer
65547836SJohn.Forte@Sun.COM  *
65557836SJohn.Forte@Sun.COM  *  Description: Resets the value of the timed counter.
65567836SJohn.Forte@Sun.COM  *
65577836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter
65587836SJohn.Forte@Sun.COM  *
65597836SJohn.Forte@Sun.COM  * Return Value: Nothing
65607836SJohn.Forte@Sun.COM  *
656110264SZhong.Wang@Sun.COM  *	Context: Kernel context.
65627836SJohn.Forte@Sun.COM  */
65637836SJohn.Forte@Sun.COM static void
fctl_tc_timer(void * arg)656410264SZhong.Wang@Sun.COM fctl_tc_timer(void *arg)
65657836SJohn.Forte@Sun.COM {
65667836SJohn.Forte@Sun.COM 	timed_counter_t	*tc = (timed_counter_t *)arg;
65677836SJohn.Forte@Sun.COM 
65687836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
65697836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
65707836SJohn.Forte@Sun.COM 
65717836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
65727836SJohn.Forte@Sun.COM 	if (tc->active) {
65737836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
65747836SJohn.Forte@Sun.COM 		tc->counter = 0;
65757836SJohn.Forte@Sun.COM 	}
65767836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
65777836SJohn.Forte@Sun.COM }
65787836SJohn.Forte@Sun.COM 
65797836SJohn.Forte@Sun.COM /*
65807836SJohn.Forte@Sun.COM  *     Function: fctl_tc_constructor
65817836SJohn.Forte@Sun.COM  *
65827836SJohn.Forte@Sun.COM  *  Description: Constructs a timed counter.
65837836SJohn.Forte@Sun.COM  *
65847836SJohn.Forte@Sun.COM  *    Arguments: *tc		Address where the timed counter will reside.
658510264SZhong.Wang@Sun.COM  *		 max_value	Maximum value the counter is allowed to take.
65867836SJohn.Forte@Sun.COM  *		 timer		Number of microseconds after which the counter
65877836SJohn.Forte@Sun.COM  *				will be reset. The timer is started when the
65887836SJohn.Forte@Sun.COM  *				value of the counter goes from 0 to 1.
65897836SJohn.Forte@Sun.COM  *
65907836SJohn.Forte@Sun.COM  * Return Value: Nothing
65917836SJohn.Forte@Sun.COM  *
659210264SZhong.Wang@Sun.COM  *	Context: Kernel context.
65937836SJohn.Forte@Sun.COM  */
65947836SJohn.Forte@Sun.COM void
fctl_tc_constructor(timed_counter_t * tc,uint32_t max_value,clock_t timer)659510264SZhong.Wang@Sun.COM fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer)
65967836SJohn.Forte@Sun.COM {
65977836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
65987836SJohn.Forte@Sun.COM 	ASSERT(tc->sig != tc);
65997836SJohn.Forte@Sun.COM 
66007836SJohn.Forte@Sun.COM 	bzero(tc, sizeof (*tc));
66017836SJohn.Forte@Sun.COM 	mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL);
66027836SJohn.Forte@Sun.COM 	tc->timer = drv_usectohz(timer);
66037836SJohn.Forte@Sun.COM 	tc->active = B_FALSE;
66047836SJohn.Forte@Sun.COM 	tc->maxed_out = B_FALSE;
66057836SJohn.Forte@Sun.COM 	tc->max_value = max_value;
66067836SJohn.Forte@Sun.COM 	tc->sig = tc;
66077836SJohn.Forte@Sun.COM }
66087836SJohn.Forte@Sun.COM 
66097836SJohn.Forte@Sun.COM /*
66107836SJohn.Forte@Sun.COM  *     Function: fctl_tc_destructor
66117836SJohn.Forte@Sun.COM  *
66127836SJohn.Forte@Sun.COM  *  Description: Destroyes a timed counter.
66137836SJohn.Forte@Sun.COM  *
66147836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to destroy.
66157836SJohn.Forte@Sun.COM  *
66167836SJohn.Forte@Sun.COM  * Return Value: Nothing
66177836SJohn.Forte@Sun.COM  *
661810264SZhong.Wang@Sun.COM  *	Context: Kernel context.
66197836SJohn.Forte@Sun.COM  */
66207836SJohn.Forte@Sun.COM void
fctl_tc_destructor(timed_counter_t * tc)662110264SZhong.Wang@Sun.COM fctl_tc_destructor(timed_counter_t *tc)
66227836SJohn.Forte@Sun.COM {
66237836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
66247836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
66257836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&tc->mutex));
66267836SJohn.Forte@Sun.COM 
66277836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
66287836SJohn.Forte@Sun.COM 	if (tc->active) {
66297836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
6630*11922SSriram.Popuri@sun.com 		mutex_exit(&tc->mutex);
66317836SJohn.Forte@Sun.COM 		(void) untimeout(tc->tid);
6632*11922SSriram.Popuri@sun.com 		mutex_enter(&tc->mutex);
66337836SJohn.Forte@Sun.COM 		tc->sig = NULL;
66347836SJohn.Forte@Sun.COM 	}
66357836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
66367836SJohn.Forte@Sun.COM 	mutex_destroy(&tc->mutex);
66377836SJohn.Forte@Sun.COM }
66387836SJohn.Forte@Sun.COM 
66397836SJohn.Forte@Sun.COM /*
66407836SJohn.Forte@Sun.COM  *     Function: fctl_tc_increment
66417836SJohn.Forte@Sun.COM  *
66427836SJohn.Forte@Sun.COM  *  Description: Increments a timed counter
66437836SJohn.Forte@Sun.COM  *
66447836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to increment.
66457836SJohn.Forte@Sun.COM  *
66467836SJohn.Forte@Sun.COM  * Return Value: B_TRUE		Counter reached the max value.
66477836SJohn.Forte@Sun.COM  *		 B_FALSE	Counter hasn't reached the max value.
66487836SJohn.Forte@Sun.COM  *
664910264SZhong.Wang@Sun.COM  *	Context: Kernel or interrupt context.
66507836SJohn.Forte@Sun.COM  */
66517836SJohn.Forte@Sun.COM boolean_t
fctl_tc_increment(timed_counter_t * tc)665210264SZhong.Wang@Sun.COM fctl_tc_increment(timed_counter_t *tc)
66537836SJohn.Forte@Sun.COM {
66547836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
66557836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
66567836SJohn.Forte@Sun.COM 
66577836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
66587836SJohn.Forte@Sun.COM 	if (!tc->maxed_out) {
66597836SJohn.Forte@Sun.COM 		/* Hasn't maxed out yet. */
66607836SJohn.Forte@Sun.COM 		++tc->counter;
66617836SJohn.Forte@Sun.COM 		if (tc->counter >= tc->max_value) {
66627836SJohn.Forte@Sun.COM 			/* Just maxed out. */
66637836SJohn.Forte@Sun.COM 			tc->maxed_out = B_TRUE;
66647836SJohn.Forte@Sun.COM 		}
66657836SJohn.Forte@Sun.COM 		if (!tc->active) {
66667836SJohn.Forte@Sun.COM 			tc->tid = timeout(fctl_tc_timer, tc, tc->timer);
66677836SJohn.Forte@Sun.COM 			tc->active = B_TRUE;
66687836SJohn.Forte@Sun.COM 		}
66697836SJohn.Forte@Sun.COM 	}
66707836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
66717836SJohn.Forte@Sun.COM 
66727836SJohn.Forte@Sun.COM 	return (tc->maxed_out);
66737836SJohn.Forte@Sun.COM }
66747836SJohn.Forte@Sun.COM 
66757836SJohn.Forte@Sun.COM /*
66767836SJohn.Forte@Sun.COM  *     Function: fctl_tc_reset
66777836SJohn.Forte@Sun.COM  *
66787836SJohn.Forte@Sun.COM  *  Description: Resets a timed counter.  The caller of this function has to
66797836SJohn.Forte@Sun.COM  *		 to make sure that while in fctl_tc_reset() fctl_tc_increment()
66807836SJohn.Forte@Sun.COM  *		 is not called.
66817836SJohn.Forte@Sun.COM  *
66827836SJohn.Forte@Sun.COM  *    Arguments: *tc		Timed counter to reset.
66837836SJohn.Forte@Sun.COM  *
66847836SJohn.Forte@Sun.COM  * Return Value: 0		Counter reached the max value.
66857836SJohn.Forte@Sun.COM  *		 Not 0		Counter hasn't reached the max value.
66867836SJohn.Forte@Sun.COM  *
668710264SZhong.Wang@Sun.COM  *	Context: Kernel or interrupt context.
66887836SJohn.Forte@Sun.COM  */
66897836SJohn.Forte@Sun.COM void
fctl_tc_reset(timed_counter_t * tc)669010264SZhong.Wang@Sun.COM fctl_tc_reset(timed_counter_t *tc)
66917836SJohn.Forte@Sun.COM {
66927836SJohn.Forte@Sun.COM 	ASSERT(tc != NULL);
66937836SJohn.Forte@Sun.COM 	ASSERT(tc->sig == tc);
66947836SJohn.Forte@Sun.COM 
66957836SJohn.Forte@Sun.COM 	mutex_enter(&tc->mutex);
66967836SJohn.Forte@Sun.COM 	tc->counter = 0;
66977836SJohn.Forte@Sun.COM 	tc->maxed_out = B_FALSE;
66987836SJohn.Forte@Sun.COM 	if (tc->active) {
66997836SJohn.Forte@Sun.COM 		tc->active = B_FALSE;
67007836SJohn.Forte@Sun.COM 		(void) untimeout(tc->tid);
67017836SJohn.Forte@Sun.COM 	}
67027836SJohn.Forte@Sun.COM 	mutex_exit(&tc->mutex);
67037836SJohn.Forte@Sun.COM }
67047836SJohn.Forte@Sun.COM 
67057836SJohn.Forte@Sun.COM void
fc_ulp_log_device_event(opaque_t port_handle,int type)67067836SJohn.Forte@Sun.COM fc_ulp_log_device_event(opaque_t port_handle, int type)
67077836SJohn.Forte@Sun.COM {
67087836SJohn.Forte@Sun.COM 	fc_local_port_t *port = port_handle;
67097836SJohn.Forte@Sun.COM 	nvlist_t *attr_list;
67107836SJohn.Forte@Sun.COM 
67117836SJohn.Forte@Sun.COM 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
67127836SJohn.Forte@Sun.COM 	    KM_SLEEP) != DDI_SUCCESS) {
67137836SJohn.Forte@Sun.COM 		return;
67147836SJohn.Forte@Sun.COM 	}
67157836SJohn.Forte@Sun.COM 
67167836SJohn.Forte@Sun.COM 	if (nvlist_add_uint32(attr_list, "instance",
67177836SJohn.Forte@Sun.COM 	    port->fp_instance) != DDI_SUCCESS) {
67187836SJohn.Forte@Sun.COM 		goto error;
67197836SJohn.Forte@Sun.COM 	}
67207836SJohn.Forte@Sun.COM 
67217836SJohn.Forte@Sun.COM 	if (nvlist_add_byte_array(attr_list, "port-wwn",
67227836SJohn.Forte@Sun.COM 	    port->fp_service_params.nport_ww_name.raw_wwn,
67237836SJohn.Forte@Sun.COM 	    sizeof (la_wwn_t)) != DDI_SUCCESS) {
67247836SJohn.Forte@Sun.COM 		goto error;
67257836SJohn.Forte@Sun.COM 	}
67267836SJohn.Forte@Sun.COM 
67277836SJohn.Forte@Sun.COM 	(void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
67287836SJohn.Forte@Sun.COM 	    (type == FC_ULP_DEVICE_ONLINE) ?
67297836SJohn.Forte@Sun.COM 	    ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE,
67307836SJohn.Forte@Sun.COM 	    attr_list, NULL, DDI_SLEEP);
67317836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
67327836SJohn.Forte@Sun.COM 	return;
67337836SJohn.Forte@Sun.COM 
67347836SJohn.Forte@Sun.COM error:
67357836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
67367836SJohn.Forte@Sun.COM }
6737